diff --git a/.cspell/frigate-dictionary.txt b/.cspell/frigate-dictionary.txt index dbab9600e..77e4ede62 100644 --- a/.cspell/frigate-dictionary.txt +++ b/.cspell/frigate-dictionary.txt @@ -108,7 +108,6 @@ imagestream imdecode imencode imread -imutils imwrite interp iostat diff --git a/.github/DISCUSSION_TEMPLATE/camera-support.yml b/.github/DISCUSSION_TEMPLATE/camera-support.yml index a76fd5caf..521d65ded 100644 --- a/.github/DISCUSSION_TEMPLATE/camera-support.yml +++ b/.github/DISCUSSION_TEMPLATE/camera-support.yml @@ -73,7 +73,7 @@ body: attributes: label: Operating system options: - - HassOS + - Home Assistant OS - Debian - Other Linux - Proxmox @@ -87,7 +87,7 @@ body: attributes: label: Install method options: - - HassOS Addon + - Home Assistant Add-on - Docker Compose - Docker CLI - Proxmox via Docker diff --git a/.github/DISCUSSION_TEMPLATE/config-support.yml b/.github/DISCUSSION_TEMPLATE/config-support.yml index 4934d7936..575f7f640 100644 --- a/.github/DISCUSSION_TEMPLATE/config-support.yml +++ b/.github/DISCUSSION_TEMPLATE/config-support.yml @@ -59,7 +59,7 @@ body: attributes: label: Operating system options: - - HassOS + - Home Assistant OS - Debian - Other Linux - Proxmox @@ -73,7 +73,7 @@ body: attributes: label: Install method options: - - HassOS Addon + - Home Assistant Add-on - Docker Compose - Docker CLI - Proxmox via Docker diff --git a/.github/DISCUSSION_TEMPLATE/detector-support.yml b/.github/DISCUSSION_TEMPLATE/detector-support.yml index 442b2527a..fb994500f 100644 --- a/.github/DISCUSSION_TEMPLATE/detector-support.yml +++ b/.github/DISCUSSION_TEMPLATE/detector-support.yml @@ -53,7 +53,7 @@ body: attributes: label: Install method options: - - HassOS Addon + - Home Assistant Add-on - Docker Compose - Docker CLI - Proxmox via Docker diff --git a/.github/DISCUSSION_TEMPLATE/general-support.yml b/.github/DISCUSSION_TEMPLATE/general-support.yml index 7af52bdf5..0b9f225b6 100644 --- a/.github/DISCUSSION_TEMPLATE/general-support.yml +++ b/.github/DISCUSSION_TEMPLATE/general-support.yml @@ -73,7 +73,7 @@ body: attributes: label: Install method options: - - HassOS Addon + - Home Assistant Add-on - Docker Compose - Docker CLI - Proxmox via Docker diff --git a/.github/DISCUSSION_TEMPLATE/hardware-acceleration-support.yml b/.github/DISCUSSION_TEMPLATE/hardware-acceleration-support.yml index 43fb3503b..861156696 100644 --- a/.github/DISCUSSION_TEMPLATE/hardware-acceleration-support.yml +++ b/.github/DISCUSSION_TEMPLATE/hardware-acceleration-support.yml @@ -69,7 +69,7 @@ body: attributes: label: Install method options: - - HassOS Addon + - Home Assistant Add-on - Docker Compose - Docker CLI - Proxmox via Docker diff --git a/.github/DISCUSSION_TEMPLATE/report-a-bug.yml b/.github/DISCUSSION_TEMPLATE/report-a-bug.yml index dba6d695e..21e4f746f 100644 --- a/.github/DISCUSSION_TEMPLATE/report-a-bug.yml +++ b/.github/DISCUSSION_TEMPLATE/report-a-bug.yml @@ -97,7 +97,7 @@ body: attributes: label: Operating system options: - - HassOS + - Home Assistant OS - Debian - Other Linux - Proxmox @@ -111,7 +111,7 @@ body: attributes: label: Install method options: - - HassOS Addon + - Home Assistant Add-on - Docker Compose - Docker CLI validations: diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 69425b735..3204244a6 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,12 +2,12 @@ @@ -24,7 +24,7 @@ ## Additional information - This PR fixes or closes issue: fixes # -- This PR is related to issue: +- This PR is related to issue: ## Checklist @@ -35,4 +35,5 @@ - [ ] The code change is tested and works locally. - [ ] Local tests pass. **Your PR cannot be merged unless tests pass** - [ ] There is no commented out code in this PR. +- [ ] UI changes including text have used i18n keys and have been added to the `en` locale. - [ ] The code has been formatted using Ruff (`ruff format frigate`) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5778d32d1..6c19ca6cb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,14 +39,14 @@ jobs: STABLE_TAG=${BASE}:stable PULL_TAG=${BASE}:${BUILD_TAG} docker run --rm -v $HOME/.docker/config.json:/config.json quay.io/skopeo/stable:latest copy --authfile /config.json --multi-arch all docker://${PULL_TAG} docker://${VERSION_TAG} - for variant in standard-arm64 tensorrt tensorrt-jp5 tensorrt-jp6 rk h8l rocm; do + for variant in standard-arm64 tensorrt tensorrt-jp6 rk rocm; do docker run --rm -v $HOME/.docker/config.json:/config.json quay.io/skopeo/stable:latest copy --authfile /config.json --multi-arch all docker://${PULL_TAG}-${variant} docker://${VERSION_TAG}-${variant} done # stable tag if [[ "${BUILD_TYPE}" == "stable" ]]; then docker run --rm -v $HOME/.docker/config.json:/config.json quay.io/skopeo/stable:latest copy --authfile /config.json --multi-arch all docker://${PULL_TAG} docker://${STABLE_TAG} - for variant in standard-arm64 tensorrt tensorrt-jp5 tensorrt-jp6 rk h8l rocm; do + for variant in standard-arm64 tensorrt tensorrt-jp6 rk rocm; do docker run --rm -v $HOME/.docker/config.json:/config.json quay.io/skopeo/stable:latest copy --authfile /config.json --multi-arch all docker://${PULL_TAG}-${variant} docker://${STABLE_TAG}-${variant} done fi diff --git a/README.md b/README.md index 5b67c86c3..35e8cb7e9 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,15 @@ # Frigate - NVR With Realtime Object Detection for IP Cameras + +Translation status + + +\[English\] | [简体中文](https://github.com/blakeblackshear/frigate/blob/dev/README_CN.md) + A complete and local NVR designed for [Home Assistant](https://www.home-assistant.io) with AI object detection. Uses OpenCV and Tensorflow to perform realtime object detection locally for IP cameras. -Use of a [Google Coral Accelerator](https://coral.ai/products/) is optional, but highly recommended. The Coral will outperform even the best CPUs and can process 100+ FPS with very little overhead. +Use of a GPU or AI accelerator such as a [Google Coral](https://coral.ai/products/) or [Hailo](https://hailo.ai/) is highly recommended. AI accelerators will outperform even the best CPUs with very little overhead. - Tight integration with Home Assistant via a [custom component](https://github.com/blakeblackshear/frigate-hass-integration) - Designed to minimize resource use and maximize performance by only looking for objects when and where it is necessary @@ -30,21 +36,33 @@ If you would like to make a donation to support development, please use [Github ## Screenshots ### Live dashboard +
Live dashboard
### Streamlined review workflow +
Streamlined review workflow
### Multi-camera scrubbing +
Multi-camera scrubbing
### Built-in mask and zone editor +
Multi-camera scrubbing
+ +## Translations + +We use [Weblate](https://hosted.weblate.org/projects/frigate-nvr/) to support language translations. Contributions are always welcome. + + +Translation status + diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 000000000..efcea3480 --- /dev/null +++ b/README_CN.md @@ -0,0 +1,64 @@ +

+ logo +

+ +# Frigate - 一个具有实时目标检测的本地NVR + +[English](https://github.com/blakeblackshear/frigate) | \[简体中文\] + + +翻译状态 + + +一个完整的本地网络视频录像机(NVR),专为[Home Assistant](https://www.home-assistant.io)设计,具备AI物体检测功能。使用OpenCV和TensorFlow在本地为IP摄像头执行实时物体检测。 + +强烈推荐使用GPU或者AI加速器(例如[Google Coral加速器](https://coral.ai/products/) 或者 [Hailo](https://hailo.ai/))。它们的性能甚至超过目前的顶级CPU,并且可以以极低的耗电实现更优的性能。 +- 通过[自定义组件](https://github.com/blakeblackshear/frigate-hass-integration)与Home Assistant紧密集成 +- 设计上通过仅在必要时和必要地点寻找物体,最大限度地减少资源使用并最大化性能 +- 大量利用多进程处理,强调实时性而非处理每一帧 +- 使用非常低开销的运动检测来确定运行物体检测的位置 +- 使用TensorFlow进行物体检测,运行在单独的进程中以达到最大FPS +- 通过MQTT进行通信,便于集成到其他系统中 +- 根据检测到的物体设置保留时间进行视频录制 +- 24/7全天候录制 +- 通过RTSP重新流传输以减少摄像头的连接数 +- 支持WebRTC和MSE,实现低延迟的实时观看 + +## 社区中文翻译文档 + +你可以在这里查看文档 https://docs.frigate-cn.video + +## 赞助 + +如果您想通过捐赠支持开发,请使用 [Github Sponsors](https://github.com/sponsors/blakeblackshear)。 + +## 截图 + +### 实时监控面板 +
+实时监控面板 +
+ +### 简单的审查工作流程 +
+简单的审查工作流程 +
+ +### 多摄像头可按时间轴查看 +
+多摄像头可按时间轴查看 +
+ +### 内置遮罩和区域编辑器 +
+内置遮罩和区域编辑器 +
+ + +## 翻译 +我们使用 [Weblate](https://hosted.weblate.org/projects/frigate-nvr/) 平台提供翻译支持,欢迎参与进来一起完善。 + + +## 非官方中文讨论社区 +欢迎加入中文讨论QQ群:1043861059 +Bilibili:https://space.bilibili.com/3546894915602564 diff --git a/benchmark.py b/benchmark.py index 7db09a5d7..1f39302a7 100755 --- a/benchmark.py +++ b/benchmark.py @@ -6,7 +6,7 @@ import numpy as np import frigate.util as util from frigate.config import DetectorTypeEnum -from frigate.object_detection import ( +from frigate.object_detection.base import ( ObjectDetectProcess, RemoteObjectDetector, load_labels, diff --git a/docker-compose.yml b/docker-compose.yml index 2d905d385..db63297d5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,8 @@ -version: "3" services: devcontainer: container_name: frigate-devcontainer - # add groups from host for render, plugdev, video + # Check host system's actual render/video/plugdev group IDs with 'getent group render', 'getent group video', and 'getent group plugdev' + # Must add these exact IDs in container's group_add section or OpenVINO GPU acceleration will fail group_add: - "109" # render - "110" # render @@ -24,8 +24,8 @@ services: # capabilities: [gpu] environment: YOLO_MODELS: "" - devices: - - /dev/bus/usb:/dev/bus/usb + # devices: + # - /dev/bus/usb:/dev/bus/usb # Uncomment for Google Coral USB # - /dev/dri:/dev/dri # for intel hwaccel, needs to be updated for your hardware volumes: - .:/workspace/frigate:cached @@ -33,9 +33,10 @@ services: - /etc/localtime:/etc/localtime:ro - ./config:/config - ./debug:/media/frigate - - /dev/bus/usb:/dev/bus/usb + # - /dev/bus/usb:/dev/bus/usb # Uncomment for Google Coral USB mqtt: container_name: mqtt - image: eclipse-mosquitto:1.6 + image: eclipse-mosquitto:2.0 + command: mosquitto -c /mosquitto-no-auth.conf # enable no-auth mode ports: - - "1883:1883" \ No newline at end of file + - "1883:1883" diff --git a/docker/hailo8l/user_installation.sh b/docker/hailo8l/user_installation.sh index f1d92b5d5..d96dfb129 100644 --- a/docker/hailo8l/user_installation.sh +++ b/docker/hailo8l/user_installation.sh @@ -4,7 +4,7 @@ sudo apt-get update sudo apt-get install -y build-essential cmake git wget -hailo_version="4.20.0" +hailo_version="4.20.1" arch=$(uname -m) if [[ $arch == "x86_64" ]]; then diff --git a/docker/main/Dockerfile b/docker/main/Dockerfile index 2a7d388bc..f58e3d5a9 100644 --- a/docker/main/Dockerfile +++ b/docker/main/Dockerfile @@ -78,8 +78,9 @@ COPY docker/main/requirements-ov.txt /requirements-ov.txt RUN apt-get -qq update \ && apt-get -qq install -y wget python3 python3-dev python3-distutils gcc pkg-config libhdf5-dev \ && wget -q https://bootstrap.pypa.io/get-pip.py -O get-pip.py \ + && sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' get-pip.py \ && python3 get-pip.py "pip" \ - && pip install -r /requirements-ov.txt + && pip3 install -r /requirements-ov.txt # Get OpenVino Model RUN --mount=type=bind,source=docker/main/build_ov_model.py,target=/build_ov_model.py \ @@ -172,6 +173,7 @@ RUN apt-get -qq update \ RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 1 RUN wget -q https://bootstrap.pypa.io/get-pip.py -O get-pip.py \ + && sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' get-pip.py \ && python3 get-pip.py "pip" COPY docker/main/requirements.txt /requirements.txt @@ -235,6 +237,7 @@ ENV DEFAULT_FFMPEG_VERSION="7.0" ENV INCLUDED_FFMPEG_VERSIONS="${DEFAULT_FFMPEG_VERSION}:5.0" RUN wget -q https://bootstrap.pypa.io/get-pip.py -O get-pip.py \ + && sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' get-pip.py \ && python3 get-pip.py "pip" RUN --mount=type=bind,from=wheels,source=/wheels,target=/deps/wheels \ @@ -257,12 +260,12 @@ ENTRYPOINT ["/init"] CMD [] HEALTHCHECK --start-period=300s --start-interval=5s --interval=15s --timeout=5s --retries=3 \ - CMD curl --fail --silent --show-error http://127.0.0.1:5000/api/version || exit 1 + CMD test -f /dev/shm/.frigate-is-stopping && exit 0; curl --fail --silent --show-error http://127.0.0.1:5000/api/version || exit 1 # Frigate deps with Node.js and NPM for devcontainer FROM deps AS devcontainer -# Do not start the actual Frigate service on devcontainer as it will be started by VSCode +# Do not start the actual Frigate service on devcontainer as it will be started by VS Code # But start a fake service for simulating the logs COPY docker/main/fake_frigate_run /etc/s6-overlay/s6-rc.d/frigate/run diff --git a/docker/main/build_nginx.sh b/docker/main/build_nginx.sh index 2591810e3..606682665 100755 --- a/docker/main/build_nginx.sh +++ b/docker/main/build_nginx.sh @@ -2,7 +2,7 @@ set -euxo pipefail -NGINX_VERSION="1.25.3" +NGINX_VERSION="1.27.4" VOD_MODULE_VERSION="1.31" SECURE_TOKEN_MODULE_VERSION="1.5" SET_MISC_MODULE_VERSION="v0.33" diff --git a/docker/main/install_hailort.sh b/docker/main/install_hailort.sh index e050bd591..174b905fd 100755 --- a/docker/main/install_hailort.sh +++ b/docker/main/install_hailort.sh @@ -2,7 +2,7 @@ set -euxo pipefail -hailo_version="4.20.0" +hailo_version="4.20.1" if [[ "${TARGETARCH}" == "amd64" ]]; then arch="x86_64" @@ -10,5 +10,5 @@ elif [[ "${TARGETARCH}" == "arm64" ]]; then arch="aarch64" fi -wget -qO- "https://github.com/frigate-nvr/hailort/releases/download/v${hailo_version}/hailort-${TARGETARCH}.tar.gz" | tar -C / -xzf - +wget -qO- "https://github.com/frigate-nvr/hailort/releases/download/v${hailo_version}/hailort-debian12-${TARGETARCH}.tar.gz" | tar -C / -xzf - wget -P /wheels/ "https://github.com/frigate-nvr/hailort/releases/download/v${hailo_version}/hailort-${hailo_version}-cp311-cp311-linux_${arch}.whl" diff --git a/docker/main/requirements-wheels.txt b/docker/main/requirements-wheels.txt index ac0fa158b..4dd4d4d31 100644 --- a/docker/main/requirements-wheels.txt +++ b/docker/main/requirements-wheels.txt @@ -7,7 +7,6 @@ starlette-context == 0.3.6 fastapi == 0.115.* uvicorn == 0.30.* slowapi == 0.1.* -imutils == 0.5.* joserfc == 1.0.* pathvalidate == 3.2.* markupsafe == 3.0.* diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/finish b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/finish index 75869b5e7..27a02843c 100755 --- a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/finish +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/finish @@ -25,4 +25,7 @@ elif [[ "${exit_code_service}" -ne 0 ]]; then fi fi +# used by the docker healthcheck +touch /dev/shm/.frigate-is-stopping + exec /run/s6/basedir/bin/halt diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/run index f764fd6b0..a3ecb4668 100755 --- a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/run +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/run @@ -4,44 +4,16 @@ set -o errexit -o nounset -o pipefail +# opt out of openvino telemetry +if [ -e /usr/local/bin/opt_in_out ]; then + /usr/local/bin/opt_in_out --opt_out +fi + # Logs should be sent to stdout so that s6 can collect them # Tell S6-Overlay not to restart this service s6-svc -O . -function migrate_db_path() { - # Find config file in yaml or yml, but prefer yaml - local config_file="${CONFIG_FILE:-"/config/config.yml"}" - local config_file_yaml="${config_file//.yml/.yaml}" - if [[ -f "${config_file_yaml}" ]]; then - config_file="${config_file_yaml}" - elif [[ ! -f "${config_file}" ]]; then - # Frigate will create the config file on startup - return 0 - fi - unset config_file_yaml - - # Use yq to check if database.path is set - local user_db_path - user_db_path=$(yq eval '.database.path' "${config_file}") - - if [[ "${user_db_path}" == "null" ]]; then - local previous_db_path="/media/frigate/frigate.db" - local new_db_dir="/config" - if [[ -f "${previous_db_path}" ]]; then - if mountpoint --quiet "${new_db_dir}"; then - # /config is a mount point, move the db - echo "[INFO] Moving db from '${previous_db_path}' to the '${new_db_dir}' dir..." - # Move all files that starts with frigate.db to the new directory - mv -vf "${previous_db_path}"* "${new_db_dir}" - else - echo "[ERROR] Trying to migrate the db path from '${previous_db_path}' to the '${new_db_dir}' dir, but '${new_db_dir}' is not a mountpoint, please mount the '${new_db_dir}' dir" - return 1 - fi - fi - fi -} - function set_libva_version() { local ffmpeg_path ffmpeg_path=$(python3 /usr/local/ffmpeg/get_ffmpeg_path.py) @@ -50,8 +22,8 @@ function set_libva_version() { } echo "[INFO] Preparing Frigate..." -migrate_db_path set_libva_version + echo "[INFO] Starting Frigate..." cd /opt/frigate || echo "[ERROR] Failed to change working directory to /opt/frigate" diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/dependencies.d/base b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/dependencies.d/prepare similarity index 100% rename from docker/main/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/dependencies.d/base rename to docker/main/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/dependencies.d/prepare diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/run index 2c3a7ab6f..46bc3175f 100755 --- a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/run +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/run @@ -61,7 +61,7 @@ if [[ ! -f "/dev/shm/go2rtc.yaml" ]]; then echo "[INFO] Preparing new go2rtc config..." if [[ -n "${SUPERVISOR_TOKEN:-}" ]]; then - # Running as a Home Assistant add-on, infer the IP address and port + # Running as a Home Assistant Add-on, infer the IP address and port get_ip_and_port_from_supervisor fi diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run index 677126a6d..273182930 100755 --- a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run @@ -79,6 +79,11 @@ if [ ! \( -f "$letsencrypt_path/privkey.pem" -a -f "$letsencrypt_path/fullchain. -keyout "$letsencrypt_path/privkey.pem" -out "$letsencrypt_path/fullchain.pem" 2>/dev/null fi +# build templates for optional FRIGATE_BASE_PATH environment variable +python3 /usr/local/nginx/get_base_path.py | \ + tempio -template /usr/local/nginx/templates/base_path.gotmpl \ + -out /usr/local/nginx/conf/base_path.conf + # build templates for optional TLS support python3 /usr/local/nginx/get_tls_settings.py | \ tempio -template /usr/local/nginx/templates/listen.gotmpl \ diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/prepare/dependencies.d/base b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/prepare/dependencies.d/base new file mode 100644 index 000000000..e69de29bb diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/prepare/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/prepare/run new file mode 100755 index 000000000..27b1d6326 --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/prepare/run @@ -0,0 +1,146 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +# Do preparation tasks before starting the main services + +set -o errexit -o nounset -o pipefail + +function migrate_addon_config_dir() { + local home_assistant_config_dir="/homeassistant" + + if ! mountpoint --quiet "${home_assistant_config_dir}"; then + # Not running as a Home Assistant Add-on + return 0 + fi + + local config_dir="/config" + local new_config_file="${config_dir}/config.yml" + local new_config_file_yaml="${new_config_file//.yml/.yaml}" + if [[ -f "${new_config_file_yaml}" || -f "${new_config_file}" ]]; then + # Already migrated + return 0 + fi + + local old_config_file="${home_assistant_config_dir}/frigate.yml" + local old_config_file_yaml="${old_config_file//.yml/.yaml}" + if [[ -f "${old_config_file}" ]]; then + : + elif [[ -f "${old_config_file_yaml}" ]]; then + old_config_file="${old_config_file_yaml}" + new_config_file="${new_config_file_yaml}" + else + # Nothing to migrate + return 0 + fi + unset old_config_file_yaml new_config_file_yaml + + echo "[INFO] Starting migration from Home Assistant config dir to Add-on config dir..." >&2 + + local db_path + db_path=$(yq -r '.database.path' "${old_config_file}") + if [[ "${db_path}" == "null" ]]; then + db_path="${config_dir}/frigate.db" + fi + if [[ "${db_path}" == "${config_dir}/"* ]]; then + # replace /config/ prefix with /homeassistant/ + local old_db_path="${home_assistant_config_dir}/${db_path:8}" + + if [[ -f "${old_db_path}" ]]; then + local new_db_dir + new_db_dir="$(dirname "${db_path}")" + echo "[INFO] Migrating database from '${old_db_path}' to '${new_db_dir}' dir..." >&2 + mkdir -vp "${new_db_dir}" + mv -vf "${old_db_path}" "${new_db_dir}" + local db_file + for db_file in "${old_db_path}"-shm "${old_db_path}"-wal; do + if [[ -f "${db_file}" ]]; then + mv -vf "${db_file}" "${new_db_dir}" + fi + done + unset db_file + fi + fi + + local config_entry + for config_entry in .model.path .model.labelmap_path .ffmpeg.path .mqtt.tls_ca_certs .mqtt.tls_client_cert .mqtt.tls_client_key; do + local config_entry_path + config_entry_path=$(yq -r "${config_entry}" "${old_config_file}") + if [[ "${config_entry_path}" == "${config_dir}/"* ]]; then + # replace /config/ prefix with /homeassistant/ + local old_config_entry_path="${home_assistant_config_dir}/${config_entry_path:8}" + + if [[ -f "${old_config_entry_path}" ]]; then + local new_config_entry_entry + new_config_entry_entry="$(dirname "${config_entry_path}")" + echo "[INFO] Migrating ${config_entry} from '${old_config_entry_path}' to '${config_entry_path}'..." >&2 + mkdir -vp "${new_config_entry_entry}" + mv -vf "${old_config_entry_path}" "${config_entry_path}" + fi + fi + done + + local old_model_cache_path="${home_assistant_config_dir}/model_cache" + if [[ -d "${old_model_cache_path}" ]]; then + echo "[INFO] Migrating '${old_model_cache_path}' to '${config_dir}'..." >&2 + mv -f "${old_model_cache_path}" "${config_dir}" + fi + + echo "[INFO] Migrating other files from '${home_assistant_config_dir}' to '${config_dir}'..." >&2 + local file + for file in .exports .jwt_secret .timeline .vacuum go2rtc; do + file="${home_assistant_config_dir}/${file}" + if [[ -f "${file}" ]]; then + mv -vf "${file}" "${config_dir}" + fi + done + + echo "[INFO] Migrating config file from '${old_config_file}' to '${new_config_file}'..." >&2 + mv -vf "${old_config_file}" "${new_config_file}" + + echo "[INFO] Migration from Home Assistant config dir to Add-on config dir completed." >&2 +} + +function migrate_db_from_media_to_config() { + # Find config file in yml or yaml, but prefer yml + local config_file="${CONFIG_FILE:-"/config/config.yml"}" + local config_file_yaml="${config_file//.yml/.yaml}" + if [[ -f "${config_file}" ]]; then + : + elif [[ -f "${config_file_yaml}" ]]; then + config_file="${config_file_yaml}" + else + # Frigate will create the config file on startup + return 0 + fi + unset config_file_yaml + + local user_db_path + user_db_path=$(yq -r '.database.path' "${config_file}") + if [[ "${user_db_path}" == "null" ]]; then + local old_db_path="/media/frigate/frigate.db" + local new_db_dir="/config" + if [[ -f "${old_db_path}" ]]; then + echo "[INFO] Migrating database from '${old_db_path}' to '${new_db_dir}' dir..." >&2 + if mountpoint --quiet "${new_db_dir}"; then + # /config is a mount point, move the db + mv -vf "${old_db_path}" "${new_db_dir}" + local db_file + for db_file in "${old_db_path}"-shm "${old_db_path}"-wal; do + if [[ -f "${db_file}" ]]; then + mv -vf "${db_file}" "${new_db_dir}" + fi + done + unset db_file + else + echo "[ERROR] Trying to migrate the database path from '${old_db_path}' to '${new_db_dir}' dir, but '${new_db_dir}' is not a mountpoint, please mount the '${new_db_dir}' dir" >&2 + return 1 + fi + fi + fi +} + +# remove leftover from last run, not normally needed, but just in case +# used by the docker healthcheck +rm -f /dev/shm/.frigate-is-stopping + +migrate_addon_config_dir +migrate_db_from_media_to_config diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/prepare/type b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/prepare/type new file mode 100644 index 000000000..bdd22a185 --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/prepare/type @@ -0,0 +1 @@ +oneshot diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/prepare/up b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/prepare/up new file mode 100644 index 000000000..ea17af548 --- /dev/null +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/prepare/up @@ -0,0 +1 @@ +/etc/s6-overlay/s6-rc.d/prepare/run diff --git a/docker/main/rootfs/usr/local/ffmpeg/get_ffmpeg_path.py b/docker/main/rootfs/usr/local/ffmpeg/get_ffmpeg_path.py index ed7f6a891..3de7d9f4a 100644 --- a/docker/main/rootfs/usr/local/ffmpeg/get_ffmpeg_path.py +++ b/docker/main/rootfs/usr/local/ffmpeg/get_ffmpeg_path.py @@ -1,5 +1,4 @@ import json -import os import sys from ruamel.yaml import YAML @@ -9,17 +8,13 @@ from frigate.const import ( DEFAULT_FFMPEG_VERSION, INCLUDED_FFMPEG_VERSIONS, ) +from frigate.util.config import find_config_file sys.path.remove("/opt/frigate") yaml = YAML() -config_file = os.environ.get("CONFIG_FILE", "/config/config.yml") - -# Check if we can use .yaml instead of .yml -config_file_yaml = config_file.replace(".yml", ".yaml") -if os.path.isfile(config_file_yaml): - config_file = config_file_yaml +config_file = find_config_file() try: with open(config_file) as f: diff --git a/docker/main/rootfs/usr/local/go2rtc/create_config.py b/docker/main/rootfs/usr/local/go2rtc/create_config.py index d7c21c7f7..21da66f3e 100644 --- a/docker/main/rootfs/usr/local/go2rtc/create_config.py +++ b/docker/main/rootfs/usr/local/go2rtc/create_config.py @@ -15,6 +15,7 @@ from frigate.const import ( LIBAVFORMAT_VERSION_MAJOR, ) from frigate.ffmpeg_presets import parse_preset_hardware_acceleration_encode +from frigate.util.config import find_config_file sys.path.remove("/opt/frigate") @@ -29,12 +30,7 @@ if os.path.isdir("/run/secrets"): Path(os.path.join("/run/secrets", secret_file)).read_text().strip() ) -config_file = os.environ.get("CONFIG_FILE", "/config/config.yml") - -# Check if we can use .yaml instead of .yml -config_file_yaml = config_file.replace(".yml", ".yaml") -if os.path.isfile(config_file_yaml): - config_file = config_file_yaml +config_file = find_config_file() try: with open(config_file) as f: @@ -57,7 +53,7 @@ elif go2rtc_config["api"].get("origin") is None: # Need to set default location for HA config if go2rtc_config.get("hass") is None: - go2rtc_config["hass"] = {"config": "/config"} + go2rtc_config["hass"] = {"config": "/homeassistant"} # we want to ensure that logs are easy to read if go2rtc_config.get("log") is None: @@ -106,7 +102,7 @@ elif go2rtc_config["ffmpeg"].get("bin") is None: # need to replace ffmpeg command when using ffmpeg4 if LIBAVFORMAT_VERSION_MAJOR < 59: - rtsp_args = "-fflags nobuffer -flags low_delay -stimeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_transport tcp -i {input}" + rtsp_args = "-fflags nobuffer -flags low_delay -stimeout 10000000 -user_agent go2rtc/ffmpeg -rtsp_transport tcp -i {input}" if go2rtc_config.get("ffmpeg") is None: go2rtc_config["ffmpeg"] = {"rtsp": rtsp_args} elif go2rtc_config["ffmpeg"].get("rtsp") is None: diff --git a/docker/main/rootfs/usr/local/nginx/conf/nginx.conf b/docker/main/rootfs/usr/local/nginx/conf/nginx.conf index 8a98da1f2..c855fb926 100644 --- a/docker/main/rootfs/usr/local/nginx/conf/nginx.conf +++ b/docker/main/rootfs/usr/local/nginx/conf/nginx.conf @@ -30,7 +30,7 @@ http { gzip on; gzip_comp_level 6; - gzip_types text/plain text/css application/json application/x-javascript application/javascript text/javascript image/svg+xml image/x-icon image/bmp image/png image/gif image/jpeg image/jpg; + gzip_types text/plain text/css application/json application/x-javascript application/javascript text/javascript image/svg+xml image/x-icon image/bmp; gzip_proxied no-cache no-store private expired auth; gzip_vary on; @@ -82,7 +82,7 @@ http { aio on; # file upload size - client_max_body_size 10M; + client_max_body_size 20M; # https://github.com/kaltura/nginx-vod-module#vod_open_file_thread_pool vod_open_file_thread_pool default; @@ -96,6 +96,7 @@ http { gzip_types application/vnd.apple.mpegurl; include auth_location.conf; + include base_path.conf; location /vod/ { include auth_request.conf; @@ -299,11 +300,29 @@ http { add_header Cache-Control "public"; } + location /locales/ { + access_log off; + add_header Cache-Control "public"; + } + + location ~ ^/.*-([A-Za-z0-9]+)\.webmanifest$ { + access_log off; + expires 1y; + add_header Cache-Control "public"; + default_type application/json; + proxy_set_header Accept-Encoding ""; + sub_filter_once off; + sub_filter_types application/json; + sub_filter '"start_url": "/BASE_PATH/"' '"start_url" : "$http_x_ingress_path/"'; + sub_filter '"src": "/BASE_PATH/' '"src": "$http_x_ingress_path/'; + } + sub_filter 'href="/BASE_PATH/' 'href="$http_x_ingress_path/'; sub_filter 'url(/BASE_PATH/' 'url($http_x_ingress_path/'; sub_filter '"/BASE_PATH/dist/' '"$http_x_ingress_path/dist/'; sub_filter '"/BASE_PATH/js/' '"$http_x_ingress_path/js/'; sub_filter '"/BASE_PATH/assets/' '"$http_x_ingress_path/assets/'; + sub_filter '"/BASE_PATH/locales/' '"$http_x_ingress_path/locales/'; sub_filter '"/BASE_PATH/monacoeditorwork/' '"$http_x_ingress_path/assets/'; sub_filter 'return"/BASE_PATH/"' 'return window.baseUrl'; sub_filter '' ''; diff --git a/docker/main/rootfs/usr/local/nginx/get_base_path.py b/docker/main/rootfs/usr/local/nginx/get_base_path.py new file mode 100644 index 000000000..e6fc8cfc6 --- /dev/null +++ b/docker/main/rootfs/usr/local/nginx/get_base_path.py @@ -0,0 +1,10 @@ +"""Prints the base path as json to stdout.""" + +import json +import os + +base_path = os.environ.get("FRIGATE_BASE_PATH", "") + +result: dict[str, any] = {"base_path": base_path} + +print(json.dumps(result)) diff --git a/docker/main/rootfs/usr/local/nginx/get_tls_settings.py b/docker/main/rootfs/usr/local/nginx/get_tls_settings.py index f1a4c85de..2ababa282 100644 --- a/docker/main/rootfs/usr/local/nginx/get_tls_settings.py +++ b/docker/main/rootfs/usr/local/nginx/get_tls_settings.py @@ -1,18 +1,18 @@ """Prints the tls config as json to stdout.""" import json -import os +import sys from ruamel.yaml import YAML +sys.path.insert(0, "/opt/frigate") +from frigate.util.config import find_config_file + +sys.path.remove("/opt/frigate") + yaml = YAML() -config_file = os.environ.get("CONFIG_FILE", "/config/config.yml") - -# Check if we can use .yaml instead of .yml -config_file_yaml = config_file.replace(".yml", ".yaml") -if os.path.isfile(config_file_yaml): - config_file = config_file_yaml +config_file = find_config_file() try: with open(config_file) as f: diff --git a/docker/main/rootfs/usr/local/nginx/templates/base_path.gotmpl b/docker/main/rootfs/usr/local/nginx/templates/base_path.gotmpl new file mode 100644 index 000000000..ace4443ee --- /dev/null +++ b/docker/main/rootfs/usr/local/nginx/templates/base_path.gotmpl @@ -0,0 +1,19 @@ +{{ if .base_path }} +location = {{ .base_path }} { + return 302 {{ .base_path }}/; +} + +location ^~ {{ .base_path }}/ { + # remove base_url from the path before passing upstream + rewrite ^{{ .base_path }}/(.*) /$1 break; + + proxy_pass $scheme://127.0.0.1:8971; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Ingress-Path {{ .base_path }}; + + access_log off; +} +{{ end }} diff --git a/docker/rockchip/Dockerfile b/docker/rockchip/Dockerfile index 59c8ad791..c38b2d49e 100644 --- a/docker/rockchip/Dockerfile +++ b/docker/rockchip/Dockerfile @@ -26,7 +26,7 @@ COPY --from=rootfs / / COPY docker/rockchip/COCO /COCO COPY docker/rockchip/conv2rknn.py /opt/conv2rknn.py -ADD https://github.com/MarcA711/rknn-toolkit2/releases/download/v2.3.0/librknnrt.so /usr/lib/ +ADD https://github.com/MarcA711/rknn-toolkit2/releases/download/v2.3.2/librknnrt.so /usr/lib/ ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.1-7/ffmpeg /usr/lib/ffmpeg/6.0/bin/ ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.1-7/ffprobe /usr/lib/ffmpeg/6.0/bin/ diff --git a/docker/rockchip/conv2rknn.py b/docker/rockchip/conv2rknn.py index 4f4a315e1..4880d9868 100644 --- a/docker/rockchip/conv2rknn.py +++ b/docker/rockchip/conv2rknn.py @@ -14,7 +14,7 @@ try: with open("/config/conv2rknn.yaml", "r") as config_file: configuration = yaml.safe_load(config_file) except FileNotFoundError: - raise Exception("Please place a config.yaml file in /config/conv2rknn.yaml") + raise Exception("Please place a config file at /config/conv2rknn.yaml") if configuration["config"] != None: rknn_config = configuration["config"] diff --git a/docker/rockchip/requirements-wheels-rk.txt b/docker/rockchip/requirements-wheels-rk.txt index 8d5b5efe0..f841f26db 100644 --- a/docker/rockchip/requirements-wheels-rk.txt +++ b/docker/rockchip/requirements-wheels-rk.txt @@ -1,2 +1,2 @@ -rknn-toolkit2 == 2.3.0 -rknn-toolkit-lite2 == 2.3.0 \ No newline at end of file +rknn-toolkit2 == 2.3.2 +rknn-toolkit-lite2 == 2.3.2 \ No newline at end of file diff --git a/docker/rocm/Dockerfile b/docker/rocm/Dockerfile index 78f91b96f..d04e93df3 100644 --- a/docker/rocm/Dockerfile +++ b/docker/rocm/Dockerfile @@ -39,6 +39,7 @@ WORKDIR /opt/frigate COPY --from=rootfs / / RUN wget -q https://bootstrap.pypa.io/get-pip.py -O get-pip.py \ + && sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' get-pip.py \ && python3 get-pip.py "pip" --break-system-packages RUN python3 -m pip config set global.break-system-packages true diff --git a/docker/tensorrt/Dockerfile.arm64 b/docker/tensorrt/Dockerfile.arm64 index 5d5d5d939..6e2e0280f 100644 --- a/docker/tensorrt/Dockerfile.arm64 +++ b/docker/tensorrt/Dockerfile.arm64 @@ -9,9 +9,9 @@ ARG DEBIAN_FRONTEND # Add deadsnakes PPA for python3.11 RUN apt-get -qq update && \ - apt-get -qq install -y --no-install-recommends \ - software-properties-common \ - && add-apt-repository ppa:deadsnakes/ppa + apt-get -qq install -y --no-install-recommends \ + software-properties-common \ + && add-apt-repository ppa:deadsnakes/ppa # Use a separate container to build wheels to prevent build dependencies in final image RUN apt-get -qq update \ @@ -24,6 +24,7 @@ RUN apt-get -qq update \ RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 1 RUN wget -q https://bootstrap.pypa.io/get-pip.py -O get-pip.py \ + && sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' get-pip.py \ && python3 get-pip.py "pip" FROM build-wheels AS trt-wheels diff --git a/docker/tensorrt/Dockerfile.base b/docker/tensorrt/Dockerfile.base index 4305f1d74..79a7f3c98 100644 --- a/docker/tensorrt/Dockerfile.base +++ b/docker/tensorrt/Dockerfile.base @@ -21,7 +21,20 @@ RUN --mount=type=bind,source=docker/tensorrt/detector/tensorrt_libyolo.sh,target RUN mkdir -p /usr/local/cuda-deps RUN if [ "$TARGETARCH" = "amd64" ]; then \ cp /usr/local/cuda-12.3/targets/x86_64-linux/lib/libcurand.so.* /usr/local/cuda-deps/ && \ - cp /usr/local/cuda-12.3/targets/x86_64-linux/lib/libnvrtc.so.* /usr/local/cuda-deps/ ; \ + cp /usr/local/cuda-12.3/targets/x86_64-linux/lib/libnvrtc.so.* /usr/local/cuda-deps/ && \ + cd /usr/local/cuda-deps/ && \ + for lib in libnvrtc.so.*; do \ + if [[ "$lib" =~ libnvrtc.so\.([0-9]+\.[0-9]+\.[0-9]+) ]]; then \ + version="${BASH_REMATCH[1]}"; \ + ln -sf "libnvrtc.so.$version" libnvrtc.so; \ + fi; \ + done && \ + for lib in libcurand.so.*; do \ + if [[ "$lib" =~ libcurand.so\.([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+) ]]; then \ + version="${BASH_REMATCH[1]}"; \ + ln -sf "libcurand.so.$version" libcurand.so; \ + fi; \ + done; \ fi # Frigate w/ TensorRT Support as separate image diff --git a/docker/tensorrt/detector/rootfs/etc/ld.so.conf.d/cuda_tensorrt.conf b/docker/tensorrt/detector/rootfs/etc/ld.so.conf.d/cuda_tensorrt.conf index 72eec56e0..f66af7dc6 100644 --- a/docker/tensorrt/detector/rootfs/etc/ld.so.conf.d/cuda_tensorrt.conf +++ b/docker/tensorrt/detector/rootfs/etc/ld.so.conf.d/cuda_tensorrt.conf @@ -1,8 +1,7 @@ /usr/local/lib /usr/local/cuda +/usr/local/lib/python3.11/dist-packages/tensorrt /usr/local/lib/python3.11/dist-packages/nvidia/cudnn/lib /usr/local/lib/python3.11/dist-packages/nvidia/cuda_runtime/lib /usr/local/lib/python3.11/dist-packages/nvidia/cublas/lib -/usr/local/lib/python3.11/dist-packages/nvidia/cuda_nvrtc/lib -/usr/local/lib/python3.11/dist-packages/tensorrt /usr/local/lib/python3.11/dist-packages/nvidia/cufft/lib \ No newline at end of file diff --git a/docs/docs/configuration/advanced.md b/docs/docs/configuration/advanced.md index c889d2d26..818440fae 100644 --- a/docs/docs/configuration/advanced.md +++ b/docs/docs/configuration/advanced.md @@ -44,7 +44,7 @@ go2rtc: ### `environment_vars` -This section can be used to set environment variables for those unable to modify the environment of the container (ie. within HassOS) +This section can be used to set environment variables for those unable to modify the environment of the container, like within Home Assistant OS. Example: @@ -172,6 +172,38 @@ listen [::]:8971 ipv6only=off ssl; listen [::]:5000 ipv6only=off; ``` +## Base path + +By default, Frigate runs at the root path (`/`). However some setups require to run Frigate under a custom path prefix (e.g. `/frigate`), especially when Frigate is located behind a reverse proxy that requires path-based routing. + +### Set Base Path via HTTP Header +The preferred way to configure the base path is through the `X-Ingress-Path` HTTP header, which needs to be set to the desired base path in an upstream reverse proxy. + +For example, in Nginx: +``` +location /frigate { + proxy_set_header X-Ingress-Path /frigate; + proxy_pass http://frigate_backend; +} +``` + +### Set Base Path via Environment Variable +When it is not feasible to set the base path via a HTTP header, it can also be set via the `FRIGATE_BASE_PATH` environment variable in the Docker Compose file. + +For example: +``` +services: + frigate: + image: blakeblackshear/frigate:latest + environment: + - FRIGATE_BASE_PATH=/frigate +``` + +This can be used for example to access Frigate via a Tailscale agent (https), by simply forwarding all requests to the base path (http): +``` +tailscale serve --https=443 --bg --set-path /frigate http://localhost:5000/frigate +``` + ## Custom Dependencies ### Custom ffmpeg build diff --git a/docs/docs/configuration/authentication.md b/docs/docs/configuration/authentication.md index 36994381d..f83659c52 100644 --- a/docs/docs/configuration/authentication.md +++ b/docs/docs/configuration/authentication.md @@ -43,13 +43,13 @@ Restarting Frigate will reset the rate limits. If you are running Frigate behind a proxy, you will want to set `trusted_proxies` or these rate limits will apply to the upstream proxy IP address. This means that a brute force attack will rate limit login attempts from other devices and could temporarily lock you out of your instance. In order to ensure rate limits only apply to the actual IP address where the requests are coming from, you will need to list the upstream networks that you want to trust. These trusted proxies are checked against the `X-Forwarded-For` header when looking for the IP address where the request originated. -If you are running a reverse proxy in the same docker compose file as Frigate, here is an example of how your auth config might look: +If you are running a reverse proxy in the same Docker Compose file as Frigate, here is an example of how your auth config might look: ```yaml auth: failed_login_rate_limit: "1/second;5/minute;20/hour" trusted_proxies: - - 172.18.0.0/16 # <---- this is the subnet for the internal docker compose network + - 172.18.0.0/16 # <---- this is the subnet for the internal Docker Compose network ``` ## JWT Token Secret @@ -66,7 +66,7 @@ Frigate looks for a JWT token secret in the following order: 1. An environment variable named `FRIGATE_JWT_SECRET` 2. A docker secret named `FRIGATE_JWT_SECRET` in `/run/secrets/` -3. A `jwt_secret` option from the Home Assistant Addon options +3. A `jwt_secret` option from the Home Assistant Add-on options 4. A `.jwt_secret` file in the config directory If no secret is found on startup, Frigate generates one and stores it in a `.jwt_secret` file in the config directory. @@ -77,7 +77,7 @@ Changing the secret will invalidate current tokens. Frigate can be configured to leverage features of common upstream authentication proxies such as Authelia, Authentik, oauth2_proxy, or traefik-forward-auth. -If you are leveraging the authentication of an upstream proxy, you likely want to disable Frigate's authentication. Optionally, if communication between the reverse proxy and Frigate is over an untrusted network, you should set an `auth_secret` in the `proxy` config and configure the proxy to send the secret value as a header named `X-Proxy-Secret`. Assuming this is an untrusted network, you will also want to [configure a real TLS certificate](tls.md) to ensure the traffic can't simply be sniffed to steal the secret. +If you are leveraging the authentication of an upstream proxy, you likely want to disable Frigate's authentication as there is no correspondence between users in Frigate's database and users authenticated via the proxy. Optionally, if communication between the reverse proxy and Frigate is over an untrusted network, you should set an `auth_secret` in the `proxy` config and configure the proxy to send the secret value as a header named `X-Proxy-Secret`. Assuming this is an untrusted network, you will also want to [configure a real TLS certificate](tls.md) to ensure the traffic can't simply be sniffed to steal the secret. Here is an example of how to disable Frigate's authentication and also ensure the requests come only from your known proxy. @@ -109,6 +109,14 @@ proxy: Frigate supports both `admin` and `viewer` roles (see below). When using port `8971`, Frigate validates these headers and subsequent requests use the headers `remote-user` and `remote-role` for authorization. +A default role can be provided. Any value in the mapped `role` header will override the default. + +```yaml +proxy: + ... + default_role: viewer +``` + #### Port Considerations **Authenticated Port (8971)** diff --git a/docs/docs/configuration/bird_classification.md b/docs/docs/configuration/bird_classification.md new file mode 100644 index 000000000..398729290 --- /dev/null +++ b/docs/docs/configuration/bird_classification.md @@ -0,0 +1,31 @@ +--- +id: bird_classification +title: Bird Classification +--- + +Bird classification identifies known birds using a quantized Tensorflow model. When a known bird is recognized, its common name will be added as a `sub_label`. This information is included in the UI, filters, as well as in notifications. + +## Minimum System Requirements + +Bird classification runs a lightweight tflite model on the CPU, there are no significantly different system requirements than running Frigate itself. + +## Model + +The classification model used is the MobileNet INat Bird Classification, [available identifiers can be found here.](https://raw.githubusercontent.com/google-coral/test_data/master/inat_bird_labels.txt) + +## Configuration + +Bird classification is disabled by default, it must be enabled in your config file before it can be used. Bird classification is a global configuration setting. + +```yaml +classification: + bird: + enabled: true +``` + +## Advanced Configuration + +Fine-tune bird classification with these optional parameters: + +- `threshold`: Classification confidence score required to set the sub label on the object. + - Default: `0.9`. diff --git a/docs/docs/configuration/birdseye.md b/docs/docs/configuration/birdseye.md index 2c9fbbdf4..d4bd1a15e 100644 --- a/docs/docs/configuration/birdseye.md +++ b/docs/docs/configuration/birdseye.md @@ -4,7 +4,7 @@ In addition to Frigate's Live camera dashboard, Birdseye allows a portable heads Birdseye can be viewed by adding the "Birdseye" camera to a Camera Group in the Web UI. Add a Camera Group by pressing the "+" icon on the Live page, and choose "Birdseye" as one of the cameras. -Birdseye can also be used in HomeAssistant dashboards, cast to media devices, etc. +Birdseye can also be used in Home Assistant dashboards, cast to media devices, etc. ## Birdseye Behavior diff --git a/docs/docs/configuration/camera_specific.md b/docs/docs/configuration/camera_specific.md index 0cd1efd47..36d9e9256 100644 --- a/docs/docs/configuration/camera_specific.md +++ b/docs/docs/configuration/camera_specific.md @@ -15,6 +15,17 @@ Many cameras support encoding options which greatly affect the live view experie ::: +## H.265 Cameras via Safari + +Some cameras support h265 with different formats, but Safari only supports the annexb format. When using h265 camera streams for recording with devices that use the Safari browser, the `apple_compatibility` option should be used. + +```yaml +cameras: + h265_cam: # <------ Doesn't matter what the camera is called + ffmpeg: + apple_compatibility: true # <- Adds compatibility with MacOS and iPhone +``` + ## MJPEG Cameras Note that mjpeg cameras require encoding the video into h264 for recording, and restream roles. This will use significantly more CPU than if the cameras supported h264 feeds directly. It is recommended to use the restream role to create an h264 restream and then use that as the source for ffmpeg. diff --git a/docs/docs/configuration/face_recognition.md b/docs/docs/configuration/face_recognition.md index aac1be9b5..7a4cde558 100644 --- a/docs/docs/configuration/face_recognition.md +++ b/docs/docs/configuration/face_recognition.md @@ -3,25 +3,38 @@ id: face_recognition title: Face Recognition --- -Face recognition identifies known individuals by matching detected faces with previously learned facial data. When a known person is recognized, their name will be added as a `sub_label`. This information is included in the UI, filters, as well as in notifications. +Face recognition identifies known individuals by matching detected faces with previously learned facial data. When a known `person` is recognized, their name will be added as a `sub_label`. This information is included in the UI, filters, as well as in notifications. ## Model Requirements -Frigate has support for CV2 Local Binary Pattern Face Recognizer to recognize faces, which runs locally. A lightweight face landmark detection model is also used to align faces before running them through the face recognizer. +### Face Detection -Users running a Frigate+ model (or any custom model that natively detects faces) should ensure that `face` is added to the [list of objects to track](../plus/#available-label-types) either globally or for a specific camera. This will allow face detection to run at the same time as object detection and be more efficient. +When running a Frigate+ model (or any custom model that natively detects faces) should ensure that `face` is added to the [list of objects to track](../plus/#available-label-types) either globally or for a specific camera. This will allow face detection to run at the same time as object detection and be more efficient. -Users without a model that detects faces can still run face recognition. Frigate uses a lightweight DNN face detection model that runs on the CPU. In this case, you should _not_ define `face` in your list of objects to track. +When running a default COCO model or another model that does not include `face` as a detectable label, face detection will run via CV2 using a lightweight DNN model that runs on the CPU. In this case, you should _not_ define `face` in your list of objects to track. :::note -Frigate needs to first detect a `face` before it can recognize a face. +Frigate needs to first detect a `person` before it can detect and recognize a face. ::: +### Face Recognition + +Frigate has support for two face recognition model types: + +- **small**: Frigate will run a FaceNet embedding model to recognize faces, which runs locally on the CPU. This model is optimized for efficiency and is not as accurate. +- **large**: Frigate will run a large ArcFace embedding model that is optimized for accuracy. It is only recommended to be run when an integrated or dedicated GPU is available. + +In both cases, a lightweight face landmark detection model is also used to align faces before running recognition. + +All of these features run locally on your system. + ## Minimum System Requirements -Face recognition is lightweight and runs on the CPU, there are no significantly different system requirements than running Frigate itself. +The `small` model is optimized for efficiency and runs on the CPU, most CPUs should run the model efficiently. + +The `large` model is optimized for accuracy, an integrated or discrete GPU is required. See the [Hardware Accelerated Enrichments](/configuration/hardware_acceleration_enrichments.md) documentation. ## Configuration @@ -34,7 +47,7 @@ face_recognition: ## Advanced Configuration -Fine-tune face recognition with these optional parameters: +Fine-tune face recognition with these optional parameters at the global level of your config. The only optional parameters that can be set at the camera level are `enabled` and `min_area`. ### Detection @@ -47,12 +60,24 @@ Fine-tune face recognition with these optional parameters: ### Recognition +- `model_size`: Which model size to use, options are `small` or `large` +- `unknown_score`: Min score to mark a person as a potential match, matches at or below this will be marked as unknown. + - Default: `0.8`. - `recognition_threshold`: Recognition confidence score required to add the face to the object as a sub label. - Default: `0.9`. +- `save_attempts`: Number of images of recognized faces to save for training. + - Default: `100`. - `blur_confidence_filter`: Enables a filter that calculates how blurry the face is and adjusts the confidence based on this. - Default: `True`. -## Dataset +## Usage + +1. **Enable face recognition** in your configuration file and restart Frigate. +2. **Upload your face** using the **Add Face** button's wizard in the Face Library section of the Frigate UI. +3. When Frigate detects and attempts to recognize a face, it will appear in the **Train** tab of the Face Library, along with its associated recognition confidence. +4. From the **Train** tab, you can **assign the face** to a new or existing person to improve recognition accuracy for the future. + +## Creating a Robust Training Set The number of images needed for a sufficient training set for face recognition varies depending on several factors: @@ -61,11 +86,9 @@ The number of images needed for a sufficient training set for face recognition v However, here are some general guidelines: -- Minimum: For basic face recognition tasks, a minimum of 10-20 images per person is often recommended. -- Recommended: For more robust and accurate systems, 30-50 images per person is a good starting point. -- Ideal: For optimal performance, especially in challenging conditions, 100 or more images per person can be beneficial. - -## Creating a Robust Training Set +- Minimum: For basic face recognition tasks, a minimum of 5-10 images per person is often recommended. +- Recommended: For more robust and accurate systems, 20-30 images per person is a good starting point. +- Ideal: For optimal performance, especially in challenging conditions, 50-100 images per person can be beneficial. The accuracy of face recognition is heavily dependent on the quality of data given to it for training. It is recommended to build the face training library in phases. @@ -74,19 +97,75 @@ The accuracy of face recognition is heavily dependent on the quality of data giv When choosing images to include in the face training set it is recommended to always follow these recommendations: - If it is difficult to make out details in a persons face it will not be helpful in training. -- Avoid images with under/over-exposure. +- Avoid images with extreme under/over-exposure. - Avoid blurry / pixelated images. -- Be careful when uploading images of people when they are wearing clothing that covers a lot of their face as this may confuse the training. -- Do not upload too many images at the same time, it is recommended to train 4-6 images for each person each day so it is easier to know if the previously added images helped or hurt performance. +- Avoid training on infrared (gray-scale). The models are trained on color images and will be able to extract features from gray-scale images. +- Using images of people wearing hats / sunglasses may confuse the model. +- Do not upload too many similar images at the same time, it is recommended to train no more than 4-6 similar images for each person to avoid over-fitting. ::: ### Step 1 - Building a Strong Foundation -When first enabling face recognition it is important to build a foundation of strong images. It is recommended to start by uploading 1-2 photos taken by a smartphone for each person. It is important that the person's face in the photo is straight-on and not turned which will ensure a good starting point. +When first enabling face recognition it is important to build a foundation of strong images. It is recommended to start by uploading 1-5 photos containing just this person's face. It is important that the person's face in the photo is front-facing and not turned, this will ensure a good starting point. -Then it is recommended to use the `Face Library` tab in Frigate to select and train images for each person as they are detected. When building a strong foundation it is strongly recommended to only train on images that are straight-on. Ignore images from cameras that recognize faces from an angle. Once a person starts to be consistently recognized correctly on images that are straight-on, it is time to move on to the next step. +Then it is recommended to use the `Face Library` tab in Frigate to select and train images for each person as they are detected. When building a strong foundation it is strongly recommended to only train on images that are front-facing. Ignore images from cameras that recognize faces from an angle. + +Aim to strike a balance between the quality of images while also having a range of conditions (day / night, different weather conditions, different times of day, etc.) in order to have diversity in the images used for each person and not have over-fitting. + +Once a person starts to be consistently recognized correctly on images that are front-facing, it is time to move on to the next step. ### Step 2 - Expanding The Dataset -Once straight-on images are performing well, start choosing slightly off-angle images to include for training. It is important to still choose images where enough face detail is visible to recognize someone. +Once front-facing images are performing well, start choosing slightly off-angle images to include for training. It is important to still choose images where enough face detail is visible to recognize someone. + +## FAQ + +### Why can't I bulk upload photos? + +It is important to methodically add photos to the library, bulk importing photos (especially from a general photo library) will lead to over-fitting in that particular scenario and hurt recognition performance. + +### Why can't I bulk reprocess faces? + +Face embedding models work by breaking apart faces into different features. This means that when reprocessing an image, only images from a similar angle will have its score affected. + +### Why do unknown people score similarly to known people? + +This can happen for a few different reasons, but this is usually an indicator that the training set needs to be improved. This is often related to over-fitting: + +- If you train with only a few images per person, especially if those images are very similar, the recognition model becomes overly specialized to those specific images. +- When you provide images with different poses, lighting, and expressions, the algorithm extracts features that are consistent across those variations. +- By training on a diverse set of images, the algorithm becomes less sensitive to minor variations and noise in the input image. + +Review your face collections and remove most of the unclear or low-quality images. Then, use the **Reprocess** button on each face in the **Train** tab to evaluate how the changes affect recognition scores. + +Avoid training on images that already score highly, as this can lead to over-fitting. Instead, focus on relatively clear images that score lower - ideally with different lighting, angles, and conditions—to help the model generalize more effectively. + +### Frigate misidentified a face. Can I tell it that a face is "not" a specific person? + +No, face recognition does not support negative training (i.e., explicitly telling it who someone is _not_). Instead, the best approach is to improve the training data by using a more diverse and representative set of images for each person. +For more guidance, refer to the section above on improving recognition accuracy. + +### I see scores above the threshold in the train tab, but a sub label wasn't assigned? + +The Frigate considers the recognition scores across all recognition attempts for each person object. The scores are continually weighted based on the area of the face, and a sub label will only be assigned to person if a person is confidently recognized consistently. This avoids cases where a single high confidence recognition would throw off the results. + +### Can I use other face recognition software like DoubleTake at the same time as the built in face recognition? + +No, using another face recognition service will interfere with Frigate's built in face recognition. When using double-take the sub_label feature must be disabled if the built in face recognition is also desired. + +### Does face recognition run on the recording stream? + +Face recognition does not run on the recording stream, this would be suboptimal for many reasons: + +1. The latency of accessing the recordings means the notifications would not include the names of recognized people because recognition would not complete until after. +2. The embedding models used run on a set image size, so larger images will be scaled down to match this anyway. +3. Motion clarity is much more important than extra pixels, over-compression and motion blur are much more detrimental to results than resolution. + +### I get an unknown error when taking a photo directly with my iPhone + +By default iOS devices will use HEIC (High Efficiency Image Container) for images, but this format is not supported for uploads. Choosing `large` as the format instead of `original` will use JPG which will work correctly. + +## How can I delete the face database and start over? + +Frigate does not store anything in its database related to face recognition. You can simply delete all of your faces through the Frigate UI or remove the contents of the `/media/frigate/clips/faces` directory. diff --git a/docs/docs/configuration/ffmpeg_presets.md b/docs/docs/configuration/ffmpeg_presets.md index 0dc8cdedd..e8c6e6eee 100644 --- a/docs/docs/configuration/ffmpeg_presets.md +++ b/docs/docs/configuration/ffmpeg_presets.md @@ -9,7 +9,7 @@ Some presets of FFmpeg args are provided by default to make the configuration ea It is highly recommended to use hwaccel presets in the config. These presets not only replace the longer args, but they also give Frigate hints of what hardware is available and allows Frigate to make other optimizations using the GPU such as when encoding the birdseye restream or when scaling a stream that has a size different than the native stream size. -See [the hwaccel docs](/configuration/hardware_acceleration.md) for more info on how to setup hwaccel for your GPU / iGPU. +See [the hwaccel docs](/configuration/hardware_acceleration_video.md) for more info on how to setup hwaccel for your GPU / iGPU. | Preset | Usage | Other Notes | | --------------------- | ------------------------------ | ----------------------------------------------------- | diff --git a/docs/docs/configuration/hardware_acceleration_enrichments.md b/docs/docs/configuration/hardware_acceleration_enrichments.md new file mode 100644 index 000000000..6bd731bd2 --- /dev/null +++ b/docs/docs/configuration/hardware_acceleration_enrichments.md @@ -0,0 +1,32 @@ +--- +id: hardware_acceleration_enrichments +title: Enrichments +--- + +# Enrichments + +Some of Frigate's enrichments can use a discrete GPU for accelerated processing. + +## Requirements + +Object detection and enrichments (like Semantic Search, Face Recognition, and License Plate Recognition) are independent features. To use a GPU for object detection, see the [Object Detectors](/configuration/object_detectors.md) documentation. If you want to use your GPU for any supported enrichments, you must choose the appropriate Frigate Docker image for your GPU and configure the enrichment according to its specific documentation. + +- **AMD** + + - ROCm will automatically be detected and used for enrichments in the `-rocm` Frigate image. + +- **Intel** + + - OpenVINO will automatically be detected and used for enrichments in the default Frigate image. + +- **Nvidia** + - Nvidia GPUs will automatically be detected and used for enrichments in the `-tensorrt` Frigate image. + - Jetson devices will automatically be detected and used for enrichments in the `-tensorrt-jp6` Frigate image. + +Utilizing a GPU for enrichments does not require you to use the same GPU for object detection. For example, you can run the `tensorrt` Docker image for enrichments and still use other dedicated hardware for object detection. + +:::note + +A Google Coral is a TPU (Tensor Processing Unit), not a dedicated GPU (Graphics Processing Unit) and therefore does not provide any kind of acceleration for Frigate's enrichments. + +::: diff --git a/docs/docs/configuration/hardware_acceleration.md b/docs/docs/configuration/hardware_acceleration_video.md similarity index 87% rename from docs/docs/configuration/hardware_acceleration.md rename to docs/docs/configuration/hardware_acceleration_video.md index e3bff0a0e..58651dc2d 100644 --- a/docs/docs/configuration/hardware_acceleration.md +++ b/docs/docs/configuration/hardware_acceleration_video.md @@ -1,20 +1,20 @@ --- -id: hardware_acceleration -title: Hardware Acceleration +id: hardware_acceleration_video +title: Video Decoding --- -# Hardware Acceleration +# Video Decoding -It is highly recommended to use a GPU for hardware acceleration in Frigate. Some types of hardware acceleration are detected and used automatically, but you may need to update your configuration to enable hardware accelerated decoding in ffmpeg. +It is highly recommended to use a GPU for hardware acceleration video decoding in Frigate. Some types of hardware acceleration are detected and used automatically, but you may need to update your configuration to enable hardware accelerated decoding in ffmpeg. Depending on your system, these parameters may not be compatible. More information on hardware accelerated decoding for ffmpeg can be found here: https://trac.ffmpeg.org/wiki/HWAccelIntro -# Officially Supported +# Object Detection ## Raspberry Pi 3/4 Ensure you increase the allocated RAM for your GPU to at least 128 (`raspi-config` > Performance Options > GPU Memory). -If you are using the HA addon, you may need to use the full access variant and turn off `Protection mode` for hardware acceleration. +If you are using the HA Add-on, you may need to use the full access variant and turn off _Protection mode_ for hardware acceleration. ```yaml # if you want to decode a h264 stream @@ -28,8 +28,8 @@ ffmpeg: :::note -If running Frigate in Docker, you either need to run in privileged mode or -map the `/dev/video*` devices to Frigate. With Docker compose add: +If running Frigate through Docker, you either need to run in privileged mode or +map the `/dev/video*` devices to Frigate. With Docker Compose add: ```yaml services: @@ -69,18 +69,18 @@ Or map in all the `/dev/video*` devices. **Recommended hwaccel Preset** -| CPU Generation | Intel Driver | Recommended Preset | Notes | -| -------------- | ------------ | ------------------ | ----------------------------------- | -| gen1 - gen7 | i965 | preset-vaapi | qsv is not supported | -| gen8 - gen12 | iHD | preset-vaapi | preset-intel-qsv-* can also be used | -| gen13+ | iHD / Xe | preset-intel-qsv-* | | -| Intel Arc GPU | iHD / Xe | preset-intel-qsv-* | | +| CPU Generation | Intel Driver | Recommended Preset | Notes | +| -------------- | ------------ | ------------------- | ------------------------------------ | +| gen1 - gen7 | i965 | preset-vaapi | qsv is not supported | +| gen8 - gen12 | iHD | preset-vaapi | preset-intel-qsv-\* can also be used | +| gen13+ | iHD / Xe | preset-intel-qsv-\* | | +| Intel Arc GPU | iHD / Xe | preset-intel-qsv-\* | | ::: :::note -The default driver is `iHD`. You may need to change the driver to `i965` by adding the following environment variable `LIBVA_DRIVER_NAME=i965` to your docker-compose file or [in the `frigate.yaml` for HA OS users](advanced.md#environment_vars). +The default driver is `iHD`. You may need to change the driver to `i965` by adding the following environment variable `LIBVA_DRIVER_NAME=i965` to your docker-compose file or [in the `config.yml` for HA Add-on users](advanced.md#environment_vars). See [The Intel Docs](https://www.intel.com/content/www/us/en/support/articles/000005505/processors.html) to figure out what generation your CPU is. @@ -191,7 +191,7 @@ VAAPI supports automatic profile selection so it will work automatically with bo :::note -You need to change the driver to `radeonsi` by adding the following environment variable `LIBVA_DRIVER_NAME=radeonsi` to your docker-compose file or [in the `frigate.yaml` for HA OS users](advanced.md#environment_vars). +You need to change the driver to `radeonsi` by adding the following environment variable `LIBVA_DRIVER_NAME=radeonsi` to your docker-compose file or [in the `config.yml` for HA Add-on users](advanced.md#environment_vars). ::: @@ -295,8 +295,7 @@ These instructions were originally based on the [Jellyfin documentation](https:/ ## NVIDIA Jetson (Orin AGX, Orin NX, Orin Nano\*, Xavier AGX, Xavier NX, TX2, TX1, Nano) A separate set of docker images is available that is based on Jetpack/L4T. They come with an `ffmpeg` build -with codecs that use the Jetson's dedicated media engine. If your Jetson host is running Jetpack 5.0+ use the `stable-tensorrt-jp5` -tagged image, or if your Jetson host is running Jetpack 6.0+ use the `stable-tensorrt-jp6` tagged image. Note that the Orin Nano has no video encoder, so frigate will use software encoding on this platform, but the image will still allow hardware decoding and tensorrt object detection. +with codecs that use the Jetson's dedicated media engine. If your Jetson host is running Jetpack 6.0+ use the `stable-tensorrt-jp6` tagged image. Note that the Orin Nano has no video encoder, so frigate will use software encoding on this platform, but the image will still allow hardware decoding and tensorrt object detection. You will need to use the image with the nvidia container runtime: @@ -306,17 +305,16 @@ You will need to use the image with the nvidia container runtime: docker run -d \ ... --runtime nvidia - ghcr.io/blakeblackshear/frigate:stable-tensorrt-jp5 + ghcr.io/blakeblackshear/frigate:stable-tensorrt-jp6 ``` ### Docker Compose - Jetson ```yaml -version: '2.4' services: frigate: ... - image: ghcr.io/blakeblackshear/frigate:stable-tensorrt-jp5 + image: ghcr.io/blakeblackshear/frigate:stable-tensorrt-jp6 runtime: nvidia # Add this ``` diff --git a/docs/docs/configuration/index.md b/docs/docs/configuration/index.md index a60da3499..b1fa876f9 100644 --- a/docs/docs/configuration/index.md +++ b/docs/docs/configuration/index.md @@ -3,10 +3,12 @@ id: index title: Frigate Configuration --- -For Home Assistant Addon installations, the config file needs to be in the root of your Home Assistant config directory (same location as `configuration.yaml`). It can be named `frigate.yaml` or `frigate.yml`, but if both files exist `frigate.yaml` will be preferred and `frigate.yml` will be ignored. +For Home Assistant Add-on installations, the config file should be at `/addon_configs//config.yml`, where `` is specific to the variant of the Frigate Add-on you are running. See the list of directories [here](#accessing-add-on-config-dir). For all other installation types, the config file should be mapped to `/config/config.yml` inside the container. +It can be named `config.yml` or `config.yaml`, but if both files exist `config.yml` will be preferred and `config.yaml` will be ignored. + It is recommended to start with a minimal configuration and add to it as described in [this guide](../guides/getting_started.md) and use the built in configuration editor in Frigate's UI which supports validation. ```yaml @@ -23,9 +25,24 @@ cameras: - detect ``` -## VSCode Configuration Schema +## Accessing the Home Assistant Add-on configuration directory {#accessing-add-on-config-dir} -VSCode supports JSON schemas for automatically validating configuration files. You can enable this feature by adding `# yaml-language-server: $schema=http://frigate_host:5000/api/config/schema.json` to the beginning of the configuration file. Replace `frigate_host` with the IP address or hostname of your Frigate server. If you're using both VSCode and Frigate as an add-on, you should use `ccab4aaf-frigate` instead. Make sure to expose the internal unauthenticated port `5000` when accessing the config from VSCode on another machine. +When running Frigate through the HA Add-on, the Frigate `/config` directory is mapped to `/addon_configs/` in the host, where `` is specific to the variant of the Frigate Add-on you are running. + +| Add-on Variant | Configuration directory | +| -------------------------- | -------------------------------------------- | +| Frigate | `/addon_configs/ccab4aaf_frigate` | +| Frigate (Full Access) | `/addon_configs/ccab4aaf_frigate-fa` | +| Frigate Beta | `/addon_configs/ccab4aaf_frigate-beta` | +| Frigate Beta (Full Access) | `/addon_configs/ccab4aaf_frigate-fa-beta` | + +**Whenever you see `/config` in the documentation, it refers to this directory.** + +If for example you are running the standard Add-on variant and use the [VS Code Add-on](https://github.com/hassio-addons/addon-vscode) to browse your files, you can click _File_ > _Open folder..._ and navigate to `/addon_configs/ccab4aaf_frigate` to access the Frigate `/config` directory and edit the `config.yaml` file. You can also use the built-in file editor in the Frigate UI to edit the configuration file. + +## VS Code Configuration Schema + +VS Code supports JSON schemas for automatically validating configuration files. You can enable this feature by adding `# yaml-language-server: $schema=http://frigate_host:5000/api/config/schema.json` to the beginning of the configuration file. Replace `frigate_host` with the IP address or hostname of your Frigate server. If you're using both VS Code and Frigate as an Add-on, you should use `ccab4aaf-frigate` instead. Make sure to expose the internal unauthenticated port `5000` when accessing the config from VS Code on another machine. ## Environment Variable Substitution @@ -65,10 +82,10 @@ genai: Here are some common starter configuration examples. Refer to the [reference config](./reference.md) for detailed information about all the config values. -### Raspberry Pi Home Assistant Addon with USB Coral +### Raspberry Pi Home Assistant Add-on with USB Coral - Single camera with 720p, 5fps stream for detect -- MQTT connected to home assistant mosquitto addon +- MQTT connected to the Home Assistant Mosquitto Add-on - Hardware acceleration for decoding video - USB Coral detector - Save all video with any detectable motion for 7 days regardless of whether any objects were detected or not diff --git a/docs/docs/configuration/license_plate_recognition.md b/docs/docs/configuration/license_plate_recognition.md index ee490a7a6..65f6e5442 100644 --- a/docs/docs/configuration/license_plate_recognition.md +++ b/docs/docs/configuration/license_plate_recognition.md @@ -3,32 +3,34 @@ id: license_plate_recognition title: License Plate Recognition (LPR) --- -Frigate can recognize license plates on vehicles and automatically add the detected characters to the `recognized_license_plate` field or a known name as a `sub_label` to objects that are of type `car`. A common use case may be to read the license plates of cars pulling into a driveway or cars passing by on a street. +Frigate can recognize license plates on vehicles and automatically add the detected characters to the `recognized_license_plate` field or a known name as a `sub_label` to tracked objects of type `car` or `motorcycle`. A common use case may be to read the license plates of cars pulling into a driveway or cars passing by on a street. LPR works best when the license plate is clearly visible to the camera. For moving vehicles, Frigate continuously refines the recognition process, keeping the most confident result. However, LPR does not run on stationary vehicles. -When a plate is recognized, the recognized name is: +When a plate is recognized, the details are: -- Added to the `car` tracked object as a `sub_label` (if known) or the `recognized_license_plate` field (if unknown) -- Viewable in the Review Item Details pane in Review and the Tracked Object Details pane in Explore. +- Added as a `sub_label` (if known) or the `recognized_license_plate` field (if unknown) to a tracked object. +- Viewable in the Review Item Details pane in Review (sub labels). +- Viewable in the Tracked Object Details pane in Explore (sub labels and recognized license plates). - Filterable through the More Filters menu in Explore. -- Published via the `frigate/events` MQTT topic as a `sub_label` (known) or `recognized_license_plate` (unknown) for the tracked object. +- Published via the `frigate/events` MQTT topic as a `sub_label` (known) or `recognized_license_plate` (unknown) for the `car` or `motorcycle` tracked object. +- Published via the `frigate/tracked_object_update` MQTT topic with `name` (if known) and `plate`. ## Model Requirements Users running a Frigate+ model (or any custom model that natively detects license plates) should ensure that `license_plate` is added to the [list of objects to track](https://docs.frigate.video/plus/#available-label-types) either globally or for a specific camera. This will improve the accuracy and performance of the LPR model. -Users without a model that detects license plates can still run LPR. Frigate uses a lightweight YOLOv9 license plate detection model that runs on your CPU. In this case, you should _not_ define `license_plate` in your list of objects to track. +Users without a model that detects license plates can still run LPR. Frigate uses a lightweight YOLOv9 license plate detection model that can be configured to run on your CPU or GPU. In this case, you should _not_ define `license_plate` in your list of objects to track. :::note -Frigate needs to first detect a `car` before it can recognize a license plate. If you're using a dedicated LPR camera or have a zoomed-in view, make sure the camera captures enough of the `car` for Frigate to detect it reliably. +In the default mode, Frigate's LPR needs to first detect a `car` or `motorcycle` before it can recognize a license plate. If you're using a dedicated LPR camera and have a zoomed-in view where a `car` or `motorcycle` will not be detected, you can still run LPR, but the configuration parameters will differ from the default mode. See the [Dedicated LPR Cameras](#dedicated-lpr-cameras) section below. ::: ## Minimum System Requirements -License plate recognition works by running AI models locally on your system. The models are relatively lightweight and run on your CPU. At least 4GB of RAM is required. +License plate recognition works by running AI models locally on your system. The models are relatively lightweight and can run on your CPU or GPU, depending on your configuration. At least 4GB of RAM is required. ## Configuration @@ -39,22 +41,38 @@ lpr: enabled: True ``` -Ensure that your camera is configured to detect objects of type `car`, and that a car is actually being detected by Frigate. Otherwise, LPR will not run. +Like other enrichments in Frigate, LPR **must be enabled globally** to use the feature. You should disable it for specific cameras at the camera level if you don't want to run LPR on cars on those cameras: + +```yaml +cameras: + garage: + ... + lpr: + enabled: False +``` + +For non-dedicated LPR cameras, ensure that your camera is configured to detect objects of type `car` or `motorcycle`, and that a car or motorcycle is actually being detected by Frigate. Otherwise, LPR will not run. Like the other real-time processors in Frigate, license plate recognition runs on the camera stream defined by the `detect` role in your config. To ensure optimal performance, select a suitable resolution for this stream in your camera's firmware that fits your specific scene and requirements. ## Advanced Configuration -Fine-tune the LPR feature using these optional parameters: +Fine-tune the LPR feature using these optional parameters at the global level of your config. The only optional parameters that can be set at the camera level are `enabled`, `min_area`, and `enhancement`. ### Detection - **`detection_threshold`**: License plate object detection confidence score required before recognition runs. - Default: `0.7` - - Note: This is field only applies to the standalone license plate detection model, `min_score` should be used to filter for models that have license plate detection built in. -- **`min_area`**: Defines the minimum size (in pixels) a license plate must be before recognition runs. - - Default: `1000` pixels. + - Note: This is field only applies to the standalone license plate detection model, `threshold` and `min_score` object filters should be used for models like Frigate+ that have license plate detection built in. +- **`min_area`**: Defines the minimum area (in pixels) a license plate must be before recognition runs. + - Default: `1000` pixels. Note: this is intentionally set very low as it is an _area_ measurement (length x width). For reference, 1000 pixels represents a ~32x32 pixel square in your camera image. - Depending on the resolution of your camera's `detect` stream, you can increase this value to ignore small or distant plates. +- **`device`**: Device to use to run license plate recognition models. + - Default: `CPU` + - This can be `CPU` or `GPU`. For users without a model that detects license plates natively, using a GPU may increase performance of the models, especially the YOLOv9 license plate detector model. See the [Hardware Accelerated Enrichments](/configuration/hardware_acceleration_enrichments.md) documentation. +- **`model_size`**: The size of the model used to detect text on plates. + - Default: `small` + - This can be `small` or `large`. The `large` model uses an enhanced text detector and is more accurate at finding text on plates but slower than the `small` model. For most users, the small model is recommended. For users in countries with multiple lines of text on plates, the large model is recommended. Note that using the large model does not improve _text recognition_, but it may improve _text detection_. ### Recognition @@ -69,19 +87,35 @@ Fine-tune the LPR feature using these optional parameters: ### Matching -- **`known_plates`**: List of strings or regular expressions that assign custom a `sub_label` to `car` objects when a recognized plate matches a known value. +- **`known_plates`**: List of strings or regular expressions that assign custom a `sub_label` to `car` and `motorcycle` objects when a recognized plate matches a known value. - These labels appear in the UI, filters, and notifications. - Unknown plates are still saved but are added to the `recognized_license_plate` field rather than the `sub_label`. - **`match_distance`**: Allows for minor variations (missing/incorrect characters) when matching a detected plate to a known plate. - For example, setting `match_distance: 1` allows a plate `ABCDE` to match `ABCBE` or `ABCD`. - This parameter will _not_ operate on known plates that are defined as regular expressions. You should define the full string of your plate in `known_plates` in order to use `match_distance`. +### Image Enhancement + +- **`enhancement`**: A value between 0 and 10 that adjusts the level of image enhancement applied to captured license plates before they are processed for recognition. This preprocessing step can sometimes improve accuracy but may also have the opposite effect. + - Default: `0` (no enhancement) + - Higher values increase contrast, sharpen details, and reduce noise, but excessive enhancement can blur or distort characters, actually making them much harder for Frigate to recognize. + - This setting is best adjusted at the camera level if running LPR on multiple cameras. + - If Frigate is already recognizing plates correctly, leave this setting at the default of `0`. However, if you're experiencing frequent character issues or incomplete plates and you can already easily read the plates yourself, try increasing the value gradually, starting at 5 and adjusting as needed. You should see how different enhancement levels affect your plates. Use the `debug_save_plates` configuration option (see below). + +### Debugging + +- **`debug_save_plates`**: Set to `True` to save captured text on plates for debugging. These images are stored in `/media/frigate/clips/lpr`, organized into subdirectories by `/`, and named based on the capture timestamp. + - These saved images are not full plates but rather the specific areas of text detected on the plates. It is normal for the text detection model to sometimes find multiple areas of text on the plate. Use them to analyze what text Frigate recognized and how image enhancement affects detection. + - **Note:** Frigate does **not** automatically delete these debug images. Once LPR is functioning correctly, you should disable this option and manually remove the saved files to free up storage. + ## Configuration Examples +These configuration parameters are available at the global level of your config. The only optional parameters that should be set at the camera level are `enabled`, `min_area`, and `enhancement`. + ```yaml lpr: enabled: True - min_area: 1500 # Ignore plates smaller than 1500 pixels + min_area: 1500 # Ignore plates with an area (length x width) smaller than 1500 pixels min_plate_length: 4 # Only recognize plates with 4 or more characters known_plates: Wife's Car: @@ -98,7 +132,7 @@ lpr: ```yaml lpr: enabled: True - min_area: 4000 # Run recognition on larger plates only + min_area: 4000 # Run recognition on larger plates only (4000 pixels represents a 63x63 pixel square in your image) recognition_threshold: 0.85 format: "^[A-Z]{2} [A-Z][0-9]{4}$" # Only recognize plates that are two letters, followed by a space, followed by a single letter and 4 numbers match_distance: 1 # Allow one character variation in plate matching @@ -110,22 +144,176 @@ lpr: - "MN D3163" ``` +:::note + +If you want to detect cars on cameras but don't want to use resources to run LPR on those cars, you should disable LPR for those specific cameras. + +```yaml +cameras: + side_yard: + lpr: + enabled: False + ... +``` + +::: + +## Dedicated LPR Cameras + +Dedicated LPR cameras are single-purpose cameras with powerful optical zoom to capture license plates on distant vehicles, often with fine-tuned settings to capture plates at night. + +To mark a camera as a dedicated LPR camera, add `type: "lpr"` the camera configuration. + +Users can configure Frigate's dedicated LPR mode in two different ways depending on whether a Frigate+ (or native `license_plate` detecting) model is used: + +### Using a Frigate+ (or Native `license_plate` Detecting) Model + +Users running a Frigate+ model (or any model that natively detects `license_plate`) can take advantage of `license_plate` detection. This allows license plates to be treated as standard objects in dedicated LPR mode, meaning that alerts, detections, snapshots, zones, and other Frigate features work as usual, and plates are detected efficiently through your configured object detector. + +An example configuration for a dedicated LPR camera using a `license_plate`-detecting model: + +```yaml +# LPR global configuration +lpr: + enabled: True + device: CPU # can also be GPU if available + +# Dedicated LPR camera configuration +cameras: + dedicated_lpr_camera: + type: "lpr" # required to use dedicated LPR camera mode + ffmpeg: ... # add your streams + detect: + enabled: True + fps: 5 # increase to 10 if vehicles move quickly across your frame. Higher than 10 is unnecessary and is not recommended. + min_initialized: 2 + width: 1920 + height: 1080 + objects: + track: + - license_plate + filters: + license_plate: + threshold: 0.7 + motion: + threshold: 30 + contour_area: 60 # use an increased value to tune out small motion changes + improve_contrast: false + mask: 0.704,0.007,0.709,0.052,0.989,0.055,0.993,0.001 # ensure your camera's timestamp is masked + record: + enabled: True # disable recording if you only want snapshots + snapshots: + enabled: True + review: + detections: + labels: + - license_plate +``` + +With this setup: + +- License plates are treated as normal objects in Frigate. +- Scores, alerts, detections, snapshots, zones, and object masks work as expected. +- Snapshots will have license plate bounding boxes on them. +- The `frigate/events` MQTT topic will publish tracked object updates. +- Debug view will display `license_plate` bounding boxes. +- If you are using a Frigate+ model and want to submit images from your dedicated LPR camera for model training and fine-tuning, annotate both the `car` / `motorcycle` and the `license_plate` in the snapshots on the Frigate+ website, even if the car is barely visible. + +### Using the Secondary LPR Pipeline (Without Frigate+) + +If you are not running a Frigate+ model, you can use Frigate’s built-in secondary dedicated LPR pipeline. In this mode, Frigate bypasses the standard object detection pipeline and runs a local license plate detector model on the full frame whenever motion activity occurs. + +An example configuration for a dedicated LPR camera using the secondary pipeline: + +```yaml +# LPR global configuration +lpr: + enabled: True + device: CPU # can also be GPU if available and correct Docker image is used + detection_threshold: 0.7 # change if necessary + +# Dedicated LPR camera configuration +cameras: + dedicated_lpr_camera: + type: "lpr" # required to use dedicated LPR camera mode + lpr: + enabled: True + enhancement: 3 # optional, enhance the image before trying to recognize characters + ffmpeg: ... # add your streams + detect: + enabled: False # disable Frigate's standard object detection pipeline + fps: 5 # increase if necessary, though high values may slow down Frigate's enrichments pipeline and use considerable CPU + width: 1920 + height: 1080 + objects: + track: [] # required when not using a Frigate+ model for dedicated LPR mode + motion: + threshold: 30 + contour_area: 60 # use an increased value here to tune out small motion changes + improve_contrast: false + mask: 0.704,0.007,0.709,0.052,0.989,0.055,0.993,0.001 # ensure your camera's timestamp is masked + record: + enabled: True # disable recording if you only want snapshots + review: + detections: + enabled: True + retain: + default: 7 +``` + +With this setup: + +- The standard object detection pipeline is bypassed. Any detected license plates on dedicated LPR cameras are treated similarly to manual events in Frigate. You must **not** specify `license_plate` as an object to track. +- The license plate detector runs on the full frame whenever motion is detected and processes frames according to your detect `fps` setting. +- Review items will always be classified as a `detection`. +- Snapshots will always be saved. +- Zones and object masks are **not** used. +- The `frigate/events` MQTT topic will **not** publish tracked object updates with the license plate bounding box and score, though `frigate/reviews` will publish if recordings are enabled. If a plate is recognized as a known plate, publishing will occur with an updated `sub_label` field. If characters are recognized, publishing will occur with an updated `recognized_license_plate` field. +- License plate snapshots are saved at the highest-scoring moment and appear in Explore. +- Debug view will not show `license_plate` bounding boxes. + +### Summary + +| Feature | Native `license_plate` detecting Model (like Frigate+) | Secondary Pipeline (without native model or Frigate+) | +| ----------------------- | ------------------------------------------------------ | --------------------------------------------------------------- | +| License Plate Detection | Uses `license_plate` as a tracked object | Runs a dedicated LPR pipeline | +| FPS Setting | 5 (increase for fast-moving cars) | 5 (increase for fast-moving cars, but it may use much more CPU) | +| Object Detection | Standard Frigate+ detection applies | Bypasses standard object detection | +| Zones & Object Masks | Supported | Not supported | +| Debug View | May show `license_plate` bounding boxes | May **not** show `license_plate` bounding boxes | +| MQTT `frigate/events` | Publishes tracked object updates | Publishes limited updates | +| Explore | Recognized plates available in More Filters | Recognized plates available in More Filters | + +By selecting the appropriate configuration, users can optimize their dedicated LPR cameras based on whether they are using a Frigate+ model or the secondary LPR pipeline. + +### Best practices for using Dedicated LPR camera mode + +- Tune your motion detection and increase the `contour_area` until you see only larger motion boxes being created as cars pass through the frame (likely somewhere between 50-90 for a 1920x1080 detect stream). Increasing the `contour_area` filters out small areas of motion and will prevent excessive resource use from looking for license plates in frames that don't even have a car passing through it. +- Disable the `improve_contrast` motion setting, especially if you are running LPR at night and the frame is mostly dark. This will prevent small pixel changes and smaller areas of motion from triggering license plate detection. +- Ensure your camera's timestamp is covered with a motion mask so that it's not incorrectly detected as a license plate. +- For non-Frigate+ users, you may need to change your camera settings for a clearer image or decrease your global `recognition_threshold` config if your plates are not being accurately recognized at night. +- The secondary pipeline mode runs a local AI model on your CPU or GPU (depending on how `device` is configured) to detect plates. Increasing detect `fps` will increase resource usage proportionally. + ## FAQ ### Why isn't my license plate being detected and recognized? Ensure that: -- Your camera has a clear, human-readable, well-lit view of the plate. If you can't read the plate, Frigate certainly won't be able to. This may require changing video size, quality, or frame rate settings on your camera, depending on your scene and how fast the vehicles are traveling. +- Your camera has a clear, human-readable, well-lit view of the plate. If you can't read the plate's characters, Frigate certainly won't be able to, even if the model is recognizing a `license_plate`. This may require changing video size, quality, or frame rate settings on your camera, depending on your scene and how fast the vehicles are traveling. - The plate is large enough in the image (try adjusting `min_area`) or increasing the resolution of your camera's stream. -- A `car` is detected first, as LPR only runs on recognized vehicles. +- Your `enhancement` level (if you've changed it from the default of `0`) is not too high. Too much enhancement will run too much denoising and cause the plate characters to become blurry and unreadable. If you are using a Frigate+ model or a custom model that detects license plates, ensure that `license_plate` is added to your list of objects to track. If you are using the free model that ships with Frigate, you should _not_ add `license_plate` to the list of objects to track. -### Can I run LPR without detecting `car` objects? +Recognized plates will show as object labels in the debug view and will appear in the "Recognized License Plates" select box in the More Filters popout in Explore. -No, Frigate requires a `car` to be detected first before recognizing a license plate. +If you are still having issues detecting plates, start with a basic configuration and see the debugging tips below. + +### Can I run LPR without detecting `car` or `motorcycle` objects? + +In normal LPR mode, Frigate requires a `car` or `motorcycle` to be detected first before recognizing a license plate. If you have a dedicated LPR camera, you can change the camera `type` to `"lpr"` to use the Dedicated LPR Camera algorithm. This comes with important caveats, though. See the [Dedicated LPR Cameras](#dedicated-lpr-cameras) section above. ### How can I improve detection accuracy? @@ -137,6 +325,10 @@ No, Frigate requires a `car` to be detected first before recognizing a license p Yes, but performance depends on camera quality, lighting, and infrared capabilities. Make sure your camera can capture clear images of plates at night. +### Can I limit LPR to specific zones? + +LPR, like other Frigate enrichments, runs at the camera level rather than the zone level. While you can't restrict LPR to specific zones directly, you can control when recognition runs by setting a `min_area` value to filter out smaller detections. + ### How can I match known plates with minor variations? Use `match_distance` to allow small character mismatches. Alternatively, define multiple variations in `known_plates`. @@ -144,10 +336,37 @@ Use `match_distance` to allow small character mismatches. Alternatively, define ### How do I debug LPR issues? - View MQTT messages for `frigate/events` to verify detected plates. -- Adjust `detection_threshold` and `recognition_threshold` settings. -- If you are using a Frigate+ model or a model that detects license plates, watch the debug view (Settings --> Debug) to ensure that `license_plate` is being detected with a `car`. +- If you are using a Frigate+ model or a model that detects license plates, watch the debug view (Settings --> Debug) to ensure that `license_plate` is being detected with a `car` or `motorcycle`. +- Watch the debug view to see plates recognized in real-time. For non-dedicated LPR cameras, the `car` or `motorcycle` label will change to the recognized plate when LPR is enabled and working. +- Adjust `detection_threshold` and `recognition_threshold` settings per the suggestions [above](#advanced-configuration). +- Enable `debug_save_plates` to save images of detected text on plates to the clips directory (`/media/frigate/clips/lpr`). Ensure these images are readable and the text is clear. - Enable debug logs for LPR by adding `frigate.data_processing.common.license_plate: debug` to your `logger` configuration. These logs are _very_ verbose, so only enable this when necessary. + ```yaml + logger: + default: info + logs: + frigate.data_processing.common.license_plate: debug + ``` + ### Will LPR slow down my system? -LPR runs on the CPU, so performance impact depends on your hardware. Ensure you have at least 4GB RAM and a capable CPU for optimal results. +LPR's performance impact depends on your hardware. Ensure you have at least 4GB RAM and a capable CPU or GPU for optimal results. If you are running the Dedicated LPR Camera mode, resource usage will be higher compared to users who run a model that natively detects license plates. Tune your motion detection settings for your dedicated LPR camera so that the license plate detection model runs only when necessary. + +### I am seeing a YOLOv9 plate detection metric in Enrichment Metrics, but I have a Frigate+ or custom model that detects `license_plate`. Why is the YOLOv9 model running? + +The YOLOv9 license plate detector model will run (and the metric will appear) if you've enabled LPR but haven't defined `license_plate` as an object to track, either at the global or camera level. + +If you are detecting `car` or `motorcycle` on cameras where you don't want to run LPR, make sure you disable LPR it at the camera level. And if you do want to run LPR on those cameras, make sure you define `license_plate` as an object to track. + +### It looks like Frigate picked up my camera's timestamp or overlay text as the license plate. How can I prevent this? + +This could happen if cars or motorcycles travel close to your camera's timestamp or overlay text. You could either move the text through your camera's firmware, or apply a mask to it in Frigate. + +If you are using a model that natively detects `license_plate`, add an _object mask_ of type `license_plate` and a _motion mask_ over your text. + +If you are not using a model that natively detects `license_plate` or you are using dedicated LPR camera mode, only a _motion mask_ over your text is required. + +### I see "Error running ... model" in my logs. How can I fix this? + +This usually happens when your GPU is unable to compile or use one of the LPR models. Set your `device` to `CPU` and try again. GPU acceleration only provides a slight performance increase, and the models are lightweight enough to run without issue on most CPUs. diff --git a/docs/docs/configuration/live.md b/docs/docs/configuration/live.md index 42809739a..cdf2d537d 100644 --- a/docs/docs/configuration/live.md +++ b/docs/docs/configuration/live.md @@ -42,6 +42,16 @@ go2rtc: - "ffmpeg:http_cam#audio=opus" # <- copy of the stream which transcodes audio to the missing codec (usually will be opus) ``` +If your camera does not support AAC audio or are having problems with Live view, try transcoding to AAC audio directly: + +```yaml +go2rtc: + streams: + rtsp_cam: # <- for RTSP streams + - "ffmpeg:rtsp://192.168.1.5:554/live0#video=copy#audio=aac" # <- copies video stream and transcodes to aac audio + - "ffmpeg:rtsp_cam#audio=opus" # <- provides support for WebRTC +``` + If your camera does not have audio and you are having problems with Live view, you should have go2rtc send video only: ```yaml @@ -104,9 +114,9 @@ cameras: WebRTC works by creating a TCP or UDP connection on port `8555`. However, it requires additional configuration: - For external access, over the internet, setup your router to forward port `8555` to port `8555` on the Frigate device, for both TCP and UDP. -- For internal/local access, unless you are running through the add-on, you will also need to set the WebRTC candidates list in the go2rtc config. For example, if `192.168.1.10` is the local IP of the device running Frigate: +- For internal/local access, unless you are running through the HA Add-on, you will also need to set the WebRTC candidates list in the go2rtc config. For example, if `192.168.1.10` is the local IP of the device running Frigate: - ```yaml title="/config/frigate.yaml" + ```yaml title="config.yml" go2rtc: streams: test_cam: ... @@ -121,9 +131,9 @@ WebRTC works by creating a TCP or UDP connection on port `8555`. However, it req :::tip -This extra configuration may not be required if Frigate has been installed as a Home Assistant add-on, as Frigate uses the Supervisor's API to generate a WebRTC candidate. +This extra configuration may not be required if Frigate has been installed as a Home Assistant Add-on, as Frigate uses the Supervisor's API to generate a WebRTC candidate. -However, it is recommended if issues occur to define the candidates manually. You should do this if the Frigate add-on fails to generate a valid candidate. If an error occurs you will see some warnings like the below in the add-on logs page during the initialization: +However, it is recommended if issues occur to define the candidates manually. You should do this if the Frigate Add-on fails to generate a valid candidate. If an error occurs you will see some warnings like the below in the Add-on logs page during the initialization: ```log [WARN] Failed to get IP address from supervisor @@ -203,9 +213,11 @@ Note that disabling a camera through the config file (`enabled: False`) removes Frigate intelligently selects the live streaming technology based on a number of factors (user-selected modes like two-way talk, camera settings, browser capabilities, available bandwidth) and prioritizes showing an actual up-to-date live view of your camera's stream as quickly as possible. - When you have go2rtc configured, Live view initially attempts to load and play back your stream with a clearer, fluent stream technology (MSE). An initial timeout, a low bandwidth condition that would cause buffering of the stream, or decoding errors in the stream will cause Frigate to switch to the stream defined by the `detect` role, using the jsmpeg format. This is what the UI labels as "low bandwidth mode". On Live dashboards, the mode will automatically reset when smart streaming is configured and activity stops. You can also try using the _Reset_ button to force a reload of your stream. + When you have go2rtc configured, Live view initially attempts to load and play back your stream with a clearer, fluent stream technology (MSE). An initial timeout, a low bandwidth condition that would cause buffering of the stream, or decoding errors in the stream will cause Frigate to switch to the stream defined by the `detect` role, using the jsmpeg format. This is what the UI labels as "low bandwidth mode". On Live dashboards, the mode will automatically reset when smart streaming is configured and activity stops. Continuous streaming mode does not have an automatic reset mechanism, but you can use the _Reset_ option to force a reload of your stream. - If you are still experiencing Frigate falling back to low bandwidth mode, you may need to adjust your camera's settings per the recommendations above or ensure you have enough bandwidth available. + If you are using continuous streaming or you are loading more than a few high resolution streams at once on the dashboard, your browser may struggle to begin playback of your streams before the timeout. Frigate always prioritizes showing a live stream as quickly as possible, even if it is a lower quality jsmpeg stream. You can use the "Reset" link/button to try loading your high resolution stream again. + + If you are still experiencing Frigate falling back to low bandwidth mode, you may need to adjust your camera's settings per the [recommendations above](#camera_settings_recommendations). 3. **It doesn't seem like my cameras are streaming on the Live dashboard. Why?** @@ -221,6 +233,8 @@ Note that disabling a camera through the config file (`enabled: False`) removes This static image is pulled from the stream defined in your config with the `detect` role. When activity is detected, images from the `detect` stream immediately begin updating at ~5 frames per second so you can see the activity until the live player is loaded and begins playing. This usually only takes a second or two. If the live player times out, buffers, or has streaming errors, the jsmpeg player is loaded and plays a video-only stream from the `detect` role. When activity ends, the players are destroyed and a static image is displayed until activity is detected again, and the process repeats. + Smart streaming depends on having your camera's motion `threshold` and `contour_area` config values dialed in. Use the Motion Tuner in Settings in the UI to tune these values in real-time. + This is Frigate's default and recommended setting because it results in a significant bandwidth savings, especially for high resolution cameras. 6. **I have unmuted some cameras on my dashboard, but I do not hear sound. Why?** diff --git a/docs/docs/configuration/motion_detection.md b/docs/docs/configuration/motion_detection.md index 7621489ff..ec6d7ca25 100644 --- a/docs/docs/configuration/motion_detection.md +++ b/docs/docs/configuration/motion_detection.md @@ -77,7 +77,7 @@ At this point if motion is working as desired there is no reason to continue wit Once daytime motion detection is tuned, there is a chance that the settings will work well for motion detection during the night as well. If this is the case then the preferred settings can be written to the config file and left alone. -However, if the preferred day settings do not work well at night it is recommended to use HomeAssistant or some other solution to automate changing the settings. That way completely separate sets of motion settings can be used for optimal day and night motion detection. +However, if the preferred day settings do not work well at night it is recommended to use Home Assistant or some other solution to automate changing the settings. That way completely separate sets of motion settings can be used for optimal day and night motion detection. ## Tuning For Large Changes In Motion diff --git a/docs/docs/configuration/object_detectors.md b/docs/docs/configuration/object_detectors.md index c562923d7..d85939f96 100644 --- a/docs/docs/configuration/object_detectors.md +++ b/docs/docs/configuration/object_detectors.md @@ -28,7 +28,7 @@ Frigate supports multiple different detectors that work on different types of ha **Nvidia** - [TensortRT](#nvidia-tensorrt-detector): TensorRT can run on Nvidia GPUs and Jetson devices, using one of many default models. -- [ONNX](#onnx): TensorRT will automatically be detected and used as a detector in the `-tensorrt` or `-tensorrt-jp(4/5)` Frigate images when a supported ONNX model is configured. +- [ONNX](#onnx): TensorRT will automatically be detected and used as a detector in the `-tensorrt` or `-tensorrt-jp6` Frigate images when a supported ONNX model is configured. **Rockchip** @@ -130,8 +130,8 @@ detectors: type: edgetpu device: pci ``` ---- +--- ## Hailo-8 @@ -141,18 +141,21 @@ See the [installation docs](../frigate/installation.md#hailo-8l) for information ### Configuration +When configuring the Hailo detector, you have two options to specify the model: a local **path** or a **URL**. When configuring the Hailo detector, you have two options to specify the model: a local **path** or a **URL**. If both are provided, the detector will first check for the model at the given local path. If the file is not found, it will download the model from the specified URL. The model file is cached under `/config/model_cache/hailo`. +#### YOLO #### YOLO Use this configuration for YOLO-based models. When no custom model path or URL is provided, the detector automatically downloads the default model based on the detected hardware: + - **Hailo-8 hardware:** Uses **YOLOv6n** (default: `yolov6n.hef`) - **Hailo-8L hardware:** Uses **YOLOv6n** (default: `yolov6n.hef`) ```yaml detectors: - hailo8l: + hailo: type: hailo8l device: PCIe @@ -163,6 +166,7 @@ model: input_pixel_format: rgb input_dtype: int model_type: yolo-generic + labelmap_path: /labelmap/coco-80.txt # The detector automatically selects the default model based on your hardware: # - For Hailo-8 hardware: YOLOv6n (default: yolov6n.hef) @@ -184,7 +188,7 @@ For SSD-based models, provide either a model path or URL to your compiled SSD mo ```yaml detectors: - hailo8l: + hailo: type: hailo8l device: PCIe @@ -208,7 +212,7 @@ The Hailo detector supports all YOLO models compiled for Hailo hardware that inc ```yaml detectors: - hailo8l: + hailo: type: hailo8l device: PCIe @@ -219,12 +223,14 @@ model: input_pixel_format: rgb input_dtype: int model_type: yolo-generic + labelmap_path: /labelmap/coco-80.txt # Optional: Specify a local model path. # path: /config/model_cache/hailo/custom_model.hef # # Alternatively, or as a fallback, provide a custom URL: # path: https://custom-model-url.com/path/to/model.hef ``` + For additional ready-to-use models, please visit: https://github.com/hailo-ai/hailo_model_zoo Hailo8 supports all models in the Hailo Model Zoo that include HailoRT post-processing. You're welcome to choose any of these pre-configured models for your implementation. @@ -370,13 +376,13 @@ model: Note that the labelmap uses a subset of the complete COCO label set that has only 80 objects. -#### YOLOv9 +#### YOLO (v3, v4, v7, v9) -[YOLOv9](https://github.com/WongKinYiu/yolov9) models are supported, but not included by default. +YOLOv3, YOLOv4, YOLOv7, and [YOLOv9](https://github.com/WongKinYiu/yolov9) models are supported, but not included by default. :::tip -The YOLOv9 detector has been designed to support YOLOv9 models, but may support other YOLO model architectures as well. +The YOLO detector has been designed to support YOLOv3, YOLOv4, YOLOv7, and YOLOv9 models, but may support other YOLO model architectures as well. ::: @@ -389,12 +395,69 @@ detectors: device: GPU model: - model_type: yolov9 - width: 640 # <--- should match the imgsize set during model export - height: 640 # <--- should match the imgsize set during model export + model_type: yolo-generic + width: 320 # <--- should match the imgsize set during model export + height: 320 # <--- should match the imgsize set during model export input_tensor: nchw input_dtype: float - path: /config/model_cache/yolov9-t.onnx + path: /config/model_cache/yolo.onnx + labelmap_path: /labelmap/coco-80.txt +``` + +Note that the labelmap uses a subset of the complete COCO label set that has only 80 objects. + +#### RF-DETR + +[RF-DETR](https://github.com/roboflow/rf-detr) is a DETR based model. The ONNX exported models are supported, but not included by default. See [the models section](#downloading-rf-detr-model) for more informatoin on downloading the RF-DETR model for use in Frigate. + +:::warning + +Due to the size and complexity of the RF-DETR model, it is only recommended to be run with discrete Arc Graphics Cards. + +::: + +After placing the downloaded onnx model in your `config/model_cache` folder, you can use the following configuration: + +```yaml +detectors: + ov: + type: openvino + device: GPU + +model: + model_type: rfdetr + width: 560 + height: 560 + input_tensor: nchw + input_dtype: float + path: /config/model_cache/rfdetr.onnx +``` + +#### D-FINE + +[D-FINE](https://github.com/Peterande/D-FINE) is a DETR based model. The ONNX exported models are supported, but not included by default. See [the models section](#downloading-d-fine-model) for more information on downloading the D-FINE model for use in Frigate. + +:::warning + +Currently D-FINE models only run on OpenVINO in CPU mode, GPUs currently fail to compile the model + +::: + +After placing the downloaded onnx model in your config/model_cache folder, you can use the following configuration: + +```yaml +detectors: + ov: + type: openvino + device: GPU + +model: + model_type: dfine + width: 640 + height: 640 + input_tensor: nchw + input_dtype: float + path: /config/model_cache/dfine_s_obj2coco.onnx labelmap_path: /labelmap/coco-80.txt ``` @@ -485,7 +548,7 @@ frigate: ### Configuration Parameters -The TensorRT detector can be selected by specifying `tensorrt` as the model type. The GPU will need to be passed through to the docker container using the same methods described in the [Hardware Acceleration](hardware_acceleration.md#nvidia-gpus) section. If you pass through multiple GPUs, you can select which GPU is used for a detector with the `device` configuration parameter. The `device` parameter is an integer value of the GPU index, as shown by `nvidia-smi` within the container. +The TensorRT detector can be selected by specifying `tensorrt` as the model type. The GPU will need to be passed through to the docker container using the same methods described in the [Hardware Acceleration](hardware_acceleration_video.md#nvidia-gpus) section. If you pass through multiple GPUs, you can select which GPU is used for a detector with the `device` configuration parameter. The `device` parameter is an integer value of the GPU index, as shown by `nvidia-smi` within the container. The TensorRT detector uses `.trt` model files that are located in `/config/model_cache/tensorrt` by default. These model path and dimensions used will depend on which model you have generated. @@ -522,7 +585,7 @@ $ docker run --device=/dev/kfd --device=/dev/dri \ ... ``` -When using docker compose: +When using Docker Compose: ```yaml services: @@ -554,7 +617,7 @@ $ docker run -e HSA_OVERRIDE_GFX_VERSION=9.0.0 \ ... ``` -When using docker compose: +When using Docker Compose: ```yaml services: @@ -589,6 +652,7 @@ $ docker exec -it frigate /bin/bash -c '(unset HSA_OVERRIDE_GFX_VERSION && /opt/ ### Supported Models See [ONNX supported models](#supported-models) for supported models, there are some caveats: + - D-FINE models are not supported - YOLO-NAS models are known to not run well on integrated GPUs @@ -610,7 +674,7 @@ If the correct build is used for your GPU then the GPU will be detected and used - **Nvidia** - Nvidia GPUs will automatically be detected and used with the ONNX detector in the `-tensorrt` Frigate image. - - Jetson devices will automatically be detected and used with the ONNX detector in the `-tensorrt-jp(4/5)` Frigate image. + - Jetson devices will automatically be detected and used with the ONNX detector in the `-tensorrt-jp6` Frigate image. ::: @@ -653,13 +717,13 @@ model: labelmap_path: /labelmap/coco-80.txt ``` -#### YOLOv9 +#### YOLO (v3, v4, v7, v9) -[YOLOv9](https://github.com/WongKinYiu/yolov9) models are supported, but not included by default. +YOLOv3, YOLOv4, YOLOv7, and [YOLOv9](https://github.com/WongKinYiu/yolov9) models are supported, but not included by default. :::tip -The YOLOv9 detector has been designed to support YOLOv9 models, but may support other YOLO model architectures as well. +The YOLO detector has been designed to support YOLOv3, YOLOv4, YOLOv7, and YOLOv9 models, but may support other YOLO model architectures as well. See [the models section](#downloading-yolo-models) for more information on downloading YOLO models for use in Frigate. ::: @@ -671,28 +735,65 @@ detectors: type: onnx model: - model_type: yolov9 - width: 640 # <--- should match the imgsize set during model export - height: 640 # <--- should match the imgsize set during model export + model_type: yolo-generic + width: 320 # <--- should match the imgsize set during model export + height: 320 # <--- should match the imgsize set during model export input_tensor: nchw input_dtype: float - path: /config/model_cache/yolov9-t.onnx + path: /config/model_cache/yolo.onnx labelmap_path: /labelmap/coco-80.txt ``` Note that the labelmap uses a subset of the complete COCO label set that has only 80 objects. +#### YOLOx + +[YOLOx](https://github.com/Megvii-BaseDetection/YOLOX) models are supported, but not included by default. See [the models section](#downloading-yolo-models) for more information on downloading the YOLOx model for use in Frigate. + +After placing the downloaded onnx model in your config folder, you can use the following configuration: + +```yaml +detectors: + onnx: + type: onnx + +model: + model_type: yolox + width: 416 # <--- should match the imgsize set during model export + height: 416 # <--- should match the imgsize set during model export + input_tensor: nchw + input_dtype: float_denorm + path: /config/model_cache/yolox_tiny.onnx + labelmap_path: /labelmap/coco-80.txt +``` + +Note that the labelmap uses a subset of the complete COCO label set that has only 80 objects. + +#### RF-DETR + +[RF-DETR](https://github.com/roboflow/rf-detr) is a DETR based model. The ONNX exported models are supported, but not included by default. See [the models section](#downloading-rf-detr-model) for more information on downloading the RF-DETR model for use in Frigate. + +After placing the downloaded onnx model in your `config/model_cache` folder, you can use the following configuration: + +```yaml +detectors: + onnx: + type: onnx + +model: + model_type: rfdetr + width: 560 + height: 560 + input_tensor: nchw + input_dtype: float + path: /config/model_cache/rfdetr.onnx +``` + #### D-FINE -[D-FINE](https://github.com/Peterande/D-FINE) is the [current state of the art](https://paperswithcode.com/sota/real-time-object-detection-on-coco?p=d-fine-redefine-regression-task-in-detrs-as) at the time of writing. The ONNX exported models are supported, but not included by default. See [the models section](#downloading-d-fine-model) for more information on downloading the D-FINE model for use in Frigate. +[D-FINE](https://github.com/Peterande/D-FINE) is a DETR based model. The ONNX exported models are supported, but not included by default. See [the models section](#downloading-d-fine-model) for more information on downloading the D-FINE model for use in Frigate. -:::warning - -D-FINE is currently not supported on OpenVINO - -::: - -After placing the downloaded onnx model in your config/model_cache folder, you can use the following configuration: +After placing the downloaded onnx model in your `config/model_cache` folder, you can use the following configuration: ```yaml detectors: @@ -774,66 +875,27 @@ Hardware accelerated object detection is supported on the following SoCs: - RK3576 - RK3588 -This implementation uses the [Rockchip's RKNN-Toolkit2](https://github.com/airockchip/rknn-toolkit2/), version v2.3.0. Currently, only [Yolo-NAS](https://github.com/Deci-AI/super-gradients/blob/master/YOLONAS.md) is supported as object detection model. +This implementation uses the [Rockchip's RKNN-Toolkit2](https://github.com/airockchip/rknn-toolkit2/), version v2.3.2. -### Prerequisites +:::tip -Make sure to follow the [Rockchip specific installation instrucitions](/frigate/installation#rockchip-platform). - -### Configuration - -This `config.yml` shows all relevant options to configure the detector and explains them. All values shown are the default values (except for two). Lines that are required at least to use the detector are labeled as required, all other lines are optional. +When using many cameras one detector may not be enough to keep up. Multiple detectors can be defined assuming NPU resources are available. An example configuration would be: ```yaml -detectors: # required - rknn: # required - type: rknn # required - # number of NPU cores to use - # 0 means choose automatically - # increase for better performance if you have a multicore NPU e.g. set to 3 on rk3588 +detectors: + rknn_0: + type: rknn + num_cores: 0 + rknn_1: + type: rknn num_cores: 0 - -model: # required - # name of model (will be automatically downloaded) or path to your own .rknn model file - # possible values are: - # - deci-fp16-yolonas_s - # - deci-fp16-yolonas_m - # - deci-fp16-yolonas_l - # - /config/model_cache/your_custom_model.rknn - path: deci-fp16-yolonas_s - # width and height of detection frames - width: 320 - height: 320 - # pixel format of detection frame - # default value is rgb but yolo models usually use bgr format - input_pixel_format: bgr # required - # shape of detection frame - input_tensor: nhwc - # needs to be adjusted to model, see below - labelmap_path: /labelmap.txt # required ``` -The correct labelmap must be loaded for each model. If you use a custom model (see notes below), you must make sure to provide the correct labelmap. The table below lists the correct paths for the bundled models: - -| `path` | `labelmap_path` | -| --------------------- | --------------------- | -| deci-fp16-yolonas\_\* | /labelmap/coco-80.txt | - -### Choosing a model - -:::warning - -The pre-trained YOLO-NAS weights from DeciAI are subject to their license and can't be used commercially. For more information, see: https://docs.deci.ai/super-gradients/latest/LICENSE.YOLONAS.html - ::: -The inference time was determined on a rk3588 with 3 NPU cores. +### Prerequisites -| Model | Size in mb | Inference time in ms | -| ------------------- | ---------- | -------------------- | -| deci-fp16-yolonas_s | 24 | 25 | -| deci-fp16-yolonas_m | 62 | 35 | -| deci-fp16-yolonas_l | 81 | 45 | +Make sure to follow the [Rockchip specific installation instructions](/frigate/installation#rockchip-platform). :::tip @@ -846,9 +908,99 @@ $ cat /sys/kernel/debug/rknpu/load ::: +### Supported Models + +This `config.yml` shows all relevant options to configure the detector and explains them. All values shown are the default values (except for two). Lines that are required at least to use the detector are labeled as required, all other lines are optional. + +```yaml +detectors: # required + rknn: # required + type: rknn # required + # number of NPU cores to use + # 0 means choose automatically + # increase for better performance if you have a multicore NPU e.g. set to 3 on rk3588 + num_cores: 0 +``` + +The inference time was determined on a rk3588 with 3 NPU cores. + +| Model | Size in mb | Inference time in ms | +| --------------------- | ---------- | -------------------- | +| deci-fp16-yolonas_s | 24 | 25 | +| deci-fp16-yolonas_m | 62 | 35 | +| deci-fp16-yolonas_l | 81 | 45 | +| frigate-fp16-yolov9-t | 6 | 35 | +| rock-i8-yolox_nano | 3 | 14 | +| rock-i8_yolox_tiny | 6 | 18 | + - All models are automatically downloaded and stored in the folder `config/model_cache/rknn_cache`. After upgrading Frigate, you should remove older models to free up space. - You can also provide your own `.rknn` model. You should not save your own models in the `rknn_cache` folder, store them directly in the `model_cache` folder or another subfolder. To convert a model to `.rknn` format see the `rknn-toolkit2` (requires a x86 machine). Note, that there is only post-processing for the supported models. +#### YOLO-NAS + +```yaml +model: # required + # name of model (will be automatically downloaded) or path to your own .rknn model file + # possible values are: + # - deci-fp16-yolonas_s + # - deci-fp16-yolonas_m + # - deci-fp16-yolonas_l + # your yolonas_model.rknn + path: deci-fp16-yolonas_s + model_type: yolonas + width: 320 + height: 320 + input_pixel_format: bgr + input_tensor: nhwc + labelmap_path: /labelmap/coco-80.txt +``` + +:::warning + +The pre-trained YOLO-NAS weights from DeciAI are subject to their license and can't be used commercially. For more information, see: https://docs.deci.ai/super-gradients/latest/LICENSE.YOLONAS.html + +::: + +#### YOLO (v9) + +```yaml +model: # required + # name of model (will be automatically downloaded) or path to your own .rknn model file + # possible values are: + # - frigate-fp16-yolov9-t + # - frigate-fp16-yolov9-s + # - frigate-fp16-yolov9-m + # - frigate-fp16-yolov9-c + # - frigate-fp16-yolov9-e + # your yolo_model.rknn + path: frigate-fp16-yolov9-t + model_type: yolo-generic + width: 320 + height: 320 + input_tensor: nhwc + input_dtype: float + labelmap_path: /labelmap/coco-80.txt +``` + +#### YOLOx + +```yaml +model: # required + # name of model (will be automatically downloaded) or path to your own .rknn model file + # possible values are: + # - rock-i8-yolox_nano + # - rock-i8-yolox_tiny + # - rock-fp16-yolox_nano + # - rock-fp16-yolox_tiny + # your yolox_model.rknn + path: rock-i8-yolox_nano + model_type: yolox + width: 416 + height: 416 + input_tensor: nhwc + labelmap_path: /labelmap/coco-80.txt +``` + ### Converting your own onnx model to rknn format To convert a onnx model to the rknn format using the [rknn-toolkit2](https://github.com/airockchip/rknn-toolkit2/) you have to: @@ -868,7 +1020,7 @@ output_name: "{input_basename}" config: mean_values: [[0, 0, 0]] std_values: [[255, 255, 255]] - quant_img_rgb2bgr: true + quant_img_RGB2BGR: true ``` Explanation of the paramters: @@ -881,7 +1033,7 @@ Explanation of the paramters: - `soc`: the SoC this model was build for (e.g. "rk3588") - `tk_version`: Version of `rknn-toolkit2` (e.g. "2.3.0") - **example**: Specifying `output_name = "frigate-{quant}-{input_basename}-{soc}-v{tk_version}"` could result in a model called `frigate-i8-my_model-rk3588-v2.3.0.rknn`. -- `config`: Configuration passed to `rknn-toolkit2` for model conversion. For an explanation of all available parameters have a look at section "2.2. Model configuration" of [this manual](https://github.com/MarcA711/rknn-toolkit2/releases/download/v2.3.0/03_Rockchip_RKNPU_API_Reference_RKNN_Toolkit2_V2.3.0_EN.pdf). +- `config`: Configuration passed to `rknn-toolkit2` for model conversion. For an explanation of all available parameters have a look at section "2.2. Model configuration" of [this manual](https://github.com/MarcA711/rknn-toolkit2/releases/download/v2.3.2/03_Rockchip_RKNPU_API_Reference_RKNN_Toolkit2_V2.3.2_EN.pdf). # Models @@ -914,6 +1066,26 @@ Make sure you change the batch size to 1 before exporting. ::: +### Download RF-DETR Model + +To export as ONNX: + +1. `pip3 install rfdetr` +2. `python3` +3. `from rfdetr import RFDETRBase` +4. `x = RFDETRBase()` +5. `x.export()` + +#### Additional Configuration + +The input tensor resolution can be customized: + +```python +from rfdetr import RFDETRBase +x = RFDETRBase(resolution=560) # resolution must be a multiple of 56 +x.export() +``` + ### Downloading YOLO-NAS Model You can build and download a compatible model with pre-trained weights using [this notebook](https://github.com/blakeblackshear/frigate/blob/dev/notebooks/YOLO_NAS_Pretrained_Export.ipynb) [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/blakeblackshear/frigate/blob/dev/notebooks/YOLO_NAS_Pretrained_Export.ipynb). @@ -925,3 +1097,41 @@ The pre-trained YOLO-NAS weights from DeciAI are subject to their license and ca ::: The input image size in this notebook is set to 320x320. This results in lower CPU usage and faster inference times without impacting performance in most cases due to the way Frigate crops video frames to areas of interest before running detection. The notebook and config can be updated to 640x640 if desired. + +### Downloading YOLO Models + +#### YOLOx + +YOLOx models can be downloaded [from the YOLOx repo](https://github.com/Megvii-BaseDetection/YOLOX/tree/main/demo/ONNXRuntime). + +#### YOLOv3, YOLOv4, and YOLOv7 + +To export as ONNX: + +```sh +git clone https://github.com/NateMeyer/tensorrt_demos +cd tensorrt_demos/yolo +./download_yolo.sh +python3 yolo_to_onnx.py -m yolov7-320 +``` + +#### YOLOv9 + +YOLOv9 models can be exported using the below code or they [can be downloaded from hugging face](https://huggingface.co/Xenova/yolov9-onnx/tree/main) + +```sh +git clone https://github.com/WongKinYiu/yolov9 +cd yolov9 + +# setup the virtual environment so installation doesn't affect main system +python3 -m venv ./ +bin/pip install -r requirements.txt +bin/pip install onnx onnxruntime onnx-simplifier>=0.4.1 + +# download the weights +wget -O yolov9-t.pt "https://github.com/WongKinYiu/yolov9/releases/download/v0.1/yolov9-t-converted.pt" # download the weights + +# prepare and run export script +sed -i "s/ckpt = torch.load(attempt_download(w), map_location='cpu')/ckpt = torch.load(attempt_download(w), map_location='cpu', weights_only=False)/g" ./models/experimental.py +bin/python3 export.py --weights ./yolov9-t.pt --imgsz 320 --simplify --include onnx +``` diff --git a/docs/docs/configuration/record.md b/docs/docs/configuration/record.md index f84d84cee..52c0f0c88 100644 --- a/docs/docs/configuration/record.md +++ b/docs/docs/configuration/record.md @@ -146,7 +146,7 @@ The above configuration example can be added globally or on a per camera basis. ## Can I have "continuous" recordings, but only at certain times? -Using Frigate UI, HomeAssistant, or MQTT, cameras can be automated to only record in certain situations or at certain times. +Using Frigate UI, Home Assistant, or MQTT, cameras can be automated to only record in certain situations or at certain times. ## How do I export recordings? @@ -174,6 +174,10 @@ To reduce the output file size the ffmpeg parameter `-qp n` can be utilized (whe ::: +## Apple Compatibility with H.265 Streams + +Apple devices running the Safari browser may fail to playback h.265 recordings. The [apple compatibility option](../configuration/camera_specific.md#h265-cameras-via-safari) should be used to ensure seamless playback on Apple devices. + ## Syncing Recordings With Disk In some cases the recordings files may be deleted but Frigate will not know this has happened. Recordings sync can be enabled which will tell Frigate to check the file system and delete any db entries for files which don't exist. diff --git a/docs/docs/configuration/reference.md b/docs/docs/configuration/reference.md index 9a880aade..dbea03678 100644 --- a/docs/docs/configuration/reference.md +++ b/docs/docs/configuration/reference.md @@ -78,16 +78,19 @@ proxy: # Optional: Mapping for headers from upstream proxies. Only used if Frigate's auth # is disabled. # NOTE: Many authentication proxies pass a header downstream with the authenticated - # user name. Not all values are supported. It must be a whitelisted header. + # user name and role. Not all values are supported. It must be a whitelisted header. # See the docs for more info. header_map: user: x-forwarded-user + role: x-forwarded-role # Optional: Url for logging out a user. This sets the location of the logout url in # the UI. logout_url: /api/logout # Optional: Auth secret that is checked against the X-Proxy-Secret header sent from # the proxy. If not set, all requests are trusted regardless of origin. auth_secret: None + # Optional: The default role to use for proxy auth. Must be "admin" or "viewer" + default_role: viewer # Optional: Authentication configuration auth: @@ -125,7 +128,7 @@ auth: # NOTE: The default values are for the EdgeTPU detector. # Other detectors will require the model config to be set. model: - # Required: path to the model (default: automatic based on detector) + # Required: path to the model. Frigate+ models use plus:// (default: automatic based on detector) path: /edgetpu_model.tflite # Required: path to the labelmap (default: shown below) labelmap_path: /labelmap.txt @@ -543,17 +546,35 @@ semantic_search: model_size: "small" # Optional: Configuration for face recognition capability +# NOTE: enabled, min_area can be overridden at the camera level face_recognition: - # Optional: Enable semantic search (default: shown below) + # Optional: Enable face recognition (default: shown below) enabled: False - # Optional: Set the model size used for embeddings. (default: shown below) - # NOTE: small model runs on CPU and large model runs on GPU - model_size: "small" + # Optional: Minimum face distance score required to mark as a potential match (default: shown below) + unknown_score: 0.8 + # Optional: Minimum face detection score required to detect a face (default: shown below) + # NOTE: This only applies when not running a Frigate+ model + detection_threshold: 0.7 + # Optional: Minimum face distance score required to be considered a match (default: shown below) + recognition_threshold: 0.9 + # Optional: Min area of detected face box to consider running face recognition (default: shown below) + min_area: 500 + # Optional: Number of images of recognized faces to save for training (default: shown below) + save_attempts: 100 + # Optional: Apply a blur quality filter to adjust confidence based on the blur level of the image (default: shown below) + blur_confidence_filter: True + # Optional: Set the model size used face recognition. (default: shown below) + model_size: small # Optional: Configuration for license plate recognition capability +# NOTE: enabled, min_area, and enhancement can be overridden at the camera level lpr: # Optional: Enable license plate recognition (default: shown below) enabled: False + # Optional: The device to run the models on (default: shown below) + device: CPU + # Optional: Set the model size used for text detection. (default: shown below) + model_size: small # Optional: License plate object confidence score required to begin running recognition (default: shown below) detection_threshold: 0.7 # Optional: Minimum area of license plate to begin running recognition (default: shown below) @@ -568,6 +589,11 @@ lpr: match_distance: 1 # Optional: Known plates to track (strings or regular expressions) (default: shown below) known_plates: {} + # Optional: Enhance the detected plate image with contrast adjustment and denoising (default: shown below) + # A value between 0 and 10. Higher values are not always better and may perform worse than lower values. + enhancement: 0 + # Optional: Save plate images to /media/frigate/clips/lpr for debugging purposes (default: shown below) + debug_save_plates: False # Optional: Configuration for AI generated tracked object descriptions # WARNING: Depending on the provider, this will send thumbnails over the internet @@ -645,6 +671,9 @@ cameras: # If disabled: config is used but no live stream and no capture etc. # Events/Recordings are still viewable. enabled: True + # Optional: camera type used for some Frigate features (default: shown below) + # Options are "generic" and "lpr" + type: "generic" # Required: ffmpeg settings for the camera ffmpeg: # Required: A list of input streams for the camera. See documentation for more information. @@ -875,7 +904,7 @@ telemetry: # NOTE: The container must either be privileged or have cap_net_admin, cap_net_raw capabilities enabled. network_bandwidth: False # Optional: Enable the latest version outbound check (default: shown below) - # NOTE: If you use the HomeAssistant integration, disabling this will prevent it from reporting new versions + # NOTE: If you use the Home Assistant integration, disabling this will prevent it from reporting new versions version_check: True # Optional: Camera groups (default: no groups are setup) diff --git a/docs/docs/configuration/restream.md b/docs/docs/configuration/restream.md index 288dc8fd9..4564595cc 100644 --- a/docs/docs/configuration/restream.md +++ b/docs/docs/configuration/restream.md @@ -152,7 +152,7 @@ go2rtc: my_camera: rtsp://username:$%40foo%25@192.168.1.100 ``` -See [this comment(https://github.com/AlexxIT/go2rtc/issues/1217#issuecomment-2242296489) for more information. +See [this comment](https://github.com/AlexxIT/go2rtc/issues/1217#issuecomment-2242296489) for more information. ## Advanced Restream Configurations diff --git a/docs/docs/configuration/semantic_search.md b/docs/docs/configuration/semantic_search.md index 07e2cbfb2..80fce2958 100644 --- a/docs/docs/configuration/semantic_search.md +++ b/docs/docs/configuration/semantic_search.md @@ -19,7 +19,7 @@ For best performance, 16GB or more of RAM and a dedicated GPU are recommended. ## Configuration -Semantic Search is disabled by default, and must be enabled in your config file or in the UI's Settings page before it can be used. Semantic Search is a global configuration setting. +Semantic Search is disabled by default, and must be enabled in your config file or in the UI's Classification Settings page before it can be used. Semantic Search is a global configuration setting. ```yaml semantic_search: @@ -29,9 +29,9 @@ semantic_search: :::tip -The embeddings database can be re-indexed from the existing tracked objects in your database by adding `reindex: True` to your `semantic_search` configuration or by toggling the switch on the Search Settings page in the UI and restarting Frigate. Depending on the number of tracked objects you have, it can take a long while to complete and may max out your CPU while indexing. Make sure to turn the UI's switch off or set the config back to `False` before restarting Frigate again. +The embeddings database can be re-indexed from the existing tracked objects in your database by pressing the "Reindex" button in the Classification Settings in the UI or by adding `reindex: True` to your `semantic_search` configuration and restarting Frigate. Depending on the number of tracked objects you have, it can take a long while to complete and may max out your CPU while indexing. -If you are enabling Semantic Search for the first time, be advised that Frigate does not automatically index older tracked objects. You will need to enable the `reindex` feature in order to do that. +If you are enabling Semantic Search for the first time, be advised that Frigate does not automatically index older tracked objects. You will need to reindex as described above. ::: @@ -72,7 +72,7 @@ For most users, especially native English speakers, the V1 model remains the rec :::note -Switching between V1 and V2 requires reindexing your embeddings. To do this, set `reindex: True` in your Semantic Search configuration and restart Frigate. The embeddings from V1 and V2 are incompatible, and failing to reindex will result in incorrect search results. +Switching between V1 and V2 requires reindexing your embeddings. The embeddings from V1 and V2 are incompatible, and failing to reindex will result in incorrect search results. ::: @@ -90,19 +90,7 @@ semantic_search: If the correct build is used for your GPU and the `large` model is configured, then the GPU will be detected and used automatically. -**NOTE:** Object detection and Semantic Search are independent features. If you want to use your GPU with Semantic Search, you must choose the appropriate Frigate Docker image for your GPU. - -- **AMD** - - - ROCm will automatically be detected and used for Semantic Search in the `-rocm` Frigate image. - -- **Intel** - - - OpenVINO will automatically be detected and used for Semantic Search in the default Frigate image. - -- **Nvidia** - - Nvidia GPUs will automatically be detected and used for Semantic Search in the `-tensorrt` Frigate image. - - Jetson devices will automatically be detected and used for Semantic Search in the `-tensorrt-jp(4/5)` Frigate image. +See the [Hardware Accelerated Enrichments](/configuration/hardware_acceleration_enrichments.md) documentation. ::: diff --git a/docs/docs/configuration/snapshots.md b/docs/docs/configuration/snapshots.md index e6c260913..815e301ba 100644 --- a/docs/docs/configuration/snapshots.md +++ b/docs/docs/configuration/snapshots.md @@ -5,7 +5,7 @@ title: Snapshots Frigate can save a snapshot image to `/media/frigate/clips` for each object that is detected named as `-.jpg`. They are also accessible [via the api](../integrations/api/event-snapshot-events-event-id-snapshot-jpg-get.api.mdx) -For users with Frigate+ enabled, snapshots are accessible in the UI in the Frigate+ pane to allow for quick submission to the Frigate+ service. +Snapshots are accessible in the UI in the Explore pane. This allows for quick submission to the Frigate+ service. To only save snapshots for objects that enter a specific zone, [see the zone docs](./zones.md#restricting-snapshots-to-specific-zones) diff --git a/docs/docs/configuration/zones.md b/docs/docs/configuration/zones.md index 0c6793d58..a23a3a617 100644 --- a/docs/docs/configuration/zones.md +++ b/docs/docs/configuration/zones.md @@ -84,7 +84,13 @@ Only car objects can trigger the `front_yard_street` zone and only person can tr ### Zone Loitering -Sometimes objects are expected to be passing through a zone, but an object loitering in an area is unexpected. Zones can be configured to have a minimum loitering time before the object will be considered in the zone. +Sometimes objects are expected to be passing through a zone, but an object loitering in an area is unexpected. Zones can be configured to have a minimum loitering time after which the object will be considered in the zone. + +:::note + +When using loitering zones, a review item will remain active until the object leaves. Loitering zones are only meant to be used in areas where loitering is not expected behavior. + +::: ```yaml cameras: diff --git a/docs/docs/development/contributing-boards.md b/docs/docs/development/contributing-boards.md index 49a65722d..930c99dec 100644 --- a/docs/docs/development/contributing-boards.md +++ b/docs/docs/development/contributing-boards.md @@ -72,17 +72,17 @@ COPY --from=rootfs / / The images for each board will be built for each Frigate release, this is done in the `.github/workflows/ci.yml` file. The board build workflow will need to be added here. ```yml - - name: Build and push board build - uses: docker/bake-action@v3 - with: - push: true - targets: board # this is the target in the board.hcl file - files: docker/board/board.hcl # this should be updated with the actual board type - # the tags should be updated with the actual board types as well - # the community board builds should never push to cache, but it can pull from cache - set: | - board.tags=ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}:${{ github.ref_name }}-${{ env.SHORT_SHA }}-board - *.cache-from=type=gha +- name: Build and push board build + uses: docker/bake-action@v3 + with: + push: true + targets: board # this is the target in the board.hcl file + files: docker/board/board.hcl # this should be updated with the actual board type + # the tags should be updated with the actual board types as well + # the community board builds should never push to cache, but it can pull from cache + set: | + board.tags=ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}:${{ github.ref_name }}-${{ env.SHORT_SHA }}-board + *.cache-from=type=gha ``` ### Code Owner File @@ -91,4 +91,4 @@ The `CODEOWNERS` file should be updated to include the `docker/board` along with # Docs -At a minimum the `installation`, `object_detectors`, `hardware_acceleration`, and `ffmpeg-presets` docs should be updated (if applicable) to reflect the configuration of this community board. +At a minimum the `installation`, `object_detectors`, `hardware_acceleration_video`, and `ffmpeg-presets` docs should be updated (if applicable) to reflect the configuration of this community board. diff --git a/docs/docs/development/contributing.md b/docs/docs/development/contributing.md index eb33765fe..a123f70b8 100644 --- a/docs/docs/development/contributing.md +++ b/docs/docs/development/contributing.md @@ -17,15 +17,15 @@ From here, follow the guides for: - [Web Interface](#web-interface) - [Documentation](#documentation) -### Frigate Home Assistant Addon +### Frigate Home Assistant Add-on -This repository holds the Home Assistant Addon, for use with Home Assistant OS and compatible installations. It is the piece that allows you to run Frigate from your Home Assistant Supervisor tab. +This repository holds the Home Assistant Add-on, for use with Home Assistant OS and compatible installations. It is the piece that allows you to run Frigate from your Home Assistant Supervisor tab. Fork [blakeblackshear/frigate-hass-addons](https://github.com/blakeblackshear/frigate-hass-addons) to your own Github profile, then clone the forked repo to your local machine. ### Frigate Home Assistant Integration -This repository holds the custom integration that allows your Home Assistant installation to automatically create entities for your Frigate instance, whether you run that with the [addon](#frigate-home-assistant-addon) or in a separate Docker instance. +This repository holds the custom integration that allows your Home Assistant installation to automatically create entities for your Frigate instance, whether you are running Frigate as a standalone Docker container or as a [Home Assistant Add-on](#frigate-home-assistant-add-on). Fork [blakeblackshear/frigate-hass-integration](https://github.com/blakeblackshear/frigate-hass-integration) to your own GitHub profile, then clone the forked repo to your local machine. @@ -77,14 +77,15 @@ Create and place these files in a `debug` folder in the root of the repo. This i #### 4. Run Frigate from the command line -VSCode will start the docker compose file for you and open a terminal window connected to `frigate-dev`. +VS Code will start the Docker Compose file for you and open a terminal window connected to `frigate-dev`. +- Depending on what hardware you're developing on, you may need to amend `docker-compose.yml` in the project root to pass through a USB Coral or GPU for hardware acceleration. - Run `python3 -m frigate` to start the backend. - In a separate terminal window inside VS Code, change into the `web` directory and run `npm install && npm run dev` to start the frontend. #### 5. Teardown -After closing VSCode, you may still have containers running. To close everything down, just run `docker-compose down -v` to cleanup all containers. +After closing VS Code, you may still have containers running. To close everything down, just run `docker-compose down -v` to cleanup all containers. ### Testing @@ -235,3 +236,11 @@ When testing nginx config changes from within the dev container, the following c ```console sudo cp docker/main/rootfs/usr/local/nginx/conf/* /usr/local/nginx/conf/ && sudo /usr/local/nginx/sbin/nginx -s reload ``` + +## Contributing translations of the Web UI + +Frigate uses [Weblate](https://weblate.org) to manage translations of the Web UI. To contribute translation, sign up for an account at Weblate and navigate to the Frigate NVR project: + +https://hosted.weblate.org/projects/frigate-nvr/ + +When translating, maintain the existing key structure while translating only the values. Ensure your translations maintain proper formatting, including any placeholder variables (like `{{example}}`). diff --git a/docs/docs/frigate/camera_setup.md b/docs/docs/frigate/camera_setup.md index 421046dd7..0d4bbfc24 100644 --- a/docs/docs/frigate/camera_setup.md +++ b/docs/docs/frigate/camera_setup.md @@ -28,7 +28,7 @@ For the Dahua/Loryta 5442 camera, I use the following settings: - Encode Mode: H.264 - Resolution: 2688\*1520 - Frame Rate(FPS): 15 -- I Frame Interval: 30 (15 can also be used to prioritize streaming performance - see the [camera settings recommendations](../configuration/live) for more info) +- I Frame Interval: 30 (15 can also be used to prioritize streaming performance - see the [camera settings recommendations](/configuration/live#camera_settings_recommendations) for more info) **Sub Stream (Detection)** diff --git a/docs/docs/frigate/hardware.md b/docs/docs/frigate/hardware.md index c9bfe16d6..bf54de5b9 100644 --- a/docs/docs/frigate/hardware.md +++ b/docs/docs/frigate/hardware.md @@ -38,9 +38,10 @@ Frigate supports multiple different detectors that work on different types of ha **Most Hardware** - [Hailo](#hailo-8): The Hailo8 and Hailo8L AI Acceleration module is available in m.2 format with a HAT for RPi devices offering a wide range of compatibility with devices. + - [Supports many model architectures](../../configuration/object_detectors#configuration) - Runs best with tiny or small size models - + - [Google Coral EdgeTPU](#google-coral-tpu): The Google Coral EdgeTPU is available in USB and m.2 format allowing for a wide range of compatibility with devices. - [Supports primarily ssdlite and mobilenet model architectures](../../configuration/object_detectors#edge-tpu-detector) @@ -73,10 +74,10 @@ Frigate supports multiple different detectors that work on different types of ha ### Hailo-8 - Frigate supports both the Hailo-8 and Hailo-8L AI Acceleration Modules on compatible hardware platforms—including the Raspberry Pi 5 with the PCIe hat from the AI kit. The Hailo detector integration in Frigate automatically identifies your hardware type and selects the appropriate default model when a custom model isn’t provided. **Default Model Configuration:** + - **Hailo-8L:** Default model is **YOLOv6n**. - **Hailo-8:** Default model is **YOLOv6n**. @@ -89,7 +90,8 @@ In real-world deployments, even with multiple cameras running concurrently, Frig ### Google Coral TPU -Frigate supports both the USB and M.2 versions of the Google Coral. +Frigate supports both the USB and M.2 versions of the Google Coral. + - The USB version is compatible with the widest variety of hardware and does not require a driver on the host machine. However, it does lack the automatic throttling features of the other versions. - The PCIe and M.2 versions require installation of a driver on the host. Follow the instructions for your version from https://coral.ai @@ -107,23 +109,17 @@ More information is available [in the detector docs](/configuration/object_detec Inference speeds vary greatly depending on the CPU or GPU used, some known examples of GPU inference times are below: -| Name | MobileNetV2 Inference Time | YOLO-NAS Inference Time | Notes | -| -------------------- | -------------------------- | ------------------------- | -------------------------------------- | -| Intel Celeron J4105 | ~ 25 ms | | Can only run one detector instance | -| Intel Celeron N3060 | 130 - 150 ms | | Can only run one detector instance | -| Intel Celeron N3205U | ~ 120 ms | | Can only run one detector instance | -| Intel Celeron N4020 | 50 - 200 ms | | Inference speed depends on other loads | -| Intel i3 6100T | 15 - 35 ms | | Can only run one detector instance | -| Intel i3 8100 | ~ 15 ms | | | -| Intel i5 4590 | ~ 20 ms | | | -| Intel i5 6500 | ~ 15 ms | | | -| Intel i5 7200u | 15 - 25 ms | | | -| Intel i5 7500 | ~ 15 ms | | | -| Intel i5 1135G7 | 10 - 15 ms | | | -| Intel i3 12000 | | 320: ~ 19 ms 640: ~ 54 ms | | -| Intel i5 12600K | ~ 15 ms | 320: ~ 20 ms 640: ~ 46 ms | | -| Intel Arc A380 | ~ 6 ms | 320: ~ 10 ms | | -| Intel Arc A750 | ~ 4 ms | 320: ~ 8 ms | | +| Name | MobileNetV2 Inference Time | YOLO-NAS Inference Time | RF-DETR Inference Time | Notes | +| -------------- | -------------------------- | ------------------------- | ---------------------- | ---------------------------------- | +| Intel HD 530 | 15 - 35 ms | | | Can only run one detector instance | +| Intel HD 620 | 15 - 25 ms | 320: ~ 35 ms | | | +| Intel HD 630 | ~ 15 ms | 320: ~ 30 ms | | | +| Intel UHD 730 | ~ 10 ms | 320: ~ 19 ms 640: ~ 54 ms | | | +| Intel UHD 770 | ~ 15 ms | 320: ~ 20 ms 640: ~ 46 ms | | | +| Intel N100 | ~ 15 ms | 320: ~ 20 ms | | | +| Intel Iris XE | ~ 10 ms | 320: ~ 18 ms 640: ~ 50 ms | | | +| Intel Arc A380 | ~ 6 ms | 320: ~ 10 ms 640: ~ 22 ms | 336: 20 ms 448: 27 ms | | +| Intel Arc A750 | ~ 4 ms | 320: ~ 8 ms | | | ### TensorRT - Nvidia GPU @@ -132,29 +128,31 @@ The TensortRT detector is able to run on x86 hosts that have an Nvidia GPU which Inference speeds will vary greatly depending on the GPU and the model used. `tiny` variants are faster than the equivalent non-tiny model, some known examples are below: -| Name | YoloV7 Inference Time | YOLO-NAS Inference Time | -| --------------- | --------------------- | ------------------------- | -| GTX 1060 6GB | ~ 7 ms | | -| GTX 1070 | ~ 6 ms | | -| GTX 1660 SUPER | ~ 4 ms | | -| RTX 3050 | 5 - 7 ms | 320: ~ 10 ms 640: ~ 16 ms | -| RTX 3070 Mobile | ~ 5 ms | | -| Quadro P400 2GB | 20 - 25 ms | | -| Quadro P2000 | ~ 12 ms | | +| Name | YOLOv7 Inference Time | YOLO-NAS Inference Time | RF-DETR Inference Time | +| --------------- | --------------------- | ------------------------- | ------------------------- | +| GTX 1060 6GB | ~ 7 ms | | | +| GTX 1070 | ~ 6 ms | | | +| GTX 1660 SUPER | ~ 4 ms | | | +| RTX 3050 | 5 - 7 ms | 320: ~ 10 ms 640: ~ 16 ms | 336: ~ 16 ms 560: ~ 40 ms | +| RTX 3070 Mobile | ~ 5 ms | | | +| RTX 3070 | 4 - 6 ms | 320: ~ 6 ms 640: ~ 12 ms | 336: ~ 14 ms 560: ~ 36 ms | +| Quadro P400 2GB | 20 - 25 ms | | | +| Quadro P2000 | ~ 12 ms | | | ### AMD GPUs With the [rocm](../configuration/object_detectors.md#amdrocm-gpu-detector) detector Frigate can take advantage of many discrete AMD GPUs. -| Name | YoloV9 Inference Time | YOLO-NAS Inference Time | -| --------------- | --------------------- | ------------------------- | -| AMD 780M | ~ 14 ms | ~ 60 ms | +| Name | YOLOv9 Inference Time | YOLO-NAS Inference Time | +| --------- | --------------------- | ------------------------- | +| AMD 780M | ~ 14 ms | 320: ~ 30 ms 640: ~ 60 ms | +| AMD 8700G | | 320: ~ 20 ms 640: ~ 40 ms | ## Community Supported Detectors ### Nvidia Jetson -Frigate supports all Jetson boards, from the inexpensive Jetson Nano to the powerful Jetson Orin AGX. It will [make use of the Jetson's hardware media engine](/configuration/hardware_acceleration#nvidia-jetson-orin-agx-orin-nx-orin-nano-xavier-agx-xavier-nx-tx2-tx1-nano) when configured with the [appropriate presets](/configuration/ffmpeg_presets#hwaccel-presets), and will make use of the Jetson's GPU and DLA for object detection when configured with the [TensorRT detector](/configuration/object_detectors#nvidia-tensorrt-detector). +Frigate supports all Jetson boards, from the inexpensive Jetson Nano to the powerful Jetson Orin AGX. It will [make use of the Jetson's hardware media engine](/configuration/hardware_acceleration_video#nvidia-jetson-orin-agx-orin-nx-orin-nano-xavier-agx-xavier-nx-tx2-tx1-nano) when configured with the [appropriate presets](/configuration/ffmpeg_presets#hwaccel-presets), and will make use of the Jetson's GPU and DLA for object detection when configured with the [TensorRT detector](/configuration/object_detectors#nvidia-tensorrt-detector). Inference speed will vary depending on the YOLO model, jetson platform and jetson nvpmodel (GPU/DLA/EMC clock speed). It is typically 20-40 ms for most models. The DLA is more efficient than the GPU, but not faster, so using the DLA will reduce power consumption but will slightly increase inference time. @@ -168,6 +166,11 @@ Frigate supports hardware video processing on all Rockchip boards. However, hard - RK3576 - RK3588 +| Name | YOLOv9 Inference Time | YOLO-NAS Inference Time | YOLOx Inference Time | +| -------------- | --------------------- | --------------------------- | ----------------------- | +| rk3588 3 cores | tiny: ~ 35 ms | small: ~ 20 ms med: ~ 30 ms | nano: 14 ms tiny: 18 ms | +| rk3566 1 core | | small: ~ 96 ms | | + The inference time of a rk3588 with all 3 cores enabled is typically 25-30 ms for yolo-nas s. ## What does Frigate use the CPU for and what does it use a detector for? (ELI5 Version) diff --git a/docs/docs/frigate/installation.md b/docs/docs/frigate/installation.md index b270df5ff..ced680171 100644 --- a/docs/docs/frigate/installation.md +++ b/docs/docs/frigate/installation.md @@ -3,11 +3,11 @@ id: installation title: Installation --- -Frigate is a Docker container that can be run on any Docker host including as a [HassOS Addon](https://www.home-assistant.io/addons/). Note that a Home Assistant Addon is **not** the same thing as the integration. The [integration](/integrations/home-assistant) is required to integrate Frigate into Home Assistant. +Frigate is a Docker container that can be run on any Docker host including as a [Home Assistant Add-on](https://www.home-assistant.io/addons/). Note that the Home Assistant Add-on is **not** the same thing as the integration. The [integration](/integrations/home-assistant) is required to integrate Frigate into Home Assistant, whether you are running Frigate as a standalone Docker container or as a Home Assistant Add-on. :::tip -If you already have Frigate installed as a Home Assistant addon, check out the [getting started guide](../guides/getting_started#configuring-frigate) to configure Frigate. +If you already have Frigate installed as a Home Assistant Add-on, check out the [getting started guide](../guides/getting_started#configuring-frigate) to configure Frigate. ::: @@ -45,7 +45,7 @@ The following ports are used by Frigate and can be mapped via docker as required | `8554` | RTSP restreaming. By default, these streams are unauthenticated. Authentication can be configured in go2rtc section of config. | | `8555` | WebRTC connections for low latency live views. | -#### Common docker compose storage configurations +#### Common Docker Compose storage configurations Writing to a local disk or external USB drive: @@ -73,7 +73,7 @@ Users of the Snapcraft build of Docker cannot use storage locations outside your Frigate utilizes shared memory to store frames during processing. The default `shm-size` provided by Docker is **64MB**. -The default shm size of **128MB** is fine for setups with **2 cameras** detecting at **720p**. If Frigate is exiting with "Bus error" messages, it is likely because you have too many high resolution cameras and you need to specify a higher shm size, using [`--shm-size`](https://docs.docker.com/engine/reference/run/#runtime-constraints-on-resources) (or [`service.shm_size`](https://docs.docker.com/compose/compose-file/compose-file-v2/#shm_size) in docker-compose). +The default shm size of **128MB** is fine for setups with **2 cameras** detecting at **720p**. If Frigate is exiting with "Bus error" messages, it is likely because you have too many high resolution cameras and you need to specify a higher shm size, using [`--shm-size`](https://docs.docker.com/engine/reference/run/#runtime-constraints-on-resources) (or [`service.shm_size`](https://docs.docker.com/compose/compose-file/compose-file-v2/#shm_size) in Docker Compose). The Frigate container also stores logs in shm, which can take up to **40MB**, so make sure to take this into account in your math as well. @@ -165,6 +165,8 @@ devices: - /dev/dma_heap - /dev/rga - /dev/mpp_service +volumes: + - /sys/:/sys/:ro ``` or add these options to your `docker run` command: @@ -175,19 +177,19 @@ or add these options to your `docker run` command: --device /dev/dri \ --device /dev/dma_heap \ --device /dev/rga \ ---device /dev/mpp_service +--device /dev/mpp_service \ +--volume /sys/:/sys/:ro ``` #### Configuration -Next, you should configure [hardware object detection](/configuration/object_detectors#rockchip-platform) and [hardware video processing](/configuration/hardware_acceleration#rockchip-platform). +Next, you should configure [hardware object detection](/configuration/object_detectors#rockchip-platform) and [hardware video processing](/configuration/hardware_acceleration_video#rockchip-platform). ## Docker -Running in Docker with compose is the recommended install method. +Running through Docker with Docker Compose is the recommended install method. ```yaml -version: "3.9" services: frigate: container_name: frigate @@ -219,7 +221,7 @@ services: FRIGATE_RTSP_PASSWORD: "password" ``` -If you can't use docker compose, you can run the container with something similar to this: +If you can't use Docker Compose, you can run the container with something similar to this: ```bash docker run -d \ @@ -243,25 +245,23 @@ docker run -d \ The official docker image tags for the current stable version are: -- `stable` - Standard Frigate build for amd64 & RPi Optimized Frigate build for arm64 +- `stable` - Standard Frigate build for amd64 & RPi Optimized Frigate build for arm64. This build includes support for Hailo devices as well. - `stable-standard-arm64` - Standard Frigate build for arm64 - `stable-tensorrt` - Frigate build specific for amd64 devices running an nvidia GPU +- `stable-rocm` - Frigate build for [AMD GPUs](../configuration/object_detectors.md#amdrocm-gpu-detector) The community supported docker image tags for the current stable version are: -- `stable-tensorrt-jp5` - Frigate build optimized for nvidia Jetson devices running Jetpack 5 - `stable-tensorrt-jp6` - Frigate build optimized for nvidia Jetson devices running Jetpack 6 - `stable-rk` - Frigate build for SBCs with Rockchip SoC -- `stable-rocm` - Frigate build for [AMD GPUs](../configuration/object_detectors.md#amdrocm-gpu-detector) - - `stable-h8l` - Frigate build for the Hailo-8L M.2 PICe Raspberry Pi 5 hat -## Home Assistant Addon +## Home Assistant Add-on :::warning -As of HomeAssistant OS 10.2 and Core 2023.6 defining separate network storage for media is supported. +As of Home Assistant Operating System 10.2 and Home Assistant 2023.6 defining separate network storage for media is supported. -There are important limitations in Home Assistant Operating System to be aware of: +There are important limitations in HA OS to be aware of: - Separate local storage for media is not yet supported by Home Assistant - AMD GPUs are not supported because HA OS does not include the mesa driver. @@ -275,24 +275,27 @@ See [the network storage guide](/guides/ha_network_storage.md) for instructions ::: -HassOS users can install via the addon repository. +Home Assistant OS users can install via the Add-on repository. -1. Navigate to Supervisor > Add-on Store > Repositories -2. Add https://github.com/blakeblackshear/frigate-hass-addons -3. Install your desired Frigate NVR Addon and navigate to it's page +1. In Home Assistant, navigate to _Settings_ > _Add-ons_ > _Add-on Store_ > _Repositories_ +2. Add `https://github.com/blakeblackshear/frigate-hass-addons` +3. Install the desired variant of the Frigate Add-on (see below) 4. Setup your network configuration in the `Configuration` tab -5. (not for proxy addon) Create the file `frigate.yaml` in your `config` directory with your detailed Frigate configuration -6. Start the addon container -7. (not for proxy addon) If you are using hardware acceleration for ffmpeg, you may need to disable "Protection mode" +5. Start the Add-on +6. Use the _Open Web UI_ button to access the Frigate UI, then click in the _cog icon_ > _Configuration editor_ and configure Frigate to your liking -There are several versions of the addon available: +There are several variants of the Add-on available: -| Addon Version | Description | -| ------------------------------ | ---------------------------------------------------------- | -| Frigate NVR | Current release with protection mode on | -| Frigate NVR (Full Access) | Current release with the option to disable protection mode | -| Frigate NVR Beta | Beta release with protection mode on | -| Frigate NVR Beta (Full Access) | Beta release with the option to disable protection mode | +| Add-on Variant | Description | +| -------------------------- | ---------------------------------------------------------- | +| Frigate | Current release with protection mode on | +| Frigate (Full Access) | Current release with the option to disable protection mode | +| Frigate Beta | Beta release with protection mode on | +| Frigate Beta (Full Access) | Beta release with the option to disable protection mode | + +If you are using hardware acceleration for ffmpeg, you **may** need to use the _Full Access_ variant of the Add-on. This is because the Frigate Add-on runs in a container with limited access to the host system. The _Full Access_ variant allows you to disable _Protection mode_ and give Frigate full access to the host system. + +You can also edit the Frigate configuration file through the [VS Code Add-on](https://github.com/hassio-addons/addon-vscode) or similar. In that case, the configuration file will be at `/addon_configs//config.yml`, where `` is specific to the variant of the Frigate Add-on you are running. See the list of directories [here](../configuration/index.md#accessing-add-on-config-dir). ## Kubernetes @@ -313,7 +316,8 @@ If you choose to run Frigate via LXC in Proxmox the setup can be complex so be p ::: - Suggestions include: +Suggestions include: + - For Intel-based hardware acceleration, to allow access to the `/dev/dri/renderD128` device with major number 226 and minor number 128, add the following lines to the `/etc/pve/lxc/.conf` LXC configuration: - `lxc.cgroup2.devices.allow: c 226:128 rwm` - `lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file` @@ -404,7 +408,7 @@ mkdir -p /share/share_vol2/frigate/media # Also replace the time zone value for 'TZ' in the sample command. # Example command will create a docker container that uses at most 2 CPUs and 4G RAM. # You may need to add "--env=LIBVA_DRIVER_NAME=i965 \" to the following docker run command if you -# have certain CPU (e.g., J4125). See https://docs.frigate.video/configuration/hardware_acceleration. +# have certain CPU (e.g., J4125). See https://docs.frigate.video/configuration/hardware_acceleration_video. docker run \ --name=frigate \ --shm-size=256m \ diff --git a/docs/docs/guides/configuring_go2rtc.md b/docs/docs/guides/configuring_go2rtc.md index 3b8a8af1f..652aa3b26 100644 --- a/docs/docs/guides/configuring_go2rtc.md +++ b/docs/docs/guides/configuring_go2rtc.md @@ -115,3 +115,7 @@ section. 1. If the stream you added to go2rtc is also used by Frigate for the `record` or `detect` role, you can migrate your config to pull from the RTSP restream to reduce the number of connections to your camera as shown [here](/configuration/restream#reduce-connections-to-camera). 2. You may also prefer to [setup WebRTC](/configuration/live#webrtc-extra-configuration) for slightly lower latency than MSE. Note that WebRTC only supports h264 and specific audio formats and may require opening ports on your router. + +## Important considerations + +If you are configuring go2rtc to publish HomeKit camera streams, on pairing the configuration is written to the `/dev/shm/go2rtc.yaml` file inside the container. These changes must be manually copied across to the `go2rtc` section of your Frigate configuration in order to persist through restarts. diff --git a/docs/docs/guides/getting_started.md b/docs/docs/guides/getting_started.md index 6fe3a8e22..89176ad4b 100644 --- a/docs/docs/guides/getting_started.md +++ b/docs/docs/guides/getting_started.md @@ -9,7 +9,7 @@ title: Getting started If you already have an environment with Linux and Docker installed, you can continue to [Installing Frigate](#installing-frigate) below. -If you already have Frigate installed in Docker or as a Home Assistant addon, you can continue to [Configuring Frigate](#configuring-frigate) below. +If you already have Frigate installed through Docker or through a Home Assistant Add-on, you can continue to [Configuring Frigate](#configuring-frigate) below. ::: @@ -81,7 +81,7 @@ Now you have a minimal Debian server that requires very little maintenance. ## Installing Frigate -This section shows how to create a minimal directory structure for a Docker installation on Debian. If you have installed Frigate as a Home Assistant addon or another way, you can continue to [Configuring Frigate](#configuring-frigate). +This section shows how to create a minimal directory structure for a Docker installation on Debian. If you have installed Frigate as a Home Assistant Add-on or another way, you can continue to [Configuring Frigate](#configuring-frigate). ### Setup directories @@ -110,7 +110,6 @@ This `docker-compose.yml` file is just a starter for amd64 devices. You will nee `docker-compose.yml` ```yaml -version: "3.9" services: frigate: container_name: frigate @@ -163,14 +162,13 @@ FFmpeg arguments for other types of cameras can be found [here](../configuration ### Step 3: Configure hardware acceleration (recommended) -Now that you have a working camera configuration, you want to setup hardware acceleration to minimize the CPU required to decode your video streams. See the [hardware acceleration](../configuration/hardware_acceleration.md) config reference for examples applicable to your hardware. +Now that you have a working camera configuration, you want to setup hardware acceleration to minimize the CPU required to decode your video streams. See the [hardware acceleration](../configuration/hardware_acceleration_video.md) config reference for examples applicable to your hardware. Here is an example configuration with hardware acceleration configured to work with most Intel processors with an integrated GPU using the [preset](../configuration/ffmpeg_presets.md): `docker-compose.yml` (after modifying, you will need to run `docker compose up -d` to apply changes) ```yaml -version: "3.9" services: frigate: ... @@ -199,7 +197,6 @@ By default, Frigate will use a single CPU detector. If you have a USB Coral, you `docker-compose.yml` (after modifying, you will need to run `docker compose up -d` to apply changes) ```yaml -version: "3.9" services: frigate: ... @@ -306,6 +303,7 @@ By default, Frigate will retain video of all tracked objects for 10 days. The fu ### Step 7: Complete config At this point you have a complete config with basic functionality. + - View [common configuration examples](../configuration/index.md#common-configuration-examples) for a list of common configuration examples. - View [full config reference](../configuration/reference.md) for a complete list of configuration options. diff --git a/docs/docs/guides/ha_network_storage.md b/docs/docs/guides/ha_network_storage.md index fe00311ab..78cddddeb 100644 --- a/docs/docs/guides/ha_network_storage.md +++ b/docs/docs/guides/ha_network_storage.md @@ -3,24 +3,18 @@ id: ha_network_storage title: Home Assistant network storage --- -As of Home Assistant Core 2023.6, Network Mounted Storage is supported for addons. +As of Home Assistant 2023.6, Network Mounted Storage is supported for Add-ons. ## Setting Up Remote Storage For Frigate ### Prerequisites -- HA Core 2023.6 or newer is installed -- Running HA OS 10.2 or newer OR Running Supervised with latest os-agent installed (this is required for supervised install) +- Home Assistant 2023.6 or newer is installed +- Running Home Assistant Operating System 10.2 or newer OR Running Supervised with latest os-agent installed (this is required for supervised install) ### Initial Setup -1. Stop the Frigate addon -2. Update your [config](configuration/index.md) so the DB is stored in the /config directory by adding: - -```yaml -database: - path: /config/frigate.db -``` +1. Stop the Frigate Add-on ### Move current data @@ -43,4 +37,4 @@ Keeping the current data is optional, but the data will need to be moved regardl 4. Fill out the additional required info for your particular NAS 5. Connect 6. Move files from `/media/frigate_tmp` to `/media/frigate` if they were kept in previous step -7. Start the Frigate addon +7. Start the Frigate Add-on diff --git a/docs/docs/integrations/home-assistant.md b/docs/docs/integrations/home-assistant.md index 19330b6b8..34a76d4fe 100644 --- a/docs/docs/integrations/home-assistant.md +++ b/docs/docs/integrations/home-assistant.md @@ -51,7 +51,7 @@ When configuring the integration, you will be asked for the `URL` of your Frigat ### Docker Compose Examples -If you are running Home Assistant Core and Frigate with Docker Compose on the same device, here are some examples. +If you are running Home Assistant and Frigate with Docker Compose on the same device, here are some examples. #### Home Assistant running with host networking @@ -60,7 +60,6 @@ It is not recommended to run Frigate in host networking mode. In this example, y ```yaml services: homeassistant: - container_name: hass image: ghcr.io/home-assistant/home-assistant:stable network_mode: host ... @@ -80,7 +79,6 @@ In this example, it is recommended to connect to the authenticated port, for exa ```yaml services: homeassistant: - container_name: hass image: ghcr.io/home-assistant/home-assistant:stable # network_mode: host ... @@ -93,17 +91,16 @@ services: ... ``` -### HassOS Addon +### Home Assistant Add-on -If you are using HassOS with the addon, the URL should be one of the following depending on which addon version you are using. Note that if you are using the Proxy Addon, you do NOT point the integration at the proxy URL. Just enter the URL used to access Frigate directly from your network. +If you are using Home Assistant Add-on, the URL should be one of the following depending on which Add-on variant you are using. Note that if you are using the Proxy Add-on, you should NOT point the integration at the proxy URL. Just enter the same URL used to access Frigate directly from your network. -| Addon Version | URL | -| ------------------------------ | ----------------------------------------- | -| Frigate NVR | `http://ccab4aaf-frigate:5000` | -| Frigate NVR (Full Access) | `http://ccab4aaf-frigate-fa:5000` | -| Frigate NVR Beta | `http://ccab4aaf-frigate-beta:5000` | -| Frigate NVR Beta (Full Access) | `http://ccab4aaf-frigate-fa-beta:5000` | -| Frigate NVR HailoRT Beta | `http://ccab4aaf-frigate-hailo-beta:5000` | +| Add-on Variant | URL | +| -------------------------- | ----------------------------------------- | +| Frigate | `http://ccab4aaf-frigate:5000` | +| Frigate (Full Access) | `http://ccab4aaf-frigate-fa:5000` | +| Frigate Beta | `http://ccab4aaf-frigate-beta:5000` | +| Frigate Beta (Full Access) | `http://ccab4aaf-frigate-fa-beta:5000` | ### Frigate running on a separate machine diff --git a/docs/docs/integrations/mqtt.md b/docs/docs/integrations/mqtt.md index abbc12974..d6dcaa3fb 100644 --- a/docs/docs/integrations/mqtt.md +++ b/docs/docs/integrations/mqtt.md @@ -104,7 +104,9 @@ Message published for each changed tracked object. The first message is publishe ### `frigate/tracked_object_update` -Message published for updates to tracked object metadata, for example when GenAI runs and returns a tracked object description. +Message published for updates to tracked object metadata, for example: + +#### Generative AI Description Update ```json { @@ -114,6 +116,33 @@ Message published for updates to tracked object metadata, for example when GenAI } ``` +#### Face Recognition Update + +```json +{ + "type": "face", + "id": "1607123955.475377-mxklsc", + "name": "John", + "score": 0.95, + "camera": "front_door_cam", + "timestamp": 1607123958.748393, +} +``` + +#### License Plate Recognition Update + +```json +{ + "type": "lpr", + "id": "1607123955.475377-mxklsc", + "name": "John's Car", + "plate": "123ABC", + "score": 0.95, + "camera": "driveway_cam", + "timestamp": 1607123958.748393, +} +``` + ### `frigate/reviews` Message published for each changed review item. The first message is published when the `detection` or `alert` is initiated. When additional objects are detected or when a zone change occurs, it will publish a, `update` message with the same id. When the review activity has ended a final `end` message is published. @@ -305,6 +334,10 @@ Topic to adjust motion contour area for a camera. Expected value is an integer. Topic with current motion contour area for a camera. Published value is an integer. +### `frigate//review_status` + +Topic with current activity status of the camera. Possible values are `NONE`, `DETECTION`, or `ALERT`. + ### `frigate//ptz` Topic to send PTZ commands to camera. diff --git a/docs/docs/integrations/plus.md b/docs/docs/integrations/plus.md index 0a2b7f2d0..70c6ef92e 100644 --- a/docs/docs/integrations/plus.md +++ b/docs/docs/integrations/plus.md @@ -19,11 +19,11 @@ Once logged in, you can generate an API key for Frigate in Settings. ### Set your API key -In Frigate, you can use an environment variable or a docker secret named `PLUS_API_KEY` to enable the `Frigate+` buttons on the Explore page. Home Assistant Addon users can set it under Settings > Addons > Frigate NVR > Configuration > Options (be sure to toggle the "Show unused optional configuration options" switch). +In Frigate, you can use an environment variable or a docker secret named `PLUS_API_KEY` to enable the `Frigate+` buttons on the Explore page. Home Assistant Addon users can set it under Settings > Add-ons > Frigate > Configuration > Options (be sure to toggle the "Show unused optional configuration options" switch). :::warning -You cannot use the `environment_vars` section of your Frigate configuration file to set this environment variable. It must be defined as an environment variable in the docker config or HA addon config. +You cannot use the `environment_vars` section of your Frigate configuration file to set this environment variable. It must be defined as an environment variable in the docker config or Home Assistant Add-on config. ::: @@ -51,6 +51,8 @@ You can view all of your submitted images at [https://plus.frigate.video](https: Once you have [requested your first model](../plus/first_model.md) and gotten your own model ID, it can be used with a special model path. No other information needs to be configured for Frigate+ models because it fetches the remaining config from Frigate+ automatically. +You can either choose the new model from the Frigate+ pane in the Settings page of the Frigate UI, or manually set the model at the root level in your config: + ```yaml model: path: plus:// diff --git a/docs/docs/integrations/third_party_extensions.md b/docs/docs/integrations/third_party_extensions.md index e1f9a1053..c90e98c96 100644 --- a/docs/docs/integrations/third_party_extensions.md +++ b/docs/docs/integrations/third_party_extensions.md @@ -21,7 +21,7 @@ This is a fork (with fixed errors and new features) of [original Double Take](ht ## [Frigate Notify](https://github.com/0x2142/frigate-notify) -[Frigate Notify](https://github.com/0x2142/frigate-notify) is a simple app designed to send notifications from Frigate NVR to your favorite platforms. Intended to be used with standalone Frigate installations - Home Assistant not required, MQTT is optional but recommended. +[Frigate Notify](https://github.com/0x2142/frigate-notify) is a simple app designed to send notifications from Frigate to your favorite platforms. Intended to be used with standalone Frigate installations - Home Assistant not required, MQTT is optional but recommended. ## [Frigate telegram](https://github.com/OldTyT/frigate-telegram) diff --git a/docs/docs/plus/faq.md b/docs/docs/plus/faq.md index fb0cd2512..151eb3f60 100644 --- a/docs/docs/plus/faq.md +++ b/docs/docs/plus/faq.md @@ -22,3 +22,13 @@ Yes. Models and metadata are stored in the `model_cache` directory within the co ### Can I keep using my Frigate+ models even if I do not renew my subscription? Yes. Subscriptions to Frigate+ provide access to the infrastructure used to train the models. Models trained with your subscription are yours to keep and use forever. However, do note that the terms and conditions prohibit you from sharing, reselling, or creating derivative products from the models. + +### Why can't I submit images to Frigate+? + +If you've configured your API key and the Frigate+ Settings page in the UI shows that the key is active, you need to ensure that you've enabled both snapshots and `clean_copy` snapshots for the cameras you'd like to submit images for. Note that `clean_copy` is enabled by default when snapshots are enabled. + +```yaml +snapshots: + enabled: true + clean_copy: true +``` diff --git a/docs/docs/plus/index.md b/docs/docs/plus/index.md index 589adca72..a727f571f 100644 --- a/docs/docs/plus/index.md +++ b/docs/docs/plus/index.md @@ -3,7 +3,7 @@ id: index title: Models --- -Frigate+ offers models trained on images submitted by Frigate+ users from their security cameras and is specifically designed for the way Frigate NVR analyzes video footage. These models offer higher accuracy with less resources. The images you upload are used to fine tune a baseline model trained from images uploaded by all Frigate+ users. This fine tuning process results in a model that is optimized for accuracy in your specific conditions. +Frigate+ offers models trained on images submitted by Frigate+ users from their security cameras and is specifically designed for the way Frigate analyzes video footage. These models offer higher accuracy with less resources. The images you upload are used to fine tune a baseline model trained from images uploaded by all Frigate+ users. This fine tuning process results in a model that is optimized for accuracy in your specific conditions. :::info diff --git a/docs/docs/troubleshooting/edgetpu.md b/docs/docs/troubleshooting/edgetpu.md index 90006c41e..5c2656405 100644 --- a/docs/docs/troubleshooting/edgetpu.md +++ b/docs/docs/troubleshooting/edgetpu.md @@ -32,7 +32,7 @@ The USB coral can draw up to 900mA and this can be too much for some on-device U The USB coral has different IDs when it is uninitialized and initialized. - When running Frigate in a VM, Proxmox lxc, etc. you must ensure both device IDs are mapped. -- When running HA OS you may need to run the Full Access version of the Frigate addon with the `Protected Mode` switch disabled so that the coral can be accessed. +- When running through the Home Assistant OS you may need to run the Full Access variant of the Frigate Add-on with the _Protection mode_ switch disabled so that the coral can be accessed. ### Synology 716+II running DSM 7.2.1-69057 Update 5 diff --git a/docs/docs/troubleshooting/faqs.md b/docs/docs/troubleshooting/faqs.md index 1af1508e4..ff2379ea7 100644 --- a/docs/docs/troubleshooting/faqs.md +++ b/docs/docs/troubleshooting/faqs.md @@ -34,7 +34,7 @@ Frigate generally [recommends cameras with configurable sub streams](/frigate/ha To do this efficiently the following setup is required: 1. A GPU or iGPU must be available to do the scaling. -2. [ffmpeg presets for hwaccel](/configuration/hardware_acceleration.md) must be used +2. [ffmpeg presets for hwaccel](/configuration/hardware_acceleration_video.md) must be used 3. Set the desired detection resolution for `detect -> width` and `detect -> height`. When this is done correctly, the GPU will do the decoding and scaling which will result in a small increase in CPU usage but with better results. diff --git a/docs/docs/troubleshooting/recordings.md b/docs/docs/troubleshooting/recordings.md index 667ea1e8f..d26a3614e 100644 --- a/docs/docs/troubleshooting/recordings.md +++ b/docs/docs/troubleshooting/recordings.md @@ -47,10 +47,9 @@ On linux, some helpful tools/commands in diagnosing would be: On modern linux kernels, the system will utilize some swap if enabled. Setting vm.swappiness=1 no longer means that the kernel will only swap in order to avoid OOM. To prevent any swapping inside a container, set allocations memory and memory+swap to be the same and disable swapping by setting the following docker/podman run parameters: -**Compose example** +**Docker Compose example** ```yaml -version: "3.9" services: frigate: ... diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index 865cb53d2..5e80e844a 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -17,6 +17,15 @@ const config: Config = { markdown: { mermaid: true, }, + i18n: { + defaultLocale: 'en', + locales: ['en'], + localeConfigs: { + en: { + label: 'English', + } + }, + }, themeConfig: { algolia: { appId: 'WIURGBNBPY', @@ -82,6 +91,16 @@ const config: Config = { label: 'Demo', position: 'right', }, + { + type: 'localeDropdown', + position: 'right', + dropdownItemsAfter: [ + { + label: '简体中文(社区翻译)', + href: 'https://docs.frigate-cn.video', + } + ] + }, { href: 'https://github.com/blakeblackshear/frigate', label: 'GitHub', diff --git a/docs/package-lock.json b/docs/package-lock.json index ce3f0649e..6ddff08e5 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -8,9 +8,9 @@ "name": "docs", "version": "0.0.0", "dependencies": { - "@docusaurus/core": "^3.6.3", + "@docusaurus/core": "^3.7.0", "@docusaurus/plugin-content-docs": "^3.6.3", - "@docusaurus/preset-classic": "^3.6.3", + "@docusaurus/preset-classic": "^3.7.0", "@docusaurus/theme-mermaid": "^3.6.3", "@mdx-js/react": "^3.1.0", "clsx": "^2.1.1", @@ -31,34 +31,34 @@ } }, "node_modules/@algolia/autocomplete-core": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", - "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.9.tgz", + "integrity": "sha512-O7BxrpLDPJWWHv/DLA9DRFWs+iY1uOJZkqUwjS5HSZAGcl0hIVCQ97LTLewiZmZ402JYUrun+8NqFP+hCknlbQ==", "license": "MIT", "dependencies": { - "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", - "@algolia/autocomplete-shared": "1.17.7" + "@algolia/autocomplete-plugin-algolia-insights": "1.17.9", + "@algolia/autocomplete-shared": "1.17.9" } }, "node_modules/@algolia/autocomplete-plugin-algolia-insights": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", - "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.9.tgz", + "integrity": "sha512-u1fEHkCbWF92DBeB/KHeMacsjsoI0wFhjZtlCq2ddZbAehshbZST6Hs0Avkc0s+4UyBGbMDnSuXHLuvRWK5iDQ==", "license": "MIT", "dependencies": { - "@algolia/autocomplete-shared": "1.17.7" + "@algolia/autocomplete-shared": "1.17.9" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "node_modules/@algolia/autocomplete-preset-algolia": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", - "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.9.tgz", + "integrity": "sha512-Na1OuceSJeg8j7ZWn5ssMu/Ax3amtOwk76u4h5J4eK2Nx2KB5qt0Z4cOapCsxot9VcEN11ADV5aUSlQF4RhGjQ==", "license": "MIT", "dependencies": { - "@algolia/autocomplete-shared": "1.17.7" + "@algolia/autocomplete-shared": "1.17.9" }, "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", @@ -66,189 +66,109 @@ } }, "node_modules/@algolia/autocomplete-shared": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", - "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.9.tgz", + "integrity": "sha512-iDf05JDQ7I0b7JEA/9IektxN/80a2MZ1ToohfmNS3rfeuQnIKI3IJlIafD0xu4StbtQTghx9T3Maa97ytkXenQ==", "license": "MIT", "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, - "node_modules/@algolia/cache-browser-local-storage": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz", - "integrity": "sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww==", - "license": "MIT", - "dependencies": { - "@algolia/cache-common": "4.24.0" - } - }, - "node_modules/@algolia/cache-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.24.0.tgz", - "integrity": "sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g==", - "license": "MIT" - }, - "node_modules/@algolia/cache-in-memory": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.24.0.tgz", - "integrity": "sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w==", - "license": "MIT", - "dependencies": { - "@algolia/cache-common": "4.24.0" - } - }, "node_modules/@algolia/client-abtesting": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.18.0.tgz", - "integrity": "sha512-DLIrAukjsSrdMNNDx1ZTks72o4RH/1kOn8Wx5zZm8nnqFexG+JzY4SANnCNEjnFQPJTTvC+KpgiNW/CP2lumng==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.24.0.tgz", + "integrity": "sha512-pNTIB5YqVVwu6UogvdX8TqsRZENaflqMMjdY7/XIPMNGrBoNH9tewINLI7+qc9tIaOLcAp3ZldqoEwAihZZ3ig==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.18.0", - "@algolia/requester-browser-xhr": "5.18.0", - "@algolia/requester-fetch": "5.18.0", - "@algolia/requester-node-http": "5.18.0" + "@algolia/client-common": "5.24.0", + "@algolia/requester-browser-xhr": "5.24.0", + "@algolia/requester-fetch": "5.24.0", + "@algolia/requester-node-http": "5.24.0" }, "engines": { "node": ">= 14.0.0" } }, - "node_modules/@algolia/client-account": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.24.0.tgz", - "integrity": "sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "node_modules/@algolia/client-account/node_modules/@algolia/client-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", - "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", - "license": "MIT", - "dependencies": { - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "node_modules/@algolia/client-account/node_modules/@algolia/client-search": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", - "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, "node_modules/@algolia/client-analytics": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.24.0.tgz", - "integrity": "sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.24.0.tgz", + "integrity": "sha512-IF+r9RRQsIf0ylIBNFxo7c6hDxxuhIfIbffhBXEF1HD13rjhP5AVfiaea9RzbsAZoySkm318plDpH/nlGIjbRA==", "license": "MIT", "dependencies": { - "@algolia/client-common": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "node_modules/@algolia/client-analytics/node_modules/@algolia/client-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", - "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", - "license": "MIT", - "dependencies": { - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "node_modules/@algolia/client-analytics/node_modules/@algolia/client-search": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", - "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" + "@algolia/client-common": "5.24.0", + "@algolia/requester-browser-xhr": "5.24.0", + "@algolia/requester-fetch": "5.24.0", + "@algolia/requester-node-http": "5.24.0" + }, + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.18.0.tgz", - "integrity": "sha512-X1WMSC+1ve2qlMsemyTF5bIjwipOT+m99Ng1Tyl36ZjQKTa54oajBKE0BrmM8LD8jGdtukAgkUhFoYOaRbMcmQ==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.24.0.tgz", + "integrity": "sha512-p8K6tiXQTebRBxbrzWIfGCvfkT+Umml+2lzI92acZjHsvl6KYH6igOfVstKqXJRei9pvRzEEvVDNDLXDVleGTA==", "license": "MIT", "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-insights": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.18.0.tgz", - "integrity": "sha512-FAJRNANUOSs/FgYOJ/Njqp+YTe4TMz2GkeZtfsw1TMiA5mVNRS/nnMpxas9771aJz7KTEWvK9GwqPs0K6RMYWg==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.24.0.tgz", + "integrity": "sha512-jOHF0+tixR3IZJMhZPquFNdCVPzwzzXoiqVsbTvfKojeaY6ZXybgUiTSB8JNX+YpsUT8Ebhu3UvRy4mw2PbEzw==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.18.0", - "@algolia/requester-browser-xhr": "5.18.0", - "@algolia/requester-fetch": "5.18.0", - "@algolia/requester-node-http": "5.18.0" + "@algolia/client-common": "5.24.0", + "@algolia/requester-browser-xhr": "5.24.0", + "@algolia/requester-fetch": "5.24.0", + "@algolia/requester-node-http": "5.24.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.24.0.tgz", - "integrity": "sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.24.0.tgz", + "integrity": "sha512-Fx/Fp6d8UmDBHecTt0XYF8C9TAaA3qeCQortfGSZzWp4gVmtrUCFNZ1SUwb8ULREnO9DanVrM5hGE8R8C4zZTQ==", "license": "MIT", "dependencies": { - "@algolia/client-common": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "node_modules/@algolia/client-personalization/node_modules/@algolia/client-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", - "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", - "license": "MIT", - "dependencies": { - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" + "@algolia/client-common": "5.24.0", + "@algolia/requester-browser-xhr": "5.24.0", + "@algolia/requester-fetch": "5.24.0", + "@algolia/requester-node-http": "5.24.0" + }, + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.18.0.tgz", - "integrity": "sha512-x6XKIQgKFTgK/bMasXhghoEjHhmgoP61pFPb9+TaUJ32aKOGc65b12usiGJ9A84yS73UDkXS452NjyP50Knh/g==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.24.0.tgz", + "integrity": "sha512-F8ypOedSMhz6W7zuT5O1SXXsdXSOVhY2U6GkRbYk/mzrhs3jWFR3uQIfeQVWmsJjUwIGZmPoAr9E+T/Zm2M4wA==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.18.0", - "@algolia/requester-browser-xhr": "5.18.0", - "@algolia/requester-fetch": "5.18.0", - "@algolia/requester-node-http": "5.18.0" + "@algolia/client-common": "5.24.0", + "@algolia/requester-browser-xhr": "5.24.0", + "@algolia/requester-fetch": "5.24.0", + "@algolia/requester-node-http": "5.24.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.18.0.tgz", - "integrity": "sha512-qI3LcFsVgtvpsBGR7aNSJYxhsR+Zl46+958ODzg8aCxIcdxiK7QEVLMJMZAR57jGqW0Lg/vrjtuLFDMfSE53qA==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.24.0.tgz", + "integrity": "sha512-k+nuciQuq7WERNNE+hsx3DX636zIy+9R4xdtvW3PANT2a2BDGOv3fv2mta8+QUMcVTVcGe/Mo3QCb4pc1HNoxA==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.18.0", - "@algolia/requester-browser-xhr": "5.18.0", - "@algolia/requester-fetch": "5.18.0", - "@algolia/requester-node-http": "5.18.0" + "@algolia/client-common": "5.24.0", + "@algolia/requester-browser-xhr": "5.24.0", + "@algolia/requester-fetch": "5.24.0", + "@algolia/requester-node-http": "5.24.0" }, "engines": { "node": ">= 14.0.0" @@ -261,177 +181,125 @@ "license": "MIT" }, "node_modules/@algolia/ingestion": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.18.0.tgz", - "integrity": "sha512-bGvJg7HnGGm+XWYMDruZXWgMDPVt4yCbBqq8DM6EoaMBK71SYC4WMfIdJaw+ABqttjBhe6aKNRkWf/bbvYOGyw==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.24.0.tgz", + "integrity": "sha512-/lqVxmrvwoA+OyVK4XLMdz/PJaCTW4qYchX1AZ+98fdnH3K6XM/kMydQLfP0bUNGBQbmVrF88MqhqZRnZEn/MA==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.18.0", - "@algolia/requester-browser-xhr": "5.18.0", - "@algolia/requester-fetch": "5.18.0", - "@algolia/requester-node-http": "5.18.0" + "@algolia/client-common": "5.24.0", + "@algolia/requester-browser-xhr": "5.24.0", + "@algolia/requester-fetch": "5.24.0", + "@algolia/requester-node-http": "5.24.0" }, "engines": { "node": ">= 14.0.0" } }, - "node_modules/@algolia/logger-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.24.0.tgz", - "integrity": "sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==", - "license": "MIT" - }, - "node_modules/@algolia/logger-console": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.24.0.tgz", - "integrity": "sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg==", - "license": "MIT", - "dependencies": { - "@algolia/logger-common": "4.24.0" - } - }, "node_modules/@algolia/monitoring": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.18.0.tgz", - "integrity": "sha512-lBssglINIeGIR+8KyzH05NAgAmn1BCrm5D2T6pMtr/8kbTHvvrm1Zvcltc5dKUQEFyyx3J5+MhNc7kfi8LdjVw==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.24.0.tgz", + "integrity": "sha512-cRisDXQJhvfZCXL4hD22qca2CmW52TniOx6L7pvkaBDx0oQk1k9o+3w11fgfcCG+47OndMeNx5CMpu+K+COMzg==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.18.0", - "@algolia/requester-browser-xhr": "5.18.0", - "@algolia/requester-fetch": "5.18.0", - "@algolia/requester-node-http": "5.18.0" + "@algolia/client-common": "5.24.0", + "@algolia/requester-browser-xhr": "5.24.0", + "@algolia/requester-fetch": "5.24.0", + "@algolia/requester-node-http": "5.24.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.24.0.tgz", - "integrity": "sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.24.0.tgz", + "integrity": "sha512-JTMz0JqN2gidvKa2QCF/rMe8LNtdHaght03px2cluZaZfBRYy8TgHgkCeBspKKvV/abWJwl7J0FzWThCshqT3w==", "license": "MIT", "dependencies": { - "@algolia/cache-browser-local-storage": "4.24.0", - "@algolia/cache-common": "4.24.0", - "@algolia/cache-in-memory": "4.24.0", - "@algolia/client-common": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/logger-common": "4.24.0", - "@algolia/logger-console": "4.24.0", - "@algolia/requester-browser-xhr": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/requester-node-http": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "node_modules/@algolia/recommend/node_modules/@algolia/client-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", - "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", - "license": "MIT", - "dependencies": { - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "node_modules/@algolia/recommend/node_modules/@algolia/client-search": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", - "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "node_modules/@algolia/recommend/node_modules/@algolia/requester-browser-xhr": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz", - "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==", - "license": "MIT", - "dependencies": { - "@algolia/requester-common": "4.24.0" - } - }, - "node_modules/@algolia/recommend/node_modules/@algolia/requester-node-http": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz", - "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==", - "license": "MIT", - "dependencies": { - "@algolia/requester-common": "4.24.0" - } - }, - "node_modules/@algolia/requester-browser-xhr": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.18.0.tgz", - "integrity": "sha512-1XFjW0C3pV0dS/9zXbV44cKI+QM4ZIz9cpatXpsjRlq6SUCpLID3DZHsXyE6sTb8IhyPaUjk78GEJT8/3hviqg==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.18.0" + "@algolia/client-common": "5.24.0", + "@algolia/requester-browser-xhr": "5.24.0", + "@algolia/requester-fetch": "5.24.0", + "@algolia/requester-node-http": "5.24.0" }, "engines": { "node": ">= 14.0.0" } }, - "node_modules/@algolia/requester-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.24.0.tgz", - "integrity": "sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==", - "license": "MIT" - }, - "node_modules/@algolia/requester-fetch": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.18.0.tgz", - "integrity": "sha512-0uodeNdAHz1YbzJh6C5xeQ4T6x5WGiUxUq3GOaT/R4njh5t78dq+Rb187elr7KtnjUmETVVuCvmEYaThfTHzNg==", + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.24.0.tgz", + "integrity": "sha512-B2Gc+iSxct1WSza5CF6AgfNgmLvVb61d5bqmIWUZixtJIhyAC6lSQZuF+nvt+lmKhQwuY2gYjGGClil8onQvKQ==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.18.0" + "@algolia/client-common": "5.24.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.24.0.tgz", + "integrity": "sha512-6E5+hliqGc5w8ZbyTAQ+C3IGLZ/GiX623Jl2bgHA974RPyFWzVSj4rKqkboUAxQmrFY7Z02ybJWVZS5OhPQocA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.24.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.18.0.tgz", - "integrity": "sha512-tZCqDrqJ2YE2I5ukCQrYN8oiF6u3JIdCxrtKq+eniuLkjkO78TKRnXrVcKZTmfFJyyDK8q47SfDcHzAA3nHi6w==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.24.0.tgz", + "integrity": "sha512-zM+nnqZpiQj20PyAh6uvgdSz+hD7Rj7UfAZwizqNP+bLvcbGXZwABERobuilkCQqyDBBH4uv0yqIcPRl8dSBEg==", "license": "MIT", "dependencies": { - "@algolia/client-common": "5.18.0" + "@algolia/client-common": "5.24.0" }, "engines": { "node": ">= 14.0.0" } }, - "node_modules/@algolia/transporter": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.24.0.tgz", - "integrity": "sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==", - "license": "MIT", - "dependencies": { - "@algolia/cache-common": "4.24.0", - "@algolia/logger-common": "4.24.0", - "@algolia/requester-common": "4.24.0" - } - }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, + "node_modules/@antfu/install-pkg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.0.0.tgz", + "integrity": "sha512-xvX6P/lo1B3ej0OsaErAjqgFYzYVcJpamjLAFLYh9vRJngBrMoUG7aVnrGTeqM7yxbyTD5p3F2+0/QUEh8Vzhw==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^0.2.8", + "tinyexec": "^0.3.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@antfu/utils": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-8.1.1.tgz", + "integrity": "sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.7.0", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.0.tgz", - "integrity": "sha512-pRrmXMCwnmrkS3MLgAIW5dXRzeTv6GLjkjb4HmxNnvAKXN1Nfzp4KmGADBQvlVUcqi+a5D+hfGDLLnd5NnYxog==", + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.9.3.tgz", + "integrity": "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==", "license": "MIT", "dependencies": { "@jsdevtools/ono": "^7.1.3", @@ -446,44 +314,44 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", - "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.1.tgz", + "integrity": "sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", + "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helpers": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -502,18 +370,19 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", - "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", + "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.3", - "@babel/types": "^7.26.3", + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -523,25 +392,25 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz", + "integrity": "sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", - "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.1.tgz", + "integrity": "sha512-2YaDd/Rd9E598B5+WIc8wJPmWETiiJXFYVE60oX8FDohv7rAUU3CQj+A1MgeEmcsk2+dQuEjIe/GDvig0SqL4g==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", + "@babel/compat-data": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -560,17 +429,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", - "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", + "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/traverse": "^7.25.9", + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.27.1", "semver": "^6.3.1" }, "engines": { @@ -590,12 +459,12 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz", - "integrity": "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-annotate-as-pure": "^7.27.1", "regexpu-core": "^6.2.0", "semver": "^6.3.1" }, @@ -610,14 +479,15 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", - "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz", + "integrity": "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==", "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", @@ -631,40 +501,40 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", - "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", + "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -674,35 +544,35 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", - "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", - "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-wrap-function": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -712,14 +582,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", - "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -729,79 +599,79 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", - "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", - "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", + "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", "license": "MIT", "dependencies": { - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", - "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", + "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", "license": "MIT", "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.0" + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", - "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.1.tgz", + "integrity": "sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.3" + "@babel/types": "^7.27.1" }, "bin": { "parser": "bin/babel-parser.js" @@ -811,13 +681,13 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", - "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -827,12 +697,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", - "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -842,12 +712,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", - "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -857,14 +727,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -874,13 +744,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", - "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", + "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -893,6 +763,7 @@ "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", "engines": { "node": ">=6.9.0" }, @@ -904,6 +775,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -912,12 +784,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", - "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -927,12 +799,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -942,12 +814,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -957,12 +829,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -975,6 +847,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -987,12 +860,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", - "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1002,14 +875,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", - "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.27.1.tgz", + "integrity": "sha512-eST9RrwlpaoJBDHShc+DS2SG4ATTi2MYNb4OxYkf3n+7eb49LWpnS+HSpVfW4x927qQwgk8A2hGNVaajAEw0EA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-remap-async-to-generator": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1019,14 +892,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", - "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-remap-async-to-generator": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1036,12 +909,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", - "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1051,12 +924,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", - "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.1.tgz", + "integrity": "sha512-QEcFlMl9nGTgh1rn2nIeU5bkfb9BAjaQcWbiP4LvKxUot52ABcTkpcyJ7f2Q2U2RuQ84BNLgts3jRme2dTx6Fw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1066,13 +939,13 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", - "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1082,13 +955,13 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", - "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", + "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1098,16 +971,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", - "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.1.tgz", + "integrity": "sha512-7iLhfFAubmpeJe/Wo2TVuDrykh/zlWXLzPNdL0Jqn/Xu8R3QQ8h9ff8FQoISZOsw74/HFqFI7NX63HN7QFIHKA==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/traverse": "^7.25.9", + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.27.1", "globals": "^11.1.0" }, "engines": { @@ -1118,13 +991,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", - "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/template": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1134,12 +1007,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", - "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.1.tgz", + "integrity": "sha512-ttDCqhfvpE9emVkXbPD8vyxxh4TWYACVybGkDj+oReOGwnp066ITEivDlLwe0b1R0+evJ13IXQuLNB5w1fhC5Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1149,13 +1022,13 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", - "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1165,12 +1038,12 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", - "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1180,13 +1053,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1196,12 +1069,12 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", - "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1211,12 +1084,12 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", - "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1226,12 +1099,12 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", - "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1241,13 +1114,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", - "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1257,14 +1130,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", - "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1274,12 +1147,12 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", - "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1289,12 +1162,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", - "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1304,12 +1177,12 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", - "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1319,12 +1192,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", - "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1334,13 +1207,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", - "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1350,13 +1223,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", - "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1366,15 +1239,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", - "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1384,13 +1257,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", - "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1400,13 +1273,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1416,12 +1289,12 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", - "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1431,12 +1304,12 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", - "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1446,12 +1319,12 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", - "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1461,14 +1334,14 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", - "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.1.tgz", + "integrity": "sha512-/sSliVc9gHE20/7D5qsdGlq7RG5NCDTWsAhyqzGuq174EtWJoGzIu1BQ7G56eDsTcy1jseBZwv50olSdXOlGuA==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/plugin-transform-parameters": "^7.25.9" + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1478,13 +1351,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", - "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1494,12 +1367,12 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", - "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1509,13 +1382,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1525,12 +1398,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", - "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.1.tgz", + "integrity": "sha512-018KRk76HWKeZ5l4oTj2zPpSh+NbGdt0st5S6x0pga6HgrjBOJb24mMDHorFopOOd6YHkLgOZ+zaCjZGPO4aKg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1540,13 +1413,13 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", - "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1556,14 +1429,14 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", - "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1573,12 +1446,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", - "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1588,12 +1461,12 @@ } }, "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.25.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.1.tgz", - "integrity": "sha512-SLV/giH/V4SmloZ6Dt40HjTGTAIkxn33TVIHxNGNvo8ezMhrxBkzisj4op1KZYPIOHFLqhv60OHvX+YRu4xbmQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.27.1.tgz", + "integrity": "sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.8" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1603,12 +1476,12 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", - "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.27.1.tgz", + "integrity": "sha512-p9+Vl3yuHPmkirRrg021XiP+EETmPMQTLr6Ayjj85RLNEbb3Eya/4VI0vAdzQG9SEAl2Lnt7fy5lZyMzjYoZQQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1618,16 +1491,16 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", - "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", + "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/plugin-syntax-jsx": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1637,12 +1510,12 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz", - "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", + "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", "license": "MIT", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.25.9" + "@babel/plugin-transform-react-jsx": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1652,13 +1525,13 @@ } }, "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz", - "integrity": "sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", + "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1668,13 +1541,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", - "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.1.tgz", + "integrity": "sha512-B19lbbL7PMrKr52BNPjCqg1IyNUIjTcxKj8uX9zHO+PmWN93s19NDr/f69mIkEp2x9nmDJ08a7lgHaTTzvW7mw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "regenerator-transform": "^0.15.2" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1684,13 +1556,13 @@ } }, "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", - "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1700,12 +1572,12 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", - "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1715,15 +1587,15 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz", - "integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.27.1.tgz", + "integrity": "sha512-TqGF3desVsTcp3WrJGj4HfKokfCXCLcHpt4PJF0D8/iT6LPd9RS82Upw3KPeyr6B22Lfd3DO8MVrmp0oRkUDdw==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-corejs3": "^0.11.0", "babel-plugin-polyfill-regenerator": "^0.6.1", "semver": "^6.3.1" }, @@ -1744,12 +1616,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", - "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1759,13 +1631,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", - "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1775,12 +1647,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", - "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1790,12 +1662,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", - "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1805,12 +1677,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", - "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1820,16 +1692,16 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.3.tgz", - "integrity": "sha512-6+5hpdr6mETwSKjmJUdYw0EIkATiQhnELWlE3kJFBwSg/BGIVwVaVbX+gOXBCdc7Ln1RXZxyWGecIXhUfnl7oA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.1.tgz", + "integrity": "sha512-Q5sT5+O4QUebHdbwKedFBEwRLb02zJ7r4A5Gg2hUoLuU3FjdMcyqcywqUrLCaDsFCxzokf7u9kuy7qz51YUuAg==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-syntax-typescript": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1839,12 +1711,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", - "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1854,13 +1726,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", - "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1870,13 +1742,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", - "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1886,13 +1758,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", - "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1902,79 +1774,79 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", - "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.27.1.tgz", + "integrity": "sha512-TZ5USxFpLgKDpdEt8YWBR7p6g+bZo6sHaXLqP2BY/U0acaoI8FTVflcYCr/v94twM1C5IWFdZ/hscq9WjUeLXA==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/compat-data": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.26.0", - "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.25.9", - "@babel/plugin-transform-async-generator-functions": "^7.25.9", - "@babel/plugin-transform-async-to-generator": "^7.25.9", - "@babel/plugin-transform-block-scoped-functions": "^7.25.9", - "@babel/plugin-transform-block-scoping": "^7.25.9", - "@babel/plugin-transform-class-properties": "^7.25.9", - "@babel/plugin-transform-class-static-block": "^7.26.0", - "@babel/plugin-transform-classes": "^7.25.9", - "@babel/plugin-transform-computed-properties": "^7.25.9", - "@babel/plugin-transform-destructuring": "^7.25.9", - "@babel/plugin-transform-dotall-regex": "^7.25.9", - "@babel/plugin-transform-duplicate-keys": "^7.25.9", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-dynamic-import": "^7.25.9", - "@babel/plugin-transform-exponentiation-operator": "^7.25.9", - "@babel/plugin-transform-export-namespace-from": "^7.25.9", - "@babel/plugin-transform-for-of": "^7.25.9", - "@babel/plugin-transform-function-name": "^7.25.9", - "@babel/plugin-transform-json-strings": "^7.25.9", - "@babel/plugin-transform-literals": "^7.25.9", - "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", - "@babel/plugin-transform-member-expression-literals": "^7.25.9", - "@babel/plugin-transform-modules-amd": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.25.9", - "@babel/plugin-transform-modules-systemjs": "^7.25.9", - "@babel/plugin-transform-modules-umd": "^7.25.9", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-new-target": "^7.25.9", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", - "@babel/plugin-transform-numeric-separator": "^7.25.9", - "@babel/plugin-transform-object-rest-spread": "^7.25.9", - "@babel/plugin-transform-object-super": "^7.25.9", - "@babel/plugin-transform-optional-catch-binding": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9", - "@babel/plugin-transform-parameters": "^7.25.9", - "@babel/plugin-transform-private-methods": "^7.25.9", - "@babel/plugin-transform-private-property-in-object": "^7.25.9", - "@babel/plugin-transform-property-literals": "^7.25.9", - "@babel/plugin-transform-regenerator": "^7.25.9", - "@babel/plugin-transform-regexp-modifiers": "^7.26.0", - "@babel/plugin-transform-reserved-words": "^7.25.9", - "@babel/plugin-transform-shorthand-properties": "^7.25.9", - "@babel/plugin-transform-spread": "^7.25.9", - "@babel/plugin-transform-sticky-regex": "^7.25.9", - "@babel/plugin-transform-template-literals": "^7.25.9", - "@babel/plugin-transform-typeof-symbol": "^7.25.9", - "@babel/plugin-transform-unicode-escapes": "^7.25.9", - "@babel/plugin-transform-unicode-property-regex": "^7.25.9", - "@babel/plugin-transform-unicode-regex": "^7.25.9", - "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.27.1", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.27.1", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.27.1", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.27.1", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.27.1", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-corejs3": "^0.11.0", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.38.1", + "core-js-compat": "^3.40.0", "semver": "^6.3.1" }, "engines": { @@ -1988,6 +1860,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -1996,6 +1869,7 @@ "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", @@ -2006,17 +1880,17 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz", - "integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.27.1.tgz", + "integrity": "sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-transform-react-display-name": "^7.25.9", - "@babel/plugin-transform-react-jsx": "^7.25.9", - "@babel/plugin-transform-react-jsx-development": "^7.25.9", - "@babel/plugin-transform-react-pure-annotations": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.27.1", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -2026,16 +1900,16 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", - "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", + "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-syntax-jsx": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.25.9", - "@babel/plugin-transform-typescript": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -2045,55 +1919,51 @@ } }, "node_modules/@babel/runtime": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", - "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.26.0.tgz", - "integrity": "sha512-YXHu5lN8kJCb1LOb9PgV6pvak43X2h4HvRApcN5SdWeaItQOzfn1hgP6jasD6KWQyJDBxrVmA9o9OivlnNJK/w==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.27.1.tgz", + "integrity": "sha512-909rVuj3phpjW6y0MCXAZ5iNeORePa6ldJvp2baWGcTjwqbBDDz6xoS5JHJ7lS88NlwLYj07ImL/8IUMtDZzTA==", "license": "MIT", "dependencies": { - "core-js-pure": "^3.30.2", - "regenerator-runtime": "^0.14.0" + "core-js-pure": "^3.30.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.1.tgz", + "integrity": "sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.26.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", - "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", + "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.3", - "@babel/parser": "^7.26.3", - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.3", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.1", + "@babel/parser": "^7.27.1", + "@babel/template": "^7.27.1", + "@babel/types": "^7.27.1", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2102,27 +1972,68 @@ } }, "node_modules/@babel/types": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", - "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", + "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@braintree/sanitize-url": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz", - "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==" + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.1.tgz", + "integrity": "sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==", + "license": "MIT" + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "license": "Apache-2.0" }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "license": "MIT", "optional": true, "engines": { "node": ">=0.1.90" @@ -2152,9 +2063,9 @@ } }, "node_modules/@csstools/color-helpers": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", - "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", + "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", "funding": [ { "type": "github", @@ -2171,9 +2082,9 @@ } }, "node_modules/@csstools/css-calc": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.0.tgz", - "integrity": "sha512-X69PmFOrjTZfN5ijxtI8hZ9kRADFSLrmmQ6hgDJ272Il049WGKpDY64KhrFm/7rbWve0z81QepawzjkKlqkNGw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.3.tgz", + "integrity": "sha512-XBG3talrhid44BY1x3MHzUx/aTG8+x/Zi57M4aTKK9RFB4aLlF3TTSzfzn8nWVHWL3FgAXAxmupmDd6VWww+pw==", "funding": [ { "type": "github", @@ -2194,9 +2105,9 @@ } }, "node_modules/@csstools/css-color-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.6.tgz", - "integrity": "sha512-S/IjXqTHdpI4EtzGoNCHfqraXF37x12ZZHA1Lk7zoT5pm2lMjFuqhX/89L7dqX4CcMacKK+6ZCs5TmEGb/+wKw==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.9.tgz", + "integrity": "sha512-wILs5Zk7BU86UArYBJTPy/FMPPKVKHMj1ycCEyf3VUptol0JNRLFU/BZsJ4aiIHJEbSLiizzRrw8Pc1uAEDrXw==", "funding": [ { "type": "github", @@ -2209,8 +2120,8 @@ ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^5.0.1", - "@csstools/css-calc": "^2.1.0" + "@csstools/color-helpers": "^5.0.2", + "@csstools/css-calc": "^2.1.3" }, "engines": { "node": ">=18" @@ -2333,9 +2244,9 @@ } }, "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -2346,9 +2257,9 @@ } }, "node_modules/@csstools/postcss-color-function": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.6.tgz", - "integrity": "sha512-EcvXfC60cTIumzpsxWuvVjb7rsJEHPvqn3jeMEBUaE3JSc4FRuP7mEQ+1eicxWmIrs3FtzMH9gR3sgA5TH+ebQ==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.9.tgz", + "integrity": "sha512-2UeQCGMO5+EeQsPQK2DqXp0dad+P6nIz6G2dI06APpBuYBKxZEq7CTH+UiztFQ8cB1f89dnO9+D/Kfr+JfI2hw==", "funding": [ { "type": "github", @@ -2361,10 +2272,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2375,9 +2286,9 @@ } }, "node_modules/@csstools/postcss-color-mix-function": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.6.tgz", - "integrity": "sha512-jVKdJn4+JkASYGhyPO+Wa5WXSx1+oUgaXb3JsjJn/BlrtFh5zjocCY7pwWi0nuP24V1fY7glQsxEYcYNy0dMFg==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.9.tgz", + "integrity": "sha512-Enj7ZIIkLD7zkGCN31SZFx4H1gKiCs2Y4taBo/v/cqaHN7p1qGrf5UTMNSjQFZ7MgClGufHx4pddwFTGL+ipug==", "funding": [ { "type": "github", @@ -2390,10 +2301,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2404,9 +2315,9 @@ } }, "node_modules/@csstools/postcss-content-alt-text": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.4.tgz", - "integrity": "sha512-YItlZUOuZJCBlRaCf8Aucc1lgN41qYGALMly0qQllrxYJhiyzlI6RxOTMUvtWk+KhS8GphMDsDhKQ7KTPfEMSw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.5.tgz", + "integrity": "sha512-9BOS535v6YmyOYk32jAHXeddRV+iyd4vRcbrEekpwxmueAXX5J8WgbceFnE4E4Pmw/ysnB9v+n/vSWoFmcLMcA==", "funding": [ { "type": "github", @@ -2421,7 +2332,7 @@ "dependencies": { "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2432,9 +2343,9 @@ } }, "node_modules/@csstools/postcss-exponential-functions": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.5.tgz", - "integrity": "sha512-mi8R6dVfA2nDoKM3wcEi64I8vOYEgQVtVKCfmLHXupeLpACfGAided5ddMt5f+CnEodNu4DifuVwb0I6fQDGGQ==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.8.tgz", + "integrity": "sha512-vHgDXtGIBPpFQnFNDftMQg4MOuXcWnK91L/7REjBNYzQ/p2Fa/6RcnehTqCRrNtQ46PNIolbRsiDdDuxiHolwQ==", "funding": [ { "type": "github", @@ -2447,7 +2358,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-calc": "^2.1.0", + "@csstools/css-calc": "^2.1.3", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3" }, @@ -2485,9 +2396,9 @@ } }, "node_modules/@csstools/postcss-gamut-mapping": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.6.tgz", - "integrity": "sha512-0ke7fmXfc8H+kysZz246yjirAH6JFhyX9GTlyRnM0exHO80XcA9zeJpy5pOp5zo/AZiC/q5Pf+Hw7Pd6/uAoYA==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.9.tgz", + "integrity": "sha512-quksIsFm3DGsf8Qbr9KiSGBF2w3RwxSfOfma5wbORDB1AFF15r4EVW7sUuWw3s5IAEGMqzel/dE2rQsI7Yb8mA==", "funding": [ { "type": "github", @@ -2500,7 +2411,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3" }, @@ -2512,9 +2423,9 @@ } }, "node_modules/@csstools/postcss-gradients-interpolation-method": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.6.tgz", - "integrity": "sha512-Itrbx6SLUzsZ6Mz3VuOlxhbfuyLTogG5DwEF1V8dAi24iMuvQPIHd7Ti+pNDp7j6WixndJGZaoNR0f9VSzwuTg==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.9.tgz", + "integrity": "sha512-duqTeUHF4ambUybAmhX9KonkicLM/WNp2JjMUbegRD4O8A/tb6fdZ7jUNdp/UUiO1FIdDkMwmNw6856bT0XF8Q==", "funding": [ { "type": "github", @@ -2527,10 +2438,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2541,9 +2452,9 @@ } }, "node_modules/@csstools/postcss-hwb-function": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.6.tgz", - "integrity": "sha512-927Pqy3a1uBP7U8sTfaNdZVB0mNXzIrJO/GZ8us9219q9n06gOqCdfZ0E6d1P66Fm0fYHvxfDbfcUuwAn5UwhQ==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.9.tgz", + "integrity": "sha512-sDpdPsoGAhYl/PMSYfu5Ez82wXb2bVkg1Cb8vsRLhpXhAk4OSlsJN+GodAql6tqc1B2G/WToxsFU6G74vkhPvA==", "funding": [ { "type": "github", @@ -2556,10 +2467,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2570,9 +2481,9 @@ } }, "node_modules/@csstools/postcss-ic-unit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.0.tgz", - "integrity": "sha512-9QT5TDGgx7wD3EEMN3BSUG6ckb6Eh5gSPT5kZoVtUuAonfPmLDJyPhqR4ntPpMYhUKAMVKAg3I/AgzqHMSeLhA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.1.tgz", + "integrity": "sha512-lECc38i1w3qU9nhrUhP6F8y4BfcQJkR1cb8N6tZNf2llM6zPkxnqt04jRCwsUgNcB3UGKDy+zLenhOYGHqCV+Q==", "funding": [ { "type": "github", @@ -2585,7 +2496,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, @@ -2597,9 +2508,9 @@ } }, "node_modules/@csstools/postcss-initial": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.0.tgz", - "integrity": "sha512-dv2lNUKR+JV+OOhZm9paWzYBXOCi+rJPqJ2cJuhh9xd8USVrd0cBEPczla81HNOyThMQWeCcdln3gZkQV2kYxA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.1.tgz", + "integrity": "sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg==", "funding": [ { "type": "github", @@ -2667,9 +2578,9 @@ } }, "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -2680,9 +2591,9 @@ } }, "node_modules/@csstools/postcss-light-dark-function": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.7.tgz", - "integrity": "sha512-ZZ0rwlanYKOHekyIPaU+sVm3BEHCe+Ha0/px+bmHe62n0Uc1lL34vbwrLYn6ote8PHlsqzKeTQdIejQCJ05tfw==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.8.tgz", + "integrity": "sha512-v8VU5WtrZIyEtk88WB4fkG22TGd8HyAfSFfZZQ1uNN0+arMJdZc++H3KYTfbYDpJRGy8GwADYH8ySXiILn+OyA==", "funding": [ { "type": "github", @@ -2697,7 +2608,7 @@ "dependencies": { "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2825,9 +2736,9 @@ } }, "node_modules/@csstools/postcss-media-minmax": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.5.tgz", - "integrity": "sha512-sdh5i5GToZOIAiwhdntRWv77QDtsxP2r2gXW/WbLSCoLr00KTq/yiF1qlQ5XX2+lmiFa8rATKMcbwl3oXDMNew==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.8.tgz", + "integrity": "sha512-Skum5wIXw2+NyCQWUyfstN3c1mfSh39DRAo+Uh2zzXOglBG8xB9hnArhYFScuMZkzeM+THVa//mrByKAfumc7w==", "funding": [ { "type": "github", @@ -2840,7 +2751,7 @@ ], "license": "MIT", "dependencies": { - "@csstools/css-calc": "^2.1.0", + "@csstools/css-calc": "^2.1.3", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "@csstools/media-query-list-parser": "^4.0.2" @@ -2931,9 +2842,9 @@ } }, "node_modules/@csstools/postcss-oklab-function": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.6.tgz", - "integrity": "sha512-Hptoa0uX+XsNacFBCIQKTUBrFKDiplHan42X73EklG6XmQLG7/aIvxoNhvZ7PvOWMt67Pw3bIlUY2nD6p5vL8A==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.9.tgz", + "integrity": "sha512-UHrnujimwtdDw8BYDcWJtBXuJ13uc/BjAddPdfMc/RsWxhg8gG8UbvTF0tnMtHrZ4i7lwy85fPEzK1AiykMyRA==", "funding": [ { "type": "github", @@ -2946,10 +2857,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -2960,9 +2871,9 @@ } }, "node_modules/@csstools/postcss-progressive-custom-properties": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.0.0.tgz", - "integrity": "sha512-XQPtROaQjomnvLUSy/bALTR5VCtTVUFwYs1SblvYgLSeTo2a/bMNwUwo2piXw5rTv/FEYiy5yPSXBqg9OKUx7Q==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.0.1.tgz", + "integrity": "sha512-Ofz81HaY8mmbP8/Qr3PZlUzjsyV5WuxWmvtYn+jhYGvvjFazTmN9R2io5W5znY1tyk2CA9uM0IPWyY4ygDytCw==", "funding": [ { "type": "github", @@ -2985,9 +2896,9 @@ } }, "node_modules/@csstools/postcss-random-function": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-1.0.1.tgz", - "integrity": "sha512-Ab/tF8/RXktQlFwVhiC70UNfpFQRhtE5fQQoP2pO+KCPGLsLdWFiOuHgSRtBOqEshCVAzR4H6o38nhvRZq8deA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-2.0.0.tgz", + "integrity": "sha512-MYZKxSr4AKfjECL8vg49BbfNNzK+t3p2OWX+Xf7rXgMaTP44oy/e8VGWu4MLnJ3NUd9tFVkisLO/sg+5wMTNsg==", "funding": [ { "type": "github", @@ -3000,7 +2911,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-calc": "^2.1.0", + "@csstools/css-calc": "^2.1.3", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3" }, @@ -3012,9 +2923,9 @@ } }, "node_modules/@csstools/postcss-relative-color-syntax": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.6.tgz", - "integrity": "sha512-yxP618Xb+ji1I624jILaYM62uEmZcmbdmFoZHoaThw896sq0vU39kqTTF+ZNic9XyPtPMvq0vyvbgmHaszq8xg==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.9.tgz", + "integrity": "sha512-+AGOcLF5PmMnTRPnOdCvY7AwvD5veIOhTWbJV6vC3hB1tt0ii/k6QOwhWfsGGg1ZPQ0JY15u+wqLR4ZTtB0luA==", "funding": [ { "type": "github", @@ -3027,10 +2938,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -3066,9 +2977,9 @@ } }, "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -3079,9 +2990,9 @@ } }, "node_modules/@csstools/postcss-sign-functions": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.0.tgz", - "integrity": "sha512-SLcc20Nujx/kqbSwDmj6oaXgpy3UjFhBy1sfcqPgDkHfOIfUtUVH7OXO+j7BU4v/At5s61N5ZX6shvgPwluhsA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.3.tgz", + "integrity": "sha512-4F4GRhj8xNkBtLZ+3ycIhReaDfKJByXI+cQGIps3AzCO8/CJOeoDPxpMnL5vqZrWKOceSATHEQJUO/Q/r2y7OQ==", "funding": [ { "type": "github", @@ -3094,7 +3005,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-calc": "^2.1.0", + "@csstools/css-calc": "^2.1.3", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3" }, @@ -3106,9 +3017,9 @@ } }, "node_modules/@csstools/postcss-stepped-value-functions": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.5.tgz", - "integrity": "sha512-G6SJ6hZJkhxo6UZojVlLo14MohH4J5J7z8CRBrxxUYy9JuZiIqUo5TBYyDGcE0PLdzpg63a7mHSJz3VD+gMwqw==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.8.tgz", + "integrity": "sha512-6Y4yhL4fNhgzbZ/wUMQ4EjFUfoNNMpEXZnDw1JrlcEBHUT15gplchtFsZGk7FNi8PhLHJfCUwVKrEHzhfhKK+g==", "funding": [ { "type": "github", @@ -3121,7 +3032,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-calc": "^2.1.0", + "@csstools/css-calc": "^2.1.3", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3" }, @@ -3133,9 +3044,9 @@ } }, "node_modules/@csstools/postcss-text-decoration-shorthand": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.1.tgz", - "integrity": "sha512-xPZIikbx6jyzWvhms27uugIc0I4ykH4keRvoa3rxX5K7lEhkbd54rjj/dv60qOCTisoS+3bmwJTeyV1VNBrXaw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.2.tgz", + "integrity": "sha512-8XvCRrFNseBSAGxeaVTaNijAu+FzUvjwFXtcrynmazGb/9WUdsPCpBX+mHEHShVRq47Gy4peYAoxYs8ltUnmzA==", "funding": [ { "type": "github", @@ -3148,7 +3059,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/color-helpers": "^5.0.1", + "@csstools/color-helpers": "^5.0.2", "postcss-value-parser": "^4.2.0" }, "engines": { @@ -3159,9 +3070,9 @@ } }, "node_modules/@csstools/postcss-trigonometric-functions": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.5.tgz", - "integrity": "sha512-/YQThYkt5MLvAmVu7zxjhceCYlKrYddK6LEmK5I4ojlS6BmO9u2yO4+xjXzu2+NPYmHSTtP4NFSamBCMmJ1NJA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.8.tgz", + "integrity": "sha512-YcDvYTRu7f78/91B6bX+mE1WoAO91Su7/8KSRpuWbIGUB8hmaNSRu9wziaWSLJ1lOB1aQe+bvo9BIaLKqPOo/g==", "funding": [ { "type": "github", @@ -3174,7 +3085,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-calc": "^2.1.0", + "@csstools/css-calc": "^2.1.3", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3" }, @@ -3239,26 +3150,26 @@ } }, "node_modules/@docsearch/css": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz", - "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.9.0.tgz", + "integrity": "sha512-cQbnVbq0rrBwNAKegIac/t6a8nWoUAn8frnkLFW6YARaRmAQr5/Eoe6Ln2fqkUCZ40KpdrKbpSAmgrkviOxuWA==", "license": "MIT" }, "node_modules/@docsearch/react": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz", - "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.9.0.tgz", + "integrity": "sha512-mb5FOZYZIkRQ6s/NWnM98k879vu5pscWqTLubLFBO87igYYT4VzVazh4h5o/zCvTIZgEt3PvsCOMOswOUo9yHQ==", "license": "MIT", "dependencies": { - "@algolia/autocomplete-core": "1.17.7", - "@algolia/autocomplete-preset-algolia": "1.17.7", - "@docsearch/css": "3.8.2", + "@algolia/autocomplete-core": "1.17.9", + "@algolia/autocomplete-preset-algolia": "1.17.9", + "@docsearch/css": "3.9.0", "algoliasearch": "^5.14.2" }, "peerDependencies": { - "@types/react": ">= 16.8.0 < 19.0.0", - "react": ">= 16.8.0 < 19.0.0", - "react-dom": ">= 16.8.0 < 19.0.0", + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0", "search-insights": ">= 1 < 3" }, "peerDependenciesMeta": { @@ -3276,79 +3187,10 @@ } } }, - "node_modules/@docsearch/react/node_modules/@algolia/client-analytics": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.18.0.tgz", - "integrity": "sha512-0VpGG2uQW+h2aejxbG8VbnMCQ9ary9/ot7OASXi6OjE0SRkYQ/+pkW+q09+IScif3pmsVVYggmlMPtAsmYWHng==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.18.0", - "@algolia/requester-browser-xhr": "5.18.0", - "@algolia/requester-fetch": "5.18.0", - "@algolia/requester-node-http": "5.18.0" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@docsearch/react/node_modules/@algolia/client-personalization": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.18.0.tgz", - "integrity": "sha512-I2dc94Oiwic3SEbrRp8kvTZtYpJjGtg5y5XnqubgnA15AgX59YIY8frKsFG8SOH1n2rIhUClcuDkxYQNXJLg+w==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.18.0", - "@algolia/requester-browser-xhr": "5.18.0", - "@algolia/requester-fetch": "5.18.0", - "@algolia/requester-node-http": "5.18.0" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@docsearch/react/node_modules/@algolia/recommend": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.18.0.tgz", - "integrity": "sha512-uSnkm0cdAuFwdMp4pGT5vHVQ84T6AYpTZ3I0b3k/M3wg4zXDhl3aCiY8NzokEyRLezz/kHLEEcgb/tTTobOYVw==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "5.18.0", - "@algolia/requester-browser-xhr": "5.18.0", - "@algolia/requester-fetch": "5.18.0", - "@algolia/requester-node-http": "5.18.0" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@docsearch/react/node_modules/algoliasearch": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.18.0.tgz", - "integrity": "sha512-/tfpK2A4FpS0o+S78o3YSdlqXr0MavJIDlFK3XZrlXLy7vaRXJvW5jYg3v5e/wCaF8y0IpMjkYLhoV6QqfpOgw==", - "license": "MIT", - "dependencies": { - "@algolia/client-abtesting": "5.18.0", - "@algolia/client-analytics": "5.18.0", - "@algolia/client-common": "5.18.0", - "@algolia/client-insights": "5.18.0", - "@algolia/client-personalization": "5.18.0", - "@algolia/client-query-suggestions": "5.18.0", - "@algolia/client-search": "5.18.0", - "@algolia/ingestion": "1.18.0", - "@algolia/monitoring": "1.18.0", - "@algolia/recommend": "5.18.0", - "@algolia/requester-browser-xhr": "5.18.0", - "@algolia/requester-fetch": "5.18.0", - "@algolia/requester-node-http": "5.18.0" - }, - "engines": { - "node": ">= 14.0.0" - } - }, "node_modules/@docusaurus/babel": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.6.3.tgz", - "integrity": "sha512-7dW9Hat9EHYCVicFXYA4hjxBY38+hPuCURL8oRF9fySRm7vzNWuEOghA1TXcykuXZp0HLG2td4RhDxCvGG7tNw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.7.0.tgz", + "integrity": "sha512-0H5uoJLm14S/oKV3Keihxvh8RV+vrid+6Gv+2qhuzbqHanawga8tYnsdpjEyt36ucJjqlby2/Md2ObWjA02UXQ==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.9", @@ -3361,8 +3203,8 @@ "@babel/runtime": "^7.25.9", "@babel/runtime-corejs3": "^7.25.9", "@babel/traverse": "^7.25.9", - "@docusaurus/logger": "3.6.3", - "@docusaurus/utils": "3.6.3", + "@docusaurus/logger": "3.7.0", + "@docusaurus/utils": "3.7.0", "babel-plugin-dynamic-import-node": "^2.3.3", "fs-extra": "^11.1.1", "tslib": "^2.6.0" @@ -3372,17 +3214,17 @@ } }, "node_modules/@docusaurus/bundler": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.6.3.tgz", - "integrity": "sha512-47JLuc8D4wA+6VOvmMd5fUC9rFppBQpQOnxDYiVXffm/DeV/wmm3sbpNd5Y+O+G2+nevLTRnvCm/qyancv0Y3A==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.7.0.tgz", + "integrity": "sha512-CUUT9VlSGukrCU5ctZucykvgCISivct+cby28wJwCC/fkQFgAHRp/GKv2tx38ZmXb7nacrKzFTcp++f9txUYGg==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.9", - "@docusaurus/babel": "3.6.3", - "@docusaurus/cssnano-preset": "3.6.3", - "@docusaurus/logger": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils": "3.6.3", + "@docusaurus/babel": "3.7.0", + "@docusaurus/cssnano-preset": "3.7.0", + "@docusaurus/logger": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils": "3.7.0", "babel-loader": "^9.2.1", "clean-css": "^5.3.2", "copy-webpack-plugin": "^11.0.0", @@ -3416,18 +3258,18 @@ } }, "node_modules/@docusaurus/core": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.6.3.tgz", - "integrity": "sha512-xL7FRY9Jr5DWqB6pEnqgKqcMPJOX5V0pgWXi5lCiih11sUBmcFKM7c3+GyxcVeeWFxyYSDP3grLTWqJoP4P9Vw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.7.0.tgz", + "integrity": "sha512-b0fUmaL+JbzDIQaamzpAFpTviiaU4cX3Qz8cuo14+HGBCwa0evEK0UYCBFY3n4cLzL8Op1BueeroUD2LYAIHbQ==", "license": "MIT", "dependencies": { - "@docusaurus/babel": "3.6.3", - "@docusaurus/bundler": "3.6.3", - "@docusaurus/logger": "3.6.3", - "@docusaurus/mdx-loader": "3.6.3", - "@docusaurus/utils": "3.6.3", - "@docusaurus/utils-common": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", + "@docusaurus/babel": "3.7.0", + "@docusaurus/bundler": "3.7.0", + "@docusaurus/logger": "3.7.0", + "@docusaurus/mdx-loader": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-common": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", "boxen": "^6.2.1", "chalk": "^4.1.2", "chokidar": "^3.5.3", @@ -3448,13 +3290,12 @@ "p-map": "^4.0.0", "prompts": "^2.4.2", "react-dev-utils": "^12.0.1", - "react-helmet-async": "^1.3.0", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", "react-loadable-ssr-addon-v5-slorber": "^1.0.1", "react-router": "^5.3.4", "react-router-config": "^5.1.1", "react-router-dom": "^5.3.4", - "rtl-detect": "^1.0.4", "semver": "^7.5.4", "serve-handler": "^6.1.6", "shelljs": "^0.8.5", @@ -3473,28 +3314,14 @@ }, "peerDependencies": { "@mdx-js/react": "^3.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@docusaurus/core/node_modules/webpack-merge": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", - "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", - "license": "MIT", - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.1" - }, - "engines": { - "node": ">=18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/cssnano-preset": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.6.3.tgz", - "integrity": "sha512-qP7SXrwZ+23GFJdPN4aIHQrZW+oH/7tzwEuc/RNL0+BdZdmIjYQqUxdXsjE4lFxLNZjj0eUrSNYIS6xwfij+5Q==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.7.0.tgz", + "integrity": "sha512-X9GYgruZBSOozg4w4dzv9uOz8oK/EpPVQXkp0MM6Tsgp/nRIU9hJzJ0Pxg1aRa3xCeEQTOimZHcocQFlLwYajQ==", "license": "MIT", "dependencies": { "cssnano-preset-advanced": "^6.1.2", @@ -3507,9 +3334,9 @@ } }, "node_modules/@docusaurus/logger": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.6.3.tgz", - "integrity": "sha512-xSubJixcNyMV9wMV4q0s47CBz3Rlc5jbcCCuij8pfQP8qn/DIpt0ks8W6hQWzHAedg/J/EwxxUOUrnEoKzJo8g==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.7.0.tgz", + "integrity": "sha512-z7g62X7bYxCYmeNNuO9jmzxLQG95q9QxINCwpboVcNff3SJiHJbGrarxxOVMVmAh1MsrSfxWkVGv4P41ktnFsA==", "license": "MIT", "dependencies": { "chalk": "^4.1.2", @@ -3520,14 +3347,14 @@ } }, "node_modules/@docusaurus/mdx-loader": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.6.3.tgz", - "integrity": "sha512-3iJdiDz9540ppBseeI93tWTDtUGVkxzh59nMq4ignylxMuXBLK8dFqVeaEor23v1vx6TrGKZ2FuLaTB+U7C0QQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.7.0.tgz", + "integrity": "sha512-OFBG6oMjZzc78/U3WNPSHs2W9ZJ723ewAcvVJaqS0VgyeUfmzUV8f1sv+iUHA0DtwiR5T5FjOxj6nzEE8LY6VA==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.6.3", - "@docusaurus/utils": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", + "@docusaurus/logger": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", "@mdx-js/mdx": "^3.0.0", "@slorber/remark-comment": "^1.0.0", "escape-html": "^1.0.3", @@ -3554,22 +3381,22 @@ "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/module-type-aliases": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.6.3.tgz", - "integrity": "sha512-MjaXX9PN/k5ugNvfRZdWyKWq4FsrhN4LEXaj0pEmMebJuBNlFeGyKQUa9DRhJHpadNaiMLrbo9m3U7Ig5YlsZg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.7.0.tgz", + "integrity": "sha512-g7WdPqDNaqA60CmBrr0cORTrsOit77hbsTj7xE2l71YhBn79sxdm7WMK7wfhcaafkbpIh7jv5ef5TOpf1Xv9Lg==", "license": "MIT", "dependencies": { - "@docusaurus/types": "3.6.3", + "@docusaurus/types": "3.7.0", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", "@types/react-router-dom": "*", - "react-helmet-async": "*", + "react-helmet-async": "npm:@slorber/react-helmet-async@*", "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" }, "peerDependencies": { @@ -3578,19 +3405,19 @@ } }, "node_modules/@docusaurus/plugin-content-blog": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.6.3.tgz", - "integrity": "sha512-k0ogWwwJU3pFRFfvW1kRVHxzf2DutLGaaLjAnHVEU6ju+aRP0Z5ap/13DHyPOfHeE4WKpn/M0TqjdwZAcY3kAw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.7.0.tgz", + "integrity": "sha512-EFLgEz6tGHYWdPU0rK8tSscZwx+AsyuBW/r+tNig2kbccHYGUJmZtYN38GjAa3Fda4NU+6wqUO5kTXQSRBQD3g==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/logger": "3.6.3", - "@docusaurus/mdx-loader": "3.6.3", - "@docusaurus/theme-common": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils": "3.6.3", - "@docusaurus/utils-common": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", + "@docusaurus/core": "3.7.0", + "@docusaurus/logger": "3.7.0", + "@docusaurus/mdx-loader": "3.7.0", + "@docusaurus/theme-common": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-common": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", "cheerio": "1.0.0-rc.12", "feed": "^4.2.2", "fs-extra": "^11.1.1", @@ -3607,25 +3434,25 @@ }, "peerDependencies": { "@docusaurus/plugin-content-docs": "*", - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/plugin-content-docs": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.6.3.tgz", - "integrity": "sha512-r2wS8y/fsaDcxkm20W5bbYJFPzdWdEaTWVYjNxlHlcmX086eqQR1Fomlg9BHTJ0dLXPzAlbC8EN4XqMr3QzNCQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.7.0.tgz", + "integrity": "sha512-GXg5V7kC9FZE4FkUZA8oo/NrlRb06UwuICzI6tcbzj0+TVgjq/mpUXXzSgKzMS82YByi4dY2Q808njcBCyy6tQ==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/logger": "3.6.3", - "@docusaurus/mdx-loader": "3.6.3", - "@docusaurus/module-type-aliases": "3.6.3", - "@docusaurus/theme-common": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils": "3.6.3", - "@docusaurus/utils-common": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", + "@docusaurus/core": "3.7.0", + "@docusaurus/logger": "3.7.0", + "@docusaurus/mdx-loader": "3.7.0", + "@docusaurus/module-type-aliases": "3.7.0", + "@docusaurus/theme-common": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-common": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", "@types/react-router-config": "^5.0.7", "combine-promises": "^1.1.0", "fs-extra": "^11.1.1", @@ -3639,21 +3466,21 @@ "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/plugin-content-pages": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.6.3.tgz", - "integrity": "sha512-eHrmTgjgLZsuqfsYr5X2xEwyIcck0wseSofWrjTwT9FLOWp+KDmMAuVK+wRo7sFImWXZk3oV/xX/g9aZrhD7OA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.7.0.tgz", + "integrity": "sha512-YJSU3tjIJf032/Aeao8SZjFOrXJbz/FACMveSMjLyMH4itQyZ2XgUIzt4y+1ISvvk5zrW4DABVT2awTCqBkx0Q==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/mdx-loader": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", + "@docusaurus/core": "3.7.0", + "@docusaurus/mdx-loader": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", "fs-extra": "^11.1.1", "tslib": "^2.6.0", "webpack": "^5.88.1" @@ -3662,19 +3489,19 @@ "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/plugin-debug": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.6.3.tgz", - "integrity": "sha512-zB9GXfIZNPRfzKnNjU6xGVrqn9bPXuGhpjgsuc/YtcTDjnjhasg38NdYd5LEqXex5G/zIorQgWB3n6x/Ut62vQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.7.0.tgz", + "integrity": "sha512-Qgg+IjG/z4svtbCNyTocjIwvNTNEwgRjSXXSJkKVG0oWoH0eX/HAPiu+TS1HBwRPQV+tTYPWLrUypYFepfujZA==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils": "3.6.3", + "@docusaurus/core": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils": "3.7.0", "fs-extra": "^11.1.1", "react-json-view-lite": "^1.2.0", "tslib": "^2.6.0" @@ -3683,38 +3510,38 @@ "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/plugin-google-analytics": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.6.3.tgz", - "integrity": "sha512-rCDNy1QW8Dag7nZq67pcum0bpFLrwvxJhYuVprhFh8BMBDxV0bY+bAkGHbSf68P3Bk9C3hNOAXX1srGLIDvcTA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.7.0.tgz", + "integrity": "sha512-otIqiRV/jka6Snjf+AqB360XCeSv7lQC+DKYW+EUZf6XbuE8utz5PeUQ8VuOcD8Bk5zvT1MC4JKcd5zPfDuMWA==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", + "@docusaurus/core": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", "tslib": "^2.6.0" }, "engines": { "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/plugin-google-gtag": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.6.3.tgz", - "integrity": "sha512-+OyDvhM6rqVkQOmLVkQWVJAizEEfkPzVWtIHXlWPOCFGK9X4/AWeBSrU0WG4iMg9Z4zD4YDRrU+lvI4s6DSC+w==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.7.0.tgz", + "integrity": "sha512-M3vrMct1tY65ModbyeDaMoA+fNJTSPe5qmchhAbtqhDD/iALri0g9LrEpIOwNaoLmm6lO88sfBUADQrSRSGSWA==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", + "@docusaurus/core": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", "@types/gtag.js": "^0.0.12", "tslib": "^2.6.0" }, @@ -3722,41 +3549,41 @@ "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/plugin-google-tag-manager": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.6.3.tgz", - "integrity": "sha512-1M6UPB13gWUtN2UHX083/beTn85PlRI9ABItTl/JL1FJ5dJTWWFXXsHf9WW/6hrVwthwTeV/AGbGKvLKV+IlCA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.7.0.tgz", + "integrity": "sha512-X8U78nb8eiMiPNg3jb9zDIVuuo/rE1LjGDGu+5m5CX4UBZzjMy+klOY2fNya6x8ACyE/L3K2erO1ErheP55W/w==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", + "@docusaurus/core": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", "tslib": "^2.6.0" }, "engines": { "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/plugin-sitemap": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.6.3.tgz", - "integrity": "sha512-94qOO4M9Fwv9KfVQJsgbe91k+fPJ4byf1L3Ez8TUa6TAFPo/BrLwQ80zclHkENlL1824TuxkcMKv33u6eydQCg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.7.0.tgz", + "integrity": "sha512-bTRT9YLZ/8I/wYWKMQke18+PF9MV8Qub34Sku6aw/vlZ/U+kuEuRpQ8bTcNOjaTSfYsWkK4tTwDMHK2p5S86cA==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/logger": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils": "3.6.3", - "@docusaurus/utils-common": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", + "@docusaurus/core": "3.7.0", + "@docusaurus/logger": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-common": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", "fs-extra": "^11.1.1", "sitemap": "^7.1.1", "tslib": "^2.6.0" @@ -3765,57 +3592,81 @@ "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, - "node_modules/@docusaurus/preset-classic": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.6.3.tgz", - "integrity": "sha512-VHSYWROT3flvNNI1SrnMOtW1EsjeHNK9dhU6s9eY5hryZe79lUqnZJyze/ymDe2LXAqzyj6y5oYvyBoZZk6ErA==", + "node_modules/@docusaurus/plugin-svgr": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.7.0.tgz", + "integrity": "sha512-HByXIZTbc4GV5VAUkZ2DXtXv1Qdlnpk3IpuImwSnEzCDBkUMYcec5282hPjn6skZqB25M1TYCmWS91UbhBGxQg==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/plugin-content-blog": "3.6.3", - "@docusaurus/plugin-content-docs": "3.6.3", - "@docusaurus/plugin-content-pages": "3.6.3", - "@docusaurus/plugin-debug": "3.6.3", - "@docusaurus/plugin-google-analytics": "3.6.3", - "@docusaurus/plugin-google-gtag": "3.6.3", - "@docusaurus/plugin-google-tag-manager": "3.6.3", - "@docusaurus/plugin-sitemap": "3.6.3", - "@docusaurus/theme-classic": "3.6.3", - "@docusaurus/theme-common": "3.6.3", - "@docusaurus/theme-search-algolia": "3.6.3", - "@docusaurus/types": "3.6.3" + "@docusaurus/core": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", + "@svgr/core": "8.1.0", + "@svgr/webpack": "^8.1.0", + "tslib": "^2.6.0", + "webpack": "^5.88.1" }, "engines": { "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.7.0.tgz", + "integrity": "sha512-nPHj8AxDLAaQXs+O6+BwILFuhiWbjfQWrdw2tifOClQoNfuXDjfjogee6zfx6NGHWqshR23LrcN115DmkHC91Q==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.7.0", + "@docusaurus/plugin-content-blog": "3.7.0", + "@docusaurus/plugin-content-docs": "3.7.0", + "@docusaurus/plugin-content-pages": "3.7.0", + "@docusaurus/plugin-debug": "3.7.0", + "@docusaurus/plugin-google-analytics": "3.7.0", + "@docusaurus/plugin-google-gtag": "3.7.0", + "@docusaurus/plugin-google-tag-manager": "3.7.0", + "@docusaurus/plugin-sitemap": "3.7.0", + "@docusaurus/plugin-svgr": "3.7.0", + "@docusaurus/theme-classic": "3.7.0", + "@docusaurus/theme-common": "3.7.0", + "@docusaurus/theme-search-algolia": "3.7.0", + "@docusaurus/types": "3.7.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/theme-classic": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.6.3.tgz", - "integrity": "sha512-1RRLK1tSArI2c00qugWYO3jRocjOZwGF1mBzPPylDVRwWCS/rnWWR91ChdbbaxIupRJ+hX8ZBYrwr5bbU0oztQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.7.0.tgz", + "integrity": "sha512-MnLxG39WcvLCl4eUzHr0gNcpHQfWoGqzADCly54aqCofQX6UozOS9Th4RK3ARbM9m7zIRv3qbhggI53dQtx/hQ==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/logger": "3.6.3", - "@docusaurus/mdx-loader": "3.6.3", - "@docusaurus/module-type-aliases": "3.6.3", - "@docusaurus/plugin-content-blog": "3.6.3", - "@docusaurus/plugin-content-docs": "3.6.3", - "@docusaurus/plugin-content-pages": "3.6.3", - "@docusaurus/theme-common": "3.6.3", - "@docusaurus/theme-translations": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils": "3.6.3", - "@docusaurus/utils-common": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", + "@docusaurus/core": "3.7.0", + "@docusaurus/logger": "3.7.0", + "@docusaurus/mdx-loader": "3.7.0", + "@docusaurus/module-type-aliases": "3.7.0", + "@docusaurus/plugin-content-blog": "3.7.0", + "@docusaurus/plugin-content-docs": "3.7.0", + "@docusaurus/plugin-content-pages": "3.7.0", + "@docusaurus/theme-common": "3.7.0", + "@docusaurus/theme-translations": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-common": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", "copy-text-to-clipboard": "^3.2.0", @@ -3834,20 +3685,20 @@ "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/theme-common": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.6.3.tgz", - "integrity": "sha512-b8ZkhczXHDxWWyvz+YJy4t/PlPbEogTTbgnHoflYnH7rmRtyoodTsu8WVM12la5LmlMJBclBXFl29OH8kPE7gg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.7.0.tgz", + "integrity": "sha512-8eJ5X0y+gWDsURZnBfH0WabdNm8XMCXHv8ENy/3Z/oQKwaB/EHt5lP9VsTDTf36lKEp0V6DjzjFyFIB+CetL0A==", "license": "MIT", "dependencies": { - "@docusaurus/mdx-loader": "3.6.3", - "@docusaurus/module-type-aliases": "3.6.3", - "@docusaurus/utils": "3.6.3", - "@docusaurus/utils-common": "3.6.3", + "@docusaurus/mdx-loader": "3.7.0", + "@docusaurus/module-type-aliases": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-common": "3.7.0", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -3862,21 +3713,21 @@ }, "peerDependencies": { "@docusaurus/plugin-content-docs": "*", - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/theme-mermaid": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-3.6.3.tgz", - "integrity": "sha512-kIqpjNCP/9R2GGf8UmiDxD3CkOAEJuJIEFlaKMgQtjVxa/vH+9PLI1+DFbArGoG4+0ENTYUq8phHPW7SeL36uQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-3.7.0.tgz", + "integrity": "sha512-7kNDvL7hm+tshjxSxIqYMtsLUPsEBYnkevej/ext6ru9xyLgCed+zkvTfGzTWNeq8rJIEe2YSS8/OV5gCVaPCw==", "license": "MIT", "dependencies": { - "@docusaurus/core": "3.6.3", - "@docusaurus/module-type-aliases": "3.6.3", - "@docusaurus/theme-common": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", + "@docusaurus/core": "3.7.0", + "@docusaurus/module-type-aliases": "3.7.0", + "@docusaurus/theme-common": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", "mermaid": ">=10.4", "tslib": "^2.6.0" }, @@ -3884,26 +3735,26 @@ "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/theme-search-algolia": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.6.3.tgz", - "integrity": "sha512-rt+MGCCpYgPyWCGXtbxlwFbTSobu15jWBTPI2LHsHNa5B0zSmOISX6FWYAPt5X1rNDOqMGM0FATnh7TBHRohVA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.7.0.tgz", + "integrity": "sha512-Al/j5OdzwRU1m3falm+sYy9AaB93S1XF1Lgk9Yc6amp80dNxJVplQdQTR4cYdzkGtuQqbzUA8+kaoYYO0RbK6g==", "license": "MIT", "dependencies": { - "@docsearch/react": "^3.5.2", - "@docusaurus/core": "3.6.3", - "@docusaurus/logger": "3.6.3", - "@docusaurus/plugin-content-docs": "3.6.3", - "@docusaurus/theme-common": "3.6.3", - "@docusaurus/theme-translations": "3.6.3", - "@docusaurus/utils": "3.6.3", - "@docusaurus/utils-validation": "3.6.3", - "algoliasearch": "^4.18.0", - "algoliasearch-helper": "^3.13.3", + "@docsearch/react": "^3.8.1", + "@docusaurus/core": "3.7.0", + "@docusaurus/logger": "3.7.0", + "@docusaurus/plugin-content-docs": "3.7.0", + "@docusaurus/theme-common": "3.7.0", + "@docusaurus/theme-translations": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-validation": "3.7.0", + "algoliasearch": "^5.17.1", + "algoliasearch-helper": "^3.22.6", "clsx": "^2.0.0", "eta": "^2.2.0", "fs-extra": "^11.1.1", @@ -3915,14 +3766,14 @@ "node": ">=18.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@docusaurus/theme-translations": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.6.3.tgz", - "integrity": "sha512-Gb0regclToVlngSIIwUCtBMQBq48qVUaN1XQNKW4XwlsgUyk0vP01LULdqbem7czSwIeBAFXFoORJ0RPX7ht/w==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.7.0.tgz", + "integrity": "sha512-Ewq3bEraWDmienM6eaNK7fx+/lHMtGDHQyd1O+4+3EsDxxUmrzPkV7Ct3nBWTuE0MsoZr3yNwQVKjllzCMuU3g==", "license": "MIT", "dependencies": { "fs-extra": "^11.1.1", @@ -3933,9 +3784,9 @@ } }, "node_modules/@docusaurus/types": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.6.3.tgz", - "integrity": "sha512-xD9oTGDrouWzefkhe9ogB2fDV96/82cRpNGx2HIvI5L87JHNhQVIWimQ/3JIiiX/TEd5S9s+VO6FFguwKNRVow==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.7.0.tgz", + "integrity": "sha512-kOmZg5RRqJfH31m+6ZpnwVbkqMJrPOG5t0IOl4i/+3ruXyNfWzZ0lVtVrD0u4ONc/0NOsS9sWYaxxWNkH1LdLQ==", "license": "MIT", "dependencies": { "@mdx-js/mdx": "^3.0.0", @@ -3943,26 +3794,39 @@ "@types/react": "*", "commander": "^5.1.0", "joi": "^17.9.2", - "react-helmet-async": "^1.3.0", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", "utility-types": "^3.10.0", "webpack": "^5.95.0", "webpack-merge": "^5.9.0" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/types/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" } }, "node_modules/@docusaurus/utils": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.6.3.tgz", - "integrity": "sha512-0R/FR3bKVl4yl8QwbL4TYFfR+OXBRpVUaTJdENapBGR3YMwfM6/JnhGilWQO8AOwPJGtGoDK7ib8+8UF9f3OZQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.7.0.tgz", + "integrity": "sha512-e7zcB6TPnVzyUaHMJyLSArKa2AG3h9+4CfvKXKKWNx6hRs+p0a+u7HHTJBgo6KW2m+vqDnuIHK4X+bhmoghAFA==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.6.3", - "@docusaurus/types": "3.6.3", - "@docusaurus/utils-common": "3.6.3", - "@svgr/webpack": "^8.1.0", + "@docusaurus/logger": "3.7.0", + "@docusaurus/types": "3.7.0", + "@docusaurus/utils-common": "3.7.0", "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", "fs-extra": "^11.1.1", @@ -3986,12 +3850,12 @@ } }, "node_modules/@docusaurus/utils-common": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.6.3.tgz", - "integrity": "sha512-v4nKDaANLgT3pMBewHYEMAl/ufY0LkXao1QkFWzI5huWFOmNQ2UFzv2BiKeHX5Ownis0/w6cAyoxPhVdDonlSQ==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.7.0.tgz", + "integrity": "sha512-IZeyIfCfXy0Mevj6bWNg7DG7B8G+S6o6JVpddikZtWyxJguiQ7JYr0SIZ0qWd8pGNuMyVwriWmbWqMnK7Y5PwA==", "license": "MIT", "dependencies": { - "@docusaurus/types": "3.6.3", + "@docusaurus/types": "3.7.0", "tslib": "^2.6.0" }, "engines": { @@ -3999,14 +3863,14 @@ } }, "node_modules/@docusaurus/utils-validation": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.6.3.tgz", - "integrity": "sha512-bhEGGiN5BE38h21vjqD70Gxg++j+PfYVddDUE5UFvLDup68QOcpD33CLr+2knPorlxRbEaNfz6HQDUMQ3HuqKw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.7.0.tgz", + "integrity": "sha512-w8eiKk8mRdN+bNfeZqC4nyFoxNyI1/VExMKAzD9tqpJfLLbsa46Wfn5wcKH761g9WkKh36RtFV49iL9lh1DYBA==", "license": "MIT", "dependencies": { - "@docusaurus/logger": "3.6.3", - "@docusaurus/utils": "3.6.3", - "@docusaurus/utils-common": "3.6.3", + "@docusaurus/logger": "3.7.0", + "@docusaurus/utils": "3.7.0", + "@docusaurus/utils-common": "3.7.0", "fs-extra": "^11.2.0", "joi": "^17.9.2", "js-yaml": "^4.1.0", @@ -4056,6 +3920,40 @@ "react-hook-form": "^7.0.0" } }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.3.0.tgz", + "integrity": "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.0.0", + "@antfu/utils": "^8.1.0", + "@iconify/types": "^2.0.0", + "debug": "^4.4.0", + "globals": "^15.14.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.0.0", + "mlly": "^1.7.4" + } + }, + "node_modules/@iconify/utils/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -4144,9 +4042,10 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -4161,18 +4060,20 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -4197,9 +4098,9 @@ "license": "MIT" }, "node_modules/@mdx-js/mdx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.1.tgz", - "integrity": "sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.0.tgz", + "integrity": "sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -4208,14 +4109,15 @@ "@types/mdx": "^2.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", - "estree-util-build-jsx": "^3.0.0", "estree-util-is-identifier-name": "^3.0.0", - "estree-util-to-js": "^2.0.0", + "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", - "hast-util-to-estree": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", - "periscopic": "^3.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", @@ -4248,10 +4150,20 @@ "react": ">=16" } }, + "node_modules/@mermaid-js/parser": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.4.0.tgz", + "integrity": "sha512-wla8XOWvQAwuqy+gxiZqY+c7FokraOTHRWMsbB4AgRx9Sy7zKslNyejy7E+a77qHfey5GXw/ik3IXv/NHMJgaA==", + "license": "MIT", + "dependencies": { + "langium": "3.3.1" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -4264,6 +4176,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", "engines": { "node": ">= 8" } @@ -4272,6 +4185,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -4281,9 +4195,9 @@ } }, "node_modules/@parcel/watcher": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", - "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", "hasInstallScript": true, "license": "MIT", "optional": true, @@ -4301,25 +4215,25 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.0", - "@parcel/watcher-darwin-arm64": "2.5.0", - "@parcel/watcher-darwin-x64": "2.5.0", - "@parcel/watcher-freebsd-x64": "2.5.0", - "@parcel/watcher-linux-arm-glibc": "2.5.0", - "@parcel/watcher-linux-arm-musl": "2.5.0", - "@parcel/watcher-linux-arm64-glibc": "2.5.0", - "@parcel/watcher-linux-arm64-musl": "2.5.0", - "@parcel/watcher-linux-x64-glibc": "2.5.0", - "@parcel/watcher-linux-x64-musl": "2.5.0", - "@parcel/watcher-win32-arm64": "2.5.0", - "@parcel/watcher-win32-ia32": "2.5.0", - "@parcel/watcher-win32-x64": "2.5.0" + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz", - "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", "cpu": [ "arm64" ], @@ -4337,9 +4251,9 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz", - "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", "cpu": [ "arm64" ], @@ -4357,9 +4271,9 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz", - "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", "cpu": [ "x64" ], @@ -4377,9 +4291,9 @@ } }, "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz", - "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", "cpu": [ "x64" ], @@ -4397,9 +4311,9 @@ } }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz", - "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", "cpu": [ "arm" ], @@ -4417,9 +4331,9 @@ } }, "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz", - "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", "cpu": [ "arm" ], @@ -4437,9 +4351,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz", - "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", "cpu": [ "arm64" ], @@ -4457,9 +4371,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz", - "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", "cpu": [ "arm64" ], @@ -4477,9 +4391,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz", - "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", "cpu": [ "x64" ], @@ -4497,9 +4411,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz", - "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", "cpu": [ "x64" ], @@ -4517,9 +4431,9 @@ } }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz", - "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", "cpu": [ "arm64" ], @@ -4537,9 +4451,9 @@ } }, "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz", - "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", "cpu": [ "ia32" ], @@ -4557,9 +4471,9 @@ } }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz", - "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", "cpu": [ "x64" ], @@ -4590,6 +4504,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "license": "MIT", "engines": { "node": ">=12.22.0" } @@ -4598,6 +4513,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "license": "MIT", "dependencies": { "graceful-fs": "4.2.10" }, @@ -4608,12 +4524,14 @@ "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "license": "ISC" }, "node_modules/@pnpm/npm-conf": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", - "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "license": "MIT", "dependencies": { "@pnpm/config.env-replace": "^1.1.0", "@pnpm/network.ca-file": "^1.0.1", @@ -4624,9 +4542,9 @@ } }, "node_modules/@polka/url": { - "version": "1.0.0-next.28", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", - "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", "license": "MIT" }, "node_modules/@redocly/ajv": { @@ -4646,59 +4564,30 @@ } }, "node_modules/@redocly/config": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.11.0.tgz", - "integrity": "sha512-vAc77vCuWsVgLx2LN02P6jqLBhHuot6O1LsSJEAAkWEvXARSGSQVon50QW7jlbCMg9OFTYYYRPN4W6K/YmnM3w==", + "version": "0.22.2", + "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.22.2.tgz", + "integrity": "sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==", "license": "MIT" }, "node_modules/@redocly/openapi-core": { - "version": "1.25.3", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.25.3.tgz", - "integrity": "sha512-dqJkyydgagW3FXX5cjtSUAnabsld4K6yq7RFgQ+ngI1m43PkEoSQt8pp+SfQDszSEoMbc7QKj8afbe7mZw17TA==", + "version": "1.34.2", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.2.tgz", + "integrity": "sha512-glfkQFJizLdq2fBkNvc2FJW0sxDb5exd0wIXhFk+WHaFLMREBC3CxRo2Zq7uJIdfV9U3YTceMbXJklpDfmmwFQ==", "license": "MIT", "dependencies": { "@redocly/ajv": "^8.11.2", - "@redocly/config": "^0.11.0", + "@redocly/config": "^0.22.0", "colorette": "^1.2.0", - "https-proxy-agent": "^7.0.4", + "https-proxy-agent": "^7.0.5", "js-levenshtein": "^1.1.6", "js-yaml": "^4.1.0", - "lodash.isequal": "^4.5.0", "minimatch": "^5.0.1", - "node-fetch": "^2.6.1", "pluralize": "^8.0.0", "yaml-ast-parser": "0.0.43" }, "engines": { - "node": ">=14.19.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@redocly/openapi-core/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@redocly/openapi-core/node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "license": "MIT" - }, - "node_modules/@redocly/openapi-core/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" + "node": ">=18.17.0", + "npm": ">=9.5.0" } }, "node_modules/@reduxjs/toolkit": { @@ -5036,6 +4925,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "license": "MIT", "dependencies": { "defer-to-connect": "^2.0.1" }, @@ -5052,15 +4942,6 @@ "node": ">=10.13.0" } }, - "node_modules/@types/acorn": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", - "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -5099,36 +4980,273 @@ "@types/node": "*" } }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", + "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT" + }, "node_modules/@types/d3-scale": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", - "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", "dependencies": { "@types/d3-time": "*" } }, "node_modules/@types/d3-scale-chromatic": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.2.tgz", - "integrity": "sha512-kpKNZMDT3OAX6b5ct5nS/mv6LULagnUy4DmS6yyNjclje1qVe7vbjPwY3q1TGz6+Wr2IUkgFatCzqYUl54fHag==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } }, "node_modules/@types/d3-time": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", - "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", "dependencies": { "@types/ms": "*" } }, "node_modules/@types/eslint": { - "version": "8.44.7", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.7.tgz", - "integrity": "sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -5138,15 +5256,16 @@ "version": "3.7.7", "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", "license": "MIT" }, "node_modules/@types/estree-jsx": { @@ -5171,9 +5290,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.2.tgz", - "integrity": "sha512-vluaspfvWEtE4vcSDlKRNer52DvOGrB2xv6diXy6UKyKW0lqZiWHGNApSyxOv+8DE5Z27IzVvE7hNkxg7EXIcg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", + "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", "license": "MIT", "dependencies": { "@types/node": "*", @@ -5194,6 +5313,12 @@ "@types/send": "*" } }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, "node_modules/@types/gtag.js": { "version": "0.0.12", "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz", @@ -5212,12 +5337,13 @@ "node_modules/@types/history": { "version": "4.7.11", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", - "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "license": "MIT" }, "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", - "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz", + "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==", "license": "MIT", "dependencies": { "@types/react": "*", @@ -5233,7 +5359,8 @@ "node_modules/@types/http-cache-semantics": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "license": "MIT" }, "node_modules/@types/http-errors": { "version": "2.0.4", @@ -5242,9 +5369,9 @@ "license": "MIT" }, "node_modules/@types/http-proxy": { - "version": "1.17.15", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", - "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "version": "1.17.16", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", + "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", "license": "MIT", "dependencies": { "@types/node": "*" @@ -5277,7 +5404,8 @@ "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" }, "node_modules/@types/mdast": { "version": "4.0.4", @@ -5289,9 +5417,10 @@ } }, "node_modules/@types/mdx": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.10.tgz", - "integrity": "sha512-Rllzc5KHk0Al5/WANwgSPl1/CwjqCy+AZrGd78zuK+jO9aDM6ffblZ+zIjgPNAaEBmlO0RYDvLNh7wD0zKVgEg==" + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" }, "node_modules/@types/mime": { "version": "1.3.5", @@ -5300,16 +5429,18 @@ "license": "MIT" }, "node_modules/@types/ms": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" }, "node_modules/@types/node": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", - "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", + "version": "22.15.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz", + "integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==", + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.21.0" } }, "node_modules/@types/node-forge": { @@ -5324,7 +5455,8 @@ "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" }, "node_modules/@types/parse5": { "version": "6.0.3", @@ -5333,20 +5465,21 @@ "license": "MIT" }, "node_modules/@types/prismjs": { - "version": "1.26.4", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.4.tgz", - "integrity": "sha512-rlAnzkW2sZOjbqZ743IHUhFcvzaGbqijwOu8QZnZCjfQzBqFE3s4lOTJEsxikImav9uzz/42I+O7YUs1mWgMlg==", + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", "license": "MIT" }, "node_modules/@types/prop-types": { - "version": "15.7.10", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.10.tgz", - "integrity": "sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A==" + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "license": "MIT" }, "node_modules/@types/qs": { - "version": "6.9.17", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", - "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", + "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", "license": "MIT" }, "node_modules/@types/range-parser": { @@ -5356,9 +5489,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.7.tgz", - "integrity": "sha512-KUnDCJF5+AiZd8owLIeVHqmW9yM4sqmDVf2JRJiBMFkGvkoZ4/WyV2lL4zVsoinmRS/W3FeEdZLEWFRofnT2FQ==", + "version": "18.3.20", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz", + "integrity": "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==", "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -5381,15 +5514,17 @@ "version": "5.1.20", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "license": "MIT", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*" } }, "node_modules/@types/react-router-config": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.10.tgz", - "integrity": "sha512-Wn6c/tXdEgi9adCMtDwx8Q2vGty6TsPTc/wCQQ9kAlye8UqFxj0vGFWWuhywNfkwqth+SOgJxQTLTZukrqDQmQ==", + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.11.tgz", + "integrity": "sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw==", + "license": "MIT", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*", @@ -5400,6 +5535,7 @@ "version": "5.3.3", "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "license": "MIT", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*", @@ -5460,16 +5596,23 @@ "@types/node": "*" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, "node_modules/@types/ws": { - "version": "8.5.13", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", - "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "license": "MIT", "dependencies": { "@types/node": "*" @@ -5491,9 +5634,9 @@ "license": "MIT" }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "license": "ISC" }, "node_modules/@webassemblyjs/ast": { @@ -5654,18 +5797,6 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "license": "Apache-2.0" }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -5679,27 +5810,6 @@ "node": ">= 0.6" } }, - "node_modules/accepts/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/accepts/node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -5710,9 +5820,9 @@ } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -5746,18 +5856,16 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "license": "MIT", "engines": { "node": ">= 10.0.0" } }, "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, "engines": { "node": ">= 14" } @@ -5766,6 +5874,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -5775,9 +5884,10 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -5807,6 +5917,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -5832,32 +5943,33 @@ } }, "node_modules/algoliasearch": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.24.0.tgz", - "integrity": "sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==", + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.24.0.tgz", + "integrity": "sha512-CkaUygzZ91Xbw11s0CsHMawrK3tl+Ue57725HGRgRzKgt2Z4wvXVXRCtQfvzh8K7Tp4Zp7f1pyHAtMROtTJHxg==", "license": "MIT", "dependencies": { - "@algolia/cache-browser-local-storage": "4.24.0", - "@algolia/cache-common": "4.24.0", - "@algolia/cache-in-memory": "4.24.0", - "@algolia/client-account": "4.24.0", - "@algolia/client-analytics": "4.24.0", - "@algolia/client-common": "4.24.0", - "@algolia/client-personalization": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/logger-common": "4.24.0", - "@algolia/logger-console": "4.24.0", - "@algolia/recommend": "4.24.0", - "@algolia/requester-browser-xhr": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/requester-node-http": "4.24.0", - "@algolia/transporter": "4.24.0" + "@algolia/client-abtesting": "5.24.0", + "@algolia/client-analytics": "5.24.0", + "@algolia/client-common": "5.24.0", + "@algolia/client-insights": "5.24.0", + "@algolia/client-personalization": "5.24.0", + "@algolia/client-query-suggestions": "5.24.0", + "@algolia/client-search": "5.24.0", + "@algolia/ingestion": "1.24.0", + "@algolia/monitoring": "1.24.0", + "@algolia/recommend": "5.24.0", + "@algolia/requester-browser-xhr": "5.24.0", + "@algolia/requester-fetch": "5.24.0", + "@algolia/requester-node-http": "5.24.0" + }, + "engines": { + "node": ">= 14.0.0" } }, "node_modules/algoliasearch-helper": { - "version": "3.22.6", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.22.6.tgz", - "integrity": "sha512-F2gSb43QHyvZmvH/2hxIjbk/uFdO2MguQYTFP7J+RowMW1csjIODMobEnpLI8nbLQuzZnGZdIxl5Bpy1k9+CFQ==", + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.25.0.tgz", + "integrity": "sha512-vQoK43U6HXA9/euCqLjvyNdM4G2Fiu/VFp4ae0Gau9sZeIKBPvUPnXfLYAe65Bg7PFuw03coeu5K6lTPSXRObw==", "license": "MIT", "dependencies": { "@algolia/events": "^4.0.1" @@ -5866,45 +5978,6 @@ "algoliasearch": ">= 3.1 < 6" } }, - "node_modules/algoliasearch/node_modules/@algolia/client-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", - "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", - "license": "MIT", - "dependencies": { - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "node_modules/algoliasearch/node_modules/@algolia/client-search": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", - "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", - "license": "MIT", - "dependencies": { - "@algolia/client-common": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "node_modules/algoliasearch/node_modules/@algolia/requester-browser-xhr": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz", - "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==", - "license": "MIT", - "dependencies": { - "@algolia/requester-common": "4.24.0" - } - }, - "node_modules/algoliasearch/node_modules/@algolia/requester-node-http": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz", - "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==", - "license": "MIT", - "dependencies": { - "@algolia/requester-common": "4.24.0" - } - }, "node_modules/allof-merge": { "version": "0.6.6", "resolved": "https://registry.npmjs.org/allof-merge/-/allof-merge-0.6.6.tgz", @@ -5918,6 +5991,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", "dependencies": { "string-width": "^4.1.0" } @@ -5925,12 +5999,14 @@ "node_modules/ansi-align/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, "node_modules/ansi-align/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5983,6 +6059,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { "node": ">=8" } @@ -5991,6 +6068,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6011,6 +6089,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -6028,7 +6107,8 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" }, "node_modules/array-flatten": { "version": "1.1.1", @@ -6040,44 +6120,15 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", - "license": "MIT" - }, - "node_modules/assert": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", - "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "is-nan": "^1.3.2", - "object-is": "^1.1.5", - "object.assign": "^4.1.4", - "util": "^0.12.5" - } - }, "node_modules/astring": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", - "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", "license": "MIT", "bin": { "astring": "bin/astring" @@ -6093,14 +6144,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "license": "ISC", "engines": { "node": ">= 4.0.0" } }, "node_modules/autoprefixer": { - "version": "10.4.20", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", - "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", "funding": [ { "type": "opencollective", @@ -6117,11 +6169,11 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.23.3", - "caniuse-lite": "^1.0.30001646", + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.1", + "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -6134,21 +6186,6 @@ "postcss": "^8.1.0" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/babel-loader": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", @@ -6176,13 +6213,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", - "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz", + "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==", "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.3", + "@babel/helper-define-polyfill-provider": "^0.6.4", "semver": "^6.3.1" }, "peerDependencies": { @@ -6199,25 +6236,25 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", - "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2", - "core-js-compat": "^3.38.0" + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", - "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz", + "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==", "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.3" + "@babel/helper-define-polyfill-provider": "^0.6.4" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -6236,7 +6273,8 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -6268,24 +6306,23 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "license": "MIT", "engines": { "node": "*" } }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "license": "MIT" - }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -6328,6 +6365,18 @@ "ms": "2.0.0" } }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -6362,12 +6411,14 @@ "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" }, "node_modules/boxen": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "license": "MIT", "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^6.2.0", @@ -6386,158 +6437,30 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "license": "MIT" - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "license": "MIT", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "license": "MIT", - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", - "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", - "license": "MIT", - "dependencies": { - "bn.js": "^5.2.1", - "randombytes": "^2.1.0", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", - "license": "ISC", - "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/browserify-sign/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/browserify-sign/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "license": "MIT", - "dependencies": { - "pako": "~1.0.5" - } - }, "node_modules/browserslist": { - "version": "4.24.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", - "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "funding": [ { "type": "opencollective", @@ -6593,18 +6516,7 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "license": "MIT" - }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "license": "MIT" }, "node_modules/bytes": { @@ -6620,6 +6532,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "license": "MIT", "engines": { "node": ">=14.16" } @@ -6628,6 +6541,7 @@ "version": "10.2.14", "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "license": "MIT", "dependencies": { "@types/http-cache-semantics": "^4.0.2", "get-stream": "^6.0.1", @@ -6641,17 +6555,6 @@ "node": ">=14.16" } }, - "node_modules/cacheable-request/node_modules/normalize-url": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", - "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -6671,9 +6574,9 @@ } }, "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -6684,13 +6587,13 @@ } }, "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -6709,6 +6612,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", "engines": { "node": ">=6" } @@ -6727,6 +6631,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -6747,9 +6652,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001690", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", - "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", + "version": "1.0.30001716", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001716.tgz", + "integrity": "sha512-49/c1+x3Kwz7ZIWt+4DvK3aMJy9oYXXG6/97JKsnjdCk/6n9vVyWL8NAwVt95Lwt9eigI10Hl782kDfZUUlRXw==", "funding": [ { "type": "opencollective", @@ -6780,6 +6685,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6804,6 +6710,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -6886,16 +6793,37 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -6908,14 +6836,18 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", "engines": { "node": ">=6.0" } @@ -6930,23 +6862,11 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/cipher-base": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", - "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/clean-css": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", @@ -6972,6 +6892,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", "engines": { "node": ">=6" } @@ -6980,6 +6901,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -6988,9 +6910,10 @@ } }, "node_modules/cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "license": "MIT", "dependencies": { "string-width": "^4.2.0" }, @@ -7004,12 +6927,14 @@ "node_modules/cli-table3/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, "node_modules/cli-table3/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -7074,6 +6999,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -7083,17 +7009,6 @@ "node": ">=6" } }, - "node_modules/clone-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -7117,6 +7032,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7127,7 +7043,8 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" }, "node_modules/colord": { "version": "2.9.3", @@ -7136,15 +7053,16 @@ "license": "MIT" }, "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", "license": "MIT" }, "node_modules/combine-promises": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.2.0.tgz", "integrity": "sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==", + "license": "MIT", "engines": { "node": ">=10" } @@ -7163,6 +7081,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "license": "MIT", "engines": { "node": ">= 6" } @@ -7185,19 +7104,10 @@ "node": ">= 0.6" } }, - "node_modules/compressible/node_modules/mime-db": { - "version": "1.53.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", - "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/compression": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", - "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -7260,12 +7170,20 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "license": "MIT" }, "node_modules/config-chain": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "license": "MIT", "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -7275,6 +7193,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "license": "BSD-2-Clause", "dependencies": { "dot-prop": "^6.0.1", "graceful-fs": "^4.2.6", @@ -7299,25 +7218,14 @@ } }, "node_modules/consola": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.3.0.tgz", - "integrity": "sha512-kxltocVQCwQNFvw40dlVRYeAkAvtYjMFZYNlOcsF5wExPpGwPxMwgx4IfDJvBRPtBpnQwItd5WkTaR0ZwT/TmQ==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", "license": "MIT", "engines": { "node": "^14.18.0 || >=16.10.0" } }, - "node_modules/console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", - "license": "MIT" - }, "node_modules/content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -7339,7 +7247,8 @@ "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" }, "node_modules/cookie": { "version": "0.7.1", @@ -7436,22 +7345,23 @@ } }, "node_modules/core-js": { - "version": "3.33.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.33.2.tgz", - "integrity": "sha512-XeBzWI6QL3nJQiHmdzbAOiMYqjrb7hwU7A39Qhvd/POSa/t9E1AeZyEZx3fNvp/vtM8zXwhoL0FsiS0hD0pruQ==", + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz", + "integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==", "hasInstallScript": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, "node_modules/core-js-compat": { - "version": "3.39.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", - "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.42.0.tgz", + "integrity": "sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==", "license": "MIT", "dependencies": { - "browserslist": "^4.24.2" + "browserslist": "^4.24.4" }, "funding": { "type": "opencollective", @@ -7459,9 +7369,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.39.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.39.0.tgz", - "integrity": "sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==", + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.42.0.tgz", + "integrity": "sha512-007bM04u91fF4kMgwom2I5cQxAFIy8jVulgr9eozILl/SZE53QOqnW/+vviC+wQWLv+AunBG+8Q0TLoeSsSxRQ==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -7479,6 +7389,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", "dependencies": { "layout-base": "^1.0.0" } @@ -7509,53 +7420,11 @@ } } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", - "license": "MIT" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -7565,32 +7434,6 @@ "node": ">= 8" } }, - "node_modules/crypto-browserify": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", - "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", - "license": "MIT", - "dependencies": { - "browserify-cipher": "^1.0.1", - "browserify-sign": "^4.2.3", - "create-ecdh": "^4.0.4", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "diffie-hellman": "^5.0.3", - "hash-base": "~3.0.4", - "inherits": "^2.0.4", - "pbkdf2": "^3.1.2", - "public-encrypt": "^4.0.3", - "randombytes": "^2.1.0", - "randomfill": "^1.0.4" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/crypto-js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", @@ -7601,6 +7444,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "license": "MIT", "dependencies": { "type-fest": "^1.0.1" }, @@ -7615,6 +7459,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -7648,9 +7493,9 @@ } }, "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -7722,9 +7567,9 @@ } }, "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -7868,6 +7713,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -7876,9 +7722,9 @@ } }, "node_modules/cssdb": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.2.3.tgz", - "integrity": "sha512-9BDG5XmJrJQQnJ51VFxXCAtpZ5ebDlAREmO8sxMOVU0aSxN/gocbctjIG5LMh3WBUq+xTlb/jw2LoljBEqraTA==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.2.5.tgz", + "integrity": "sha512-leAt8/hdTCtzql9ZZi86uYAmCLzVKpJMMdjbvOGVnXFXz/BWFpBmM1MHEHU/RqtPyRYmabVmEW1DtX3YGLuuLA==", "funding": [ { "type": "opencollective", @@ -8034,18 +7880,16 @@ "license": "CC0-1.0" }, "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" }, "node_modules/cytoscape": { - "version": "3.27.0", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.27.0.tgz", - "integrity": "sha512-pPZJilfX9BxESwujODz5pydeGi+FBrXq1rcaB1mfhFXXFJ9GjE6CNndAk+8jPzoXGD+16LtSS4xlYEIUiW4Abg==", - "dependencies": { - "heap": "^0.2.6", - "lodash": "^4.17.21" - }, + "version": "3.31.4", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.31.4.tgz", + "integrity": "sha512-JfUX/esCfnBGP+uNqRSkAr8jDr1HDSEm6jUNG+BToi43zwLisWrArZjIboB3NfCF5yKu2eG6sbPYaefEEaufyQ==", + "license": "MIT", "engines": { "node": ">=0.10" } @@ -8054,6 +7898,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "license": "MIT", "dependencies": { "cose-base": "^1.0.0" }, @@ -8065,6 +7910,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", "dependencies": { "cose-base": "^2.2.0" }, @@ -8076,6 +7922,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", "dependencies": { "layout-base": "^2.0.0" } @@ -8083,12 +7930,14 @@ "node_modules/cytoscape-fcose/node_modules/layout-base": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", - "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==" + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "license": "MIT" }, "node_modules/d3": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz", - "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", "dependencies": { "d3-array": "3", "d3-axis": "3", @@ -8129,6 +7978,7 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", "dependencies": { "internmap": "1 - 2" }, @@ -8140,6 +7990,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", "engines": { "node": ">=12" } @@ -8148,6 +7999,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -8163,6 +8015,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", "dependencies": { "d3-path": "1 - 3" }, @@ -8174,6 +8027,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "engines": { "node": ">=12" } @@ -8182,6 +8036,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", "dependencies": { "d3-array": "^3.2.0" }, @@ -8193,6 +8048,7 @@ "version": "6.0.4", "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", "dependencies": { "delaunator": "5" }, @@ -8204,6 +8060,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", "engines": { "node": ">=12" } @@ -8212,6 +8069,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" @@ -8224,6 +8082,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", "dependencies": { "commander": "7", "iconv-lite": "0.6", @@ -8248,25 +8107,16 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", "engines": { "node": ">= 10" } }, - "node_modules/d3-dsv/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/d3-ease": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", "engines": { "node": ">=12" } @@ -8275,6 +8125,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", "dependencies": { "d3-dsv": "1 - 3" }, @@ -8286,6 +8137,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", @@ -8299,14 +8151,16 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", "dependencies": { "d3-array": "2.5.0 - 3" }, @@ -8318,6 +8172,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", "engines": { "node": ">=12" } @@ -8326,6 +8181,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3" }, @@ -8337,6 +8193,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", "engines": { "node": ">=12" } @@ -8345,6 +8202,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", "engines": { "node": ">=12" } @@ -8353,6 +8211,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", "engines": { "node": ">=12" } @@ -8361,6 +8220,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", "engines": { "node": ">=12" } @@ -8369,6 +8229,7 @@ "version": "0.12.3", "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", "dependencies": { "d3-array": "1 - 2", "d3-shape": "^1.2.0" @@ -8378,6 +8239,7 @@ "version": "2.12.1", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", "dependencies": { "internmap": "^1.0.0" } @@ -8385,12 +8247,14 @@ "node_modules/d3-sankey/node_modules/d3-path": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" }, "node_modules/d3-sankey/node_modules/d3-shape": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", "dependencies": { "d3-path": "1" } @@ -8398,12 +8262,14 @@ "node_modules/d3-sankey/node_modules/internmap": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" }, "node_modules/d3-scale": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", @@ -8416,9 +8282,10 @@ } }, "node_modules/d3-scale-chromatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", - "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3", "d3-interpolate": "1 - 3" @@ -8431,6 +8298,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", "engines": { "node": ">=12" } @@ -8439,6 +8307,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", "dependencies": { "d3-path": "^3.1.0" }, @@ -8450,6 +8319,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", "dependencies": { "d3-array": "2 - 3" }, @@ -8461,6 +8331,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "dependencies": { "d3-time": "1 - 3" }, @@ -8472,6 +8343,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", "engines": { "node": ">=12" } @@ -8480,6 +8352,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", @@ -8498,6 +8371,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -8510,18 +8384,20 @@ } }, "node_modules/dagre-d3-es": { - "version": "7.0.10", - "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.10.tgz", - "integrity": "sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.11.tgz", + "integrity": "sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==", + "license": "MIT", "dependencies": { - "d3": "^7.8.2", + "d3": "^7.9.0", "lodash-es": "^4.17.21" } }, "node_modules/dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" }, "node_modules/debounce": { "version": "1.2.1", @@ -8530,11 +8406,12 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -8546,9 +8423,10 @@ } }, "node_modules/decode-named-character-reference": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", + "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", + "license": "MIT", "dependencies": { "character-entities": "^2.0.0" }, @@ -8561,6 +8439,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", "dependencies": { "mimic-response": "^3.1.0" }, @@ -8575,6 +8454,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -8586,6 +8466,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -8594,6 +8475,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8614,6 +8496,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "license": "MIT", "engines": { "node": ">=10" } @@ -8639,6 +8522,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", "engines": { "node": ">=8" } @@ -8664,6 +8548,7 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "license": "MIT", "dependencies": { "globby": "^11.0.1", "graceful-fs": "^4.2.4", @@ -8682,11 +8567,12 @@ } }, "node_modules/delaunator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", - "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", "dependencies": { - "robust-predicates": "^3.0.0" + "robust-predicates": "^3.0.2" } }, "node_modules/depd": { @@ -8702,20 +8588,11 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -8758,9 +8635,10 @@ } }, "node_modules/detect-port": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", - "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", + "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", + "license": "MIT", "dependencies": { "address": "^1.0.1", "debug": "4" @@ -8768,12 +8646,16 @@ "bin": { "detect": "bin/detect-port.js", "detect-port": "bin/detect-port.js" + }, + "engines": { + "node": ">= 4.0.0" } }, "node_modules/detect-port-alt": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "license": "MIT", "dependencies": { "address": "^1.0.1", "debug": "^2.6.0" @@ -8790,6 +8672,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -8797,7 +8680,8 @@ "node_modules/detect-port-alt/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/devlop": { "version": "1.1.0", @@ -8813,34 +8697,19 @@ } }, "node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", - "license": "MIT" - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -8861,9 +8730,9 @@ } }, "node_modules/docusaurus-plugin-openapi-docs": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/docusaurus-plugin-openapi-docs/-/docusaurus-plugin-openapi-docs-4.3.1.tgz", - "integrity": "sha512-uVv/mipiQzgqHIhgnTmJmsBW3UuuAufmuyXeHzQR8PGovsjMOKJU6YVDTd8qHlkXQ09IdoBLKG0RUZ9daNxt0w==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/docusaurus-plugin-openapi-docs/-/docusaurus-plugin-openapi-docs-4.3.7.tgz", + "integrity": "sha512-wCXuHniG108OGCj6qKtTOFLgyhnlztMegj63BbEyHC/OgM7PDL2Yj2VFkWsU3eCmJKI+czahanztFMhVLFD67w==", "license": "MIT", "dependencies": { "@apidevtools/json-schema-ref-parser": "^11.5.4", @@ -8889,7 +8758,7 @@ "@docusaurus/plugin-content-docs": "^3.5.0", "@docusaurus/utils": "^3.5.0", "@docusaurus/utils-validation": "^3.5.0", - "react": "^16.8.4 || ^17.0.0 || ^18.0.0" + "react": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/docusaurus-plugin-openapi-docs/node_modules/clsx": { @@ -8917,128 +8786,39 @@ } }, "node_modules/docusaurus-plugin-sass": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/docusaurus-plugin-sass/-/docusaurus-plugin-sass-0.2.5.tgz", - "integrity": "sha512-Z+D0fLFUKcFpM+bqSUmqKIU+vO+YF1xoEQh5hoFreg2eMf722+siwXDD+sqtwU8E4MvVpuvsQfaHwODNlxJAEg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/docusaurus-plugin-sass/-/docusaurus-plugin-sass-0.2.6.tgz", + "integrity": "sha512-2hKQQDkrufMong9upKoG/kSHJhuwd+FA3iAe/qzS/BmWpbIpe7XKmq5wlz4J5CJaOPu4x+iDJbgAxZqcoQf0kg==", "license": "MIT", "peer": true, "dependencies": { - "sass-loader": "^10.1.1" + "sass-loader": "^16.0.2" }, "peerDependencies": { "@docusaurus/core": "^2.0.0-beta || ^3.0.0-alpha", "sass": "^1.30.0" } }, - "node_modules/docusaurus-plugin-sass/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/docusaurus-plugin-sass/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/docusaurus-plugin-sass/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT", - "peer": true - }, - "node_modules/docusaurus-plugin-sass/node_modules/sass-loader": { - "version": "10.5.2", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.5.2.tgz", - "integrity": "sha512-vMUoSNOUKJILHpcNCCyD23X34gve1TS7Rjd9uXHeKqhvBG39x6XbswFDtpbTElj6XdMFezoWhkh5vtKudf2cgQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "klona": "^2.0.4", - "loader-utils": "^2.0.0", - "neo-async": "^2.6.2", - "schema-utils": "^3.0.0", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", - "sass": "^1.3.0", - "webpack": "^4.36.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/docusaurus-plugin-sass/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/docusaurus-theme-openapi-docs": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/docusaurus-theme-openapi-docs/-/docusaurus-theme-openapi-docs-4.3.1.tgz", - "integrity": "sha512-AeMBDckf+L3CDybLuzxUnjfBOa4zvpfux+u8g2apMSRub1Zh17EdqSWapzHWcMRw3xmknR4kqMFboWLXhwW1ew==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/docusaurus-theme-openapi-docs/-/docusaurus-theme-openapi-docs-4.3.7.tgz", + "integrity": "sha512-VRKA8gFVIlSBUu7EAYOY3JDF2WetCSVsYx5WeFo8g6/7LJWHhX7/A7Wo2fJ0B61VE/c53BSdbmvVWSJoUqnkoA==", "license": "MIT", "dependencies": { "@hookform/error-message": "^2.0.1", "@reduxjs/toolkit": "^1.7.1", "allof-merge": "^0.6.6", + "buffer": "^6.0.3", "clsx": "^1.1.1", "copy-text-to-clipboard": "^3.1.0", "crypto-js": "^4.1.1", "file-saver": "^2.0.5", "lodash": "^4.17.20", - "node-polyfill-webpack-plugin": "^3.0.0", + "pako": "^2.1.0", "postman-code-generators": "^1.10.1", "postman-collection": "^4.4.0", "prism-react-renderer": "^2.3.0", + "process": "^0.11.10", "react-hook-form": "^7.43.8", "react-live": "^4.0.0", "react-magic-dropzone": "^1.0.1", @@ -9050,7 +8830,7 @@ "sass": "^1.80.4", "sass-loader": "^16.0.2", "unist-util-visit": "^5.0.0", - "webpack": "^5.61.0", + "url": "^0.11.1", "xml-formatter": "^2.6.1" }, "engines": { @@ -9060,8 +8840,8 @@ "@docusaurus/theme-common": "^3.5.0", "docusaurus-plugin-openapi-docs": "^4.0.0", "docusaurus-plugin-sass": "^0.2.3", - "react": "^16.8.4 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.4 || ^17.0.0 || ^18.0.0" + "react": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/docusaurus-theme-openapi-docs/node_modules/@types/hast": { @@ -9164,6 +8944,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/docusaurus-theme-openapi-docs/node_modules/hast-util-raw/node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/docusaurus-theme-openapi-docs/node_modules/hast-util-to-parse5": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.1.0.tgz", @@ -9377,6 +9172,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/docusaurus-theme-openapi-docs/node_modules/mdast-util-to-markdown/node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/docusaurus-theme-openapi-docs/node_modules/mdast-util-to-string": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", @@ -9903,6 +9713,16 @@ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "license": "MIT" }, + "node_modules/docusaurus-theme-openapi-docs/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/docusaurus-theme-openapi-docs/node_modules/rehype-raw": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-6.1.1.tgz", @@ -9992,21 +9812,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/docusaurus-theme-openapi-docs/node_modules/unist-util-visit": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", - "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", - "license": "MIT", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/docusaurus-theme-openapi-docs/node_modules/unist-util-visit-parents": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", @@ -10088,18 +9893,6 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/domain-browser": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.23.0.tgz", - "integrity": "sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==", - "license": "Artistic-2.0", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, "node_modules/domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -10109,7 +9902,8 @@ "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "5.0.3", @@ -10127,14 +9921,18 @@ } }, "node_modules/dompurify": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.6.tgz", - "integrity": "sha512-ilkD8YEnnGh1zJ240uJsW7AzE+2qpbOUYjacomn3AvJ6J4JhKGSZ2nh4wUIXPZrEPppaCLx5jFe8T89Rk8tQ7w==" + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.5.tgz", + "integrity": "sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } }, "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", @@ -10149,6 +9947,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -10158,6 +9957,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "license": "MIT", "dependencies": { "is-obj": "^2.0.0" }, @@ -10172,6 +9972,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "license": "MIT", "engines": { "node": ">=8" } @@ -10193,12 +9994,14 @@ "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "license": "MIT" }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" }, "node_modules/ee-first": { "version": "1.1.1", @@ -10207,41 +10010,16 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.75", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.75.tgz", - "integrity": "sha512-Lf3++DumRE/QmweGjU+ZcKqQ+3bKkU/qjaKYhIJKEOhgIO9Xs6IiAQFkfFoj+RhgDk4LUeNsLo6plExHqSyu6Q==", + "version": "1.5.148", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.148.tgz", + "integrity": "sha512-8uc1QXwwqayD4mblcsQYZqoi+cOc97A2XmKSBOIRbEAvbp6vrqmSYs4dHD2qVygUgn7Mi0qdKgPaJ9WC8cv63A==", "license": "ISC" }, - "node_modules/elkjs": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.8.2.tgz", - "integrity": "sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==" - }, - "node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", - "license": "MIT" - }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" }, "node_modules/emojilib": { "version": "2.4.0", @@ -10253,6 +10031,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "license": "MIT", "engines": { "node": ">= 4" } @@ -10277,9 +10056,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz", - "integrity": "sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==", + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -10293,6 +10072,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -10304,6 +10084,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } @@ -10327,14 +10108,15 @@ } }, "node_modules/es-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", - "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "license": "MIT" }, "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -10349,6 +10131,38 @@ "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", "license": "MIT" }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -10362,6 +10176,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -10372,12 +10187,14 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -10389,6 +10206,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -10414,6 +10232,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -10425,6 +10244,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -10433,6 +10253,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -10476,6 +10297,20 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/estree-util-to-js": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", @@ -10492,9 +10327,9 @@ } }, "node_modules/estree-util-value-to-estree": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.1.2.tgz", - "integrity": "sha512-S0gW2+XZkmsx00tU2uJ4L9hUT7IFabbml9pHh2WQqFmAbxit++YGZne0sKJbNwkj9Wvg9E4uqWl4nCIFQMmfag==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.3.3.tgz", + "integrity": "sha512-Db+m1WSD4+mUO7UgMeKkAwdbfNWwIxLt48XF2oFU9emPfXkIu+k5/nlOj313v7wqtAPo0f9REhUvznFrPkG8CQ==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" @@ -10530,6 +10365,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -10538,6 +10374,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==", + "license": "MIT", "engines": { "node": ">=6.0.0" }, @@ -10566,15 +10403,6 @@ "node": ">= 0.8" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -10585,24 +10413,16 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", "engines": { "node": ">=0.8.x" } }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "license": "MIT", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -10730,6 +10550,12 @@ "node": ">= 0.6" } }, + "node_modules/exsolve": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.5.tgz", + "integrity": "sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==", + "license": "MIT" + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -10751,18 +10577,20 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -10771,7 +10599,8 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" }, "node_modules/fast-safe-stringify": { "version": "2.1.1", @@ -10780,9 +10609,10 @@ "license": "MIT" }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -10852,6 +10682,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", "schema-utils": "^3.0.0" @@ -10871,6 +10702,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -10886,6 +10718,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } @@ -10893,12 +10726,14 @@ "node_modules/file-loader/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" }, "node_modules/file-loader/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -10931,14 +10766,16 @@ "version": "8.0.7", "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "license": "BSD-3-Clause", "engines": { "node": ">= 0.4.0" } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -11015,6 +10852,7 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } @@ -11039,15 +10877,6 @@ } } }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "license": "MIT", - "dependencies": { - "is-callable": "^1.1.3" - } - }, "node_modules/foreach": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", @@ -11055,12 +10884,12 @@ "license": "MIT" }, "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "license": "ISC", "dependencies": { - "cross-spawn": "^7.0.0", + "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" }, "engines": { @@ -11086,6 +10915,7 @@ "version": "6.5.3", "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.8.3", "@types/json-schema": "^7.0.5", @@ -11124,6 +10954,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -11139,14 +10970,26 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "license": "MIT", "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.1.0", @@ -11162,6 +11005,7 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -11175,12 +11019,26 @@ "node_modules/fork-ts-checker-webpack-plugin/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.4", "ajv": "^6.12.2", @@ -11198,6 +11056,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -11206,6 +11065,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "license": "MIT", "engines": { "node": ">= 14.17" } @@ -11250,9 +11110,10 @@ } }, "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -11263,19 +11124,36 @@ } }, "node_modules/fs-monkey": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", - "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "license": "Unlicense" }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -11284,6 +11162,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -11298,21 +11177,21 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", - "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "dunder-proto": "^1.0.0", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", - "math-intrinsics": "^1.0.0" + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -11327,10 +11206,24 @@ "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", "license": "ISC" }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -11348,6 +11241,8 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -11367,6 +11262,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -11380,10 +11276,33 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "license": "BSD-2-Clause" }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/global-dirs": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "license": "MIT", "dependencies": { "ini": "2.0.0" }, @@ -11398,6 +11317,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "license": "ISC", "engines": { "node": ">=10" } @@ -11406,6 +11326,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "license": "MIT", "dependencies": { "global-prefix": "^3.0.0" }, @@ -11417,6 +11338,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "license": "MIT", "dependencies": { "ini": "^1.3.5", "kind-of": "^6.0.2", @@ -11430,6 +11352,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -11450,6 +11373,7 @@ "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -11481,6 +11405,7 @@ "version": "12.6.1", "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "license": "MIT", "dependencies": { "@sindresorhus/is": "^5.2.0", "@szmarczak/http-timer": "^5.0.1", @@ -11505,6 +11430,7 @@ "version": "5.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "license": "MIT", "engines": { "node": ">=14.16" }, @@ -11515,7 +11441,8 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" }, "node_modules/graphlib": { "version": "2.1.8", @@ -11567,6 +11494,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "license": "MIT", "dependencies": { "duplexer": "^0.1.2" }, @@ -11577,6 +11505,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT" + }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -11587,6 +11521,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", "engines": { "node": ">=8" } @@ -11615,25 +11550,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-yarn": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -11641,29 +11562,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hash-base": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", - "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -11677,16 +11575,16 @@ } }, "node_modules/hast-util-from-parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", - "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", - "hastscript": "^8.0.0", - "property-information": "^6.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" @@ -11710,9 +11608,9 @@ } }, "node_modules/hast-util-raw": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.4.tgz", - "integrity": "sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -11735,9 +11633,9 @@ } }, "node_modules/hast-util-to-estree": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", - "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -11751,9 +11649,9 @@ "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", - "style-to-object": "^0.4.0", + "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "zwitch": "^2.0.0" }, @@ -11763,9 +11661,9 @@ } }, "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", - "integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -11778,9 +11676,9 @@ "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", - "style-to-object": "^1.0.0", + "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" }, @@ -11789,21 +11687,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/inline-style-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.3.tgz", - "integrity": "sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==", - "license": "MIT" - }, - "node_modules/hast-util-to-jsx-runtime/node_modules/style-to-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.6.tgz", - "integrity": "sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==", - "license": "MIT", - "dependencies": { - "inline-style-parser": "0.2.3" - } - }, "node_modules/hast-util-to-parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", @@ -11823,6 +11706,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-parse5/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/hast-util-whitespace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", @@ -11837,15 +11730,15 @@ } }, "node_modules/hastscript": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", - "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" }, "funding": { @@ -11862,15 +11755,11 @@ "he": "bin/he" } }, - "node_modules/heap": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", - "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==" - }, "node_modules/history": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.1.2", "loose-envify": "^1.2.0", @@ -11880,21 +11769,11 @@ "value-equal": "^1.0.1" } }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", "dependencies": { "react-is": "^16.7.0" } @@ -11948,9 +11827,9 @@ } }, "node_modules/html-entities": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", "funding": [ { "type": "github", @@ -12003,6 +11882,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -12104,7 +11984,8 @@ "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "license": "BSD-2-Clause" }, "node_modules/http-deceiver": { "version": "1.2.7", @@ -12129,9 +12010,9 @@ } }, "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", "license": "MIT" }, "node_modules/http-proxy": { @@ -12149,9 +12030,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", - "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", @@ -12200,6 +12081,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "license": "MIT", "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.2.0" @@ -12208,19 +12090,13 @@ "node": ">=10.19.0" } }, - "node_modules/https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", - "license": "MIT" - }, "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { @@ -12231,17 +12107,18 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" @@ -12280,17 +12157,18 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/image-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz", - "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", + "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", "license": "MIT", "dependencies": { "queue": "6.0.2" @@ -12306,21 +12184,23 @@ "version": "9.0.21", "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" } }, "node_modules/immutable": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", - "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.1.tgz", + "integrity": "sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==", "license": "MIT" }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -12336,6 +12216,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "license": "MIT", "engines": { "node": ">=8" } @@ -12344,6 +12225,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -12352,6 +12234,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", "engines": { "node": ">=8" } @@ -12369,6 +12252,8 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -12377,12 +12262,14 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" }, "node_modules/inline-style-parser": { "version": "0.1.1", @@ -12394,6 +12281,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", "engines": { "node": ">=12" } @@ -12402,6 +12290,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -12410,6 +12299,7 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", "dependencies": { "loose-envify": "^1.0.0" } @@ -12447,31 +12337,17 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -12502,22 +12378,11 @@ "node": ">=4" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-ci": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "license": "MIT", "dependencies": { "ci-info": "^3.2.0" }, @@ -12526,11 +12391,15 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12550,6 +12419,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -12573,6 +12443,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -12581,29 +12452,16 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -12625,6 +12483,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "license": "MIT", "dependencies": { "global-dirs": "^3.0.0", "is-path-inside": "^3.0.2" @@ -12636,26 +12495,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-nan": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", - "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-npm": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -12667,6 +12511,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -12684,6 +12529,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "license": "MIT", "engines": { "node": ">=6" } @@ -12692,6 +12538,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "license": "MIT", "engines": { "node": ">=8" } @@ -12708,13 +12555,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-reference": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", - "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "license": "MIT", "dependencies": { - "@types/estree": "*" + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/is-regexp": { @@ -12730,6 +12580,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "license": "MIT", "engines": { "node": ">=6" } @@ -12738,6 +12589,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -12745,30 +12597,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", "dependencies": { "is-docker": "^2.0.0" }, @@ -12780,6 +12619,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "license": "MIT", "engines": { "node": ">=12" } @@ -12787,17 +12627,20 @@ "node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -12865,17 +12708,18 @@ } }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", "bin": { "jiti": "bin/jiti.js" } }, "node_modules/joi": { - "version": "17.13.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.1.tgz", - "integrity": "sha512-vaBlIKCyo4FCUtCm7Eu4QZd/q02bWcxfUO6YSXAZOWF6gzcLBeba8kwotUdYJjDLW8Cz8RywsSOqiNJZW0mNvg==", + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", "license": "BSD-3-Clause", "dependencies": { "@hapi/hoek": "^9.3.0", @@ -12897,12 +12741,14 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -12925,7 +12771,8 @@ "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" }, "node_modules/json-crawl": { "version": "0.5.3", @@ -12939,7 +12786,8 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" }, "node_modules/json-pointer": { "version": "0.6.2", @@ -12976,12 +12824,14 @@ "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -12993,6 +12843,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -13000,10 +12851,36 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/katex": { + "version": "0.16.22", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz", + "integrity": "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -13017,6 +12894,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -13025,24 +12903,38 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "license": "MIT" + }, + "node_modules/langium": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz", + "integrity": "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==", "license": "MIT", - "peer": true, + "dependencies": { + "chevrotain": "~11.0.3", + "chevrotain-allstar": "~0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.0.8" + }, "engines": { - "node": ">= 8" + "node": ">=16.0.0" } }, "node_modules/latest-version": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "license": "MIT", "dependencies": { "package-json": "^8.1.0" }, @@ -13054,9 +12946,9 @@ } }, "node_modules/launch-editor": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", - "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz", + "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==", "license": "MIT", "dependencies": { "picocolors": "^1.0.0", @@ -13066,12 +12958,14 @@ "node_modules/layout-base": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", - "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==" + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", "engines": { "node": ">=6" } @@ -13091,7 +12985,8 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" }, "node_modules/liquid-json": { "version": "0.3.1", @@ -13106,6 +13001,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "license": "MIT", "engines": { "node": ">=6.11.5" } @@ -13114,6 +13010,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -13123,6 +13020,23 @@ "node": ">=8.9.0" } }, + "node_modules/local-pkg": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.1.tgz", + "integrity": "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.0.1", + "quansync": "^0.2.8" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/locate-path": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", @@ -13141,12 +13055,14 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" }, "node_modules/lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", @@ -13154,12 +13070,6 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "license": "MIT" }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "license": "MIT" - }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -13186,6 +13096,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -13197,6 +13108,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -13205,6 +13117,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -13234,15 +13147,27 @@ } }, "node_modules/markdown-table": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", - "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/marked": { + "version": "15.0.11", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.11.tgz", + "integrity": "sha512-1BEXAU2euRCG3xwgLVT1y0xbJEld1XOrmRJpUwRCcy7rxhSCwMrmEu9LXoPhHSCJG41V7YcQ2mjKRr5BA3ITIA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -13252,17 +13177,6 @@ "node": ">= 0.4" } }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "node_modules/mdast-util-definitions": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", @@ -13336,13 +13250,14 @@ } }, "node_modules/mdast-util-directive": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz", - "integrity": "sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz", + "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", + "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", @@ -13356,9 +13271,9 @@ } }, "node_modules/mdast-util-find-and-replace": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", - "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -13384,9 +13299,9 @@ } }, "node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -13408,9 +13323,9 @@ } }, "node_modules/mdast-util-from-markdown/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -13454,9 +13369,9 @@ } }, "node_modules/mdast-util-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", - "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", "license": "MIT", "dependencies": { "mdast-util-from-markdown": "^2.0.0", @@ -13490,9 +13405,9 @@ } }, "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -13510,9 +13425,9 @@ } }, "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -13526,9 +13441,9 @@ "license": "MIT" }, "node_modules/mdast-util-gfm-footnote": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", - "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -13608,9 +13523,9 @@ } }, "node_modules/mdast-util-mdx-expression": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", - "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -13626,9 +13541,9 @@ } }, "node_modules/mdast-util-mdx-jsx": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.2.tgz", - "integrity": "sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -13641,7 +13556,6 @@ "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", - "unist-util-remove-position": "^5.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" }, @@ -13683,9 +13597,9 @@ } }, "node_modules/mdast-util-to-hast": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz", - "integrity": "sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -13704,9 +13618,9 @@ } }, "node_modules/mdast-util-to-markdown": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", - "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -13714,6 +13628,7 @@ "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" @@ -13755,6 +13670,7 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "license": "Unlicense", "dependencies": { "fs-monkey": "^1.0.4" }, @@ -13774,481 +13690,44 @@ "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/mermaid": { - "version": "10.6.1", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.6.1.tgz", - "integrity": "sha512-Hky0/RpOw/1il9X8AvzOEChfJtVvmXm+y7JML5C//ePYMy0/9jCEmW1E1g86x9oDfW9+iVEdTV/i+M6KWRNs4A==", + "version": "11.6.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.6.0.tgz", + "integrity": "sha512-PE8hGUy1LDlWIHWBP05SFdqUHGmRcCcK4IzpOKPE35eOw+G9zZgcnMpyunJVUEOgb//KBORPjysKndw8bFLuRg==", + "license": "MIT", "dependencies": { - "@braintree/sanitize-url": "^6.0.1", - "@types/d3-scale": "^4.0.3", - "@types/d3-scale-chromatic": "^3.0.0", - "cytoscape": "^3.23.0", + "@braintree/sanitize-url": "^7.0.4", + "@iconify/utils": "^2.1.33", + "@mermaid-js/parser": "^0.4.0", + "@types/d3": "^7.4.3", + "cytoscape": "^3.29.3", "cytoscape-cose-bilkent": "^4.1.0", - "cytoscape-fcose": "^2.1.0", - "d3": "^7.4.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", "d3-sankey": "^0.12.3", - "dagre-d3-es": "7.0.10", - "dayjs": "^1.11.7", - "dompurify": "^3.0.5", - "elkjs": "^0.8.2", - "khroma": "^2.0.0", + "dagre-d3-es": "7.0.11", + "dayjs": "^1.11.13", + "dompurify": "^3.2.4", + "katex": "^0.16.9", + "khroma": "^2.1.0", "lodash-es": "^4.17.21", - "mdast-util-from-markdown": "^1.3.0", - "non-layered-tidy-tree-layout": "^2.0.2", - "stylis": "^4.1.3", + "marked": "^15.0.7", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", "ts-dedent": "^2.2.0", - "uuid": "^9.0.0", - "web-worker": "^1.2.0" - } - }, - "node_modules/mermaid/node_modules/@types/mdast": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", - "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", - "dependencies": { - "@types/unist": "^2" - } - }, - "node_modules/mermaid/node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" - }, - "node_modules/mermaid/node_modules/mdast-util-from-markdown": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", - "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", - "dependencies": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "mdast-util-to-string": "^3.1.0", - "micromark": "^3.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-decode-string": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "unist-util-stringify-position": "^3.0.0", - "uvu": "^0.5.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mermaid/node_modules/mdast-util-to-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", - "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", - "dependencies": { - "@types/mdast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mermaid/node_modules/micromark": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", - "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "micromark-core-commonmark": "^1.0.1", - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-sanitize-uri": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "node_modules/mermaid/node_modules/micromark-core-commonmark": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", - "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-factory-destination": "^1.0.0", - "micromark-factory-label": "^1.0.0", - "micromark-factory-space": "^1.0.0", - "micromark-factory-title": "^1.0.0", - "micromark-factory-whitespace": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-html-tag-name": "^1.0.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-subtokenize": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.1", - "uvu": "^0.5.0" - } - }, - "node_modules/mermaid/node_modules/micromark-factory-destination": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", - "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/mermaid/node_modules/micromark-factory-label": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", - "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "node_modules/mermaid/node_modules/micromark-factory-title": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", - "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/mermaid/node_modules/micromark-factory-whitespace": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", - "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/mermaid/node_modules/micromark-util-chunked": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", - "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/mermaid/node_modules/micromark-util-classify-character": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", - "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/mermaid/node_modules/micromark-util-combine-extensions": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", - "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/mermaid/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", - "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/mermaid/node_modules/micromark-util-decode-string": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", - "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/mermaid/node_modules/micromark-util-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", - "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mermaid/node_modules/micromark-util-html-tag-name": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", - "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mermaid/node_modules/micromark-util-normalize-identifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", - "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/mermaid/node_modules/micromark-util-resolve-all": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", - "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^1.0.0" - } - }, - "node_modules/mermaid/node_modules/micromark-util-sanitize-uri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", - "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^1.0.0", - "micromark-util-encode": "^1.0.0", - "micromark-util-symbol": "^1.0.0" - } - }, - "node_modules/mermaid/node_modules/micromark-util-subtokenize": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", - "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^1.0.0", - "micromark-util-symbol": "^1.0.0", - "micromark-util-types": "^1.0.0", - "uvu": "^0.5.0" - } - }, - "node_modules/mermaid/node_modules/micromark-util-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", - "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mermaid/node_modules/unist-util-stringify-position": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", - "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mermaid/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" + "uuid": "^11.1.0" } }, "node_modules/methods": { @@ -14261,9 +13740,9 @@ } }, "node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", "funding": [ { "type": "GitHub Sponsors", @@ -14296,9 +13775,9 @@ } }, "node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", "funding": [ { "type": "GitHub Sponsors", @@ -14330,9 +13809,9 @@ } }, "node_modules/micromark-core-commonmark/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -14350,9 +13829,9 @@ } }, "node_modules/micromark-core-commonmark/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14370,9 +13849,9 @@ } }, "node_modules/micromark-core-commonmark/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14386,9 +13865,9 @@ "license": "MIT" }, "node_modules/micromark-extension-directive": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.1.tgz", - "integrity": "sha512-VGV2uxUzhEZmaP7NSFo2vtq7M2nUD+WfmYQD+d8i/1nHbzE+rMy9uzTvUybBbNiVbrhOZibg3gbyoARGqgDWyg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -14405,9 +13884,9 @@ } }, "node_modules/micromark-extension-directive/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -14425,9 +13904,9 @@ } }, "node_modules/micromark-extension-directive/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14445,9 +13924,9 @@ } }, "node_modules/micromark-extension-directive/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14477,9 +13956,9 @@ } }, "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14497,9 +13976,9 @@ } }, "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14549,9 +14028,9 @@ } }, "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14569,9 +14048,9 @@ } }, "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14605,9 +14084,9 @@ } }, "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -14625,9 +14104,9 @@ } }, "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14645,9 +14124,9 @@ } }, "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14679,9 +14158,9 @@ } }, "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14695,9 +14174,9 @@ "license": "MIT" }, "node_modules/micromark-extension-gfm-table": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", - "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -14712,9 +14191,9 @@ } }, "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -14732,9 +14211,9 @@ } }, "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14752,9 +14231,9 @@ } }, "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14798,9 +14277,9 @@ } }, "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -14818,9 +14297,9 @@ } }, "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14838,9 +14317,9 @@ } }, "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14854,9 +14333,9 @@ "license": "MIT" }, "node_modules/micromark-extension-mdx-expression": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", - "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14880,9 +14359,9 @@ } }, "node_modules/micromark-extension-mdx-expression/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -14900,9 +14379,9 @@ } }, "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14920,9 +14399,9 @@ } }, "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14936,18 +14415,18 @@ "license": "MIT" }, "node_modules/micromark-extension-mdx-jsx": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.0.tgz", - "integrity": "sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", "license": "MIT", "dependencies": { - "@types/acorn": "^4.0.0", "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" @@ -14958,9 +14437,9 @@ } }, "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -14978,9 +14457,9 @@ } }, "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -14998,9 +14477,9 @@ } }, "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15068,9 +14547,9 @@ } }, "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15088,9 +14567,9 @@ } }, "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15104,9 +14583,9 @@ "license": "MIT" }, "node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", "funding": [ { "type": "GitHub Sponsors", @@ -15125,9 +14604,9 @@ } }, "node_modules/micromark-factory-destination/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15145,9 +14624,9 @@ } }, "node_modules/micromark-factory-destination/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15161,9 +14640,9 @@ "license": "MIT" }, "node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", "funding": [ { "type": "GitHub Sponsors", @@ -15183,9 +14662,9 @@ } }, "node_modules/micromark-factory-label/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15203,9 +14682,9 @@ } }, "node_modules/micromark-factory-label/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15219,9 +14698,9 @@ "license": "MIT" }, "node_modules/micromark-factory-mdx-expression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.1.tgz", - "integrity": "sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", "funding": [ { "type": "GitHub Sponsors", @@ -15236,6 +14715,7 @@ "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -15244,10 +14724,30 @@ "vfile-message": "^4.0.0" } }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15265,9 +14765,9 @@ } }, "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15294,6 +14794,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^1.0.0", "micromark-util-types": "^1.0.0" @@ -15312,12 +14813,13 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", "funding": [ { "type": "GitHub Sponsors", @@ -15337,9 +14839,9 @@ } }, "node_modules/micromark-factory-title/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -15357,9 +14859,9 @@ } }, "node_modules/micromark-factory-title/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15377,9 +14879,9 @@ } }, "node_modules/micromark-factory-title/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15393,9 +14895,9 @@ "license": "MIT" }, "node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", "funding": [ { "type": "GitHub Sponsors", @@ -15415,9 +14917,9 @@ } }, "node_modules/micromark-factory-whitespace/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -15435,9 +14937,9 @@ } }, "node_modules/micromark-factory-whitespace/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15455,9 +14957,9 @@ } }, "node_modules/micromark-factory-whitespace/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15484,6 +14986,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^1.0.0", "micromark-util-types": "^1.0.0" @@ -15502,12 +15005,13 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", "funding": [ { "type": "GitHub Sponsors", @@ -15524,9 +15028,9 @@ } }, "node_modules/micromark-util-chunked/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15540,9 +15044,9 @@ "license": "MIT" }, "node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15561,9 +15065,9 @@ } }, "node_modules/micromark-util-classify-character/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15581,9 +15085,9 @@ } }, "node_modules/micromark-util-classify-character/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15597,9 +15101,9 @@ "license": "MIT" }, "node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", "funding": [ { "type": "GitHub Sponsors", @@ -15617,9 +15121,9 @@ } }, "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", "funding": [ { "type": "GitHub Sponsors", @@ -15636,9 +15140,9 @@ } }, "node_modules/micromark-util-decode-numeric-character-reference/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15652,9 +15156,9 @@ "license": "MIT" }, "node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", "funding": [ { "type": "GitHub Sponsors", @@ -15674,9 +15178,9 @@ } }, "node_modules/micromark-util-decode-string/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15694,9 +15198,9 @@ } }, "node_modules/micromark-util-decode-string/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15710,9 +15214,9 @@ "license": "MIT" }, "node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", "funding": [ { "type": "GitHub Sponsors", @@ -15726,9 +15230,9 @@ "license": "MIT" }, "node_modules/micromark-util-events-to-acorn": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", - "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", "funding": [ { "type": "GitHub Sponsors", @@ -15741,7 +15245,6 @@ ], "license": "MIT", "dependencies": { - "@types/acorn": "^4.0.0", "@types/estree": "^1.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", @@ -15752,9 +15255,9 @@ } }, "node_modules/micromark-util-events-to-acorn/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15768,9 +15271,9 @@ "license": "MIT" }, "node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", "funding": [ { "type": "GitHub Sponsors", @@ -15784,9 +15287,9 @@ "license": "MIT" }, "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15803,9 +15306,9 @@ } }, "node_modules/micromark-util-normalize-identifier/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15819,9 +15322,9 @@ "license": "MIT" }, "node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", "funding": [ { "type": "GitHub Sponsors", @@ -15838,9 +15341,9 @@ } }, "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", "funding": [ { "type": "GitHub Sponsors", @@ -15859,9 +15362,9 @@ } }, "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15879,9 +15382,9 @@ } }, "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15895,9 +15398,9 @@ "license": "MIT" }, "node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", "funding": [ { "type": "GitHub Sponsors", @@ -15917,9 +15420,9 @@ } }, "node_modules/micromark-util-subtokenize/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -15945,12 +15448,13 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", "funding": [ { "type": "GitHub Sponsors", @@ -15964,9 +15468,9 @@ "license": "MIT" }, "node_modules/micromark/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -15984,9 +15488,9 @@ } }, "node_modules/micromark/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -16004,9 +15508,9 @@ } }, "node_modules/micromark/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -16020,36 +15524,18 @@ "license": "MIT" }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", - "license": "MIT" - }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -16063,9 +15549,9 @@ } }, "node_modules/mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -16081,12 +15567,12 @@ } }, "node_modules/mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { - "mime-db": "~1.33.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -16096,6 +15582,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", "engines": { "node": ">=6" } @@ -16104,6 +15591,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -16137,27 +15625,23 @@ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "license": "ISC" }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "license": "MIT" - }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=10" } }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -16171,27 +15655,58 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mlly": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", + "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", + "ufo": "^1.5.4" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/mrmime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", - "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -16227,9 +15742,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", @@ -16256,7 +15771,8 @@ "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" }, "node_modules/neotraverse": { "version": "0.6.15", @@ -16271,6 +15787,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -16284,9 +15801,9 @@ "optional": true }, "node_modules/node-emoji": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.3.tgz", - "integrity": "sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", "license": "MIT", "dependencies": { "@sindresorhus/is": "^4.6.0", @@ -16339,56 +15856,6 @@ "node": ">= 6.13.0" } }, - "node_modules/node-polyfill-webpack-plugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-3.0.0.tgz", - "integrity": "sha512-QpG496dDBiaelQZu9wDcVvpLbtk7h9Ctz693RaUMZBgl8DUoFToO90ZTLKq57gP7rwKqYtGbMBXkcEgLSag2jQ==", - "license": "MIT", - "dependencies": { - "assert": "^2.1.0", - "browserify-zlib": "^0.2.0", - "buffer": "^6.0.3", - "console-browserify": "^1.2.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.12.0", - "domain-browser": "^4.22.0", - "events": "^3.3.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "^1.0.1", - "process": "^0.11.10", - "punycode": "^2.3.0", - "querystring-es3": "^0.2.1", - "readable-stream": "^4.4.2", - "stream-browserify": "^3.0.0", - "stream-http": "^3.2.0", - "string_decoder": "^1.3.0", - "timers-browserify": "^2.0.12", - "tty-browserify": "^0.0.1", - "type-fest": "^4.4.0", - "url": "^0.11.3", - "util": "^0.12.5", - "vm-browserify": "^1.1.2" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "webpack": ">=5" - } - }, - "node_modules/node-polyfill-webpack-plugin/node_modules/type-fest": { - "version": "4.30.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.30.2.tgz", - "integrity": "sha512-UJShLPYi1aWqCdq9HycOL/gwsuqda1OISdBO3t8RlXQC4QvtuIz4b5FCfe2dQIWEpmlRExKmcTBfP1r9bhY7ig==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/node-readfiles": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", @@ -16404,15 +15871,11 @@ "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "license": "MIT" }, - "node_modules/non-layered-tidy-tree-layout": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", - "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==" - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -16426,10 +15889,23 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -16447,6 +15923,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -16617,6 +16094,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -16631,9 +16109,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", - "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -16642,22 +16120,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -16718,6 +16180,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -16726,6 +16189,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -16740,6 +16204,7 @@ "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -16753,9 +16218,9 @@ } }, "node_modules/openapi-to-postmanv2": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/openapi-to-postmanv2/-/openapi-to-postmanv2-4.24.0.tgz", - "integrity": "sha512-SfWo8fftwTVmBs61ZY9SciNlQ7ddSBmPS7NTBdf+LyjHdzr2/TNuvFjyftGJ7Jnm48oghi+R9At2geq1NoBOLA==", + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/openapi-to-postmanv2/-/openapi-to-postmanv2-4.25.0.tgz", + "integrity": "sha512-sIymbkQby0gzxt2Yez8YKB6hoISEel05XwGwNrAhr6+vxJWXNxkmssQc/8UEtVkuJ9ZfUXLkip9PYACIpfPDWg==", "license": "Apache-2.0", "dependencies": { "ajv": "8.11.0", @@ -16783,22 +16248,6 @@ "node": ">=8" } }, - "node_modules/openapi-to-postmanv2/node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/openapi-to-postmanv2/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -16814,16 +16263,11 @@ "opener": "bin/opener-bin.js" } }, - "node_modules/os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", - "license": "MIT" - }, "node_modules/p-cancelable": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "license": "MIT", "engines": { "node": ">=12.20" } @@ -16862,6 +16306,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -16889,6 +16334,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", "engines": { "node": ">=6" } @@ -16897,6 +16343,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "license": "MIT", "dependencies": { "got": "^12.1.0", "registry-auth-token": "^5.0.1", @@ -16916,10 +16363,19 @@ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "license": "BlueOak-1.0.0" }, + "node_modules/package-manager-detector": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz", + "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==", + "license": "MIT", + "dependencies": { + "quansync": "^0.2.7" + } + }, "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", "license": "(MIT AND Zlib)" }, "node_modules/param-case": { @@ -16936,6 +16392,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -16943,31 +16400,13 @@ "node": ">=6" } }, - "node_modules/parse-asn1": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", - "license": "ISC", - "dependencies": { - "asn1.js": "^4.10.1", - "browserify-aes": "^1.2.0", - "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/parse-entities": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz", - "integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", - "character-entities": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", @@ -16981,15 +16420,16 @@ } }, "node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -17010,12 +16450,12 @@ "license": "ISC" }, "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "license": "MIT", "dependencies": { - "entities": "^4.4.0" + "entities": "^6.0.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -17034,6 +16474,18 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz", + "integrity": "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -17069,6 +16521,12 @@ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "license": "MIT" }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", @@ -17082,6 +16540,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -17096,6 +16555,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", "engines": { "node": ">=8" } @@ -17103,7 +16563,8 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", @@ -17128,9 +16589,10 @@ "license": "ISC" }, "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "license": "MIT", "dependencies": { "isarray": "0.0.1" } @@ -17139,51 +16601,16 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/path/node_modules/inherits": { + "node_modules/pathe": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "license": "ISC" - }, - "node_modules/path/node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "license": "MIT", - "dependencies": { - "inherits": "2.0.3" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "license": "MIT", - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/periscopic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", - "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^3.0.0", - "is-reference": "^3.0.0" - } + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", @@ -17195,6 +16622,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -17203,9 +16631,9 @@ } }, "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "license": "MIT", "engines": { "node": ">= 6" @@ -17226,10 +16654,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pkg-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz", + "integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.1", + "exsolve": "^1.0.1", + "pathe": "^2.0.3" + } + }, "node_modules/pkg-up": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "license": "MIT", "dependencies": { "find-up": "^3.0.0" }, @@ -17241,6 +16681,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", "dependencies": { "locate-path": "^3.0.0" }, @@ -17252,6 +16693,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -17264,6 +16706,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -17278,6 +16721,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", "dependencies": { "p-limit": "^2.0.0" }, @@ -17289,6 +16733,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", "engines": { "node": ">=4" } @@ -17302,19 +16747,26 @@ "node": ">=4" } }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "funding": [ { "type": "opencollective", @@ -17331,7 +16783,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -17365,9 +16817,9 @@ } }, "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -17409,9 +16861,9 @@ } }, "node_modules/postcss-color-functional-notation": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.6.tgz", - "integrity": "sha512-wLXvm8RmLs14Z2nVpB4CWlnvaWPRcOZFltJSlcbYwSJ1EDZKsKDhPKIMecCnuU054KSmlmubkqczmm6qBPCBhA==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.9.tgz", + "integrity": "sha512-WScwD3pSsIz+QP97sPkGCeJm7xUH0J18k6zV5o8O2a4cQJyv15vLUx/WFQajuJVgZhmJL5awDu8zHnqzAzm4lw==", "funding": [ { "type": "github", @@ -17424,10 +16876,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -17609,9 +17061,9 @@ } }, "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -17647,9 +17099,9 @@ } }, "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -17723,9 +17175,9 @@ } }, "node_modules/postcss-double-position-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.0.tgz", - "integrity": "sha512-JkIGah3RVbdSEIrcobqj4Gzq0h53GG4uqDPsho88SgY84WnpkTpI0k50MFK/sX7XqVisZ6OqUfFnoUO6m1WWdg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.1.tgz", + "integrity": "sha512-ZitCwmvOR4JzXmKw6sZblTgwV1dcfLvClcyjADuqZ5hU0Uk4SVNpvSN9w8NcJ7XuxhRYxVA8m8AB3gy+HNBQOA==", "funding": [ { "type": "github", @@ -17738,7 +17190,7 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0", "postcss-value-parser": "^4.2.0" }, @@ -17775,9 +17227,9 @@ } }, "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -17813,9 +17265,9 @@ } }, "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -17883,9 +17335,9 @@ } }, "node_modules/postcss-lab-function": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.6.tgz", - "integrity": "sha512-HPwvsoK7C949vBZ+eMyvH2cQeMr3UREoHvbtra76/UhDuiViZH6pir+z71UaJQohd7VDSVUdR6TkWYKExEc9aQ==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.9.tgz", + "integrity": "sha512-IGbsIXbqMDusymJAKYX+f9oakPo89wL9Pzd/qRBQOVf3EIQWT9hgvqC4Me6Dkzxp3KPuIBf6LPkjrLHe/6ZMIQ==", "funding": [ { "type": "github", @@ -17898,10 +17350,10 @@ ], "license": "MIT-0", "dependencies": { - "@csstools/css-color-parser": "^3.0.6", + "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", "@csstools/utilities": "^2.0.0" }, "engines": { @@ -17934,9 +17386,9 @@ } }, "node_modules/postcss-logical": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.0.0.tgz", - "integrity": "sha512-HpIdsdieClTjXLOyYdUPAX/XQASNIwdKt5hoZW08ZOAiI+tbV0ta1oclkpVkW5ANU+xJvk3KkA0FejkjGLXUkg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.1.0.tgz", + "integrity": "sha512-pL1hXFQ2fEXNKiNiAgtfA005T9FBxky5zkX6s4GZM2D8RkVgRqz3f4g1JUoq925zXv495qk8UNldDwh8uGEDoA==", "funding": [ { "type": "github", @@ -18102,9 +17554,9 @@ } }, "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -18130,9 +17582,9 @@ } }, "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -18229,9 +17681,9 @@ } }, "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -18472,9 +17924,9 @@ } }, "node_modules/postcss-preset-env": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.1.2.tgz", - "integrity": "sha512-OqUBZ9ByVfngWhMNuBEMy52Izj07oIFA6K/EOGBlaSv+P12MiE1+S2cqXtS1VuW82demQ/Tzc7typYk3uHunkA==", + "version": "10.1.6", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.1.6.tgz", + "integrity": "sha512-1jRD7vttKLJ7o0mcmmYWKRLm7W14rI8K1I7Y41OeXUPEVc/CAzfTssNUeJ0zKbR+zMk4boqct/gwS/poIFF5Lg==", "funding": [ { "type": "github", @@ -18488,60 +17940,60 @@ "license": "MIT-0", "dependencies": { "@csstools/postcss-cascade-layers": "^5.0.1", - "@csstools/postcss-color-function": "^4.0.6", - "@csstools/postcss-color-mix-function": "^3.0.6", - "@csstools/postcss-content-alt-text": "^2.0.4", - "@csstools/postcss-exponential-functions": "^2.0.5", + "@csstools/postcss-color-function": "^4.0.9", + "@csstools/postcss-color-mix-function": "^3.0.9", + "@csstools/postcss-content-alt-text": "^2.0.5", + "@csstools/postcss-exponential-functions": "^2.0.8", "@csstools/postcss-font-format-keywords": "^4.0.0", - "@csstools/postcss-gamut-mapping": "^2.0.6", - "@csstools/postcss-gradients-interpolation-method": "^5.0.6", - "@csstools/postcss-hwb-function": "^4.0.6", - "@csstools/postcss-ic-unit": "^4.0.0", - "@csstools/postcss-initial": "^2.0.0", + "@csstools/postcss-gamut-mapping": "^2.0.9", + "@csstools/postcss-gradients-interpolation-method": "^5.0.9", + "@csstools/postcss-hwb-function": "^4.0.9", + "@csstools/postcss-ic-unit": "^4.0.1", + "@csstools/postcss-initial": "^2.0.1", "@csstools/postcss-is-pseudo-class": "^5.0.1", - "@csstools/postcss-light-dark-function": "^2.0.7", + "@csstools/postcss-light-dark-function": "^2.0.8", "@csstools/postcss-logical-float-and-clear": "^3.0.0", "@csstools/postcss-logical-overflow": "^2.0.0", "@csstools/postcss-logical-overscroll-behavior": "^2.0.0", "@csstools/postcss-logical-resize": "^3.0.0", "@csstools/postcss-logical-viewport-units": "^3.0.3", - "@csstools/postcss-media-minmax": "^2.0.5", + "@csstools/postcss-media-minmax": "^2.0.8", "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.4", "@csstools/postcss-nested-calc": "^4.0.0", "@csstools/postcss-normalize-display-values": "^4.0.0", - "@csstools/postcss-oklab-function": "^4.0.6", - "@csstools/postcss-progressive-custom-properties": "^4.0.0", - "@csstools/postcss-random-function": "^1.0.1", - "@csstools/postcss-relative-color-syntax": "^3.0.6", + "@csstools/postcss-oklab-function": "^4.0.9", + "@csstools/postcss-progressive-custom-properties": "^4.0.1", + "@csstools/postcss-random-function": "^2.0.0", + "@csstools/postcss-relative-color-syntax": "^3.0.9", "@csstools/postcss-scope-pseudo-class": "^4.0.1", - "@csstools/postcss-sign-functions": "^1.1.0", - "@csstools/postcss-stepped-value-functions": "^4.0.5", - "@csstools/postcss-text-decoration-shorthand": "^4.0.1", - "@csstools/postcss-trigonometric-functions": "^4.0.5", + "@csstools/postcss-sign-functions": "^1.1.3", + "@csstools/postcss-stepped-value-functions": "^4.0.8", + "@csstools/postcss-text-decoration-shorthand": "^4.0.2", + "@csstools/postcss-trigonometric-functions": "^4.0.8", "@csstools/postcss-unset-value": "^4.0.0", - "autoprefixer": "^10.4.19", - "browserslist": "^4.23.1", + "autoprefixer": "^10.4.21", + "browserslist": "^4.24.4", "css-blank-pseudo": "^7.0.1", "css-has-pseudo": "^7.0.2", "css-prefers-color-scheme": "^10.0.0", - "cssdb": "^8.2.3", + "cssdb": "^8.2.5", "postcss-attribute-case-insensitive": "^7.0.1", "postcss-clamp": "^4.1.0", - "postcss-color-functional-notation": "^7.0.6", + "postcss-color-functional-notation": "^7.0.9", "postcss-color-hex-alpha": "^10.0.0", "postcss-color-rebeccapurple": "^10.0.0", "postcss-custom-media": "^11.0.5", "postcss-custom-properties": "^14.0.4", "postcss-custom-selectors": "^8.0.4", "postcss-dir-pseudo-class": "^9.0.1", - "postcss-double-position-gradients": "^6.0.0", + "postcss-double-position-gradients": "^6.0.1", "postcss-focus-visible": "^10.0.1", "postcss-focus-within": "^9.0.1", "postcss-font-variant": "^5.0.0", "postcss-gap-properties": "^6.0.0", "postcss-image-set-function": "^7.0.0", - "postcss-lab-function": "^7.0.6", - "postcss-logical": "^8.0.0", + "postcss-lab-function": "^7.0.9", + "postcss-logical": "^8.1.0", "postcss-nesting": "^13.0.1", "postcss-opacity-percentage": "^3.0.0", "postcss-overflow-shorthand": "^6.0.0", @@ -18584,9 +18036,9 @@ } }, "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -18677,9 +18129,9 @@ } }, "node_modules/postcss-selector-not/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -18767,9 +18219,9 @@ } }, "node_modules/postman-code-generators": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/postman-code-generators/-/postman-code-generators-1.13.0.tgz", - "integrity": "sha512-rbKtX+PWp+4McQpAncnRCUKqDiynt4fDB1I7AzrsvBAQc74ab6k6K3IP8qvf0icqiPuf9nYHCSdy/LB922dQLQ==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/postman-code-generators/-/postman-code-generators-1.14.2.tgz", + "integrity": "sha512-qZAyyowfQAFE4MSCu2KtMGGQE/+oG1JhMZMJNMdZHYCSfQiVVeKxgk3oI4+KJ3d1y5rrm2D6C6x+Z+7iyqm+fA==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -18812,37 +18264,25 @@ "node": ">=10" } }, - "node_modules/postman-collection/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "node_modules/postman-collection/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/postman-collection/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/postman-collection/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/postman-collection/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" + "bin": { + "uuid": "dist/bin/uuid" } }, "node_modules/postman-url-encoder": { @@ -18890,9 +18330,9 @@ } }, "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", "license": "MIT", "engines": { "node": ">=6" @@ -18917,6 +18357,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -18929,6 +18370,7 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -18936,9 +18378,9 @@ } }, "node_modules/property-information": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", - "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.0.0.tgz", + "integrity": "sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==", "license": "MIT", "funding": { "type": "github", @@ -18948,7 +18390,8 @@ "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "license": "ISC" }, "node_modules/proxy-addr": { "version": "2.0.7", @@ -18972,26 +18415,6 @@ "node": ">= 0.10" } }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", - "license": "MIT" - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -19005,6 +18428,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "license": "MIT", "dependencies": { "escape-goat": "^4.0.0" }, @@ -19016,12 +18440,12 @@ } }, "node_modules/qs": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.1.tgz", - "integrity": "sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -19030,13 +18454,21 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", - "engines": { - "node": ">=0.4.x" - } + "node_modules/quansync": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz", + "integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" }, "node_modules/queue": { "version": "6.0.2", @@ -19064,12 +18496,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -19081,17 +18515,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "license": "MIT", "dependencies": { - "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" } }, @@ -19128,10 +18553,23 @@ "node": ">= 0.8" } }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/raw-loader": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", + "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", "schema-utils": "^3.0.0" @@ -19151,6 +18589,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -19166,6 +18605,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } @@ -19173,12 +18613,14 @@ "node_modules/raw-loader/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" }, "node_modules/raw-loader/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -19196,6 +18638,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -19210,6 +18653,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -19230,6 +18674,7 @@ "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.16.0", "address": "^1.1.2", @@ -19264,6 +18709,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -19276,9 +18722,10 @@ } }, "node_modules/react-dev-utils/node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "license": "MIT", "engines": { "node": ">= 12.13.0" } @@ -19287,6 +18734,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -19301,6 +18749,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -19315,6 +18764,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -19329,6 +18779,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", "engines": { "node": ">=8" } @@ -19337,6 +18788,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -19358,19 +18810,23 @@ } }, "node_modules/react-error-overlay": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", - "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.1.0.tgz", + "integrity": "sha512-SN/U6Ytxf1QGkw/9ve5Y+NxBbZM6Ht95tuXNMKs8EJyFa/Vy/+Co3stop3KBHARfn/giv+Lj1uUnTfOJ3moFEQ==", + "license": "MIT" }, "node_modules/react-fast-compare": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", - "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" }, "node_modules/react-helmet-async": { + "name": "@slorber/react-helmet-async", "version": "1.3.0", - "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", - "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", + "resolved": "https://registry.npmjs.org/@slorber/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-e9/OK8VhwUSc67diWI8Rb3I0YgI9/SBQtnhe9aEuK6MhZm7ntZZimXgwXnd8W96YTmSOb9M4d8LwhRZyhWr/1A==", + "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.12.5", "invariant": "^2.2.4", @@ -19379,14 +18835,14 @@ "shallowequal": "^1.1.0" }, "peerDependencies": { - "react": "^16.6.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0" + "react": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/react-hook-form": { - "version": "7.53.0", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.0.tgz", - "integrity": "sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==", + "version": "7.56.1", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.56.1.tgz", + "integrity": "sha512-qWAVokhSpshhcEuQDSANHx3jiAEFzu2HAaaQIzi/r9FNPm1ioAvuJSD4EuZzWd7Al7nTRKcKPnBKO7sRn+zavQ==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -19402,7 +18858,8 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" }, "node_modules/react-json-view-lite": { "version": "1.5.0", @@ -19423,13 +18880,13 @@ "license": "MIT" }, "node_modules/react-live": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/react-live/-/react-live-4.1.7.tgz", - "integrity": "sha512-NTzl0POOAW3dkp7+QL30duOrIu2Vzf2LHdx4TaQ0BqOAtQcSTKEXujfm9jR2VoCHko0oi35PYp38yKQBXz4mrg==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/react-live/-/react-live-4.1.8.tgz", + "integrity": "sha512-B2SgNqwPuS2ekqj4lcxi5TibEcjWkdVyYykBEUBshPAPDQ527x2zPEZg560n8egNtAjUpwXFQm7pcXV65aAYmg==", "license": "MIT", "dependencies": { - "prism-react-renderer": "^2.0.6", - "sucrase": "^3.31.0", + "prism-react-renderer": "^2.4.0", + "sucrase": "^3.35.0", "use-editable": "^2.3.3" }, "engines": { @@ -19458,6 +18915,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.3" }, @@ -19983,6 +19441,16 @@ ], "license": "MIT" }, + "node_modules/react-markdown/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/react-markdown/node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -20138,9 +19606,9 @@ } }, "node_modules/react-modal": { - "version": "3.16.1", - "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz", - "integrity": "sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==", + "version": "3.16.3", + "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.3.tgz", + "integrity": "sha512-yCYRJB5YkeQDQlTt17WGAgFJ7jr2QYcWa1SHqZ3PluDmnKJ/7+tVU+E6uKyZ0nODaeEj+xCpK4LcSnKXLMC0Nw==", "license": "MIT", "dependencies": { "exenv": "^1.2.0", @@ -20148,12 +19616,9 @@ "react-lifecycles-compat": "^3.0.0", "warning": "^4.0.3" }, - "engines": { - "node": ">=8" - }, "peerDependencies": { - "react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18", - "react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18" + "react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 || ^19", + "react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 || ^19" } }, "node_modules/react-redux": { @@ -20191,6 +19656,7 @@ "version": "5.3.4", "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -20210,6 +19676,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.1.2" }, @@ -20222,6 +19689,7 @@ "version": "5.3.4", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -20236,25 +19704,24 @@ } }, "node_modules/readable-stream": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.6.0.tgz", - "integrity": "sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 6" } }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -20279,10 +19746,75 @@ "node": ">= 0.10" } }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.0.tgz", + "integrity": "sha512-5vwkv65qWwYxg+Atz95acp8DMu1JDSqdGkA2Of1j6rCreyFUE/gp15fC8MnGEuG1W68UKjM6x6+YTWIh7hZM/Q==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/recursive-readdir": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "license": "MIT", "dependencies": { "minimatch": "^3.0.5" }, @@ -20290,6 +19822,28 @@ "node": ">=6.0.0" } }, + "node_modules/recursive-readdir/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/recursive-readdir/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/redux": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", @@ -20335,20 +19889,6 @@ "node": ">=4" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, "node_modules/regexpu-core": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", @@ -20367,9 +19907,10 @@ } }, "node_modules/registry-auth-token": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", - "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz", + "integrity": "sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==", + "license": "MIT", "dependencies": { "@pnpm/npm-conf": "^2.1.0" }, @@ -20381,6 +19922,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "license": "MIT", "dependencies": { "rc": "1.2.8" }, @@ -20436,6 +19978,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", @@ -20446,9 +20003,9 @@ } }, "node_modules/remark-directive": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.0.tgz", - "integrity": "sha512-l1UyWJ6Eg1VPU7Hm/9tt0zKtReJQNOA4+iDMAxTyZNWnJnFlbS/7zhiel/rogTLQ2vMYwDzSJa4BiVNqGlqIMA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.1.tgz", + "integrity": "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -20494,9 +20051,9 @@ } }, "node_modules/remark-gfm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", - "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -20512,9 +20069,9 @@ } }, "node_modules/remark-mdx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.1.tgz", - "integrity": "sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.0.tgz", + "integrity": "sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==", "license": "MIT", "dependencies": { "mdast-util-mdx": "^3.0.0", @@ -20542,9 +20099,9 @@ } }, "node_modules/remark-rehype": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", - "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -20695,6 +20252,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -20720,17 +20278,21 @@ "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -20738,12 +20300,14 @@ "node_modules/resolve-alpn": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", "engines": { "node": ">=4" } @@ -20751,12 +20315,14 @@ "node_modules/resolve-pathname": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==", + "license": "MIT" }, "node_modules/responselike": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "license": "MIT", "dependencies": { "lowercase-keys": "^3.0.0" }, @@ -20777,9 +20343,10 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -20789,6 +20356,8 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -20799,25 +20368,23 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, "node_modules/robust-predicates": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" }, - "node_modules/rtl-detect": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.1.2.tgz", - "integrity": "sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ==" + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } }, "node_modules/rtlcss": { "version": "4.3.0", @@ -20855,6 +20422,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -20862,12 +20430,14 @@ "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "license": "MIT", "dependencies": { "mri": "^1.1.0" }, @@ -20892,17 +20462,19 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/sass": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.83.0.tgz", - "integrity": "sha512-qsSxlayzoOjdvXMVLkzF84DJFc2HZEL/rFyGIKbbilYtAvlCxyuzUeff9LawTn4btVnLKg75Z8MMr1lxU1lfGw==", + "version": "1.87.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.87.0.tgz", + "integrity": "sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==", "license": "MIT", "dependencies": { "chokidar": "^4.0.0", @@ -20920,9 +20492,9 @@ } }, "node_modules/sass-loader": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.4.tgz", - "integrity": "sha512-LavLbgbBGUt3wCiYzhuLLu65+fWXaXLmq7YxivLhEqmiupCFZ5sKUAipK3do6V80YSU0jvSxNhEdT13IXNr3rg==", + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.5.tgz", + "integrity": "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==", "license": "MIT", "dependencies": { "neo-async": "^2.6.2" @@ -20960,9 +20532,9 @@ } }, "node_modules/sass/node_modules/chokidar": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", - "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "license": "MIT", "dependencies": { "readdirp": "^4.0.1" @@ -20975,12 +20547,12 @@ } }, "node_modules/sass/node_modules/readdirp": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.1.tgz", - "integrity": "sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "license": "MIT", "engines": { - "node": ">= 14.16.0" + "node": ">= 14.18.0" }, "funding": { "type": "individual", @@ -21003,9 +20575,9 @@ } }, "node_modules/schema-utils": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", - "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -21061,9 +20633,9 @@ } }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -21076,6 +20648,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "license": "MIT", "dependencies": { "semver": "^7.3.5" }, @@ -21134,12 +20707,6 @@ "node": ">= 0.8" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "node_modules/send/node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -21173,6 +20740,49 @@ "range-parser": "1.2.0" } }, + "node_modules/serve-handler/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/serve-handler/node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-handler/node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "license": "MIT", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-handler/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/serve-handler/node_modules/path-to-regexp": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", @@ -21289,35 +20899,17 @@ "node": ">= 0.4" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "license": "MIT", "dependencies": { "kind-of": "^6.0.2" }, @@ -21328,12 +20920,14 @@ "node_modules/shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -21345,14 +20939,19 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -21361,6 +20960,7 @@ "version": "0.8.5", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "license": "BSD-3-Clause", "dependencies": { "glob": "^7.0.0", "interpret": "^1.0.0", @@ -21502,7 +21102,8 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" }, "node_modules/sirv": { "version": "2.0.4", @@ -21521,7 +21122,8 @@ "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" }, "node_modules/sitemap": { "version": "7.1.2", @@ -21564,6 +21166,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", "engines": { "node": ">=8" } @@ -21598,6 +21201,15 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/sort-css-media-queries": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz", @@ -21629,6 +21241,7 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -21638,6 +21251,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -21682,20 +21296,6 @@ "wbuf": "^1.7.3" } }, - "node_modules/spdy-transport/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -21724,61 +21324,11 @@ } }, "node_modules/std-env": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", - "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", "license": "MIT" }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "license": "MIT", - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "node_modules/stream-browserify/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/stream-http": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", - "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", - "license": "MIT", - "dependencies": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "xtend": "^4.0.2" - } - }, - "node_modules/stream-http/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -21792,6 +21342,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -21826,9 +21377,10 @@ "license": "MIT" }, "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -21840,6 +21392,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -21882,6 +21435,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -21915,6 +21469,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -21931,6 +21486,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-to-js": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.16.tgz", + "integrity": "sha512-/Q6ld50hKYPH3d/r6nr117TZkHR0w0kGGIVfpG9N6D8NymRPM9RqCUv4pRpJ62E5DqOYx2AFpbZMyCPnjQCnOw==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.8" + } + }, + "node_modules/style-to-js/node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" + }, + "node_modules/style-to-js/node_modules/style-to-object": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", + "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, "node_modules/style-to-object": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", @@ -21957,9 +21536,10 @@ } }, "node_modules/stylis": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.0.tgz", - "integrity": "sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==" + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "license": "MIT" }, "node_modules/sucrase": { "version": "3.35.0", @@ -21983,15 +21563,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/sucrase/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/sucrase/node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -22040,6 +21611,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -22051,6 +21623,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -22129,14 +21702,15 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/terser": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", - "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", + "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -22152,9 +21726,9 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.11", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz", - "integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==", + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", @@ -22189,6 +21763,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -22202,6 +21777,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -22215,12 +21791,14 @@ "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "license": "MIT" }, "node_modules/thenify": { "version": "3.3.1", @@ -22249,32 +21827,29 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "license": "MIT" }, - "node_modules/timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "license": "MIT", - "dependencies": { - "setimmediate": "^1.0.4" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/tiny-invariant": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", - "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" }, "node_modules/tiny-warning": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -22330,6 +21905,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", "engines": { "node": ">=6.10" } @@ -22341,20 +21917,16 @@ "license": "Apache-2.0" }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", - "license": "MIT" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=12.20" }, @@ -22375,39 +21947,20 @@ "node": ">= 0.6" } }, - "node_modules/type-is/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/type-is/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", "dependencies": { "is-typedarray": "^1.0.0" } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "license": "Apache-2.0", "peer": true, "bin": { "tsc": "bin/tsc", @@ -22417,10 +21970,17 @@ "node": ">=14.17" } }, + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "license": "MIT" + }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", @@ -22472,9 +22032,9 @@ } }, "node_modules/unified": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", - "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -22494,6 +22054,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "license": "MIT", "dependencies": { "crypto-random-string": "^4.0.0" }, @@ -22553,20 +22114,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-remove-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", - "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-visit": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", @@ -22613,6 +22160,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", "engines": { "node": ">= 10.0.0" } @@ -22627,9 +22175,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "funding": [ { "type": "opencollective", @@ -22647,7 +22195,7 @@ "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -22660,6 +22208,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "license": "BSD-2-Clause", "dependencies": { "boxen": "^7.0.0", "chalk": "^5.0.1", @@ -22687,6 +22236,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "license": "MIT", "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^7.0.1", @@ -22708,6 +22258,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "license": "MIT", "engines": { "node": ">=14.16" }, @@ -22716,9 +22267,10 @@ } }, "node_modules/update-notifier/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -22730,6 +22282,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -22757,6 +22310,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", "mime-types": "^2.1.27", @@ -22783,6 +22337,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -22798,6 +22353,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } @@ -22805,31 +22361,14 @@ "node_modules/url-loader/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/url-loader/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/url-loader/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" }, "node_modules/url-loader/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -22859,16 +22398,12 @@ } }, "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" + "inherits": "2.0.3" } }, "node_modules/util-deprecate": { @@ -22877,6 +22412,12 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "license": "ISC" + }, "node_modules/utila": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", @@ -22902,17 +22443,23 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/uvu": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "license": "MIT", "dependencies": { "dequal": "^2.0.0", "diff": "^5.0.0", @@ -22930,6 +22477,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", "engines": { "node": ">=6" } @@ -22970,7 +22518,8 @@ "node_modules/value-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==", + "license": "MIT" }, "node_modules/vary": { "version": "1.1.2", @@ -22982,13 +22531,12 @@ } }, "node_modules/vfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", - "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" }, "funding": { @@ -23024,10 +22572,53 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", "license": "MIT" }, "node_modules/warning": { @@ -23071,11 +22662,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/web-worker": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", - "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==" - }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -23083,13 +22669,14 @@ "license": "BSD-2-Clause" }, "node_modules/webpack": { - "version": "5.97.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", - "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", + "version": "5.99.7", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.7.tgz", + "integrity": "sha512-CNqKBRMQjwcmKR0idID5va1qlhrqVUKpovi+Ec79ksW8ux7iS1+A6VqzfZXgVYCFRKl7XL5ap3ZoMpwBJxcg0w==", "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", @@ -23106,9 +22693,9 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", + "schema-utils": "^4.3.2", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", + "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, @@ -23186,26 +22773,11 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/webpack-dev-middleware/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-middleware/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } + "node_modules/webpack-dev-middleware/node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" }, "node_modules/webpack-dev-middleware/node_modules/range-parser": { "version": "1.2.1", @@ -23275,10 +22847,16 @@ } } }, + "node_modules/webpack-dev-server/node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -23297,90 +22875,28 @@ } }, "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", - "wildcard": "^2.0.0" + "wildcard": "^2.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0" } }, "node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "license": "MIT", "engines": { "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/webpack/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/webpackbar": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-6.0.1.tgz", @@ -23490,6 +23006,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -23500,30 +23017,11 @@ "node": ">= 8" } }, - "node_modules/which-typed-array": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", - "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/widest-line": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "license": "MIT", "dependencies": { "string-width": "^5.0.1" }, @@ -23537,12 +23035,14 @@ "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "license": "MIT" }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -23594,9 +23094,10 @@ } }, "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -23608,6 +23109,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -23619,6 +23121,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -23632,12 +23135,14 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", @@ -23670,6 +23175,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -23710,15 +23216,6 @@ "node": ">= 10" } }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -23738,6 +23235,7 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", "engines": { "node": ">= 6" } @@ -23796,9 +23294,9 @@ } }, "node_modules/yocto-queue": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", - "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", "license": "MIT", "engines": { "node": ">=12.20" diff --git a/docs/package.json b/docs/package.json index f1849f6d9..43fc7a644 100644 --- a/docs/package.json +++ b/docs/package.json @@ -17,10 +17,10 @@ "write-heading-ids": "docusaurus write-heading-ids" }, "dependencies": { - "@docusaurus/core": "^3.6.3", - "@docusaurus/preset-classic": "^3.6.3", - "@docusaurus/theme-mermaid": "^3.6.3", + "@docusaurus/core": "^3.7.0", "@docusaurus/plugin-content-docs": "^3.6.3", + "@docusaurus/preset-classic": "^3.7.0", + "@docusaurus/theme-mermaid": "^3.6.3", "@mdx-js/react": "^3.1.0", "clsx": "^2.1.1", "docusaurus-plugin-openapi-docs": "^4.3.1", diff --git a/docs/sidebars.ts b/docs/sidebars.ts index bffb54349..bd89492e2 100644 --- a/docs/sidebars.ts +++ b/docs/sidebars.ts @@ -33,11 +33,12 @@ const sidebars: SidebarsConfig = { "configuration/object_detectors", "configuration/audio_detectors", ], - Classifiers: [ + Enrichments: [ "configuration/semantic_search", "configuration/genai", "configuration/face_recognition", "configuration/license_plate_recognition", + "configuration/bird_classification", ], Cameras: [ "configuration/cameras", @@ -58,10 +59,13 @@ const sidebars: SidebarsConfig = { "configuration/objects", "configuration/stationary_objects", ], + "Hardware Acceleration": [ + "configuration/hardware_acceleration_video", + "configuration/hardware_acceleration_enrichments", + ], "Extra Configuration": [ "configuration/authentication", "configuration/notifications", - "configuration/hardware_acceleration", "configuration/ffmpeg_presets", "configuration/pwa", "configuration/tls", diff --git a/docs/src/components/LanguageAlert/index.jsx b/docs/src/components/LanguageAlert/index.jsx new file mode 100644 index 000000000..b786c8a93 --- /dev/null +++ b/docs/src/components/LanguageAlert/index.jsx @@ -0,0 +1,25 @@ +import React, { useEffect, useState } from 'react'; +import { useLocation } from '@docusaurus/router'; +import styles from './styles.module.css'; + +export default function LanguageAlert() { + const [showAlert, setShowAlert] = useState(false); + const { pathname } = useLocation(); + + useEffect(() => { + const userLanguage = navigator?.language || 'en'; + const isChineseUser = userLanguage.includes('zh'); + setShowAlert(isChineseUser); + + }, [pathname]); + + if (!showAlert) return null; + + return ( +
+ 检测到您的主要语言为中文,您可以访问由中文社区翻译的 + 中文文档 + 以获得更好的体验 +
+ ); +} \ No newline at end of file diff --git a/docs/src/components/LanguageAlert/styles.module.css b/docs/src/components/LanguageAlert/styles.module.css new file mode 100644 index 000000000..f8d1e8eb2 --- /dev/null +++ b/docs/src/components/LanguageAlert/styles.module.css @@ -0,0 +1,13 @@ +.alert { + padding: 12px; + background: #fff8e6; + border-bottom: 1px solid #ffd166; + text-align: center; + font-size: 15px; + } + + .alert a { + color: #1890ff; + font-weight: 500; + margin-left: 6px; + } \ No newline at end of file diff --git a/docs/src/theme/Navbar/index.js b/docs/src/theme/Navbar/index.js new file mode 100644 index 000000000..4dd3aee15 --- /dev/null +++ b/docs/src/theme/Navbar/index.js @@ -0,0 +1,15 @@ +import React from 'react'; +import NavbarLayout from '@theme/Navbar/Layout'; +import NavbarContent from '@theme/Navbar/Content'; +import LanguageAlert from '../../components/LanguageAlert'; + +export default function Navbar() { + return ( + <> + + + + + + ); +} \ No newline at end of file diff --git a/docs/static/frigate-api.yaml b/docs/static/frigate-api.yaml index e05330a9d..cd065ede5 100644 --- a/docs/static/frigate-api.yaml +++ b/docs/static/frigate-api.yaml @@ -161,6 +161,253 @@ paths: application/json: schema: $ref: "#/components/schemas/HTTPValidationError" + "/users/{username}/role": + put: + tags: + - Auth + summary: Update Role + operationId: update_role_users__username__role_put + parameters: + - name: username + in: path + required: true + schema: + type: string + title: Username + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/AppPutRoleBody" + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" + /faces: + get: + tags: + - Events + summary: Get Faces + operationId: get_faces_faces_get + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + /faces/reprocess: + post: + tags: + - Events + summary: Reclassify Face + operationId: reclassify_face_faces_reprocess_post + requestBody: + content: + application/json: + schema: + type: object + title: Body + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" + "/faces/train/{name}/classify": + post: + tags: + - Events + summary: Train Face + operationId: train_face_faces_train__name__classify_post + parameters: + - name: name + in: path + required: true + schema: + type: string + title: Name + requestBody: + content: + application/json: + schema: + type: object + title: Body + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" + "/faces/{name}/create": + post: + tags: + - Events + summary: Create Face + operationId: create_face_faces__name__create_post + parameters: + - name: name + in: path + required: true + schema: + type: string + title: Name + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" + "/faces/{name}/register": + post: + tags: + - Events + summary: Register Face + operationId: register_face_faces__name__register_post + parameters: + - name: name + in: path + required: true + schema: + type: string + title: Name + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: >- + #/components/schemas/Body_register_face_faces__name__register_post + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" + /faces/recognize: + post: + tags: + - Events + summary: Recognize Face + operationId: recognize_face_faces_recognize_post + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: "#/components/schemas/Body_recognize_face_faces_recognize_post" + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" + "/faces/{name}/delete": + post: + tags: + - Events + summary: Deregister Faces + operationId: deregister_faces_faces__name__delete_post + parameters: + - name: name + in: path + required: true + schema: + type: string + title: Name + requestBody: + content: + application/json: + schema: + type: object + title: Body + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" + /lpr/reprocess: + put: + tags: + - Events + summary: Reprocess License Plate + operationId: reprocess_license_plate_lpr_reprocess_put + parameters: + - name: event_id + in: query + required: true + schema: + type: string + title: Event Id + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" + /reindex: + put: + tags: + - Events + summary: Reindex Embeddings + operationId: reindex_embeddings_reindex_put + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} /review: get: tags: @@ -206,9 +453,7 @@ paths: in: query required: false schema: - allOf: - - $ref: "#/components/schemas/SeverityEnum" - title: Severity + $ref: "#/components/schemas/SeverityEnum" - name: before in: query required: false @@ -237,6 +482,35 @@ paths: application/json: schema: $ref: "#/components/schemas/HTTPValidationError" + /review_ids: + get: + tags: + - Review + summary: Review Ids + operationId: review_ids_review_ids_get + parameters: + - name: ids + in: query + required: true + schema: + type: string + title: Ids + responses: + "200": + description: Successful Response + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ReviewSegmentResponse" + title: Response Review Ids Review Ids Get + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" /review/summary: get: tags: @@ -575,6 +849,19 @@ paths: application/json: schema: $ref: "#/components/schemas/HTTPValidationError" + /metrics: + get: + tags: + - App + summary: Metrics + description: Expose Prometheus metrics endpoint and update metrics with latest stats + operationId: metrics_metrics_get + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} /config: get: tags: @@ -731,6 +1018,15 @@ paths: - type: string - type: "null" title: Download + - name: stream + in: query + required: false + schema: + anyOf: + - type: boolean + - type: "null" + default: false + title: Stream - name: start in: query required: false @@ -825,6 +1121,59 @@ paths: application/json: schema: $ref: "#/components/schemas/HTTPValidationError" + /plus/models: + get: + tags: + - App + summary: Plusmodels + operationId: plusModels_plus_models_get + parameters: + - name: filterByCurrentModelDetector + in: query + required: false + schema: + type: boolean + default: false + title: Filterbycurrentmodeldetector + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" + /recognized_license_plates: + get: + tags: + - App + summary: Get Recognized License Plates + operationId: get_recognized_license_plates_recognized_license_plates_get + parameters: + - name: split_joined + in: query + required: false + schema: + anyOf: + - type: integer + - type: "null" + title: Split Joined + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" /timeline: get: tags: @@ -1158,12 +1507,12 @@ paths: application/json: schema: $ref: "#/components/schemas/HTTPValidationError" - "/export/{event_id}/{new_name}": + "/export/{event_id}/rename": patch: tags: - Export summary: Export Rename - operationId: export_rename_export__event_id___new_name__patch + operationId: export_rename_export__event_id__rename_patch parameters: - name: event_id in: path @@ -1171,12 +1520,12 @@ paths: schema: type: string title: Event Id - - name: new_name - in: path - required: true - schema: - type: string - title: New Name + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ExportRenameBody" responses: "200": description: Successful Response @@ -1409,6 +1758,31 @@ paths: - type: number - type: "null" title: Max Score + - name: min_speed + in: query + required: false + schema: + anyOf: + - type: number + - type: "null" + title: Min Speed + - name: max_speed + in: query + required: false + schema: + anyOf: + - type: number + - type: "null" + title: Max Speed + - name: recognized_license_plate + in: query + required: false + schema: + anyOf: + - type: string + - type: "null" + default: all + title: Recognized License Plate - name: is_submitted in: query required: false @@ -1684,6 +2058,31 @@ paths: - type: number - type: "null" title: Max Score + - name: min_speed + in: query + required: false + schema: + anyOf: + - type: number + - type: "null" + title: Min Speed + - name: max_speed + in: query + required: false + schema: + anyOf: + - type: number + - type: "null" + title: Max Speed + - name: recognized_license_plate + in: query + required: false + schema: + anyOf: + - type: string + - type: "null" + default: all + title: Recognized License Plate - name: sort in: query required: false @@ -1867,9 +2266,7 @@ paths: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/SubmitPlusBody" - title: Body + $ref: "#/components/schemas/SubmitPlusBody" responses: "200": description: Successful Response @@ -2056,15 +2453,13 @@ paths: content: application/json: schema: - allOf: - - $ref: "#/components/schemas/EventsCreateBody" + $ref: "#/components/schemas/EventsCreateBody" default: source_type: api score: 0 duration: 30 include_recording: true draw: {} - title: Body responses: "200": description: Successful Response @@ -2305,6 +2700,14 @@ paths: - type: integer - type: "null" title: Height + - name: store + in: query + required: false + schema: + anyOf: + - type: integer + - type: "null" + title: Store responses: "200": description: Successful Response @@ -2407,6 +2810,42 @@ paths: content: application/json: schema: {} + /recordings/summary: + get: + tags: + - Media + summary: All Recordings Summary + description: Returns true/false by day indicating if recordings exist + operationId: all_recordings_summary_recordings_summary_get + parameters: + - name: timezone + in: query + required: false + schema: + type: string + default: utc + title: Timezone + - name: cameras + in: query + required: false + schema: + anyOf: + - type: string + - type: "null" + default: all + title: Cameras + responses: + "200": + description: Successful Response + content: + application/json: + schema: {} + "422": + description: Validation Error + content: + application/json: + schema: + $ref: "#/components/schemas/HTTPValidationError" "/{camera_name}/recordings/summary": get: tags: @@ -2461,14 +2900,14 @@ paths: required: false schema: type: number - default: 1733228876.15567 + default: 1744227965.180043 title: After - name: before in: query required: false schema: type: number - default: 1733232476.15567 + default: 1744231565.180048 title: Before responses: "200": @@ -2487,6 +2926,8 @@ paths: tags: - Media summary: Recording Clip + description: >- + For iOS devices, use the master.m3u8 HLS link instead of clip.mp4. Safari does not reliably process progressive mp4 files. operationId: recording_clip__camera_name__start__start_ts__end__end_ts__clip_mp4_get parameters: - name: camera_name @@ -2749,12 +3190,12 @@ paths: application/json: schema: $ref: "#/components/schemas/HTTPValidationError" - "/events/{event_id}/thumbnail.jpg": + "/events/{event_id}/thumbnail.{extension}": get: tags: - Media summary: Event Thumbnail - operationId: event_thumbnail_events__event_id__thumbnail_jpg_get + operationId: event_thumbnail_events__event_id__thumbnail__extension__get parameters: - name: event_id in: path @@ -2762,6 +3203,12 @@ paths: schema: type: string title: Event Id + - name: extension + in: path + required: true + schema: + type: string + title: Extension - name: max_cache_age in: query required: false @@ -3251,6 +3698,12 @@ components: password: type: string title: Password + role: + anyOf: + - type: string + - type: "null" + title: Role + default: viewer type: object required: - username @@ -3265,6 +3718,35 @@ components: required: - password title: AppPutPasswordBody + AppPutRoleBody: + properties: + role: + type: string + title: Role + type: object + required: + - role + title: AppPutRoleBody + Body_recognize_face_faces_recognize_post: + properties: + file: + type: string + format: binary + title: File + type: object + required: + - file + title: Body_recognize_face_faces_recognize_post + Body_register_face_faces__name__register_post: + properties: + file: + type: string + format: binary + title: File + type: object + required: + - file + title: Body_register_face_faces__name__register_post DayReview: properties: day: @@ -3354,7 +3836,9 @@ components: - type: "null" title: End Time false_positive: - type: boolean + anyOf: + - type: boolean + - type: "null" title: False Positive zones: items: @@ -3362,7 +3846,9 @@ components: type: array title: Zones thumbnail: - type: string + anyOf: + - type: string + - type: "null" title: Thumbnail has_clip: type: boolean @@ -3394,6 +3880,7 @@ components: - type: "null" title: Model Type data: + type: object title: Data type: object required: @@ -3511,6 +3998,11 @@ components: exclusiveMinimum: 0 - type: "null" title: Score for sub label + camera: + anyOf: + - type: string + - type: "null" + title: Camera this object is detected on. type: object required: - subLabel @@ -3518,13 +4010,11 @@ components: ExportRecordingsBody: properties: playback: - allOf: - - $ref: "#/components/schemas/PlaybackFactorEnum" + $ref: "#/components/schemas/PlaybackFactorEnum" title: Playback factor default: realtime source: - allOf: - - $ref: "#/components/schemas/PlaybackSourceEnum" + $ref: "#/components/schemas/PlaybackSourceEnum" title: Playback source default: recordings name: @@ -3536,6 +4026,16 @@ components: title: Image Path type: object title: ExportRecordingsBody + ExportRenameBody: + properties: + name: + type: string + maxLength: 256 + title: Friendly name + type: object + required: + - name + title: ExportRenameBody Extension: type: string enum: diff --git a/frigate/api/app.py b/frigate/api/app.py index 05013ed12..2301d1be1 100644 --- a/frigate/api/app.py +++ b/frigate/api/app.py @@ -9,6 +9,7 @@ import traceback from datetime import datetime, timedelta from functools import reduce from io import StringIO +from pathlib import Path as FilePath from typing import Any, Optional import aiofiles @@ -73,18 +74,22 @@ def go2rtc_streams(): ) stream_data = r.json() for data in stream_data.values(): - for producer in data.get("producers", []): + for producer in data.get("producers") or []: producer["url"] = clean_camera_user_pass(producer.get("url", "")) return JSONResponse(content=stream_data) @router.get("/go2rtc/streams/{camera_name}") -def go2rtc_camera_stream(camera_name: str): +def go2rtc_camera_stream(request: Request, camera_name: str): r = requests.get( f"http://127.0.0.1:1984/api/streams?src={camera_name}&video=all&audio=allµphone" ) if not r.ok: - logger.error("Failed to fetch streams from go2rtc") + camera_config = request.app.frigate_config.cameras.get(camera_name) + + if camera_config and camera_config.enabled: + logger.error("Failed to fetch streams from go2rtc") + return JSONResponse( content=({"success": False, "message": "Error fetching stream data"}), status_code=500, @@ -174,6 +179,22 @@ def config(request: Request): config["model"]["all_attributes"] = config_obj.model.all_attributes config["model"]["non_logo_attributes"] = config_obj.model.non_logo_attributes + # Add model plus data if plus is enabled + if config["plus"]["enabled"]: + model_path = config.get("model", {}).get("path") + if model_path: + model_json_path = FilePath(model_path).with_suffix(".json") + try: + with open(model_json_path, "r") as f: + model_plus_data = json.load(f) + config["model"]["plus"] = model_plus_data + except FileNotFoundError: + config["model"]["plus"] = None + except json.JSONDecodeError: + config["model"]["plus"] = None + else: + config["model"]["plus"] = None + # use merged labelamp for detector_config in config["detectors"].values(): detector_config["model"]["labelmap"] = ( @@ -619,6 +640,48 @@ def get_sub_labels(split_joined: Optional[int] = None): return JSONResponse(content=sub_labels) +@router.get("/plus/models") +def plusModels(request: Request, filterByCurrentModelDetector: bool = False): + if not request.app.frigate_config.plus_api.is_active(): + return JSONResponse( + content=({"success": False, "message": "Frigate+ is not enabled"}), + status_code=400, + ) + + models: dict[any, any] = request.app.frigate_config.plus_api.get_models() + + if not models["list"]: + return JSONResponse( + content=({"success": False, "message": "No models found"}), + status_code=400, + ) + + modelList = models["list"] + + # current model type + modelType = request.app.frigate_config.model.model_type + + # current detectorType for comparing to supportedDetectors + detectorType = list(request.app.frigate_config.detectors.values())[0].type + + validModels = [] + + for model in sorted( + filter( + lambda m: ( + not filterByCurrentModelDetector + or (detectorType in m["supportedDetectors"] and modelType in m["type"]) + ), + modelList, + ), + key=(lambda m: m["trainDate"]), + reverse=True, + ): + validModels.append(model) + + return JSONResponse(content=validModels) + + @router.get("/recognized_license_plates") def get_recognized_license_plates(split_joined: Optional[int] = None): try: diff --git a/frigate/api/auth.py b/frigate/api/auth.py index f806a0c30..1a267b521 100644 --- a/frigate/api/auth.py +++ b/frigate/api/auth.py @@ -109,11 +109,11 @@ def get_jwt_secret() -> str: jwt_secret = ( Path(os.path.join("/run/secrets", JWT_SECRET_ENV_VAR)).read_text().strip() ) - # check for the addon options file + # check for the add-on options file elif os.path.isfile("/data/options.json"): with open("/data/options.json") as f: raw_options = f.read() - logger.debug("Using jwt secret from Home Assistant addon options file.") + logger.debug("Using jwt secret from Home Assistant Add-on options file.") options = json.loads(raw_options) jwt_secret = options.get("jwt_secret") @@ -253,22 +253,24 @@ def auth(request: Request): # pass the user header value from the upstream proxy if a mapping is specified # or use anonymous if none are specified user_header = proxy_config.header_map.user - role_header = proxy_config.header_map.role success_response.headers["remote-user"] = ( request.headers.get(user_header, default="anonymous") if user_header else "anonymous" ) + role_header = proxy_config.header_map.role role = ( - request.headers.get(role_header, default="viewer") + request.headers.get(role_header, default=proxy_config.default_role) if role_header - else "viewer" + else proxy_config.default_role ) - # if comma-separated with "admin", use "admin", else "viewer" + # if comma-separated with "admin", use "admin", else use default role success_response.headers["remote-role"] = ( - "admin" if role and "admin" in role else "viewer" + "admin" + if role and "admin" in [r.strip() for r in role.split(",")] + else proxy_config.default_role ) return success_response diff --git a/frigate/api/classification.py b/frigate/api/classification.py index 85b604379..d0fcf775c 100644 --- a/frigate/api/classification.py +++ b/frigate/api/classification.py @@ -1,11 +1,11 @@ """Object classification APIs.""" +import datetime import logging import os -import random import shutil -import string +import cv2 from fastapi import APIRouter, Depends, Request, UploadFile from fastapi.responses import JSONResponse from pathvalidate import sanitize_filename @@ -13,10 +13,13 @@ from peewee import DoesNotExist from playhouse.shortcuts import model_to_dict from frigate.api.auth import require_role +from frigate.api.defs.request.classification_body import RenameFaceBody from frigate.api.defs.tags import Tags +from frigate.config.camera import DetectConfig from frigate.const import FACE_DIR from frigate.embeddings import EmbeddingsContext from frigate.models import Event +from frigate.util.path import get_event_snapshot logger = logging.getLogger(__name__) @@ -27,6 +30,9 @@ router = APIRouter(tags=[Tags.events]) def get_faces(): face_dict: dict[str, list[str]] = {} + if not os.path.exists(FACE_DIR): + return JSONResponse(status_code=200, content={}) + for name in os.listdir(FACE_DIR): face_dir = os.path.join(FACE_DIR, name) @@ -35,10 +41,9 @@ def get_faces(): face_dict[name] = [] - for file in sorted( + for file in filter( + lambda f: (f.lower().endswith((".webp", ".png", ".jpg", ".jpeg"))), os.listdir(face_dir), - key=lambda f: os.path.getctime(os.path.join(face_dir, f)), - reverse=True, ): face_dict[name].append(file) @@ -87,26 +92,68 @@ def train_face(request: Request, name: str, body: dict = None): ) json: dict[str, any] = body or {} - training_file = os.path.join( - FACE_DIR, f"train/{sanitize_filename(json.get('training_file', ''))}" - ) + training_file_name = sanitize_filename(json.get("training_file", "")) + training_file = os.path.join(FACE_DIR, f"train/{training_file_name}") + event_id = json.get("event_id") - if not training_file or not os.path.isfile(training_file): + if not training_file_name and not event_id: return JSONResponse( content=( { "success": False, - "message": f"Invalid filename or no file exists: {training_file}", + "message": "A training file or event_id must be passed.", + } + ), + status_code=400, + ) + + if training_file_name and not os.path.isfile(training_file): + return JSONResponse( + content=( + { + "success": False, + "message": f"Invalid filename or no file exists: {training_file_name}", } ), status_code=404, ) sanitized_name = sanitize_filename(name) - rand_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=6)) - new_name = f"{sanitized_name}-{rand_id}.webp" - new_file = os.path.join(FACE_DIR, f"{sanitized_name}/{new_name}") - shutil.move(training_file, new_file) + new_name = f"{sanitized_name}-{datetime.datetime.now().timestamp()}.webp" + new_file_folder = os.path.join(FACE_DIR, f"{sanitized_name}") + + if not os.path.exists(new_file_folder): + os.mkdir(new_file_folder) + + if training_file_name: + shutil.move(training_file, os.path.join(new_file_folder, new_name)) + else: + try: + event: Event = Event.get(Event.id == event_id) + except DoesNotExist: + return JSONResponse( + content=( + { + "success": False, + "message": f"Invalid event_id or no event exists: {event_id}", + } + ), + status_code=404, + ) + + snapshot = get_event_snapshot(event) + face_box = event.data["attributes"][0]["box"] + detect_config: DetectConfig = request.app.frigate_config.cameras[ + event.camera + ].detect + + # crop onto the face box minus the bounding box itself + x1 = int(face_box[0] * detect_config.width) + 2 + y1 = int(face_box[1] * detect_config.height) + 2 + x2 = x1 + int(face_box[2] * detect_config.width) - 4 + y2 = y1 + int(face_box[3] * detect_config.height) - 4 + face = snapshot[y1:y2, x1:x2] + cv2.imwrite(os.path.join(new_file_folder, new_name), face) context: EmbeddingsContext = request.app.embeddings context.clear_face_classifier() @@ -115,7 +162,7 @@ def train_face(request: Request, name: str, body: dict = None): content=( { "success": True, - "message": f"Successfully saved {training_file} as {new_name}.", + "message": f"Successfully saved {training_file_name} as {new_name}.", } ), status_code=200, @@ -149,6 +196,42 @@ async def register_face(request: Request, name: str, file: UploadFile): context: EmbeddingsContext = request.app.embeddings result = context.register_face(name, await file.read()) + + if not isinstance(result, dict): + return JSONResponse( + status_code=500, + content={ + "success": False, + "message": "Could not process request. Try restarting Frigate.", + }, + ) + + return JSONResponse( + status_code=200 if result.get("success", True) else 400, + content=result, + ) + + +@router.post("/faces/recognize") +async def recognize_face(request: Request, file: UploadFile): + if not request.app.frigate_config.face_recognition.enabled: + return JSONResponse( + status_code=400, + content={"message": "Face recognition is not enabled.", "success": False}, + ) + + context: EmbeddingsContext = request.app.embeddings + result = context.recognize_face(await file.read()) + + if not isinstance(result, dict): + return JSONResponse( + status_code=500, + content={ + "success": False, + "message": "Could not process request. Try restarting Frigate.", + }, + ) + return JSONResponse( status_code=200 if result.get("success", True) else 400, content=result, @@ -166,12 +249,6 @@ def deregister_faces(request: Request, name: str, body: dict = None): json: dict[str, any] = body or {} list_of_ids = json.get("ids", "") - if not list_of_ids or len(list_of_ids) == 0: - return JSONResponse( - content=({"success": False, "message": "Not a valid list of ids"}), - status_code=404, - ) - context: EmbeddingsContext = request.app.embeddings context.delete_face_ids( name, map(lambda file: sanitize_filename(file), list_of_ids) @@ -182,6 +259,35 @@ def deregister_faces(request: Request, name: str, body: dict = None): ) +@router.put("/faces/{old_name}/rename", dependencies=[Depends(require_role(["admin"]))]) +def rename_face(request: Request, old_name: str, body: RenameFaceBody): + if not request.app.frigate_config.face_recognition.enabled: + return JSONResponse( + status_code=400, + content={"message": "Face recognition is not enabled.", "success": False}, + ) + + context: EmbeddingsContext = request.app.embeddings + try: + context.rename_face(old_name, body.new_name) + return JSONResponse( + content={ + "success": True, + "message": f"Successfully renamed face to {body.new_name}.", + }, + status_code=200, + ) + except ValueError as e: + logger.error(e) + return JSONResponse( + status_code=400, + content={ + "message": "Error renaming face. Check Frigate logs.", + "success": False, + }, + ) + + @router.put("/lpr/reprocess") def reprocess_license_plate(request: Request, event_id: str): if not request.app.frigate_config.lpr.enabled: @@ -213,3 +319,49 @@ def reprocess_license_plate(request: Request, event_id: str): content=response, status_code=200, ) + + +@router.put("/reindex", dependencies=[Depends(require_role(["admin"]))]) +def reindex_embeddings(request: Request): + if not request.app.frigate_config.semantic_search.enabled: + message = ( + "Cannot reindex tracked object embeddings, Semantic Search is not enabled." + ) + logger.error(message) + return JSONResponse( + content=( + { + "success": False, + "message": message, + } + ), + status_code=400, + ) + + context: EmbeddingsContext = request.app.embeddings + response = context.reindex_embeddings() + + if response == "started": + return JSONResponse( + content={ + "success": True, + "message": "Embeddings reindexing has started.", + }, + status_code=202, # 202 Accepted + ) + elif response == "in_progress": + return JSONResponse( + content={ + "success": False, + "message": "Embeddings reindexing is already in progress.", + }, + status_code=409, # 409 Conflict + ) + else: + return JSONResponse( + content={ + "success": False, + "message": "Failed to start reindexing.", + }, + status_code=500, + ) diff --git a/frigate/api/defs/request/classification_body.py b/frigate/api/defs/request/classification_body.py new file mode 100644 index 000000000..c4a32c332 --- /dev/null +++ b/frigate/api/defs/request/classification_body.py @@ -0,0 +1,5 @@ +from pydantic import BaseModel + + +class RenameFaceBody(BaseModel): + new_name: str diff --git a/frigate/api/defs/request/events_body.py b/frigate/api/defs/request/events_body.py index 0fefbe43f..0883d066f 100644 --- a/frigate/api/defs/request/events_body.py +++ b/frigate/api/defs/request/events_body.py @@ -13,6 +13,15 @@ class EventsSubLabelBody(BaseModel): ) +class EventsLPRBody(BaseModel): + recognizedLicensePlate: str = Field( + title="Recognized License Plate", max_length=100 + ) + recognizedLicensePlateScore: Optional[float] = Field( + title="Score for recognized license plate", default=None, gt=0.0, le=1.0 + ) + + class EventsDescriptionBody(BaseModel): description: Union[str, None] = Field(title="The description of the event") diff --git a/frigate/api/event.py b/frigate/api/event.py index 88a865318..4287e829a 100644 --- a/frigate/api/event.py +++ b/frigate/api/event.py @@ -31,6 +31,7 @@ from frigate.api.defs.request.events_body import ( EventsDeleteBody, EventsDescriptionBody, EventsEndBody, + EventsLPRBody, EventsSubLabelBody, SubmitPlusBody, ) @@ -701,6 +702,7 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends()) for k, v in event["data"].items() if k in [ + "attributes", "type", "score", "top_score", @@ -723,13 +725,15 @@ def events_search(request: Request, params: EventsSearchQueryParams = Depends()) if (sort is None or sort == "relevance") and search_results: processed_events.sort(key=lambda x: x.get("search_distance", float("inf"))) elif min_score is not None and max_score is not None and sort == "score_asc": - processed_events.sort(key=lambda x: x["score"]) + processed_events.sort(key=lambda x: x["data"]["score"]) elif min_score is not None and max_score is not None and sort == "score_desc": - processed_events.sort(key=lambda x: x["score"], reverse=True) + processed_events.sort(key=lambda x: x["data"]["score"], reverse=True) elif min_speed is not None and max_speed is not None and sort == "speed_asc": - processed_events.sort(key=lambda x: x["average_estimated_speed"]) + processed_events.sort(key=lambda x: x["data"]["average_estimated_speed"]) elif min_speed is not None and max_speed is not None and sort == "speed_desc": - processed_events.sort(key=lambda x: x["average_estimated_speed"], reverse=True) + processed_events.sort( + key=lambda x: x["data"]["average_estimated_speed"], reverse=True + ) elif sort == "date_asc": processed_events.sort(key=lambda x: x["start_time"]) else: @@ -1098,6 +1102,60 @@ def set_sub_label( ) +@router.post( + "/events/{event_id}/recognized_license_plate", + response_model=GenericResponse, + dependencies=[Depends(require_role(["admin"]))], +) +def set_plate( + request: Request, + event_id: str, + body: EventsLPRBody, +): + try: + event: Event = Event.get(Event.id == event_id) + except DoesNotExist: + event = None + + if request.app.detected_frames_processor: + tracked_obj: TrackedObject = None + + for state in request.app.detected_frames_processor.camera_states.values(): + tracked_obj = state.tracked_objects.get(event_id) + + if tracked_obj is not None: + break + else: + tracked_obj = None + + if not event and not tracked_obj: + return JSONResponse( + content=( + {"success": False, "message": "Event " + event_id + " not found."} + ), + status_code=404, + ) + + new_plate = body.recognizedLicensePlate + new_score = body.recognizedLicensePlateScore + + if new_plate == "": + new_plate = None + new_score = None + + request.app.event_metadata_updater.publish( + EventMetadataTypeEnum.recognized_license_plate, (event_id, new_plate, new_score) + ) + + return JSONResponse( + content={ + "success": True, + "message": f"Event {event_id} license plate set to {new_plate if new_plate is not None else 'None'}", + }, + status_code=200, + ) + + @router.post( "/events/{event_id}/description", response_model=GenericResponse, diff --git a/frigate/api/media.py b/frigate/api/media.py index 83307a15c..9aac3d7e6 100644 --- a/frigate/api/media.py +++ b/frigate/api/media.py @@ -1,7 +1,9 @@ """Image and video apis.""" +import asyncio import glob import logging +import math import os import subprocess as sp import time @@ -109,9 +111,12 @@ def imagestream( @router.get("/{camera_name}/ptz/info") async def camera_ptz_info(request: Request, camera_name: str): if camera_name in request.app.frigate_config.cameras: - return JSONResponse( - content=await request.app.onvif.get_camera_info(camera_name), + # Schedule get_camera_info in the OnvifController's event loop + future = asyncio.run_coroutine_threadsafe( + request.app.onvif.get_camera_info(camera_name), request.app.onvif.loop ) + result = future.result() + return JSONResponse(content=result) else: return JSONResponse( content={"success": False, "message": "Camera not found"}, @@ -240,25 +245,50 @@ def get_snapshot_from_recording( content={"success": False, "message": "Camera not found"}, status_code=404, ) - - recording_query = ( - Recordings.select( - Recordings.path, - Recordings.start_time, - ) - .where( - ( - (frame_time >= Recordings.start_time) - & (frame_time <= Recordings.end_time) - ) - ) - .where(Recordings.camera == camera_name) - .order_by(Recordings.start_time.desc()) - .limit(1) - ) + recording: Recordings | None = None try: - recording: Recordings = recording_query.get() + recording = ( + Recordings.select( + Recordings.path, + Recordings.start_time, + ) + .where( + ( + (frame_time >= Recordings.start_time) + & (frame_time <= Recordings.end_time) + ) + ) + .where(Recordings.camera == camera_name) + .order_by(Recordings.start_time.desc()) + .limit(1) + .get() + ) + except DoesNotExist: + # try again with a rounded frame time as it may be between + # the rounded segment start time + frame_time = math.ceil(frame_time) + try: + recording = ( + Recordings.select( + Recordings.path, + Recordings.start_time, + ) + .where( + ( + (frame_time >= Recordings.start_time) + & (frame_time <= Recordings.end_time) + ) + ) + .where(Recordings.camera == camera_name) + .order_by(Recordings.start_time.desc()) + .limit(1) + .get() + ) + except DoesNotExist: + pass + + if recording is not None: time_in_segment = frame_time - recording.start_time codec = "png" if format == "png" else "mjpeg" mime_type = "png" if format == "png" else "jpeg" @@ -279,7 +309,7 @@ def get_snapshot_from_recording( status_code=404, ) return Response(image_data, headers={"Content-Type": f"image/{mime_type}"}) - except DoesNotExist: + else: return JSONResponse( content={ "success": False, @@ -511,7 +541,10 @@ def recordings( return JSONResponse(content=list(recordings)) -@router.get("/{camera_name}/start/{start_ts}/end/{end_ts}/clip.mp4") +@router.get( + "/{camera_name}/start/{start_ts}/end/{end_ts}/clip.mp4", + description="For iOS devices, use the master.m3u8 HLS link instead of clip.mp4. Safari does not reliably process progressive mp4 files.", +) def recording_clip( request: Request, camera_name: str, @@ -876,7 +909,7 @@ def event_thumbnail( elif extension == "webp": quality_params = [int(cv2.IMWRITE_WEBP_QUALITY), 60] - _, img = cv2.imencode(f".{img}", thumbnail, quality_params) + _, img = cv2.imencode(f".{extension}", thumbnail, quality_params) thumbnail_bytes = img.tobytes() return Response( diff --git a/frigate/api/review.py b/frigate/api/review.py index b04c8353a..b90365595 100644 --- a/frigate/api/review.py +++ b/frigate/api/review.py @@ -58,13 +58,9 @@ async def review( ) clauses = [ - ( - (ReviewSegment.start_time > after) - & ( - (ReviewSegment.end_time.is_null(True)) - | (ReviewSegment.end_time < before) - ) - ) + (ReviewSegment.start_time > after) + & (ReviewSegment.start_time < before) + & ((ReviewSegment.end_time.is_null(True)) | (ReviewSegment.end_time < before)) ] if cameras != "all": @@ -176,7 +172,6 @@ async def review_summary( hour_modifier, minute_modifier, seconds_offset = get_tz_modifiers(params.timezone) day_ago = (datetime.datetime.now() - datetime.timedelta(hours=24)).timestamp() - month_ago = (datetime.datetime.now() - datetime.timedelta(days=30)).timestamp() cameras = params.cameras labels = params.labels @@ -277,7 +272,7 @@ async def review_summary( .get() ) - clauses = [(ReviewSegment.start_time > month_ago)] + clauses = [] if cameras != "all": camera_list = cameras.split(",") @@ -365,7 +360,7 @@ async def review_summary( & (UserReviewStatus.user_id == user_id) ), ) - .where(reduce(operator.and_, clauses)) + .where(reduce(operator.and_, clauses) if clauses else True) .group_by( (ReviewSegment.start_time + seconds_offset).cast("int") / day_in_seconds ) diff --git a/frigate/app.py b/frigate/app.py index f433fd50f..ac3e6d7da 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -55,7 +55,7 @@ from frigate.models import ( Timeline, User, ) -from frigate.object_detection import ObjectDetectProcess +from frigate.object_detection.base import ObjectDetectProcess from frigate.output.output import output_frames from frigate.ptz.autotrack import PtzAutoTrackerThread from frigate.ptz.onvif import OnvifController @@ -699,6 +699,10 @@ class FrigateApp: self.audio_process.terminate() self.audio_process.join() + # stop the onvif controller + if self.onvif_controller: + self.onvif_controller.close() + # ensure the capture processes are done for camera, metrics in self.camera_metrics.items(): capture_process = metrics.capture_process diff --git a/frigate/camera/state.py b/frigate/camera/state.py index 0e02c6c14..c307bea1e 100644 --- a/frigate/camera/state.py +++ b/frigate/camera/state.py @@ -5,7 +5,7 @@ import logging import os import threading from collections import defaultdict -from typing import Callable +from typing import Any, Callable import cv2 import numpy as np @@ -54,7 +54,7 @@ class CameraState: self.ptz_autotracker_thread = ptz_autotracker_thread self.prev_enabled = self.camera_config.enabled - def get_current_frame(self, draw_options={}): + def get_current_frame(self, draw_options: dict[str, Any] = {}): with self.current_frame_lock: frame_copy = np.copy(self._current_frame) frame_time = self.current_frame_time @@ -77,7 +77,9 @@ class CameraState: thickness = 1 else: thickness = 2 - color = self.config.model.colormap[obj["label"]] + color = self.config.model.colormap.get( + obj["label"], (255, 255, 255) + ) else: thickness = 1 color = (255, 0, 0) @@ -99,7 +101,9 @@ class CameraState: and obj["frame_time"] == frame_time ): thickness = 5 - color = self.config.model.colormap[obj["label"]] + color = self.config.model.colormap.get( + obj["label"], (255, 255, 255) + ) # debug autotracking zooming - show the zoom factor box if ( @@ -259,14 +263,37 @@ class CameraState: current_detections[id], ) + # add initial frame to frame cache + self.frame_cache[frame_time] = np.copy(current_frame) + + # save initial thumbnail data and best object + thumbnail_data = { + "frame_time": frame_time, + "box": new_obj.obj_data["box"], + "area": new_obj.obj_data["area"], + "region": new_obj.obj_data["region"], + "score": new_obj.obj_data["score"], + "attributes": new_obj.obj_data["attributes"], + "current_estimated_speed": 0, + "velocity_angle": 0, + "path_data": [], + "recognized_license_plate": None, + "recognized_license_plate_score": None, + } + new_obj.thumbnail_data = thumbnail_data + tracked_objects[id].thumbnail_data = thumbnail_data + self.best_objects[new_obj.obj_data["label"]] = new_obj + # call event handlers for c in self.callbacks["start"]: c(self.name, new_obj, frame_name) for id in updated_ids: updated_obj = tracked_objects[id] - thumb_update, significant_update, autotracker_update = updated_obj.update( - frame_time, current_detections[id], current_frame is not None + thumb_update, significant_update, path_update, autotracker_update = ( + updated_obj.update( + frame_time, current_detections[id], current_frame is not None + ) ) if autotracker_update or significant_update: @@ -285,11 +312,16 @@ class CameraState: # if it has been more than 5 seconds since the last thumb update # and the last update is greater than the last publish or - # the object has changed significantly + # the object has changed significantly or + # the object moved enough to update the path if ( - frame_time - updated_obj.last_published > 5 - and updated_obj.last_updated > updated_obj.last_published - ) or significant_update: + ( + frame_time - updated_obj.last_published > 5 + and updated_obj.last_updated > updated_obj.last_published + ) + or significant_update + or path_update + ): # call event handlers for c in self.callbacks["update"]: c(self.name, updated_obj, frame_name) @@ -306,7 +338,6 @@ class CameraState: # TODO: can i switch to looking this up and only changing when an event ends? # maintain best objects camera_activity: dict[str, list[any]] = { - "enabled": True, "motion": len(motion_boxes) > 0, "objects": [], } @@ -410,9 +441,13 @@ class CameraState: self.previous_frame_id = frame_name def save_manual_event_image( - self, event_id: str, label: str, draw: dict[str, list[dict]] + self, + frame: np.ndarray | None, + event_id: str, + label: str, + draw: dict[str, list[dict]], ) -> None: - img_frame = self.get_current_frame() + img_frame = frame if frame is not None else self.get_current_frame() # write clean snapshot if enabled if self.camera_config.snapshots.clean_copy: @@ -458,9 +493,9 @@ class CameraState: # create thumbnail with max height of 175 and save width = int(175 * img_frame.shape[1] / img_frame.shape[0]) thumb = cv2.resize(img_frame, dsize=(width, 175), interpolation=cv2.INTER_AREA) - cv2.imwrite( - os.path.join(THUMB_DIR, self.camera_config.name, f"{event_id}.webp"), thumb - ) + thumb_path = os.path.join(THUMB_DIR, self.camera_config.name) + os.makedirs(thumb_path, exist_ok=True) + cv2.imwrite(os.path.join(thumb_path, f"{event_id}.webp"), thumb) def shutdown(self) -> None: for obj in self.tracked_objects.values(): diff --git a/frigate/comms/detections_updater.py b/frigate/comms/detections_updater.py index a60bd0699..f585b570d 100644 --- a/frigate/comms/detections_updater.py +++ b/frigate/comms/detections_updater.py @@ -11,6 +11,7 @@ class DetectionTypeEnum(str, Enum): api = "api" video = "video" audio = "audio" + lpr = "lpr" class DetectionPublisher(Publisher): diff --git a/frigate/comms/dispatcher.py b/frigate/comms/dispatcher.py index 586b70cbb..87891ec88 100644 --- a/frigate/comms/dispatcher.py +++ b/frigate/comms/dispatcher.py @@ -135,6 +135,7 @@ class Dispatcher: "type": TrackedObjectUpdateTypesEnum.description, "id": event.id, "description": event.data["description"], + "camera": event.camera, } ), ) @@ -164,8 +165,12 @@ class Dispatcher: def handle_on_connect(): camera_status = self.camera_activity.last_camera_activity.copy() + cameras_with_status = camera_status.keys() + + for camera in self.config.cameras.keys(): + if camera not in cameras_with_status: + camera_status[camera] = {} - for camera in camera_status.keys(): camera_status[camera]["config"] = { "detect": self.config.cameras[camera].detect.enabled, "enabled": self.config.cameras[camera].enabled, diff --git a/frigate/comms/embeddings_updater.py b/frigate/comms/embeddings_updater.py index 61c2331cf..6c26af3d1 100644 --- a/frigate/comms/embeddings_updater.py +++ b/frigate/comms/embeddings_updater.py @@ -13,9 +13,11 @@ class EmbeddingsRequestEnum(Enum): embed_description = "embed_description" embed_thumbnail = "embed_thumbnail" generate_search = "generate_search" + recognize_face = "recognize_face" register_face = "register_face" reprocess_face = "reprocess_face" reprocess_plate = "reprocess_plate" + reindex = "reindex" class EmbeddingsResponder: diff --git a/frigate/comms/event_metadata_updater.py b/frigate/comms/event_metadata_updater.py index c702208bc..6adcaf4be 100644 --- a/frigate/comms/event_metadata_updater.py +++ b/frigate/comms/event_metadata_updater.py @@ -15,6 +15,8 @@ class EventMetadataTypeEnum(str, Enum): regenerate_description = "regenerate_description" sub_label = "sub_label" recognized_license_plate = "recognized_license_plate" + lpr_event_create = "lpr_event_create" + save_lpr_snapshot = "save_lpr_snapshot" class EventMetadataPublisher(Publisher): @@ -37,9 +39,6 @@ class EventMetadataSubscriber(Subscriber): def __init__(self, topic: EventMetadataTypeEnum) -> None: super().__init__(topic.value) - def check_for_update(self, timeout: float = 1) -> tuple | None: - return super().check_for_update(timeout) - def _return_object(self, topic: str, payload: tuple) -> tuple: if payload is None: return (None, None) diff --git a/frigate/comms/mqtt.py b/frigate/comms/mqtt.py index 316813518..e487b30ee 100644 --- a/frigate/comms/mqtt.py +++ b/frigate/comms/mqtt.py @@ -213,6 +213,8 @@ class MqttClient(Communicator): # type: ignore[misc] "motion_contour_area", "birdseye", "birdseye_mode", + "review_alerts", + "review_detections", ] for name in self.config.cameras.keys(): diff --git a/frigate/comms/webpush.py b/frigate/comms/webpush.py index b845c3afd..cbc274aef 100644 --- a/frigate/comms/webpush.py +++ b/frigate/comms/webpush.py @@ -303,6 +303,9 @@ class WebPushClient(Communicator): # type: ignore[misc] and len(payload["before"]["data"]["zones"]) == len(payload["after"]["data"]["zones"]) ): + logger.debug( + f"Skipping notification for {camera} - message is an update and important fields don't have an update" + ) return self.last_camera_notification_time[camera] = current_time @@ -325,6 +328,8 @@ class WebPushClient(Communicator): # type: ignore[misc] direct_url = f"/review?id={reviewId}" if state == "end" else f"/#{camera}" ttl = 3600 if state == "end" else 0 + logger.debug(f"Sending push notification for {camera}, review ID {reviewId}") + for user in self.web_pushers: self.send_push_notification( user=user, diff --git a/frigate/comms/zmq_proxy.py b/frigate/comms/zmq_proxy.py index 1661cfcc5..6a90d6887 100644 --- a/frigate/comms/zmq_proxy.py +++ b/frigate/comms/zmq_proxy.py @@ -6,6 +6,8 @@ from typing import Optional import zmq +from frigate.const import FAST_QUEUE_TIMEOUT + SOCKET_PUB = "ipc:///tmp/cache/proxy_pub" SOCKET_SUB = "ipc:///tmp/cache/proxy_sub" @@ -77,7 +79,9 @@ class Subscriber: self.socket.setsockopt_string(zmq.SUBSCRIBE, self.topic) self.socket.connect(SOCKET_SUB) - def check_for_update(self, timeout: float = 1) -> Optional[tuple[str, any]]: + def check_for_update( + self, timeout: float = FAST_QUEUE_TIMEOUT + ) -> Optional[tuple[str, any]]: """Returns message or None if no update.""" try: has_update, _, _ = zmq.select([self.socket], [], [], timeout) diff --git a/frigate/config/camera/camera.py b/frigate/config/camera/camera.py index 2d928661e..3b24dabac 100644 --- a/frigate/config/camera/camera.py +++ b/frigate/config/camera/camera.py @@ -1,4 +1,5 @@ import os +from enum import Enum from typing import Optional from pydantic import Field, PrivateAttr @@ -17,6 +18,10 @@ from frigate.util.builtin import ( ) from ..base import FrigateBaseModel +from ..classification import ( + CameraFaceRecognitionConfig, + CameraLicensePlateRecognitionConfig, +) from .audio import AudioConfig from .birdseye import BirdseyeCameraConfig from .detect import DetectConfig @@ -38,6 +43,11 @@ from .zone import ZoneConfig __all__ = ["CameraConfig"] +class CameraTypeEnum(str, Enum): + generic = "generic" + lpr = "lpr" + + class CameraConfig(FrigateBaseModel): name: Optional[str] = Field(None, title="Camera name.", pattern=REGEX_CAMERA_NAME) enabled: bool = Field(default=True, title="Enable camera.") @@ -52,6 +62,9 @@ class CameraConfig(FrigateBaseModel): detect: DetectConfig = Field( default_factory=DetectConfig, title="Object detection configuration." ) + face_recognition: CameraFaceRecognitionConfig = Field( + default_factory=CameraFaceRecognitionConfig, title="Face recognition config." + ) ffmpeg: CameraFfmpegConfig = Field(title="FFmpeg configuration for the camera.") genai: GenAICameraConfig = Field( default_factory=GenAICameraConfig, title="Generative AI configuration." @@ -59,6 +72,9 @@ class CameraConfig(FrigateBaseModel): live: CameraLiveConfig = Field( default_factory=CameraLiveConfig, title="Live playback settings." ) + lpr: CameraLicensePlateRecognitionConfig = Field( + default_factory=CameraLicensePlateRecognitionConfig, title="LPR config." + ) motion: Optional[MotionConfig] = Field( None, title="Motion detection configuration." ) @@ -92,6 +108,7 @@ class CameraConfig(FrigateBaseModel): onvif: OnvifConfig = Field( default_factory=OnvifConfig, title="Camera Onvif Configuration." ) + type: CameraTypeEnum = Field(default=CameraTypeEnum.generic, title="Camera Type") ui: CameraUiConfig = Field( default_factory=CameraUiConfig, title="Camera UI Modifications." ) diff --git a/frigate/config/camera/onvif.py b/frigate/config/camera/onvif.py index ff34e2a10..d4955799b 100644 --- a/frigate/config/camera/onvif.py +++ b/frigate/config/camera/onvif.py @@ -63,9 +63,9 @@ class PtzAutotrackConfig(FrigateBaseModel): else: raise ValueError("Invalid type for movement_weights") - if len(weights) != 5: + if len(weights) != 6: raise ValueError( - "movement_weights must have exactly 5 floats, remove this line from your config and run autotracking calibration" + "movement_weights must have exactly 6 floats, remove this line from your config and run autotracking calibration" ) return weights diff --git a/frigate/config/classification.py b/frigate/config/classification.py index 30cd12b7c..7f4f39bbd 100644 --- a/frigate/config/classification.py +++ b/frigate/config/classification.py @@ -1,11 +1,13 @@ from enum import Enum from typing import Dict, List, Optional -from pydantic import Field +from pydantic import ConfigDict, Field from .base import FrigateBaseModel __all__ = [ + "CameraFaceRecognitionConfig", + "CameraLicensePlateRecognitionConfig", "FaceRecognitionConfig", "SemanticSearchConfig", "LicensePlateRecognitionConfig", @@ -17,6 +19,11 @@ class SemanticSearchModelEnum(str, Enum): jinav2 = "jinav2" +class LPRDeviceEnum(str, Enum): + GPU = "GPU" + CPU = "CPU" + + class BirdClassificationConfig(FrigateBaseModel): enabled: bool = Field(default=False, title="Enable bird classification.") threshold: float = Field( @@ -49,8 +56,11 @@ class SemanticSearchConfig(FrigateBaseModel): class FaceRecognitionConfig(FrigateBaseModel): enabled: bool = Field(default=False, title="Enable face recognition.") - min_score: float = Field( - title="Minimum face distance score required to save the attempt.", + model_size: str = Field( + default="small", title="The size of the embeddings model used." + ) + unknown_score: float = Field( + title="Minimum face distance score required to be marked as a potential match.", default=0.8, gt=0.0, le=1.0, @@ -70,16 +80,32 @@ class FaceRecognitionConfig(FrigateBaseModel): min_area: int = Field( default=500, title="Min area of face box to consider running face recognition." ) - save_attempts: bool = Field( - default=True, title="Save images of face detections for training." + save_attempts: int = Field( + default=100, ge=0, title="Number of face attempts to save in the train tab." ) blur_confidence_filter: bool = Field( default=True, title="Apply blur quality filter to face confidence." ) +class CameraFaceRecognitionConfig(FrigateBaseModel): + enabled: bool = Field(default=False, title="Enable face recognition.") + min_area: int = Field( + default=500, title="Min area of face box to consider running face recognition." + ) + + model_config = ConfigDict(extra="forbid", protected_namespaces=()) + + class LicensePlateRecognitionConfig(FrigateBaseModel): enabled: bool = Field(default=False, title="Enable license plate recognition.") + device: Optional[LPRDeviceEnum] = Field( + default=LPRDeviceEnum.CPU, + title="The device used for license plate recognition.", + ) + model_size: str = Field( + default="small", title="The size of the embeddings model used." + ) detection_threshold: float = Field( default=0.7, title="License plate object confidence score required to begin running recognition.", @@ -112,3 +138,34 @@ class LicensePlateRecognitionConfig(FrigateBaseModel): known_plates: Optional[Dict[str, List[str]]] = Field( default={}, title="Known plates to track (strings or regular expressions)." ) + enhancement: int = Field( + default=0, + title="Amount of contrast adjustment and denoising to apply to license plate images before recognition.", + ge=0, + le=10, + ) + debug_save_plates: bool = Field( + default=False, + title="Save plates captured for LPR for debugging purposes.", + ) + + +class CameraLicensePlateRecognitionConfig(FrigateBaseModel): + enabled: bool = Field(default=False, title="Enable license plate recognition.") + expire_time: int = Field( + default=3, + title="Expire plates not seen after number of seconds (for dedicated LPR cameras only).", + gt=0, + ) + min_area: int = Field( + default=1000, + title="Minimum area of license plate to begin running recognition.", + ) + enhancement: int = Field( + default=0, + title="Amount of contrast adjustment and denoising to apply to license plate images before recognition.", + ge=0, + le=10, + ) + + model_config = ConfigDict(extra="forbid", protected_namespaces=()) diff --git a/frigate/config/config.py b/frigate/config/config.py index 633aef803..2470818b0 100644 --- a/frigate/config/config.py +++ b/frigate/config/config.py @@ -292,13 +292,30 @@ def verify_autotrack_zones(camera_config: CameraConfig) -> ValueError | None: def verify_motion_and_detect(camera_config: CameraConfig) -> ValueError | None: - """Verify that required_zones are specified when autotracking is enabled.""" + """Verify that motion detection is not disabled and object detection is enabled.""" if camera_config.detect.enabled and not camera_config.motion.enabled: raise ValueError( f"Camera {camera_config.name} has motion detection disabled and object detection enabled but object detection requires motion detection." ) +def verify_lpr_and_face( + frigate_config: FrigateConfig, camera_config: CameraConfig +) -> ValueError | None: + """Verify that lpr and face are enabled at the global level if enabled at the camera level.""" + if camera_config.lpr.enabled and not frigate_config.lpr.enabled: + raise ValueError( + f"Camera {camera_config.name} has lpr enabled but lpr is disabled at the global level of the config. You must enable lpr at the global level." + ) + if ( + camera_config.face_recognition.enabled + and not frigate_config.face_recognition.enabled + ): + raise ValueError( + f"Camera {camera_config.name} has face_recognition enabled but face_recognition is disabled at the global level of the config. You must enable face_recognition at the global level." + ) + + class FrigateConfig(FrigateBaseModel): version: Optional[str] = Field(default=None, title="Current config version.") @@ -331,19 +348,6 @@ class FrigateConfig(FrigateBaseModel): default_factory=TelemetryConfig, title="Telemetry configuration." ) tls: TlsConfig = Field(default_factory=TlsConfig, title="TLS configuration.") - classification: ClassificationConfig = Field( - default_factory=ClassificationConfig, title="Object classification config." - ) - semantic_search: SemanticSearchConfig = Field( - default_factory=SemanticSearchConfig, title="Semantic search configuration." - ) - face_recognition: FaceRecognitionConfig = Field( - default_factory=FaceRecognitionConfig, title="Face recognition config." - ) - lpr: LicensePlateRecognitionConfig = Field( - default_factory=LicensePlateRecognitionConfig, - title="License Plate recognition config.", - ) ui: UIConfig = Field(default_factory=UIConfig, title="UI configuration.") # Detector config @@ -395,6 +399,21 @@ class FrigateConfig(FrigateBaseModel): title="Global timestamp style configuration.", ) + # Classification Config + classification: ClassificationConfig = Field( + default_factory=ClassificationConfig, title="Object classification config." + ) + semantic_search: SemanticSearchConfig = Field( + default_factory=SemanticSearchConfig, title="Semantic search configuration." + ) + face_recognition: FaceRecognitionConfig = Field( + default_factory=FaceRecognitionConfig, title="Face recognition config." + ) + lpr: LicensePlateRecognitionConfig = Field( + default_factory=LicensePlateRecognitionConfig, + title="License Plate recognition config.", + ) + camera_groups: Dict[str, CameraGroupConfig] = Field( default_factory=dict, title="Camera group configuration" ) @@ -435,6 +454,8 @@ class FrigateConfig(FrigateBaseModel): include={ "audio": ..., "birdseye": ..., + "face_recognition": ..., + "lpr": ..., "record": ..., "snapshots": ..., "live": ..., @@ -451,8 +472,24 @@ class FrigateConfig(FrigateBaseModel): ) for name, camera in self.cameras.items(): + modified_global_config = global_config.copy() + + # only populate some fields down to the camera level for specific keys + allowed_fields_map = { + "face_recognition": ["enabled", "min_area"], + "lpr": ["enabled", "expire_time", "min_area", "enhancement"], + } + + for section in allowed_fields_map: + if section in modified_global_config: + modified_global_config[section] = { + k: v + for k, v in modified_global_config[section].items() + if k in allowed_fields_map[section] + } + merged_config = deep_merge( - camera.model_dump(exclude_unset=True), global_config + camera.model_dump(exclude_unset=True), modified_global_config ) camera_config: CameraConfig = CameraConfig.model_validate( {"name": name, **merged_config} @@ -492,10 +529,14 @@ class FrigateConfig(FrigateBaseModel): ) # Warn if detect fps > 10 - if camera_config.detect.fps > 10: + if camera_config.detect.fps > 10 and camera_config.type != "lpr": logger.warning( f"{camera_config.name} detect fps is set to {camera_config.detect.fps}. This does NOT need to match your camera's frame rate. High values could lead to reduced performance. Recommended value is 5." ) + if camera_config.detect.fps > 15 and camera_config.type == "lpr": + logger.warning( + f"{camera_config.name} detect fps is set to {camera_config.detect.fps}. This does NOT need to match your camera's frame rate. High values could lead to reduced performance. Recommended value for LPR cameras are between 5-15." + ) # Default min_initialized configuration min_initialized = int(camera_config.detect.fps / 2) @@ -603,11 +644,17 @@ class FrigateConfig(FrigateBaseModel): verify_required_zones_exist(camera_config) verify_autotrack_zones(camera_config) verify_motion_and_detect(camera_config) + verify_lpr_and_face(self, camera_config) self.objects.parse_all_objects(self.cameras) self.model.create_colormap(sorted(self.objects.all_objects)) self.model.check_and_load_plus_model(self.plus_api) + if self.plus_api and not self.snapshots.clean_copy: + logger.warning( + "Frigate+ is configured but clean snapshots are not enabled, submissions to Frigate+ will not be possible./" + ) + for key, detector in self.detectors.items(): adapter = TypeAdapter(DetectorConfig) model_dict = ( diff --git a/frigate/config/proxy.py b/frigate/config/proxy.py index df8a665fb..ef1529f9e 100644 --- a/frigate/config/proxy.py +++ b/frigate/config/proxy.py @@ -30,3 +30,6 @@ class ProxyConfig(FrigateBaseModel): default=None, title="Secret value for proxy authentication.", ) + default_role: Optional[str] = Field( + default="viewer", title="Default role for proxy users." + ) diff --git a/frigate/const.py b/frigate/const.py index ffd1ca406..183506a04 100644 --- a/frigate/const.py +++ b/frigate/const.py @@ -38,6 +38,7 @@ DEFAULT_ATTRIBUTE_LABEL_MAP = { "ups", "usps", ], + "motorcycle": ["license_plate"], } LABEL_CONSOLIDATION_MAP = { "car": 0.8, @@ -128,3 +129,7 @@ AUTOTRACKING_ZOOM_EDGE_THRESHOLD = 0.05 JWT_SECRET_ENV_VAR = "FRIGATE_JWT_SECRET" PASSWORD_HASH_ALGORITHM = "pbkdf2_sha256" + +# Queues + +FAST_QUEUE_TIMEOUT = 0.00001 # seconds diff --git a/frigate/data_processing/common/face/model.py b/frigate/data_processing/common/face/model.py new file mode 100644 index 000000000..0aeb76792 --- /dev/null +++ b/frigate/data_processing/common/face/model.py @@ -0,0 +1,370 @@ +import logging +import os +import queue +import threading +from abc import ABC, abstractmethod + +import cv2 +import numpy as np +from scipy import stats + +from frigate.config import FrigateConfig +from frigate.const import MODEL_CACHE_DIR +from frigate.embeddings.onnx.face_embedding import ArcfaceEmbedding, FaceNetEmbedding + +logger = logging.getLogger(__name__) + + +class FaceRecognizer(ABC): + """Face recognition runner.""" + + def __init__(self, config: FrigateConfig) -> None: + self.config = config + self.landmark_detector: cv2.face.FacemarkLBF = None + self.init_landmark_detector() + + @abstractmethod + def build(self) -> None: + """Build face recognition model.""" + pass + + @abstractmethod + def clear(self) -> None: + """Clear current built model.""" + pass + + @abstractmethod + def classify(self, face_image: np.ndarray) -> tuple[str, float] | None: + pass + + def init_landmark_detector(self) -> None: + landmark_model = os.path.join(MODEL_CACHE_DIR, "facedet/landmarkdet.yaml") + + if os.path.exists(landmark_model): + self.landmark_detector = cv2.face.createFacemarkLBF() + self.landmark_detector.loadModel(landmark_model) + + def align_face( + self, + image: np.ndarray, + output_width: int, + output_height: int, + ) -> np.ndarray: + # landmark is run on grayscale images + + if image.ndim == 3: + land_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) + else: + land_image = image + + _, lands = self.landmark_detector.fit( + land_image, np.array([(0, 0, land_image.shape[1], land_image.shape[0])]) + ) + landmarks: np.ndarray = lands[0][0] + + # get landmarks for eyes + leftEyePts = landmarks[42:48] + rightEyePts = landmarks[36:42] + + # compute the center of mass for each eye + leftEyeCenter = leftEyePts.mean(axis=0).astype("int") + rightEyeCenter = rightEyePts.mean(axis=0).astype("int") + + # compute the angle between the eye centroids + dY = rightEyeCenter[1] - leftEyeCenter[1] + dX = rightEyeCenter[0] - leftEyeCenter[0] + angle = np.degrees(np.arctan2(dY, dX)) - 180 + + # compute the desired right eye x-coordinate based on the + # desired x-coordinate of the left eye + desiredRightEyeX = 1.0 - 0.35 + + # determine the scale of the new resulting image by taking + # the ratio of the distance between eyes in the *current* + # image to the ratio of distance between eyes in the + # *desired* image + dist = np.sqrt((dX**2) + (dY**2)) + desiredDist = desiredRightEyeX - 0.35 + desiredDist *= output_width + scale = desiredDist / dist + + # compute center (x, y)-coordinates (i.e., the median point) + # between the two eyes in the input image + # grab the rotation matrix for rotating and scaling the face + eyesCenter = ( + int((leftEyeCenter[0] + rightEyeCenter[0]) // 2), + int((leftEyeCenter[1] + rightEyeCenter[1]) // 2), + ) + M = cv2.getRotationMatrix2D(eyesCenter, angle, scale) + + # update the translation component of the matrix + tX = output_width * 0.5 + tY = output_height * 0.35 + M[0, 2] += tX - eyesCenter[0] + M[1, 2] += tY - eyesCenter[1] + + # apply the affine transformation + return cv2.warpAffine( + image, M, (output_width, output_height), flags=cv2.INTER_CUBIC + ) + + def get_blur_factor(self, input: np.ndarray) -> float: + """Calculates the factor for the confidence based on the blur of the image.""" + if not self.config.face_recognition.blur_confidence_filter: + return 1.0 + + variance = cv2.Laplacian(input, cv2.CV_64F).var() + + if variance < 60: # image is very blurry + return 0.96 + elif variance < 70: # image moderately blurry + return 0.98 + elif variance < 80: # image is slightly blurry + return 0.99 + else: + return 1.0 + + +def similarity_to_confidence( + cosine_similarity: float, median=0.3, range_width=0.6, slope_factor=12 +): + """ + Default sigmoid function to map cosine similarity to confidence. + + Args: + cosine_similarity (float): The input cosine similarity. + median (float): Assumed median of cosine similarity distribution. + range_width (float): Assumed range of cosine similarity distribution (90th percentile - 10th percentile). + slope_factor (float): Adjusts the steepness of the curve. + + Returns: + float: The confidence score. + """ + + # Calculate slope and bias + slope = slope_factor / range_width + bias = median + + # Calculate confidence + confidence = 1 / (1 + np.exp(-slope * (cosine_similarity - bias))) + return confidence + + +class FaceNetRecognizer(FaceRecognizer): + def __init__(self, config: FrigateConfig): + super().__init__(config) + self.mean_embs: dict[int, np.ndarray] = {} + self.face_embedder: FaceNetEmbedding = FaceNetEmbedding() + self.model_builder_queue: queue.Queue | None = None + + def clear(self) -> None: + self.mean_embs = {} + + def run_build_task(self) -> None: + self.model_builder_queue = queue.Queue() + + def build_model(): + face_embeddings_map: dict[str, list[np.ndarray]] = {} + idx = 0 + + dir = "/media/frigate/clips/faces" + for name in os.listdir(dir): + if name == "train": + continue + + face_folder = os.path.join(dir, name) + + if not os.path.isdir(face_folder): + continue + + face_embeddings_map[name] = [] + for image in os.listdir(face_folder): + img = cv2.imread(os.path.join(face_folder, image)) + + if img is None: + continue + + img = self.align_face(img, img.shape[1], img.shape[0]) + emb = self.face_embedder([img])[0].squeeze() + face_embeddings_map[name].append(emb) + + idx += 1 + + self.model_builder_queue.put(face_embeddings_map) + + thread = threading.Thread(target=build_model, daemon=True) + thread.start() + + def build(self): + if not self.landmark_detector: + self.init_landmark_detector() + return None + + if self.model_builder_queue is not None: + try: + face_embeddings_map: dict[str, list[np.ndarray]] = ( + self.model_builder_queue.get(timeout=0.1) + ) + self.model_builder_queue = None + except queue.Empty: + return + else: + self.run_build_task() + return + + if not face_embeddings_map: + return + + for name, embs in face_embeddings_map.items(): + if embs: + self.mean_embs[name] = stats.trim_mean(embs, 0.15) + + logger.debug("Finished building ArcFace model") + + def classify(self, face_image): + if not self.landmark_detector: + return None + + if not self.mean_embs: + self.build() + + if not self.mean_embs: + return None + + # face recognition is best run on grayscale images + + # get blur factor before aligning face + blur_factor = self.get_blur_factor(face_image) + logger.debug(f"face detected with blurriness {blur_factor}") + + # align face and run recognition + img = self.align_face(face_image, face_image.shape[1], face_image.shape[0]) + embedding = self.face_embedder([img])[0].squeeze() + + score = 0 + label = "" + + for name, mean_emb in self.mean_embs.items(): + dot_product = np.dot(embedding, mean_emb) + magnitude_A = np.linalg.norm(embedding) + magnitude_B = np.linalg.norm(mean_emb) + + cosine_similarity = dot_product / (magnitude_A * magnitude_B) + confidence = similarity_to_confidence( + cosine_similarity, median=0.5, range_width=0.6 + ) + + if confidence > score: + score = confidence + label = name + + return label, round(score * blur_factor, 2) + + +class ArcFaceRecognizer(FaceRecognizer): + def __init__(self, config: FrigateConfig): + super().__init__(config) + self.mean_embs: dict[int, np.ndarray] = {} + self.face_embedder: ArcfaceEmbedding = ArcfaceEmbedding() + self.model_builder_queue: queue.Queue | None = None + + def clear(self) -> None: + self.mean_embs = {} + + def run_build_task(self) -> None: + self.model_builder_queue = queue.Queue() + + def build_model(): + face_embeddings_map: dict[str, list[np.ndarray]] = {} + idx = 0 + + dir = "/media/frigate/clips/faces" + for name in os.listdir(dir): + if name == "train": + continue + + face_folder = os.path.join(dir, name) + + if not os.path.isdir(face_folder): + continue + + face_embeddings_map[name] = [] + for image in os.listdir(face_folder): + img = cv2.imread(os.path.join(face_folder, image)) + + if img is None: + continue + + img = self.align_face(img, img.shape[1], img.shape[0]) + emb = self.face_embedder([img])[0].squeeze() + face_embeddings_map[name].append(emb) + + idx += 1 + + self.model_builder_queue.put(face_embeddings_map) + + thread = threading.Thread(target=build_model, daemon=True) + thread.start() + + def build(self): + if not self.landmark_detector: + self.init_landmark_detector() + return None + + if self.model_builder_queue is not None: + try: + face_embeddings_map: dict[str, list[np.ndarray]] = ( + self.model_builder_queue.get(timeout=0.1) + ) + self.model_builder_queue = None + except queue.Empty: + return + else: + self.run_build_task() + return + + if not face_embeddings_map: + return + + for name, embs in face_embeddings_map.items(): + if embs: + self.mean_embs[name] = stats.trim_mean(embs, 0.15) + + logger.debug("Finished building ArcFace model") + + def classify(self, face_image): + if not self.landmark_detector: + return None + + if not self.mean_embs: + self.build() + + if not self.mean_embs: + return None + + # face recognition is best run on grayscale images + + # get blur factor before aligning face + blur_factor = self.get_blur_factor(face_image) + logger.debug(f"face detected with blurriness {blur_factor}") + + # align face and run recognition + img = self.align_face(face_image, face_image.shape[1], face_image.shape[0]) + embedding = self.face_embedder([img])[0].squeeze() + + score = 0 + label = "" + + for name, mean_emb in self.mean_embs.items(): + dot_product = np.dot(embedding, mean_emb) + magnitude_A = np.linalg.norm(embedding) + magnitude_B = np.linalg.norm(mean_emb) + + cosine_similarity = dot_product / (magnitude_A * magnitude_B) + confidence = similarity_to_confidence(cosine_similarity) + + if confidence > score: + score = confidence + label = name + + return label, round(score * blur_factor, 2) diff --git a/frigate/data_processing/common/license_plate/mixin.py b/frigate/data_processing/common/license_plate/mixin.py index c07163819..e94c1b564 100644 --- a/frigate/data_processing/common/license_plate/mixin.py +++ b/frigate/data_processing/common/license_plate/mixin.py @@ -1,18 +1,31 @@ """Handle processing images for face detection and recognition.""" +import base64 import datetime +import json import logging import math +import os +import random import re +import string +from pathlib import Path from typing import List, Optional, Tuple import cv2 import numpy as np -from Levenshtein import distance +from Levenshtein import distance, jaro_winkler from pyclipper import ET_CLOSEDPOLYGON, JT_ROUND, PyclipperOffset from shapely.geometry import Polygon -from frigate.comms.event_metadata_updater import EventMetadataTypeEnum +from frigate.comms.event_metadata_updater import ( + EventMetadataPublisher, + EventMetadataTypeEnum, +) +from frigate.const import CLIPS_DIR +from frigate.embeddings.onnx.lpr_embedding import LPR_EMBEDDING_SIZE +from frigate.types import TrackedObjectUpdateTypesEnum +from frigate.util.builtin import EventsPerSecond, InferenceSpeed from frigate.util.image import area logger = logging.getLogger(__name__) @@ -23,13 +36,14 @@ WRITE_DEBUG_IMAGES = False class LicensePlateProcessingMixin: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - - self.requires_license_plate_detection = ( - "license_plate" not in self.config.objects.all_objects - ) - + self.plate_rec_speed = InferenceSpeed(self.metrics.alpr_speed) + self.plates_rec_second = EventsPerSecond() + self.plates_rec_second.start() + self.plate_det_speed = InferenceSpeed(self.metrics.yolov9_lpr_speed) + self.plates_det_second = EventsPerSecond() + self.plates_det_second.start() + self.event_metadata_publisher = EventMetadataPublisher() self.ctc_decoder = CTCDecoder() - self.batch_size = 6 # Detection specific parameters @@ -38,9 +52,12 @@ class LicensePlateProcessingMixin: self.box_thresh = 0.6 self.mask_thresh = 0.6 + # matching + self.similarity_threshold = 0.8 + def _detect(self, image: np.ndarray) -> List[np.ndarray]: """ - Detect possible license plates in the input image by first resizing and normalizing it, + Detect possible areas of text in the input image by first resizing and normalizing it, running a detection model, and filtering out low-probability regions. Args: @@ -64,9 +81,21 @@ class LicensePlateProcessingMixin: resized_image, ) - outputs = self.model_runner.detection_model([normalized_image])[0] + try: + outputs = self.model_runner.detection_model([normalized_image])[0] + except Exception as e: + logger.warning(f"Error running LPR box detection model: {e}") + return [] + outputs = outputs[0, :, :] + if False: + current_time = int(datetime.datetime.now().timestamp()) + cv2.imwrite( + f"debug/frames/probability_map_{current_time}.jpg", + (outputs * 255).astype(np.uint8), + ) + boxes, _ = self._boxes_from_bitmap(outputs, outputs > self.mask_thresh, w, h) return self._filter_polygon(boxes, (h, w)) @@ -93,12 +122,16 @@ class LicensePlateProcessingMixin: norm_img = norm_img[np.newaxis, :] norm_images.append(norm_img) - outputs = self.model_runner.classification_model(norm_images) + try: + outputs = self.model_runner.classification_model(norm_images) + except Exception as e: + logger.warning(f"Error running LPR classification model: {e}") + return return self._process_classification_output(images, outputs) def _recognize( - self, images: List[np.ndarray] + self, camera: string, images: List[np.ndarray] ) -> Tuple[List[str], List[List[float]]]: """ Recognize the characters on the detected license plates using the recognition model. @@ -112,9 +145,6 @@ class LicensePlateProcessingMixin: input_shape = [3, 48, 320] num_images = len(images) - # sort images by aspect ratio for processing - indices = np.argsort(np.array([x.shape[1] / x.shape[0] for x in images])) - for index in range(0, num_images, self.batch_size): input_h, input_w = input_shape[1], input_shape[2] max_wh_ratio = input_w / input_h @@ -122,31 +152,38 @@ class LicensePlateProcessingMixin: # calculate the maximum aspect ratio in the current batch for i in range(index, min(num_images, index + self.batch_size)): - h, w = images[indices[i]].shape[0:2] + h, w = images[i].shape[0:2] max_wh_ratio = max(max_wh_ratio, w * 1.0 / h) # preprocess the images based on the max aspect ratio for i in range(index, min(num_images, index + self.batch_size)): norm_image = self._preprocess_recognition_image( - images[indices[i]], max_wh_ratio + camera, images[i], max_wh_ratio ) norm_image = norm_image[np.newaxis, :] norm_images.append(norm_image) - outputs = self.model_runner.recognition_model(norm_images) + try: + outputs = self.model_runner.recognition_model(norm_images) + except Exception as e: + logger.warning(f"Error running LPR recognition model: {e}") return self.ctc_decoder(outputs) def _process_license_plate( - self, image: np.ndarray - ) -> Tuple[List[str], List[float], List[int]]: + self, camera: str, id: str, image: np.ndarray + ) -> Tuple[List[str], List[List[float]], List[int]]: """ Complete pipeline for detecting, classifying, and recognizing license plates in the input image. + Combines multi-line plates into a single plate string, grouping boxes by vertical alignment and ordering top to bottom, + but only combines boxes if their average confidence scores meet the threshold and their heights are similar. Args: + camera (str): Camera identifier. + id (str): Event identifier. image (np.ndarray): The input image in which to detect, classify, and recognize license plates. Returns: - Tuple[List[str], List[float], List[int]]: Detected license plate texts, confidence scores, and areas of the plates. + Tuple[List[str], List[List[float]], List[int]]: Detected license plate texts, character-level confidence scores for each plate (flattened into a single list per plate), and areas of the plates. """ if ( self.model_runner.detection_model.runner is None @@ -162,56 +199,173 @@ class LicensePlateProcessingMixin: logger.debug("No boxes found by OCR detector model") return [], [], [] - boxes = self._sort_boxes(list(boxes)) - plate_images = [self._crop_license_plate(image, x) for x in boxes] + if len(boxes) > 0: + plate_left = np.min([np.min(box[:, 0]) for box in boxes]) + plate_right = np.max([np.max(box[:, 0]) for box in boxes]) + plate_width = plate_right - plate_left + else: + plate_width = 0 + boxes = self._merge_nearby_boxes( + boxes, plate_width=plate_width, gap_fraction=0.1 + ) + + current_time = int(datetime.datetime.now().timestamp()) if WRITE_DEBUG_IMAGES: - current_time = int(datetime.datetime.now().timestamp()) - for i, img in enumerate(plate_images): - cv2.imwrite( - f"debug/frames/license_plate_cropped_{current_time}_{i + 1}.jpg", - img, + debug_image = image.copy() + for box in boxes: + box = box.astype(int) + x_min, y_min = np.min(box[:, 0]), np.min(box[:, 1]) + x_max, y_max = np.max(box[:, 0]), np.max(box[:, 1]) + cv2.rectangle( + debug_image, + (x_min, y_min), + (x_max, y_max), + color=(0, 255, 0), + thickness=2, ) - # keep track of the index of each image for correct area calc later - sorted_indices = np.argsort([x.shape[1] / x.shape[0] for x in plate_images]) - reverse_mapping = { - idx: original_idx for original_idx, idx in enumerate(sorted_indices) - } + cv2.imwrite( + f"debug/frames/license_plate_boxes_{current_time}.jpg", debug_image + ) - results, confidences = self._recognize(plate_images) + boxes = self._sort_boxes(list(boxes)) - if results: - license_plates = [""] * len(plate_images) - average_confidences = [[0.0]] * len(plate_images) - areas = [0] * len(plate_images) + # Step 1: Compute box heights and group boxes by vertical alignment and height similarity + box_info = [] + for i, box in enumerate(boxes): + y_coords = box[:, 1] + y_min, y_max = np.min(y_coords), np.max(y_coords) + height = y_max - y_min + box_info.append((y_min, y_max, height, i)) - # map results back to original image order - for i, (plate, conf) in enumerate(zip(results, confidences)): - original_idx = reverse_mapping[i] + # Initial grouping based on y-coordinate overlap and height similarity + initial_groups = [] + current_group = [box_info[0]] + height_tolerance = 0.25 # Allow 25% difference in height for grouping - height, width = plate_images[original_idx].shape[:2] - area = height * width + for i in range(1, len(box_info)): + prev_y_min, prev_y_max, prev_height, _ = current_group[-1] + curr_y_min, _, curr_height, _ = box_info[i] - average_confidence = conf + # Check y-coordinate overlap + overlap_threshold = 0.1 * (prev_y_max - prev_y_min) + overlaps = curr_y_min <= prev_y_max + overlap_threshold - # set to True to write each cropped image for debugging - if False: - save_image = cv2.cvtColor( - plate_images[original_idx], cv2.COLOR_RGB2BGR + # Check height similarity + height_ratio = min(prev_height, curr_height) / max(prev_height, curr_height) + height_similar = height_ratio >= (1 - height_tolerance) + + if overlaps and height_similar: + current_group.append(box_info[i]) + else: + initial_groups.append(current_group) + current_group = [box_info[i]] + initial_groups.append(current_group) + + # Step 2: Process each initial group, filter by confidence + all_license_plates = [] + all_confidences = [] + all_areas = [] + processed_indices = set() + + recognition_threshold = self.lpr_config.recognition_threshold + + for group in initial_groups: + # Sort group by y-coordinate (top to bottom) + group.sort(key=lambda x: x[0]) + group_indices = [item[3] for item in group] + + # Skip if all indices in this group have already been processed + if all(idx in processed_indices for idx in group_indices): + continue + + # Crop images for the group + group_boxes = [boxes[i] for i in group_indices] + group_plate_images = [ + self._crop_license_plate(image, box) for box in group_boxes + ] + + if WRITE_DEBUG_IMAGES: + for i, img in enumerate(group_plate_images): + cv2.imwrite( + f"debug/frames/license_plate_cropped_{current_time}_{group_indices[i] + 1}.jpg", + img, ) - filename = f"debug/frames/plate_{original_idx}_{plate}_{area}.jpg" - cv2.imwrite(filename, save_image) - license_plates[original_idx] = plate - average_confidences[original_idx] = average_confidence - areas[original_idx] = area + if self.config.lpr.debug_save_plates: + logger.debug(f"{camera}: Saving plates for event {id}") + Path(os.path.join(CLIPS_DIR, f"lpr/{camera}/{id}")).mkdir( + parents=True, exist_ok=True + ) + for i, img in enumerate(group_plate_images): + cv2.imwrite( + os.path.join( + CLIPS_DIR, + f"lpr/{camera}/{id}/{current_time}_{group_indices[i] + 1}.jpg", + ), + img, + ) - # Filter out plates that have a length of less than min_plate_length characters - # or that don't match the expected format (if defined) - # Sort by area, then by plate length, then by confidence all desc + # Recognize text in each cropped image + results, confidences = self._recognize(camera, group_plate_images) + + if not results: + continue + + if not confidences: + confidences = [[0.0] for _ in results] + + # Compute average confidence for each box's recognized text + avg_confidences = [] + for conf_list in confidences: + avg_conf = sum(conf_list) / len(conf_list) if conf_list else 0.0 + avg_confidences.append(avg_conf) + + # Filter boxes based on the recognition threshold + qualifying_indices = [] + qualifying_results = [] + qualifying_confidences = [] + for i, (avg_conf, result, conf_list) in enumerate( + zip(avg_confidences, results, confidences) + ): + if avg_conf >= recognition_threshold: + qualifying_indices.append(group_indices[i]) + qualifying_results.append(result) + qualifying_confidences.append(conf_list) + + if not qualifying_results: + continue + + processed_indices.update(qualifying_indices) + + # Combine the qualifying results into a single plate string + combined_plate = " ".join(qualifying_results) + + flat_confidences = [ + conf for conf_list in qualifying_confidences for conf in conf_list + ] + + # Compute the combined area for qualifying boxes + qualifying_boxes = [boxes[i] for i in qualifying_indices] + qualifying_plate_images = [ + self._crop_license_plate(image, box) for box in qualifying_boxes + ] + group_areas = [ + img.shape[0] * img.shape[1] for img in qualifying_plate_images + ] + combined_area = sum(group_areas) + + all_license_plates.append(combined_plate) + all_confidences.append(flat_confidences) + all_areas.append(combined_area) + + # Step 3: Filter and sort the combined plates + if all_license_plates: filtered_data = [] - for plate, conf, area in zip(license_plates, average_confidences, areas): + for plate, conf_list, area in zip( + all_license_plates, all_confidences, all_areas + ): if len(plate) < self.lpr_config.min_plate_length: logger.debug( f"Filtered out '{plate}' due to length ({len(plate)} < {self.lpr_config.min_plate_length})" @@ -224,11 +378,11 @@ class LicensePlateProcessingMixin: logger.debug(f"Filtered out '{plate}' due to format mismatch") continue - filtered_data.append((plate, conf, area)) + filtered_data.append((plate, conf_list, area)) sorted_data = sorted( filtered_data, - key=lambda x: (x[2], len(x[0]), x[1]), + key=lambda x: (x[2], len(x[0]), sum(x[1]) / len(x[1]) if x[1] else 0), reverse=True, ) @@ -271,6 +425,92 @@ class LicensePlateProcessingMixin: cv2.multiply(image, std, image) return image.transpose((2, 0, 1))[np.newaxis, ...] + def _merge_nearby_boxes( + self, + boxes: List[np.ndarray], + plate_width: float, + gap_fraction: float = 0.1, + min_overlap_fraction: float = -0.2, + ) -> List[np.ndarray]: + """ + Merge bounding boxes that are likely part of the same license plate based on proximity, + with a dynamic max_gap based on the provided width of the entire license plate. + + Args: + boxes (List[np.ndarray]): List of bounding boxes with shape (n, 4, 2), where n is the number of boxes, + each box has 4 corners, and each corner has (x, y) coordinates. + plate_width (float): The width of the entire license plate in pixels, used to calculate max_gap. + gap_fraction (float): Fraction of the plate width to use as the maximum gap. + Default is 0.1 (10% of the plate width). + + Returns: + List[np.ndarray]: List of merged bounding boxes. + """ + if len(boxes) == 0: + return [] + + max_gap = plate_width * gap_fraction + min_overlap = plate_width * min_overlap_fraction + + # Sort boxes by top left x + sorted_boxes = sorted(boxes, key=lambda x: x[0][0]) + + merged_boxes = [] + current_box = sorted_boxes[0] + + for i in range(1, len(sorted_boxes)): + next_box = sorted_boxes[i] + + # Calculate the horizontal gap between the current box and the next box + current_right = np.max( + current_box[:, 0] + ) # Rightmost x-coordinate of current box + next_left = np.min(next_box[:, 0]) # Leftmost x-coordinate of next box + horizontal_gap = next_left - current_right + + # Check if the boxes are vertically aligned (similar y-coordinates) + current_top = np.min(current_box[:, 1]) + current_bottom = np.max(current_box[:, 1]) + next_top = np.min(next_box[:, 1]) + next_bottom = np.max(next_box[:, 1]) + + # Consider boxes part of the same plate if they are close horizontally or overlap + # within the allowed limit and their vertical positions overlap significantly + if min_overlap <= horizontal_gap <= max_gap and max( + current_top, next_top + ) <= min(current_bottom, next_bottom): + merged_points = np.vstack((current_box, next_box)) + new_box = np.array( + [ + [ + np.min(merged_points[:, 0]), + np.min(merged_points[:, 1]), + ], + [ + np.max(merged_points[:, 0]), + np.min(merged_points[:, 1]), + ], + [ + np.max(merged_points[:, 0]), + np.max(merged_points[:, 1]), + ], + [ + np.min(merged_points[:, 0]), + np.max(merged_points[:, 1]), + ], + ] + ) + current_box = new_box + else: + # If the boxes are not close enough or overlap too much, add the current box to the result + merged_boxes.append(current_box) + current_box = next_box + + # Add the last box + merged_boxes.append(current_box) + + return np.array(merged_boxes, dtype=np.int32) + def _boxes_from_bitmap( self, output: np.ndarray, mask: np.ndarray, dest_width: int, dest_height: int ) -> Tuple[np.ndarray, List[float]]: @@ -301,42 +541,34 @@ class LicensePlateProcessingMixin: contour = contours[index] # get minimum bounding box (rotated rectangle) around the contour and the smallest side length. - points, min_side = self._get_min_boxes(contour) - logger.debug(f"min side {index}, {min_side}") - - if min_side < self.min_size: + points, sside = self._get_min_boxes(contour) + if sside < self.min_size: continue - points = np.array(points) + points = np.array(points, dtype=np.float32) score = self._box_score(output, contour) - logger.debug(f"box score {index}, {score}") if self.box_thresh > score: continue - polygon = Polygon(points) - distance = polygon.area / polygon.length + points = self._expand_box(points) - # Use pyclipper to shrink the polygon slightly based on the computed distance. - offset = PyclipperOffset() - offset.AddPath(points, JT_ROUND, ET_CLOSEDPOLYGON) - points = np.array(offset.Execute(distance * 1.75)).reshape((-1, 1, 2)) - - # get the minimum bounding box around the shrunken polygon. - box, min_side = self._get_min_boxes(points) - - if min_side < self.min_size + 2: + # Get the minimum area rectangle again after expansion + points, sside = self._get_min_boxes(points.reshape(-1, 1, 2)) + if sside < self.min_size + 2: continue - box = np.array(box) + points = np.array(points, dtype=np.float32) # normalize and clip box coordinates to fit within the destination image size. - box[:, 0] = np.clip(np.round(box[:, 0] / width * dest_width), 0, dest_width) - box[:, 1] = np.clip( - np.round(box[:, 1] / height * dest_height), 0, dest_height + points[:, 0] = np.clip( + np.round(points[:, 0] / width * dest_width), 0, dest_width + ) + points[:, 1] = np.clip( + np.round(points[:, 1] / height * dest_height), 0, dest_height ) - boxes.append(box.astype("int32")) + boxes.append(points.astype("int32")) scores.append(score) return np.array(boxes, dtype="int32"), scores @@ -602,7 +834,7 @@ class LicensePlateProcessingMixin: return images, results def _preprocess_recognition_image( - self, image: np.ndarray, max_wh_ratio: float + self, camera: string, image: np.ndarray, max_wh_ratio: float ) -> np.ndarray: """ Preprocess an image for recognition by dynamically adjusting its width. @@ -624,13 +856,53 @@ class LicensePlateProcessingMixin: assert image.shape[2] == input_shape[0], "Unexpected number of image channels." + # convert to grayscale + if image.shape[2] == 3: + gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) + else: + gray = image + + if self.config.cameras[camera].lpr.enhancement > 3: + # denoise using a configurable pixel neighborhood value + logger.debug( + f"{camera}: Denoising recognition image (level: {self.config.cameras[camera].lpr.enhancement})" + ) + smoothed = cv2.bilateralFilter( + gray, + d=5 + self.config.cameras[camera].lpr.enhancement, + sigmaColor=10 * self.config.cameras[camera].lpr.enhancement, + sigmaSpace=10 * self.config.cameras[camera].lpr.enhancement, + ) + sharpening_kernel = np.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]]) + processed = cv2.filter2D(smoothed, -1, sharpening_kernel) + else: + processed = gray + + if self.config.cameras[camera].lpr.enhancement > 0: + # always apply the same CLAHE for contrast enhancement when enhancement level is above 3 + logger.debug( + f"{camera}: Enhancing contrast for recognition image (level: {self.config.cameras[camera].lpr.enhancement})" + ) + grid_size = ( + max(4, input_w // 40), + max(4, input_h // 40), + ) + clahe = cv2.createCLAHE( + clipLimit=2 if self.config.cameras[camera].lpr.enhancement > 5 else 1.5, + tileGridSize=grid_size, + ) + enhanced = clahe.apply(processed) + else: + enhanced = processed + + # Convert back to 3-channel for model compatibility + image = cv2.cvtColor(enhanced, cv2.COLOR_GRAY2RGB) + # dynamically adjust input width based on max_wh_ratio input_w = int(input_h * max_wh_ratio) # check for model-specific input width - model_input_w = self.model_runner.recognition_model.runner.ort.get_inputs()[ - 0 - ].shape[3] + model_input_w = self.model_runner.recognition_model.runner.get_input_width() if isinstance(model_input_w, int) and model_input_w > 0: input_w = model_input_w @@ -649,6 +921,13 @@ class LicensePlateProcessingMixin: ) padded_image[:, :, :resized_w] = resized_image + if False: + current_time = int(datetime.datetime.now().timestamp() * 1000) + cv2.imwrite( + f"debug/frames/preprocessed_recognition_{current_time}.jpg", + image, + ) + return padded_image @staticmethod @@ -703,25 +982,49 @@ class LicensePlateProcessingMixin: Return the dimensions of the detected plate as [x1, y1, x2, y2]. """ - predictions = self.model_runner.yolov9_detection_model(input) + try: + predictions = self.model_runner.yolov9_detection_model(input) + except Exception as e: + logger.warning(f"Error running YOLOv9 license plate detection model: {e}") + return None confidence_threshold = self.lpr_config.detection_threshold top_score = -1 top_box = None + img_h, img_w = input.shape[0], input.shape[1] + + # Calculate resized dimensions and padding based on _preprocess_inputs + if img_w > img_h: + resized_h = int(((img_h / img_w) * LPR_EMBEDDING_SIZE) // 4 * 4) + resized_w = LPR_EMBEDDING_SIZE + x_offset = (LPR_EMBEDDING_SIZE - resized_w) // 2 + y_offset = (LPR_EMBEDDING_SIZE - resized_h) // 2 + scale_x = img_w / resized_w + scale_y = img_h / resized_h + else: + resized_w = int(((img_w / img_h) * LPR_EMBEDDING_SIZE) // 4 * 4) + resized_h = LPR_EMBEDDING_SIZE + x_offset = (LPR_EMBEDDING_SIZE - resized_w) // 2 + y_offset = (LPR_EMBEDDING_SIZE - resized_h) // 2 + scale_x = img_w / resized_w + scale_y = img_h / resized_h + # Loop over predictions for prediction in predictions: score = prediction[6] if score >= confidence_threshold: bbox = prediction[1:5] - # Scale boxes back to original image size - scale_x = input.shape[1] / 256 - scale_y = input.shape[0] / 256 - bbox[0] *= scale_x - bbox[1] *= scale_y - bbox[2] *= scale_x - bbox[3] *= scale_y + # Adjust for padding and scale to original image + bbox[0] = (bbox[0] - x_offset) * scale_x + bbox[1] = (bbox[1] - y_offset) * scale_y + bbox[2] = (bbox[2] - x_offset) * scale_x + bbox[3] = (bbox[3] - y_offset) * scale_y + + if score > top_score: + top_score = score + top_box = bbox if score > top_score: top_score = score @@ -729,8 +1032,8 @@ class LicensePlateProcessingMixin: # Return the top scoring bounding box if found if top_box is not None: - # expand box by 30% to help with OCR - expansion = (top_box[2:] - top_box[:2]) * 0.30 + # expand box by 5% to help with OCR + expansion = (top_box[2:] - top_box[:2]) * 0.05 # Expand box expanded_box = np.array( @@ -742,7 +1045,9 @@ class LicensePlateProcessingMixin: ] ).clip(0, [input.shape[1], input.shape[0]] * 2) - logger.debug(f"Found license plate: {expanded_box.astype(int)}") + logger.debug( + f"Found license plate. Bounding box: {expanded_box.astype(int)}" + ) return tuple(expanded_box.astype(int)) else: return None # No detection above the threshold @@ -750,6 +1055,7 @@ class LicensePlateProcessingMixin: def _should_keep_previous_plate( self, id, top_plate, top_char_confidences, top_area, avg_confidence ): + """Determine if the previous plate should be kept over the current one.""" if id not in self.detected_license_plates: return False @@ -764,237 +1070,356 @@ class LicensePlateProcessingMixin: ) # 1. Normalize metrics - # Length score - use relative comparison - # If lengths are equal, score is 0.5 for both - # If one is longer, it gets a higher score up to 1.0 - max_length_diff = 4 # Maximum expected difference in plate lengths + # Length score: Equal lengths = 0.5, penalize extra characters if low confidence length_diff = len(top_plate) - len(prev_plate) - curr_length_score = 0.5 + ( - length_diff / (2 * max_length_diff) - ) # Normalize to 0-1 - curr_length_score = max(0, min(1, curr_length_score)) # Clamp to 0-1 - prev_length_score = 1 - curr_length_score # Inverse relationship + max_length_diff = 3 + curr_length_score = 0.5 + (length_diff / (2 * max_length_diff)) + curr_length_score = max(0, min(1, curr_length_score)) + prev_length_score = 0.5 - (length_diff / (2 * max_length_diff)) + prev_length_score = max(0, min(1, prev_length_score)) - # Area score (normalize based on max of current and previous) + # Adjust length score based on confidence of extra characters + conf_threshold = 0.75 # Minimum confidence for a character to be "trusted" + top_plate_char_count = len(top_plate.replace(" ", "")) + prev_plate_char_count = len(prev_plate.replace(" ", "")) + + if top_plate_char_count > prev_plate_char_count: + extra_confidences = top_char_confidences[prev_plate_char_count:] + if extra_confidences: # Ensure the slice is not empty + extra_conf = min(extra_confidences) # Lowest extra char confidence + if extra_conf < conf_threshold: + curr_length_score *= extra_conf / conf_threshold # Penalize if weak + elif prev_plate_char_count > top_plate_char_count: + extra_confidences = prev_char_confidences[top_plate_char_count:] + if extra_confidences: # Ensure the slice is not empty + extra_conf = min(extra_confidences) + if extra_conf < conf_threshold: + prev_length_score *= extra_conf / conf_threshold + + # Area score: Normalize by max area max_area = max(top_area, prev_area) - curr_area_score = top_area / max_area - prev_area_score = prev_area / max_area + curr_area_score = top_area / max_area if max_area > 0 else 0 + prev_area_score = prev_area / max_area if max_area > 0 else 0 - # Average confidence score (already normalized 0-1) + # Confidence scores curr_conf_score = avg_confidence prev_conf_score = prev_avg_confidence - # Character confidence comparison score + # Character confidence comparison (average over shared length) min_length = min(len(top_plate), len(prev_plate)) if min_length > 0: curr_char_conf = sum(top_char_confidences[:min_length]) / min_length prev_char_conf = sum(prev_char_confidences[:min_length]) / min_length else: - curr_char_conf = 0 - prev_char_conf = 0 + curr_char_conf = prev_char_conf = 0 - # 2. Define weights + # Penalize any character below threshold + curr_min_conf = min(top_char_confidences) if top_char_confidences else 0 + prev_min_conf = min(prev_char_confidences) if prev_char_confidences else 0 + curr_conf_penalty = ( + 1.0 if curr_min_conf >= conf_threshold else (curr_min_conf / conf_threshold) + ) + prev_conf_penalty = ( + 1.0 if prev_min_conf >= conf_threshold else (prev_min_conf / conf_threshold) + ) + + # 2. Define weights (boost confidence importance) weights = { - "length": 0.4, - "area": 0.3, - "avg_confidence": 0.2, - "char_confidence": 0.1, + "length": 0.2, + "area": 0.2, + "avg_confidence": 0.35, + "char_confidence": 0.25, } - # 3. Calculate weighted scores + # 3. Calculate weighted scores with penalty curr_score = ( curr_length_score * weights["length"] + curr_area_score * weights["area"] + curr_conf_score * weights["avg_confidence"] + curr_char_conf * weights["char_confidence"] - ) + ) * curr_conf_penalty prev_score = ( prev_length_score * weights["length"] + prev_area_score * weights["area"] + prev_conf_score * weights["avg_confidence"] + prev_char_conf * weights["char_confidence"] - ) + ) * prev_conf_penalty - # 4. Log the comparison for debugging + # 4. Log the comparison logger.debug( - f"Plate comparison - Current plate: {top_plate} (score: {curr_score:.3f}) vs " - f"Previous plate: {prev_plate} (score: {prev_score:.3f})\n" + f"Plate comparison - Current: {top_plate} (score: {curr_score:.3f}, min_conf: {curr_min_conf:.2f}) vs " + f"Previous: {prev_plate} (score: {prev_score:.3f}, min_conf: {prev_min_conf:.2f}) " f"Metrics - Length: {len(top_plate)} vs {len(prev_plate)} (scores: {curr_length_score:.2f} vs {prev_length_score:.2f}), " f"Area: {top_area} vs {prev_area}, " - f"Avg Conf: {avg_confidence:.2f} vs {prev_avg_confidence:.2f}" + f"Avg Conf: {avg_confidence:.2f} vs {prev_avg_confidence:.2f}, " + f"Char Conf: {curr_char_conf:.2f} vs {prev_char_conf:.2f}" ) - # 5. Return True if we should keep the previous plate (i.e., if it scores higher) + # 5. Return True if previous plate scores higher return prev_score > curr_score - def __update_yolov9_metrics(self, duration: float) -> None: - """ - Update inference metrics. - """ - self.metrics.yolov9_lpr_fps.value = ( - self.metrics.yolov9_lpr_fps.value * 9 + duration - ) / 10 + def _generate_plate_event(self, camera: str, plate: str, plate_score: float) -> str: + """Generate a unique ID for a plate event based on camera and text.""" + now = datetime.datetime.now().timestamp() + rand_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=6)) + event_id = f"{now}-{rand_id}" - def __update_lpr_metrics(self, duration: float) -> None: - """ - Update inference metrics. - """ - self.metrics.alpr_pps.value = (self.metrics.alpr_pps.value * 9 + duration) / 10 + self.event_metadata_publisher.publish( + EventMetadataTypeEnum.lpr_event_create, + ( + now, + camera, + "license_plate", + event_id, + True, + plate_score, + None, + plate, + ), + ) + return event_id - def lpr_process(self, obj_data: dict[str, any], frame: np.ndarray): + def lpr_process( + self, obj_data: dict[str, any], frame: np.ndarray, dedicated_lpr: bool = False + ): """Look for license plates in image.""" + self.metrics.alpr_pps.value = self.plates_rec_second.eps() + self.metrics.yolov9_lpr_pps.value = self.plates_det_second.eps() + camera = obj_data if dedicated_lpr else obj_data["camera"] + current_time = int(datetime.datetime.now().timestamp()) - id = obj_data["id"] - - # don't run for non car objects - if obj_data.get("label") != "car": - logger.debug("Not a processing license plate for non car object.") + if not self.config.cameras[camera].lpr.enabled: return - # don't run for stationary car objects - if obj_data.get("stationary") == True: - logger.debug("Not a processing license plate for a stationary car object.") - return - - # don't overwrite sub label for objects that have a sub label - # that is not a license plate - if obj_data.get("sub_label") and id not in self.detected_license_plates: - logger.debug( - f"Not processing license plate due to existing sub label: {obj_data.get('sub_label')}." - ) - return - - license_plate: Optional[dict[str, any]] = None - - if self.requires_license_plate_detection: - logger.debug("Running manual license_plate detection.") - - car_box = obj_data.get("box") - - if not car_box: - return + # dedicated LPR cam without frigate+ + if dedicated_lpr: + id = "dedicated-lpr" rgb = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420) - left, top, right, bottom = car_box - car = rgb[top:bottom, left:right] - # double the size of the car for better box detection - car = cv2.resize(car, (int(2 * car.shape[1]), int(2 * car.shape[0]))) + # apply motion mask + rgb[self.config.cameras[obj_data].motion.mask == 0] = [0, 0, 0] if WRITE_DEBUG_IMAGES: - current_time = int(datetime.datetime.now().timestamp()) cv2.imwrite( - f"debug/frames/car_frame_{current_time}.jpg", - car, + f"debug/frames/dedicated_lpr_masked_{current_time}.jpg", + rgb, ) yolov9_start = datetime.datetime.now().timestamp() - license_plate = self._detect_license_plate(car) + license_plate = self._detect_license_plate(rgb) + logger.debug( - f"YOLOv9 LPD inference time: {(datetime.datetime.now().timestamp() - yolov9_start) * 1000:.2f} ms" + f"{camera}: YOLOv9 LPD inference time: {(datetime.datetime.now().timestamp() - yolov9_start) * 1000:.2f} ms" ) - self.__update_yolov9_metrics( + self.plates_det_second.update() + self.plate_det_speed.update( datetime.datetime.now().timestamp() - yolov9_start ) if not license_plate: - logger.debug("Detected no license plates for car object.") + logger.debug(f"{camera}: Detected no license plates in full frame.") return - license_plate_area = max( - 0, - (license_plate[2] - license_plate[0]) - * (license_plate[3] - license_plate[1]), + license_plate_area = (license_plate[2] - license_plate[0]) * ( + license_plate[3] - license_plate[1] ) - - # check that license plate is valid - # double the value because we've doubled the size of the car - if license_plate_area < self.lpr_config.min_area * 2: - logger.debug("License plate is less than min_area") + if license_plate_area < self.config.cameras[camera].lpr.min_area: + logger.debug(f"{camera}: License plate area below minimum threshold.") return - license_plate_frame = car[ - license_plate[1] : license_plate[3], license_plate[0] : license_plate[2] - ] - else: - # don't run for object without attributes - if not obj_data.get("current_attributes"): - logger.debug("No attributes to parse.") - return - - attributes: list[dict[str, any]] = obj_data.get("current_attributes", []) - for attr in attributes: - if attr.get("label") != "license_plate": - continue - - if license_plate is None or attr.get("score", 0.0) > license_plate.get( - "score", 0.0 - ): - license_plate = attr - - # no license plates detected in this frame - if not license_plate: - return - - license_plate_box = license_plate.get("box") - - # check that license plate is valid - if ( - not license_plate_box - or area(license_plate_box) < self.lpr_config.min_area - ): - logger.debug(f"Invalid license plate box {license_plate}") - return - - license_plate_frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420) - - # Expand the license_plate_box by 30% - box_array = np.array(license_plate_box) - expansion = (box_array[2:] - box_array[:2]) * 0.30 - expanded_box = np.array( - [ - license_plate_box[0] - expansion[0], - license_plate_box[1] - expansion[1], - license_plate_box[2] + expansion[0], - license_plate_box[3] + expansion[1], - ] - ).clip(0, [license_plate_frame.shape[1], license_plate_frame.shape[0]] * 2) - - # Crop using the expanded box - license_plate_frame = license_plate_frame[ - int(expanded_box[1]) : int(expanded_box[3]), - int(expanded_box[0]) : int(expanded_box[2]), + license_plate_frame = rgb[ + license_plate[1] : license_plate[3], + license_plate[0] : license_plate[2], ] - # double the size of the license plate frame for better OCR - license_plate_frame = cv2.resize( - license_plate_frame, - ( - int(2 * license_plate_frame.shape[1]), - int(2 * license_plate_frame.shape[0]), - ), - ) - - if WRITE_DEBUG_IMAGES: - current_time = int(datetime.datetime.now().timestamp()) - cv2.imwrite( - f"debug/frames/license_plate_frame_{current_time}.jpg", + # Double the size for better OCR + license_plate_frame = cv2.resize( license_plate_frame, + ( + int(2 * license_plate_frame.shape[1]), + int(2 * license_plate_frame.shape[0]), + ), ) - start = datetime.datetime.now().timestamp() + else: + id = obj_data["id"] + + # don't run for non car/motorcycle or non license plate (dedicated lpr with frigate+) objects + if ( + obj_data.get("label") not in ["car", "motorcycle"] + and obj_data.get("label") != "license_plate" + ): + logger.debug( + f"{camera}: Not a processing license plate for non car/motorcycle object." + ) + return + + # don't run for stationary car objects + if obj_data.get("stationary") == True: + logger.debug( + f"{camera}: Not a processing license plate for a stationary car/motorcycle object." + ) + return + + # don't run for objects with no position changes + # this is the initial state after registering a new tracked object + # LPR will run 2 frames after detect.min_initialized is reached + if obj_data.get("position_changes", 0) == 0: + logger.debug( + f"{camera}: Plate detected in {self.config.cameras[camera].detect.min_initialized + 1} concurrent frames, LPR frame threshold ({self.config.cameras[camera].detect.min_initialized + 2})" + ) + return + + license_plate: Optional[dict[str, any]] = None + + if "license_plate" not in self.config.cameras[camera].objects.track: + logger.debug(f"{camera}: Running manual license_plate detection.") + + car_box = obj_data.get("box") + + if not car_box: + return + + rgb = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420) + + # apply motion mask + rgb[self.config.cameras[camera].motion.mask == 0] = [0, 0, 0] + + left, top, right, bottom = car_box + car = rgb[top:bottom, left:right] + + # double the size of the car for better box detection + car = cv2.resize(car, (int(2 * car.shape[1]), int(2 * car.shape[0]))) + + if WRITE_DEBUG_IMAGES: + cv2.imwrite( + f"debug/frames/car_frame_{current_time}.jpg", + car, + ) + + yolov9_start = datetime.datetime.now().timestamp() + license_plate = self._detect_license_plate(car) + logger.debug( + f"{camera}: YOLOv9 LPD inference time: {(datetime.datetime.now().timestamp() - yolov9_start) * 1000:.2f} ms" + ) + self.plates_det_second.update() + self.plate_det_speed.update( + datetime.datetime.now().timestamp() - yolov9_start + ) + + if not license_plate: + logger.debug( + f"{camera}: Detected no license plates for car/motorcycle object." + ) + return + + license_plate_area = max( + 0, + (license_plate[2] - license_plate[0]) + * (license_plate[3] - license_plate[1]), + ) + + # check that license plate is valid + # double the value because we've doubled the size of the car + if license_plate_area < self.config.cameras[camera].lpr.min_area * 2: + logger.debug(f"{camera}: License plate is less than min_area") + return + + license_plate_frame = car[ + license_plate[1] : license_plate[3], + license_plate[0] : license_plate[2], + ] + else: + # don't run for object without attributes if this isn't dedicated lpr with frigate+ + if ( + not obj_data.get("current_attributes") + and obj_data.get("label") != "license_plate" + ): + logger.debug(f"{camera}: No attributes to parse.") + return + + if obj_data.get("label") in ["car", "motorcycle"]: + attributes: list[dict[str, any]] = obj_data.get( + "current_attributes", [] + ) + for attr in attributes: + if attr.get("label") != "license_plate": + continue + + if license_plate is None or attr.get( + "score", 0.0 + ) > license_plate.get("score", 0.0): + license_plate = attr + + # no license plates detected in this frame + if not license_plate: + return + + # we are using dedicated lpr with frigate+ + if obj_data.get("label") == "license_plate": + license_plate = obj_data + + license_plate_box = license_plate.get("box") + + # check that license plate is valid + if ( + not license_plate_box + or area(license_plate_box) + < self.config.cameras[camera].lpr.min_area + ): + logger.debug( + f"{camera}: Area for license plate box {area(license_plate_box)} is less than min_area {self.config.cameras[camera].lpr.min_area}" + ) + return + + license_plate_frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420) + + # Expand the license_plate_box by 10% + box_array = np.array(license_plate_box) + expansion = (box_array[2:] - box_array[:2]) * 0.10 + expanded_box = np.array( + [ + license_plate_box[0] - expansion[0], + license_plate_box[1] - expansion[1], + license_plate_box[2] + expansion[0], + license_plate_box[3] + expansion[1], + ] + ).clip( + 0, [license_plate_frame.shape[1], license_plate_frame.shape[0]] * 2 + ) + + # Crop using the expanded box + license_plate_frame = license_plate_frame[ + int(expanded_box[1]) : int(expanded_box[3]), + int(expanded_box[0]) : int(expanded_box[2]), + ] + + # double the size of the license plate frame for better OCR + license_plate_frame = cv2.resize( + license_plate_frame, + ( + int(2 * license_plate_frame.shape[1]), + int(2 * license_plate_frame.shape[0]), + ), + ) + + if WRITE_DEBUG_IMAGES: + cv2.imwrite( + f"debug/frames/license_plate_frame_{current_time}.jpg", + license_plate_frame, + ) + + logger.debug(f"{camera}: Running plate recognition.") # run detection, returns results sorted by confidence, best first + start = datetime.datetime.now().timestamp() license_plates, confidences, areas = self._process_license_plate( - license_plate_frame + camera, id, license_plate_frame ) - - self.__update_lpr_metrics(datetime.datetime.now().timestamp() - start) - - logger.debug(f"Text boxes: {license_plates}") - logger.debug(f"Confidences: {confidences}") - logger.debug(f"Areas: {areas}") + self.plates_rec_second.update() + self.plate_rec_speed.update(datetime.datetime.now().timestamp() - start) if license_plates: for plate, confidence, text_area in zip(license_plates, confidences, areas): @@ -1003,10 +1428,9 @@ class LicensePlateProcessingMixin: ) logger.debug( - f"Detected text: {plate} (average confidence: {avg_confidence:.2f}, area: {text_area} pixels)" + f"{camera}: Detected text: {plate} (average confidence: {avg_confidence:.2f}, area: {text_area} pixels)" ) else: - # no plates found logger.debug("No text detected") return @@ -1021,21 +1445,57 @@ class LicensePlateProcessingMixin: else 0 ) + # Check against minimum confidence threshold + if avg_confidence < self.lpr_config.recognition_threshold: + logger.debug( + f"{camera}: Average character confidence {avg_confidence} is less than recognition_threshold ({self.lpr_config.recognition_threshold})" + ) + return + + # For dedicated LPR cameras, match or assign plate ID using Jaro-Winkler distance + if ( + dedicated_lpr + and "license_plate" not in self.config.cameras[camera].objects.track + ): + plate_id = None + + for existing_id, data in self.detected_license_plates.items(): + if ( + data["camera"] == camera + and data["last_seen"] is not None + and current_time - data["last_seen"] + <= self.config.cameras[camera].lpr.expire_time + ): + similarity = jaro_winkler(data["plate"], top_plate) + if similarity >= self.similarity_threshold: + plate_id = existing_id + logger.debug( + f"{camera}: Matched plate {top_plate} to {data['plate']} (similarity: {similarity:.3f})" + ) + break + if plate_id is None: + plate_id = self._generate_plate_event( + obj_data, top_plate, avg_confidence + ) + logger.debug( + f"{camera}: New plate event for dedicated LPR camera {plate_id}: {top_plate}" + ) + else: + logger.debug( + f"{camera}: Matched existing plate event for dedicated LPR camera {plate_id}: {top_plate}" + ) + self.detected_license_plates[plate_id]["last_seen"] = current_time + + id = plate_id + # Check if we have a previously detected plate for this ID if id in self.detected_license_plates: if self._should_keep_previous_plate( id, top_plate, top_char_confidences, top_area, avg_confidence ): - logger.debug("Keeping previous plate") + logger.debug(f"{camera}: Keeping previous plate") return - # Check against minimum confidence threshold - if avg_confidence < self.lpr_config.recognition_threshold: - logger.debug( - f"Average confidence {avg_confidence} is less than threshold ({self.lpr_config.recognition_threshold})" - ) - return - # Determine subLabel based on known plates, use regex matching # Default to the detected plate, use label name if there's a match sub_label = next( @@ -1057,22 +1517,60 @@ class LicensePlateProcessingMixin: EventMetadataTypeEnum.sub_label, (id, sub_label, avg_confidence) ) + # always publish to recognized_license_plate field + self.requestor.send_data( + "tracked_object_update", + json.dumps( + { + "type": TrackedObjectUpdateTypesEnum.lpr, + "name": sub_label, + "plate": top_plate, + "score": avg_confidence, + "id": id, + "camera": camera, + "timestamp": start, + } + ), + ) self.sub_label_publisher.publish( EventMetadataTypeEnum.recognized_license_plate, (id, top_plate, avg_confidence), ) + # save the best snapshot for dedicated lpr cams not using frigate+ + if ( + dedicated_lpr + and "license_plate" not in self.config.cameras[camera].objects.track + ): + logger.debug( + f"{camera}: Writing snapshot for {id}, {top_plate}, {current_time}" + ) + frame_bgr = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420) + _, encoded_img = cv2.imencode(".jpg", frame_bgr) + self.sub_label_publisher.publish( + EventMetadataTypeEnum.save_lpr_snapshot, + (base64.b64encode(encoded_img).decode("ASCII"), id, camera), + ) + + if id not in self.detected_license_plates: + if camera not in self.camera_current_cars: + self.camera_current_cars[camera] = [] + + self.camera_current_cars[camera].append(id) + self.detected_license_plates[id] = { "plate": top_plate, "char_confidences": top_char_confidences, "area": top_area, "obj_data": obj_data, + "camera": camera, + "last_seen": current_time if dedicated_lpr else None, } def handle_request(self, topic, request_data) -> dict[str, any] | None: return - def expire_object(self, object_id: str): + def expire_object(self, object_id: str, camera: str): if object_id in self.detected_license_plates: self.detected_license_plates.pop(object_id) diff --git a/frigate/data_processing/common/license_plate/model.py b/frigate/data_processing/common/license_plate/model.py index 25e7b2caf..f53ed7d95 100644 --- a/frigate/data_processing/common/license_plate/model.py +++ b/frigate/data_processing/common/license_plate/model.py @@ -9,7 +9,7 @@ from ...types import DataProcessorModelRunner class LicensePlateModelRunner(DataProcessorModelRunner): - def __init__(self, requestor, device: str = "CPU", model_size: str = "large"): + def __init__(self, requestor, device: str = "CPU", model_size: str = "small"): super().__init__(requestor, device, model_size) self.detection_model = PaddleOCRDetection( model_size=model_size, requestor=requestor, device=device diff --git a/frigate/data_processing/post/license_plate.py b/frigate/data_processing/post/license_plate.py index e5c8a29a8..6bd3edf60 100644 --- a/frigate/data_processing/post/license_plate.py +++ b/frigate/data_processing/post/license_plate.py @@ -9,6 +9,7 @@ from peewee import DoesNotExist from frigate.comms.embeddings_updater import EmbeddingsRequestEnum from frigate.comms.event_metadata_updater import EventMetadataPublisher +from frigate.comms.inter_process import InterProcessRequestor from frigate.config import FrigateConfig from frigate.data_processing.common.license_plate.mixin import ( WRITE_DEBUG_IMAGES, @@ -31,11 +32,13 @@ class LicensePlatePostProcessor(LicensePlateProcessingMixin, PostProcessorApi): def __init__( self, config: FrigateConfig, + requestor: InterProcessRequestor, sub_label_publisher: EventMetadataPublisher, metrics: DataProcessorMetrics, model_runner: LicensePlateModelRunner, detected_license_plates: dict[str, dict[str, any]], ): + self.requestor = requestor self.detected_license_plates = detected_license_plates self.model_runner = model_runner self.lpr_config = config.lpr @@ -54,6 +57,9 @@ class LicensePlatePostProcessor(LicensePlateProcessingMixin, PostProcessorApi): Returns: None. """ + # don't run LPR post processing for now + return + event_id = data["event_id"] camera_name = data["camera"] @@ -139,7 +145,7 @@ class LicensePlatePostProcessor(LicensePlateProcessingMixin, PostProcessorApi): scale_y = image.shape[0] / detect_height # Determine which box to enlarge based on detection mode - if self.requires_license_plate_detection: + if "license_plate" not in self.config.cameras[camera_name].objects.track: # Scale and enlarge the car box box = obj_data.get("box") if not box: @@ -189,7 +195,7 @@ class LicensePlatePostProcessor(LicensePlateProcessingMixin, PostProcessorApi): ) keyframe_obj_data = obj_data.copy() - if self.requires_license_plate_detection: + if "license_plate" not in self.config.cameras[camera_name].objects.track: # car box keyframe_obj_data["box"] = [new_left, new_top, new_right, new_bottom] else: diff --git a/frigate/data_processing/real_time/api.py b/frigate/data_processing/real_time/api.py index 1ba01d5da..3d8e735c1 100644 --- a/frigate/data_processing/real_time/api.py +++ b/frigate/data_processing/real_time/api.py @@ -50,10 +50,11 @@ class RealTimeProcessorApi(ABC): pass @abstractmethod - def expire_object(self, object_id: str) -> None: + def expire_object(self, object_id: str, camera: str) -> None: """Handle objects that are no longer detected. Args: object_id (str): id of object that is no longer detected. + camera (str): name of camera that object was detected on. Returns: None. diff --git a/frigate/data_processing/real_time/bird.py b/frigate/data_processing/real_time/bird.py index ba6d4f08c..7fd2a5edb 100644 --- a/frigate/data_processing/real_time/bird.py +++ b/frigate/data_processing/real_time/bird.py @@ -144,13 +144,14 @@ class BirdRealTimeProcessor(RealTimeProcessorApi): return self.sub_label_publisher.publish( - EventMetadataTypeEnum.sub_label, (id, self.labelmap[best_id], score) + EventMetadataTypeEnum.sub_label, + (obj_data["id"], self.labelmap[best_id], score), ) self.detected_birds[obj_data["id"]] = score def handle_request(self, topic, request_data): return None - def expire_object(self, object_id): + def expire_object(self, object_id, camera): if object_id in self.detected_birds: self.detected_birds.pop(object_id) diff --git a/frigate/data_processing/real_time/face.py b/frigate/data_processing/real_time/face.py index 7d97f8586..6936e3ea1 100644 --- a/frigate/data_processing/real_time/face.py +++ b/frigate/data_processing/real_time/face.py @@ -2,11 +2,10 @@ import base64 import datetime +import json import logging import os -import random import shutil -import string from typing import Optional import cv2 @@ -17,8 +16,16 @@ from frigate.comms.event_metadata_updater import ( EventMetadataPublisher, EventMetadataTypeEnum, ) +from frigate.comms.inter_process import InterProcessRequestor from frigate.config import FrigateConfig from frigate.const import FACE_DIR, MODEL_CACHE_DIR +from frigate.data_processing.common.face.model import ( + ArcFaceRecognizer, + FaceNetRecognizer, + FaceRecognizer, +) +from frigate.types import TrackedObjectUpdateTypesEnum +from frigate.util.builtin import EventsPerSecond, InferenceSpeed from frigate.util.image import area from ..types import DataProcessorMetrics @@ -27,24 +34,30 @@ from .api import RealTimeProcessorApi logger = logging.getLogger(__name__) -MIN_MATCHING_FACES = 2 +MAX_DETECTION_HEIGHT = 1080 +MAX_FACES_ATTEMPTS_AFTER_REC = 6 +MAX_FACE_ATTEMPTS = 12 class FaceRealTimeProcessor(RealTimeProcessorApi): def __init__( self, config: FrigateConfig, + requestor: InterProcessRequestor, sub_label_publisher: EventMetadataPublisher, metrics: DataProcessorMetrics, ): super().__init__(config, metrics) self.face_config = config.face_recognition + self.requestor = requestor self.sub_label_publisher = sub_label_publisher self.face_detector: cv2.FaceDetectorYN = None - self.landmark_detector: cv2.face.FacemarkLBF = None - self.recognizer: cv2.face.LBPHFaceRecognizer = None self.requires_face_detection = "face" not in self.config.objects.all_objects - self.detected_faces: dict[str, float] = {} + self.person_face_history: dict[str, list[tuple[str, float, int]]] = {} + self.camera_current_people: dict[str, list[str]] = {} + self.recognizer: FaceRecognizer | None = None + self.faces_per_second = EventsPerSecond() + self.inference_speed = InferenceSpeed(self.metrics.face_rec_speed) download_path = os.path.join(MODEL_CACHE_DIR, "facedet") self.model_files = { @@ -71,7 +84,13 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): self.__build_detector() self.label_map: dict[int, str] = {} - self.__build_classifier() + + if self.face_config.model_size == "small": + self.recognizer = FaceNetRecognizer(self.config) + else: + self.recognizer = ArcFaceRecognizer(self.config) + + self.recognizer.build() def __download_models(self, path: str) -> None: try: @@ -88,135 +107,28 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): os.path.join(MODEL_CACHE_DIR, "facedet/facedet.onnx"), config="", input_size=(320, 320), - score_threshold=self.face_config.detection_threshold, + score_threshold=0.5, nms_threshold=0.3, ) - self.landmark_detector = cv2.face.createFacemarkLBF() - self.landmark_detector.loadModel( - os.path.join(MODEL_CACHE_DIR, "facedet/landmarkdet.yaml") - ) + self.faces_per_second.start() - def __build_classifier(self) -> None: - if not self.landmark_detector: - return None - - labels = [] - faces = [] - - dir = "/media/frigate/clips/faces" - for idx, name in enumerate(os.listdir(dir)): - if name == "train": - continue - - face_folder = os.path.join(dir, name) - - if not os.path.isdir(face_folder): - continue - - self.label_map[idx] = name - for image in os.listdir(face_folder): - img = cv2.imread(os.path.join(face_folder, image)) - - if img is None: - continue - - img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - img = self.__align_face(img, img.shape[1], img.shape[0]) - faces.append(img) - labels.append(idx) - - if not faces: - return - - self.recognizer: cv2.face.LBPHFaceRecognizer = ( - cv2.face.LBPHFaceRecognizer_create( - radius=2, threshold=(1 - self.face_config.min_score) * 1000 - ) - ) - self.recognizer.train(faces, np.array(labels)) - - def __align_face( - self, - image: np.ndarray, - output_width: int, - output_height: int, - ) -> np.ndarray: - _, lands = self.landmark_detector.fit( - image, np.array([(0, 0, image.shape[1], image.shape[0])]) - ) - landmarks: np.ndarray = lands[0][0] - - # get landmarks for eyes - leftEyePts = landmarks[42:48] - rightEyePts = landmarks[36:42] - - # compute the center of mass for each eye - leftEyeCenter = leftEyePts.mean(axis=0).astype("int") - rightEyeCenter = rightEyePts.mean(axis=0).astype("int") - - # compute the angle between the eye centroids - dY = rightEyeCenter[1] - leftEyeCenter[1] - dX = rightEyeCenter[0] - leftEyeCenter[0] - angle = np.degrees(np.arctan2(dY, dX)) - 180 - - # compute the desired right eye x-coordinate based on the - # desired x-coordinate of the left eye - desiredRightEyeX = 1.0 - 0.35 - - # determine the scale of the new resulting image by taking - # the ratio of the distance between eyes in the *current* - # image to the ratio of distance between eyes in the - # *desired* image - dist = np.sqrt((dX**2) + (dY**2)) - desiredDist = desiredRightEyeX - 0.35 - desiredDist *= output_width - scale = desiredDist / dist - - # compute center (x, y)-coordinates (i.e., the median point) - # between the two eyes in the input image - # grab the rotation matrix for rotating and scaling the face - eyesCenter = ( - int((leftEyeCenter[0] + rightEyeCenter[0]) // 2), - int((leftEyeCenter[1] + rightEyeCenter[1]) // 2), - ) - M = cv2.getRotationMatrix2D(eyesCenter, angle, scale) - - # update the translation component of the matrix - tX = output_width * 0.5 - tY = output_height * 0.35 - M[0, 2] += tX - eyesCenter[0] - M[1, 2] += tY - eyesCenter[1] - - # apply the affine transformation - return cv2.warpAffine( - image, M, (output_width, output_height), flags=cv2.INTER_CUBIC - ) - - def __get_blur_factor(self, input: np.ndarray) -> float: - """Calculates the factor for the confidence based on the blur of the image.""" - if not self.face_config.blur_confidence_filter: - return 1.0 - - variance = cv2.Laplacian(input, cv2.CV_64F).var() - - if variance < 60: # image is very blurry - return 0.96 - elif variance < 70: # image moderately blurry - return 0.98 - elif variance < 80: # image is slightly blurry - return 0.99 - else: - return 1.0 - - def __clear_classifier(self) -> None: - self.face_recognizer = None - self.label_map = {} - - def __detect_face(self, input: np.ndarray) -> tuple[int, int, int, int]: + def __detect_face( + self, input: np.ndarray, threshold: float + ) -> tuple[int, int, int, int]: """Detect faces in input image.""" if not self.face_detector: return None + # YN face detector fails at extreme definitions + # this rescales to a size that can properly detect faces + # still retaining plenty of detail + if input.shape[0] > MAX_DETECTION_HEIGHT: + scale_factor = MAX_DETECTION_HEIGHT / input.shape[0] + new_width = int(scale_factor * input.shape[1]) + input = cv2.resize(input, (new_width, MAX_DETECTION_HEIGHT)) + else: + scale_factor = 1 + self.face_detector.setInputSize((input.shape[1], input.shape[0])) faces = self.face_detector.detect(input) @@ -226,11 +138,14 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): face = None for _, potential_face in enumerate(faces[1]): + if potential_face[-1] < threshold: + continue + raw_bbox = potential_face[0:4].astype(np.uint16) - x: int = max(raw_bbox[0], 0) - y: int = max(raw_bbox[1], 0) - w: int = raw_bbox[2] - h: int = raw_bbox[3] + x: int = int(max(raw_bbox[0], 0) / scale_factor) + y: int = int(max(raw_bbox[1], 0) / scale_factor) + w: int = int(raw_bbox[2] / scale_factor) + h: int = int(raw_bbox[3] / scale_factor) bbox = (x, y, x + w, y + h) if face is None or area(bbox) > area(face): @@ -238,40 +153,18 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): return face - def __classify_face(self, face_image: np.ndarray) -> tuple[str, float] | None: - if not self.landmark_detector: - return None - - if not self.label_map or not self.recognizer: - self.__build_classifier() - - if not self.recognizer: - return None - - # face recognition is best run on grayscale images - img = cv2.cvtColor(face_image, cv2.COLOR_BGR2GRAY) - - # get blur factor before aligning face - blur_factor = self.__get_blur_factor(img) - logger.debug(f"face detected with bluriness {blur_factor}") - - # align face and run recognition - img = self.__align_face(img, img.shape[1], img.shape[0]) - index, distance = self.recognizer.predict(img) - - if index == -1: - return None - - score = (1.0 - (distance / 1000)) * blur_factor - return self.label_map[index], round(score, 2) - def __update_metrics(self, duration: float) -> None: - self.metrics.face_rec_fps.value = ( - self.metrics.face_rec_fps.value * 9 + duration - ) / 10 + self.faces_per_second.update() + self.inference_speed.update(duration) def process_frame(self, obj_data: dict[str, any], frame: np.ndarray): """Look for faces in image.""" + self.metrics.face_rec_fps.value = self.faces_per_second.eps() + camera = obj_data["camera"] + + if not self.config.cameras[camera].face_recognition.enabled: + return + start = datetime.datetime.now().timestamp() id = obj_data["id"] @@ -282,12 +175,29 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): # don't overwrite sub label for objects that have a sub label # that is not a face - if obj_data.get("sub_label") and id not in self.detected_faces: + if obj_data.get("sub_label") and id not in self.person_face_history: logger.debug( f"Not processing face due to existing sub label: {obj_data.get('sub_label')}." ) return + # check if we have hit limits + if ( + id in self.person_face_history + and len(self.person_face_history[id]) >= MAX_FACES_ATTEMPTS_AFTER_REC + ): + # if we are at max attempts after rec and we have a rec + if obj_data.get("sub_label"): + logger.debug( + "Not processing due to hitting max attempts after true recognition." + ) + return + + # if we don't have a rec and are at max attempts + if len(self.person_face_history[id]) >= MAX_FACE_ATTEMPTS: + logger.debug("Not processing due to hitting max rec attempts.") + return + face: Optional[dict[str, any]] = None if self.requires_face_detection: @@ -300,7 +210,7 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): rgb = cv2.cvtColor(frame, cv2.COLOR_YUV2RGB_I420) left, top, right, bottom = person_box person = rgb[top:bottom, left:right] - face_box = self.__detect_face(person) + face_box = self.__detect_face(person, self.face_config.detection_threshold) if not face_box: logger.debug("Detected no faces for person object.") @@ -310,7 +220,11 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): max(0, face_box[1]) : min(frame.shape[0], face_box[3]), max(0, face_box[0]) : min(frame.shape[1], face_box[2]), ] - face_frame = cv2.cvtColor(face_frame, cv2.COLOR_RGB2BGR) + + try: + face_frame = cv2.cvtColor(face_frame, cv2.COLOR_RGB2BGR) + except Exception: + return else: # don't run for object without attributes if not obj_data.get("current_attributes"): @@ -332,7 +246,11 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): face_box = face.get("box") # check that face is valid - if not face_box or area(face_box) < self.config.face_recognition.min_area: + if ( + not face_box + or area(face_box) + < self.config.cameras[camera].face_recognition.min_area + ): logger.debug(f"Invalid face box {face}") return @@ -343,59 +261,91 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): max(0, face_box[0]) : min(frame.shape[1], face_box[2]), ] - res = self.__classify_face(face_frame) + res = self.recognizer.classify(face_frame) if not res: + self.__update_metrics(datetime.datetime.now().timestamp() - start) return sub_label, score = res - # calculate the overall face score as the probability * area of face - # this will help to reduce false positives from small side-angle faces - # if a large front-on face image may have scored slightly lower but - # is more likely to be accurate due to the larger face area - face_score = round(score * face_frame.shape[0] * face_frame.shape[1], 2) + if score <= self.face_config.unknown_score: + sub_label = "unknown" logger.debug( - f"Detected best face for person as: {sub_label} with probability {score} and overall face score {face_score}" + f"Detected best face for person as: {sub_label} with probability {score}" ) - if self.config.face_recognition.save_attempts: - # write face to library - folder = os.path.join(FACE_DIR, "train") - file = os.path.join(folder, f"{id}-{sub_label}-{score}-{face_score}.webp") - os.makedirs(folder, exist_ok=True) - cv2.imwrite(file, face_frame) - - if score < self.config.face_recognition.recognition_threshold: - logger.debug( - f"Recognized face distance {score} is less than threshold {self.config.face_recognition.recognition_threshold}" - ) - self.__update_metrics(datetime.datetime.now().timestamp() - start) - return - - if id in self.detected_faces and face_score <= self.detected_faces[id]: - logger.debug( - f"Recognized face distance {score} and overall score {face_score} is less than previous overall face score ({self.detected_faces.get(id)})." - ) - self.__update_metrics(datetime.datetime.now().timestamp() - start) - return - - self.sub_label_publisher.publish( - EventMetadataTypeEnum.sub_label, (id, sub_label, score) + self.write_face_attempt( + face_frame, id, datetime.datetime.now().timestamp(), sub_label, score ) - self.detected_faces[id] = face_score + + if id not in self.person_face_history: + self.person_face_history[id] = [] + + if camera not in self.camera_current_people: + self.camera_current_people[camera] = [] + + self.person_face_history[id].append( + (sub_label, score, face_frame.shape[0] * face_frame.shape[1]) + ) + self.camera_current_people[camera].append(id) + (weighted_sub_label, weighted_score) = self.weighted_average( + self.person_face_history[id] + ) + + self.requestor.send_data( + "tracked_object_update", + json.dumps( + { + "type": TrackedObjectUpdateTypesEnum.face, + "name": weighted_sub_label, + "score": weighted_score, + "id": id, + "camera": camera, + "timestamp": start, + } + ), + ) + + if weighted_score >= self.face_config.recognition_threshold: + self.sub_label_publisher.publish( + EventMetadataTypeEnum.sub_label, + (id, weighted_sub_label, weighted_score), + ) + self.__update_metrics(datetime.datetime.now().timestamp() - start) def handle_request(self, topic, request_data) -> dict[str, any] | None: if topic == EmbeddingsRequestEnum.clear_face_classifier.value: - self.__clear_classifier() - elif topic == EmbeddingsRequestEnum.register_face.value: - rand_id = "".join( - random.choices(string.ascii_lowercase + string.digits, k=6) + self.recognizer.clear() + elif topic == EmbeddingsRequestEnum.recognize_face.value: + img = cv2.imdecode( + np.frombuffer(base64.b64decode(request_data["image"]), dtype=np.uint8), + cv2.IMREAD_COLOR, ) + + # detect faces with lower confidence since we expect the face + # to be visible in uploaded images + face_box = self.__detect_face(img, 0.5) + + if not face_box: + return {"message": "No face was detected.", "success": False} + + face = img[face_box[1] : face_box[3], face_box[0] : face_box[2]] + res = self.recognizer.classify(face) + + if not res: + return {"success": False, "message": "No face was recognized."} + + sub_label, score = res + + if score <= self.face_config.unknown_score: + sub_label = "unknown" + + return {"success": True, "score": score, "face_name": sub_label} + elif topic == EmbeddingsRequestEnum.register_face.value: label = request_data["face_name"] - id = f"{label}-{rand_id}" if request_data.get("cropped"): thumbnail = request_data["image"] @@ -406,7 +356,10 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): ), cv2.IMREAD_COLOR, ) - face_box = self.__detect_face(img) + + # detect faces with lower confidence since we expect the face + # to be visible in uploaded images + face_box = self.__detect_face(img, 0.5) if not face_box: return { @@ -421,23 +374,25 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): # write face to library folder = os.path.join(FACE_DIR, label) - file = os.path.join(folder, f"{id}.webp") + file = os.path.join( + folder, f"{label}_{datetime.datetime.now().timestamp()}.webp" + ) os.makedirs(folder, exist_ok=True) # save face image with open(file, "wb") as output: output.write(thumbnail.tobytes()) - self.__clear_classifier() + self.recognizer.clear() return { "message": "Successfully registered face.", "success": True, } elif topic == EmbeddingsRequestEnum.reprocess_face.value: current_file: str = request_data["image_file"] - id = current_file[0 : current_file.index("-", current_file.index("-") + 1)] - face_score = current_file[current_file.rfind("-") : current_file.rfind(".")] + (id_time, id_rand, timestamp, _, _) = current_file.split("-") img = None + id = f"{id_time}-{id_rand}" if current_file: img = cv2.imread(current_file) @@ -448,21 +403,117 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): "success": False, } - res = self.__classify_face(img) + res = self.recognizer.classify(img) if not res: return sub_label, score = res + if score <= self.face_config.unknown_score: + sub_label = "unknown" + + if "-" in sub_label: + sub_label = sub_label.replace("-", "_") + if self.config.face_recognition.save_attempts: # write face to library folder = os.path.join(FACE_DIR, "train") + os.makedirs(folder, exist_ok=True) new_file = os.path.join( - folder, f"{id}-{sub_label}-{score}-{face_score}.webp" + folder, f"{id}-{timestamp}-{sub_label}-{score}.webp" ) shutil.move(current_file, new_file) - def expire_object(self, object_id: str): - if object_id in self.detected_faces: - self.detected_faces.pop(object_id) + def expire_object(self, object_id: str, camera: str): + if object_id in self.person_face_history: + self.person_face_history.pop(object_id) + + if object_id in self.camera_current_people.get(camera, []): + self.camera_current_people[camera].remove(object_id) + + if len(self.camera_current_people[camera]) == 0: + self.requestor.send_data( + "tracked_object_update", + json.dumps( + { + "type": TrackedObjectUpdateTypesEnum.face, + "name": None, + "camera": camera, + } + ), + ) + + def weighted_average( + self, results_list: list[tuple[str, float, int]], max_weight: int = 4000 + ): + """ + Calculates a robust weighted average, capping the area weight and giving more weight to higher scores. + + Args: + results_list: A list of tuples, where each tuple contains (name, score, face_area). + max_weight: The maximum weight to apply based on face area. + + Returns: + A tuple containing the prominent name and its weighted average score, or (None, 0.0) if the list is empty. + """ + if not results_list: + return None, 0.0 + + weighted_scores = {} + total_weights = {} + + for name, score, face_area in results_list: + if name == "unknown": + continue + + if name not in weighted_scores: + weighted_scores[name] = 0.0 + total_weights[name] = 0.0 + + # Capped weight based on face area + weight = min(face_area, max_weight) + + # Score-based weighting (higher scores get more weight) + weight *= (score - self.face_config.unknown_score) * 10 + weighted_scores[name] += score * weight + total_weights[name] += weight + + if not weighted_scores: + return None, 0.0 + + best_name = max(weighted_scores, key=weighted_scores.get) + weighted_average = weighted_scores[best_name] / total_weights[best_name] + + return best_name, weighted_average + + def write_face_attempt( + self, + frame: np.ndarray, + event_id: str, + timestamp: float, + sub_label: str, + score: float, + ) -> None: + if self.config.face_recognition.save_attempts: + # write face to library + folder = os.path.join(FACE_DIR, "train") + + if "-" in sub_label: + sub_label = sub_label.replace("-", "_") + + file = os.path.join( + folder, f"{event_id}-{timestamp}-{sub_label}-{score}.webp" + ) + os.makedirs(folder, exist_ok=True) + cv2.imwrite(file, frame) + + files = sorted( + filter(lambda f: (f.endswith(".webp")), os.listdir(folder)), + key=lambda f: os.path.getctime(os.path.join(folder, f)), + reverse=True, + ) + + # delete oldest face image if maximum is reached + if len(files) > self.config.face_recognition.save_attempts: + os.unlink(os.path.join(folder, files[-1])) diff --git a/frigate/data_processing/real_time/license_plate.py b/frigate/data_processing/real_time/license_plate.py index d2cb9f2a5..13596057d 100644 --- a/frigate/data_processing/real_time/license_plate.py +++ b/frigate/data_processing/real_time/license_plate.py @@ -1,10 +1,12 @@ """Handle processing images for face detection and recognition.""" +import json import logging import numpy as np from frigate.comms.event_metadata_updater import EventMetadataPublisher +from frigate.comms.inter_process import InterProcessRequestor from frigate.config import FrigateConfig from frigate.data_processing.common.license_plate.mixin import ( LicensePlateProcessingMixin, @@ -12,6 +14,7 @@ from frigate.data_processing.common.license_plate.mixin import ( from frigate.data_processing.common.license_plate.model import ( LicensePlateModelRunner, ) +from frigate.types import TrackedObjectUpdateTypesEnum from ..types import DataProcessorMetrics from .api import RealTimeProcessorApi @@ -23,25 +26,49 @@ class LicensePlateRealTimeProcessor(LicensePlateProcessingMixin, RealTimeProcess def __init__( self, config: FrigateConfig, + requestor: InterProcessRequestor, sub_label_publisher: EventMetadataPublisher, metrics: DataProcessorMetrics, model_runner: LicensePlateModelRunner, detected_license_plates: dict[str, dict[str, any]], ): + self.requestor = requestor self.detected_license_plates = detected_license_plates self.model_runner = model_runner self.lpr_config = config.lpr self.config = config self.sub_label_publisher = sub_label_publisher + self.camera_current_cars: dict[str, list[str]] = {} super().__init__(config, metrics) - def process_frame(self, obj_data: dict[str, any], frame: np.ndarray): + def process_frame( + self, + obj_data: dict[str, any], + frame: np.ndarray, + dedicated_lpr: bool | None = False, + ): """Look for license plates in image.""" - self.lpr_process(obj_data, frame) + self.lpr_process(obj_data, frame, dedicated_lpr) def handle_request(self, topic, request_data) -> dict[str, any] | None: return - def expire_object(self, object_id: str): + def expire_object(self, object_id: str, camera: str): if object_id in self.detected_license_plates: self.detected_license_plates.pop(object_id) + + if object_id in self.camera_current_cars.get(camera, []): + self.camera_current_cars[camera].remove(object_id) + + if len(self.camera_current_cars[camera]) == 0: + self.requestor.send_data( + "tracked_object_update", + json.dumps( + { + "type": TrackedObjectUpdateTypesEnum.lpr, + "name": None, + "plate": None, + "camera": camera, + } + ), + ) diff --git a/frigate/data_processing/types.py b/frigate/data_processing/types.py index 29abb22d1..a19a856bf 100644 --- a/frigate/data_processing/types.py +++ b/frigate/data_processing/types.py @@ -6,18 +6,28 @@ from multiprocessing.sharedctypes import Synchronized class DataProcessorMetrics: - image_embeddings_fps: Synchronized - text_embeddings_sps: Synchronized + image_embeddings_speed: Synchronized + image_embeddings_eps: Synchronized + text_embeddings_speed: Synchronized + text_embeddings_eps: Synchronized + face_rec_speed: Synchronized face_rec_fps: Synchronized + alpr_speed: Synchronized alpr_pps: Synchronized - yolov9_lpr_fps: Synchronized + yolov9_lpr_speed: Synchronized + yolov9_lpr_pps: Synchronized def __init__(self): - self.image_embeddings_fps = mp.Value("d", 0.01) - self.text_embeddings_sps = mp.Value("d", 0.01) - self.face_rec_fps = mp.Value("d", 0.01) - self.alpr_pps = mp.Value("d", 0.01) - self.yolov9_lpr_fps = mp.Value("d", 0.01) + self.image_embeddings_speed = mp.Value("d", 0.0) + self.image_embeddings_eps = mp.Value("d", 0.0) + self.text_embeddings_speed = mp.Value("d", 0.0) + self.text_embeddings_eps = mp.Value("d", 0.0) + self.face_rec_speed = mp.Value("d", 0.0) + self.face_rec_fps = mp.Value("d", 0.0) + self.alpr_speed = mp.Value("d", 0.0) + self.alpr_pps = mp.Value("d", 0.0) + self.yolov9_lpr_speed = mp.Value("d", 0.0) + self.yolov9_lpr_pps = mp.Value("d", 0.0) class DataProcessorModelRunner: diff --git a/frigate/detectors/detection_api.py b/frigate/detectors/detection_api.py index 403bce574..4f03f28aa 100644 --- a/frigate/detectors/detection_api.py +++ b/frigate/detectors/detection_api.py @@ -4,7 +4,7 @@ from typing import List import numpy as np -from frigate.detectors.detector_config import ModelTypeEnum +from frigate.detectors.detector_config import BaseDetectorConfig, ModelTypeEnum logger = logging.getLogger(__name__) @@ -14,9 +14,9 @@ class DetectionApi(ABC): supported_models: List[ModelTypeEnum] @abstractmethod - def __init__(self, detector_config): + def __init__(self, detector_config: BaseDetectorConfig): self.detector_config = detector_config - self.thresh = 0.5 + self.thresh = 0.4 self.height = detector_config.model.height self.width = detector_config.model.width @@ -24,58 +24,34 @@ class DetectionApi(ABC): def detect_raw(self, tensor_input): pass - def post_process_yolonas(self, output): - """ - @param output: output of inference - expected shape: [np.array(1, N, 4), np.array(1, N, 80)] - where N depends on the input size e.g. N=2100 for 320x320 images + def calculate_grids_strides(self, expanded=True) -> None: + grids = [] + expanded_strides = [] - @return: best results: np.array(20, 6) where each row is - in this order (class_id, score, y1/height, x1/width, y2/height, x2/width) - """ + # decode and orient predictions + strides = [8, 16, 32] + hsizes = [self.height // stride for stride in strides] + wsizes = [self.width // stride for stride in strides] - N = output[0].shape[1] + for hsize, wsize, stride in zip(hsizes, wsizes, strides): + xv, yv = np.meshgrid(np.arange(wsize), np.arange(hsize)) - boxes = output[0].reshape(N, 4) - scores = output[1].reshape(N, 80) - - class_ids = np.argmax(scores, axis=1) - scores = scores[np.arange(N), class_ids] - - args_best = np.argwhere(scores > self.thresh)[:, 0] - - num_matches = len(args_best) - if num_matches == 0: - return np.zeros((20, 6), np.float32) - elif num_matches > 20: - args_best20 = np.argpartition(scores[args_best], -20)[-20:] - args_best = args_best[args_best20] - - boxes = boxes[args_best] - class_ids = class_ids[args_best] - scores = scores[args_best] - - boxes = np.transpose( - np.vstack( - ( - boxes[:, 1] / self.height, - boxes[:, 0] / self.width, - boxes[:, 3] / self.height, - boxes[:, 2] / self.width, + if expanded: + grid = np.stack((xv, yv), 2).reshape(1, -1, 2) + grids.append(grid) + shape = grid.shape[:2] + expanded_strides.append(np.full((*shape, 1), stride)) + else: + xv = xv.reshape(1, 1, hsize, wsize) + yv = yv.reshape(1, 1, hsize, wsize) + grids.extend(np.concatenate((xv, yv), axis=1).tolist()) + expanded_strides.extend( + np.array([stride, stride]).reshape(1, 2, 1, 1).tolist() ) - ) - ) - results = np.hstack( - (class_ids[..., np.newaxis], scores[..., np.newaxis], boxes) - ) - - return np.resize(results, (20, 6)) - - def post_process(self, output): - if self.detector_config.model.model_type == ModelTypeEnum.yolonas: - return self.post_process_yolonas(output) + if expanded: + self.grids = np.concatenate(grids, 1) + self.expanded_strides = np.concatenate(expanded_strides, 1) else: - raise ValueError( - f'Model type "{self.detector_config.model.model_type}" is currently not supported.' - ) + self.grids = grids + self.expanded_strides = expanded_strides diff --git a/frigate/detectors/detector_config.py b/frigate/detectors/detector_config.py index be12e7fcc..f14da57a8 100644 --- a/frigate/detectors/detector_config.py +++ b/frigate/detectors/detector_config.py @@ -25,19 +25,22 @@ class PixelFormatEnum(str, Enum): class InputTensorEnum(str, Enum): nchw = "nchw" nhwc = "nhwc" + hwnc = "hwnc" + hwcn = "hwcn" class InputDTypeEnum(str, Enum): float = "float" + float_denorm = "float_denorm" # non-normalized float int = "int" class ModelTypeEnum(str, Enum): + dfine = "dfine" + rfdetr = "rfdetr" ssd = "ssd" yolox = "yolox" - yolov9 = "yolov9" yolonas = "yolonas" - dfine = "dfine" yologeneric = "yolo-generic" @@ -123,6 +126,9 @@ class ModelConfig(BaseModel): if not self.path or not self.path.startswith("plus://"): return + # ensure that model cache dir exists + os.makedirs(MODEL_CACHE_DIR, exist_ok=True) + model_id = self.path[7:] self.path = os.path.join(MODEL_CACHE_DIR, model_id) model_info_path = f"{self.path}.json" diff --git a/frigate/detectors/plugins/edgetpu_tfl.py b/frigate/detectors/plugins/edgetpu_tfl.py index c320bd89b..246d2dd41 100644 --- a/frigate/detectors/plugins/edgetpu_tfl.py +++ b/frigate/detectors/plugins/edgetpu_tfl.py @@ -1,4 +1,5 @@ import logging +import os import numpy as np from pydantic import Field @@ -45,9 +46,17 @@ class EdgeTpuTfl(DetectionApi): experimental_delegates=[edge_tpu_delegate], ) except ValueError: - logger.error( - "No EdgeTPU was detected. If you do not have a Coral device yet, you must configure CPU detectors." - ) + _, ext = os.path.splitext(detector_config.model.path) + + if ext and ext != ".tflite": + logger.error( + "Incorrect model used with EdgeTPU. Only .tflite models can be used with a Coral EdgeTPU." + ) + else: + logger.error( + "No EdgeTPU was detected. If you do not have a Coral device yet, you must configure CPU detectors." + ) + raise self.interpreter.allocate_tensors() diff --git a/frigate/detectors/plugins/hailo8l.py b/frigate/detectors/plugins/hailo8l.py index ad86ca03d..d4ef40d62 100755 --- a/frigate/detectors/plugins/hailo8l.py +++ b/frigate/detectors/plugins/hailo8l.py @@ -1,6 +1,5 @@ import logging import os -import queue import subprocess import threading import urllib.request @@ -28,37 +27,11 @@ from frigate.detectors.detection_api import DetectionApi from frigate.detectors.detector_config import ( BaseDetectorConfig, ) +from frigate.object_detection.util import RequestStore, ResponseStore logger = logging.getLogger(__name__) -# ----------------- ResponseStore Class ----------------- # -class ResponseStore: - """ - A thread-safe hash-based response store that maps request IDs - to their results. Threads can wait on the condition variable until - their request's result appears. - """ - - def __init__(self): - self.responses = {} # Maps request_id -> (original_input, infer_results) - self.lock = threading.Lock() - self.cond = threading.Condition(self.lock) - - def put(self, request_id, response): - with self.cond: - self.responses[request_id] = response - self.cond.notify_all() - - def get(self, request_id, timeout=None): - with self.cond: - if not self.cond.wait_for( - lambda: request_id in self.responses, timeout=timeout - ): - raise TimeoutError(f"Timeout waiting for response {request_id}") - return self.responses.pop(request_id) - - # ----------------- Utility Functions ----------------- # @@ -122,14 +95,14 @@ class HailoAsyncInference: def __init__( self, hef_path: str, - input_queue: queue.Queue, + input_store: RequestStore, output_store: ResponseStore, batch_size: int = 1, input_type: Optional[str] = None, output_type: Optional[Dict[str, str]] = None, send_original_frame: bool = False, ) -> None: - self.input_queue = input_queue + self.input_store = input_store self.output_store = output_store params = VDevice.create_params() @@ -202,11 +175,14 @@ class HailoAsyncInference: return self.hef.get_input_vstream_infos()[0].shape def run(self) -> None: + job = None with self.infer_model.configure() as configured_infer_model: while True: - batch_data = self.input_queue.get() + batch_data = self.input_store.get() + if batch_data is None: break + request_id, frame_data = batch_data preprocessed_batch = [frame_data] request_ids = [request_id] @@ -227,7 +203,9 @@ class HailoAsyncInference: bindings_list=bindings_list, ), ) - job.wait(100) + + if job is not None: + job.wait(100) # ----------------- HailoDetector Class ----------------- # @@ -274,16 +252,14 @@ class HailoDetector(DetectionApi): self.working_model_path = self.check_and_prepare() self.batch_size = 1 - self.input_queue = queue.Queue() + self.input_store = RequestStore() self.response_store = ResponseStore() - self.request_counter = 0 - self.request_counter_lock = threading.Lock() try: logger.debug(f"[INIT] Loading HEF model from {self.working_model_path}") self.inference_engine = HailoAsyncInference( self.working_model_path, - self.input_queue, + self.input_store, self.response_store, self.batch_size, ) @@ -364,26 +340,16 @@ class HailoDetector(DetectionApi): raise FileNotFoundError(f"Model file not found at: {self.model_path}") return cached_model_path - def _get_request_id(self) -> int: - with self.request_counter_lock: - request_id = self.request_counter - self.request_counter += 1 - if self.request_counter > 1000000: - self.request_counter = 0 - return request_id - def detect_raw(self, tensor_input): - request_id = self._get_request_id() - tensor_input = self.preprocess(tensor_input) + if isinstance(tensor_input, np.ndarray) and len(tensor_input.shape) == 3: tensor_input = np.expand_dims(tensor_input, axis=0) - self.input_queue.put((request_id, tensor_input)) + request_id = self.input_store.put(tensor_input) + try: - original_input, infer_results = self.response_store.get( - request_id, timeout=10.0 - ) + _, infer_results = self.response_store.get(request_id, timeout=10.0) except TimeoutError: logger.error( f"Timeout waiting for inference results for request {request_id}" diff --git a/frigate/detectors/plugins/onnx.py b/frigate/detectors/plugins/onnx.py index d94b4660f..45e37d6cd 100644 --- a/frigate/detectors/plugins/onnx.py +++ b/frigate/detectors/plugins/onnx.py @@ -12,7 +12,9 @@ from frigate.detectors.detector_config import ( from frigate.util.model import ( get_ort_providers, post_process_dfine, - post_process_yolov9, + post_process_rfdetr, + post_process_yolo, + post_process_yolox, ) logger = logging.getLogger(__name__) @@ -29,6 +31,8 @@ class ONNXDetector(DetectionApi): type_key = DETECTOR_KEY def __init__(self, detector_config: ONNXDetectorConfig): + super().__init__(detector_config) + try: import onnxruntime as ort @@ -50,13 +54,14 @@ class ONNXDetector(DetectionApi): path, providers=providers, provider_options=options ) - self.h = detector_config.model.height - self.w = detector_config.model.width self.onnx_model_type = detector_config.model.model_type self.onnx_model_px = detector_config.model.input_pixel_format self.onnx_model_shape = detector_config.model.input_tensor path = detector_config.model.path + if self.onnx_model_type == ModelTypeEnum.yolox: + self.calculate_grids_strides() + logger.info(f"ONNX: {path} loaded") def detect_raw(self, tensor_input: np.ndarray): @@ -65,15 +70,19 @@ class ONNXDetector(DetectionApi): None, { "images": tensor_input, - "orig_target_sizes": np.array([[self.h, self.w]], dtype=np.int64), + "orig_target_sizes": np.array( + [[self.height, self.width]], dtype=np.int64 + ), }, ) - return post_process_dfine(tensor_output, self.w, self.h) + return post_process_dfine(tensor_output, self.width, self.height) model_input_name = self.model.get_inputs()[0].name tensor_output = self.model.run(None, {model_input_name: tensor_input}) - if self.onnx_model_type == ModelTypeEnum.yolonas: + if self.onnx_model_type == ModelTypeEnum.rfdetr: + return post_process_rfdetr(tensor_output) + elif self.onnx_model_type == ModelTypeEnum.yolonas: predictions = tensor_output[0] detections = np.zeros((20, 6), np.float32) @@ -88,15 +97,22 @@ class ONNXDetector(DetectionApi): detections[i] = [ class_id, confidence, - y_min / self.h, - x_min / self.w, - y_max / self.h, - x_max / self.w, + y_min / self.height, + x_min / self.width, + y_max / self.height, + x_max / self.width, ] return detections - elif self.onnx_model_type == ModelTypeEnum.yolov9: - predictions: np.ndarray = tensor_output[0] - return post_process_yolov9(predictions, self.w, self.h) + elif self.onnx_model_type == ModelTypeEnum.yologeneric: + return post_process_yolo(tensor_output, self.width, self.height) + elif self.onnx_model_type == ModelTypeEnum.yolox: + return post_process_yolox( + tensor_output[0], + self.width, + self.height, + self.grids, + self.expanded_strides, + ) else: raise Exception( f"{self.onnx_model_type} is currently not supported for onnx. See the docs for more info on supported models." diff --git a/frigate/detectors/plugins/openvino.py b/frigate/detectors/plugins/openvino.py index 0f0b99a1f..08d068d5e 100644 --- a/frigate/detectors/plugins/openvino.py +++ b/frigate/detectors/plugins/openvino.py @@ -10,7 +10,11 @@ from typing_extensions import Literal from frigate.const import MODEL_CACHE_DIR from frigate.detectors.detection_api import DetectionApi from frigate.detectors.detector_config import BaseDetectorConfig, ModelTypeEnum -from frigate.util.model import post_process_yolov9 +from frigate.util.model import ( + post_process_dfine, + post_process_rfdetr, + post_process_yolo, +) logger = logging.getLogger(__name__) @@ -25,13 +29,16 @@ class OvDetectorConfig(BaseDetectorConfig): class OvDetector(DetectionApi): type_key = DETECTOR_KEY supported_models = [ + ModelTypeEnum.dfine, + ModelTypeEnum.rfdetr, ModelTypeEnum.ssd, ModelTypeEnum.yolonas, - ModelTypeEnum.yolov9, + ModelTypeEnum.yologeneric, ModelTypeEnum.yolox, ] def __init__(self, detector_config: OvDetectorConfig): + super().__init__(detector_config) self.ov_core = ov.Core() self.ov_model_type = detector_config.model.model_type @@ -127,25 +134,7 @@ class OvDetector(DetectionApi): break self.num_classes = tensor_shape[2] - 5 logger.info(f"YOLOX model has {self.num_classes} classes") - self.set_strides_grids() - - def set_strides_grids(self): - grids = [] - expanded_strides = [] - - strides = [8, 16, 32] - - hsize_list = [self.h // stride for stride in strides] - wsize_list = [self.w // stride for stride in strides] - - for hsize, wsize, stride in zip(hsize_list, wsize_list, strides): - xv, yv = np.meshgrid(np.arange(wsize), np.arange(hsize)) - grid = np.stack((xv, yv), 2).reshape(1, -1, 2) - grids.append(grid) - shape = grid.shape[:2] - expanded_strides.append(np.full((*shape, 1), stride)) - self.grids = np.concatenate(grids, 1) - self.expanded_strides = np.concatenate(expanded_strides, 1) + self.calculate_grids_strides() ## Takes in class ID, confidence score, and array of [x, y, w, h] that describes detection position, ## returns an array that's easily passable back to Frigate. @@ -163,12 +152,34 @@ class OvDetector(DetectionApi): infer_request = self.interpreter.create_infer_request() # TODO: see if we can use shared_memory=True input_tensor = ov.Tensor(array=tensor_input) + + if self.ov_model_type == ModelTypeEnum.dfine: + infer_request.set_tensor("images", input_tensor) + target_sizes_tensor = ov.Tensor( + np.array([[self.h, self.w]], dtype=np.int64) + ) + infer_request.set_tensor("orig_target_sizes", target_sizes_tensor) + infer_request.infer() + tensor_output = ( + infer_request.get_output_tensor(0).data, + infer_request.get_output_tensor(1).data, + infer_request.get_output_tensor(2).data, + ) + return post_process_dfine(tensor_output, self.w, self.h) + infer_request.infer(input_tensor) detections = np.zeros((20, 6), np.float32) if self.model_invalid: return detections + elif self.ov_model_type == ModelTypeEnum.rfdetr: + return post_process_rfdetr( + [ + infer_request.get_output_tensor(0).data, + infer_request.get_output_tensor(1).data, + ] + ) elif self.ov_model_type == ModelTypeEnum.ssd: results = infer_request.get_output_tensor(0).data[0][0] @@ -203,9 +214,13 @@ class OvDetector(DetectionApi): x_max / self.w, ] return detections - elif self.ov_model_type == ModelTypeEnum.yolov9: - out_tensor = infer_request.get_output_tensor(0).data - return post_process_yolov9(out_tensor, self.w, self.h) + elif self.ov_model_type == ModelTypeEnum.yologeneric: + out_tensor = [] + + for item in infer_request.output_tensors: + out_tensor.append(item.data) + + return post_process_yolo(out_tensor, self.w, self.h) elif self.ov_model_type == ModelTypeEnum.yolox: out_tensor = infer_request.get_output_tensor() # [x, y, h, w, box_score, class_no_1, ..., class_no_80], diff --git a/frigate/detectors/plugins/rknn.py b/frigate/detectors/plugins/rknn.py index 407c93917..1fdd8b9c0 100644 --- a/frigate/detectors/plugins/rknn.py +++ b/frigate/detectors/plugins/rknn.py @@ -4,11 +4,14 @@ import re import urllib.request from typing import Literal +import cv2 +import numpy as np from pydantic import Field from frigate.const import MODEL_CACHE_DIR from frigate.detectors.detection_api import DetectionApi from frigate.detectors.detector_config import BaseDetectorConfig, ModelTypeEnum +from frigate.util.model import post_process_yolo logger = logging.getLogger(__name__) @@ -16,7 +19,11 @@ DETECTOR_KEY = "rknn" supported_socs = ["rk3562", "rk3566", "rk3568", "rk3576", "rk3588"] -supported_models = {ModelTypeEnum.yolonas: "^deci-fp16-yolonas_[sml]$"} +supported_models = { + ModelTypeEnum.yologeneric: "^frigate-fp16-yolov9-[cemst]$", + ModelTypeEnum.yolonas: "^deci-fp16-yolonas_[sml]$", + ModelTypeEnum.yolox: "^rock-(fp16|i8)-yolox_(nano|tiny)$", +} model_cache_dir = os.path.join(MODEL_CACHE_DIR, "rknn_cache/") @@ -40,6 +47,9 @@ class Rknn(DetectionApi): model_props = self.parse_model_input(model_path, soc) + if self.detector_config.model.model_type == ModelTypeEnum.yolox: + self.calculate_grids_strides(expanded=False) + if model_props["preset"]: config.model.model_type = model_props["model_type"] @@ -109,7 +119,7 @@ class Rknn(DetectionApi): model_props["model_type"] = model_type if model_matched: - model_props["filename"] = model_path + f"-{soc}-v2.3.0-1.rknn" + model_props["filename"] = model_path + f"-{soc}-v2.3.2-1.rknn" model_props["path"] = model_cache_dir + model_props["filename"] @@ -130,7 +140,7 @@ class Rknn(DetectionApi): os.mkdir(model_cache_dir) urllib.request.urlretrieve( - f"https://github.com/MarcA711/rknn-models/releases/download/v2.3.0/{filename}", + f"https://github.com/MarcA711/rknn-models/releases/download/v2.3.2/{filename}", model_cache_dir + filename, ) @@ -150,6 +160,141 @@ class Rknn(DetectionApi): 'Make sure to set the model input_tensor to "nhwc" in your config.' ) + def post_process_yolonas(self, output: list[np.ndarray]): + """ + @param output: output of inference + expected shape: [np.array(1, N, 4), np.array(1, N, 80)] + where N depends on the input size e.g. N=2100 for 320x320 images + + @return: best results: np.array(20, 6) where each row is + in this order (class_id, score, y1/height, x1/width, y2/height, x2/width) + """ + + N = output[0].shape[1] + + boxes = output[0].reshape(N, 4) + scores = output[1].reshape(N, 80) + + class_ids = np.argmax(scores, axis=1) + scores = scores[np.arange(N), class_ids] + + args_best = np.argwhere(scores > self.thresh)[:, 0] + + num_matches = len(args_best) + if num_matches == 0: + return np.zeros((20, 6), np.float32) + elif num_matches > 20: + args_best20 = np.argpartition(scores[args_best], -20)[-20:] + args_best = args_best[args_best20] + + boxes = boxes[args_best] + class_ids = class_ids[args_best] + scores = scores[args_best] + + boxes = np.transpose( + np.vstack( + ( + boxes[:, 1] / self.height, + boxes[:, 0] / self.width, + boxes[:, 3] / self.height, + boxes[:, 2] / self.width, + ) + ) + ) + + results = np.hstack( + (class_ids[..., np.newaxis], scores[..., np.newaxis], boxes) + ) + + return np.resize(results, (20, 6)) + + def post_process_yolox( + self, + predictions: list[np.ndarray], + grids: np.ndarray, + expanded_strides: np.ndarray, + ) -> np.ndarray: + def sp_flatten(_in: np.ndarray): + ch = _in.shape[1] + _in = _in.transpose(0, 2, 3, 1) + return _in.reshape(-1, ch) + + boxes, scores, classes_conf = [], [], [] + + input_data = [ + _in.reshape([1, -1] + list(_in.shape[-2:])) for _in in predictions + ] + + for i in range(len(input_data)): + unprocessed_box = input_data[i][:, :4, :, :] + box_xy = unprocessed_box[:, :2, :, :] + box_wh = np.exp(unprocessed_box[:, 2:4, :, :]) * expanded_strides[i] + + box_xy += grids[i] + box_xy *= expanded_strides[i] + box = np.concatenate((box_xy, box_wh), axis=1) + + # Convert [c_x, c_y, w, h] to [x1, y1, x2, y2] + xyxy = np.copy(box) + xyxy[:, 0, :, :] = box[:, 0, :, :] - box[:, 2, :, :] / 2 # top left x + xyxy[:, 1, :, :] = box[:, 1, :, :] - box[:, 3, :, :] / 2 # top left y + xyxy[:, 2, :, :] = box[:, 0, :, :] + box[:, 2, :, :] / 2 # bottom right x + xyxy[:, 3, :, :] = box[:, 1, :, :] + box[:, 3, :, :] / 2 # bottom right y + + boxes.append(xyxy) + scores.append(input_data[i][:, 4:5, :, :]) + classes_conf.append(input_data[i][:, 5:, :, :]) + + # flatten data + boxes = np.concatenate([sp_flatten(_v) for _v in boxes]) + classes_conf = np.concatenate([sp_flatten(_v) for _v in classes_conf]) + scores = np.concatenate([sp_flatten(_v) for _v in scores]) + + # reshape and filter boxes + box_confidences = scores.reshape(-1) + class_max_score = np.max(classes_conf, axis=-1) + classes = np.argmax(classes_conf, axis=-1) + _class_pos = np.where(class_max_score * box_confidences >= 0.4) + scores = (class_max_score * box_confidences)[_class_pos] + boxes = boxes[_class_pos] + classes = classes[_class_pos] + + # run nms + indices = cv2.dnn.NMSBoxes( + bboxes=boxes, + scores=scores, + score_threshold=0.4, + nms_threshold=0.4, + ) + + results = np.zeros((20, 6), np.float32) + + if len(indices) > 0: + for i, idx in enumerate(indices.flatten()[:20]): + box = boxes[idx] + results[i] = [ + classes[idx], + scores[idx], + box[1] / self.height, + box[0] / self.width, + box[3] / self.height, + box[2] / self.width, + ] + + return results + + def post_process(self, output): + if self.detector_config.model.model_type == ModelTypeEnum.yolonas: + return self.post_process_yolonas(output) + elif self.detector_config.model.model_type == ModelTypeEnum.yologeneric: + return post_process_yolo(output, self.width, self.height) + elif self.detector_config.model.model_type == ModelTypeEnum.yolox: + return self.post_process_yolox(output, self.grids, self.expanded_strides) + else: + raise ValueError( + f'Model type "{self.detector_config.model.model_type}" is currently not supported.' + ) + def detect_raw(self, tensor_input): output = self.rknn.inference( [ diff --git a/frigate/embeddings/__init__.py b/frigate/embeddings/__init__.py index 56bd097d6..3687021b0 100644 --- a/frigate/embeddings/__init__.py +++ b/frigate/embeddings/__init__.py @@ -5,11 +5,13 @@ import json import logging import multiprocessing as mp import os +import re import signal import threading from types import FrameType from typing import Optional, Union +from pathvalidate import ValidationError, sanitize_filename from setproctitle import setproctitle from frigate.comms.embeddings_updater import EmbeddingsRequestEnum, EmbeddingsRequestor @@ -197,6 +199,14 @@ class EmbeddingsContext: }, ) + def recognize_face(self, image_data: bytes) -> dict[str, any]: + return self.requestor.send_data( + EmbeddingsRequestEnum.recognize_face.value, + { + "image": base64.b64encode(image_data).decode("ASCII"), + }, + ) + def get_face_ids(self, name: str) -> list[str]: sql_query = f""" SELECT @@ -225,6 +235,49 @@ class EmbeddingsContext: if os.path.isfile(file_path): os.unlink(file_path) + if face != "train" and len(os.listdir(folder)) == 0: + os.rmdir(folder) + + self.requestor.send_data( + EmbeddingsRequestEnum.clear_face_classifier.value, None + ) + + def rename_face(self, old_name: str, new_name: str) -> None: + valid_name_pattern = r"^[a-zA-Z0-9\s_-]{1,50}$" + + try: + sanitized_old_name = sanitize_filename(old_name, replacement_text="_") + sanitized_new_name = sanitize_filename(new_name, replacement_text="_") + except ValidationError as e: + raise ValueError(f"Invalid face name: {str(e)}") + + if not re.match(valid_name_pattern, old_name): + raise ValueError(f"Invalid old face name: {old_name}") + if not re.match(valid_name_pattern, new_name): + raise ValueError(f"Invalid new face name: {new_name}") + if sanitized_old_name != old_name: + raise ValueError(f"Old face name contains invalid characters: {old_name}") + if sanitized_new_name != new_name: + raise ValueError(f"New face name contains invalid characters: {new_name}") + + old_path = os.path.normpath(os.path.join(FACE_DIR, old_name)) + new_path = os.path.normpath(os.path.join(FACE_DIR, new_name)) + + # Prevent path traversal + if not old_path.startswith( + os.path.normpath(FACE_DIR) + ) or not new_path.startswith(os.path.normpath(FACE_DIR)): + raise ValueError("Invalid path detected") + + if not os.path.exists(old_path): + raise ValueError(f"Face {old_name} not found.") + + os.rename(old_path, new_path) + + self.requestor.send_data( + EmbeddingsRequestEnum.clear_face_classifier.value, None + ) + def update_description(self, event_id: str, description: str) -> None: self.requestor.send_data( EmbeddingsRequestEnum.embed_description.value, @@ -235,3 +288,6 @@ class EmbeddingsContext: return self.requestor.send_data( EmbeddingsRequestEnum.reprocess_plate.value, {"event": event} ) + + def reindex_embeddings(self) -> dict[str, any]: + return self.requestor.send_data(EmbeddingsRequestEnum.reindex.value, {}) diff --git a/frigate/embeddings/embeddings.py b/frigate/embeddings/embeddings.py index 7e866d1fe..096077916 100644 --- a/frigate/embeddings/embeddings.py +++ b/frigate/embeddings/embeddings.py @@ -3,6 +3,7 @@ import datetime import logging import os +import threading import time from numpy import ndarray @@ -20,7 +21,7 @@ from frigate.data_processing.types import DataProcessorMetrics from frigate.db.sqlitevecq import SqliteVecQueueDatabase from frigate.models import Event from frigate.types import ModelStatusTypesEnum -from frigate.util.builtin import serialize +from frigate.util.builtin import EventsPerSecond, InferenceSpeed, serialize from frigate.util.path import get_event_thumbnail_bytes from .onnx.jina_v1_embedding import JinaV1ImageEmbedding, JinaV1TextEmbedding @@ -74,6 +75,17 @@ class Embeddings: self.metrics = metrics self.requestor = InterProcessRequestor() + self.image_inference_speed = InferenceSpeed(self.metrics.image_embeddings_speed) + self.image_eps = EventsPerSecond() + self.image_eps.start() + self.text_inference_speed = InferenceSpeed(self.metrics.text_embeddings_speed) + self.text_eps = EventsPerSecond() + self.text_eps.start() + + self.reindex_lock = threading.Lock() + self.reindex_thread = None + self.reindex_running = False + # Create tables if they don't exist self.db.create_embeddings_tables() @@ -115,6 +127,10 @@ class Embeddings: device="GPU" if config.semantic_search.model_size == "large" else "CPU", ) + def update_stats(self) -> None: + self.metrics.image_embeddings_eps.value = self.image_eps.eps() + self.metrics.text_embeddings_eps.value = self.text_eps.eps() + def get_model_definitions(self): # Version-specific models if self.config.semantic_search.model == SemanticSearchModelEnum.jinav2: @@ -169,10 +185,8 @@ class Embeddings: (event_id, serialize(embedding)), ) - duration = datetime.datetime.now().timestamp() - start - self.metrics.image_embeddings_fps.value = ( - self.metrics.image_embeddings_fps.value * 9 + duration - ) / 10 + self.image_inference_speed.update(datetime.datetime.now().timestamp() - start) + self.image_eps.update() return embedding @@ -194,6 +208,7 @@ class Embeddings: for i in range(len(ids)): items.append(ids[i]) items.append(serialize(embeddings[i])) + self.image_eps.update() self.db.execute_sql( """ @@ -204,9 +219,7 @@ class Embeddings: ) duration = datetime.datetime.now().timestamp() - start - self.metrics.text_embeddings_sps.value = ( - self.metrics.text_embeddings_sps.value * 9 + (duration / len(ids)) - ) / 10 + self.text_inference_speed.update(duration / len(ids)) return embeddings @@ -225,10 +238,8 @@ class Embeddings: (event_id, serialize(embedding)), ) - duration = datetime.datetime.now().timestamp() - start - self.metrics.text_embeddings_sps.value = ( - self.metrics.text_embeddings_sps.value * 9 + duration - ) / 10 + self.text_inference_speed.update(datetime.datetime.now().timestamp() - start) + self.text_eps.update() return embedding @@ -249,6 +260,7 @@ class Embeddings: for i in range(len(ids)): items.append(ids[i]) items.append(serialize(embeddings[i])) + self.text_eps.update() self.db.execute_sql( """ @@ -258,10 +270,7 @@ class Embeddings: items, ) - duration = datetime.datetime.now().timestamp() - start - self.metrics.text_embeddings_sps.value = ( - self.metrics.text_embeddings_sps.value * 9 + (duration / len(ids)) - ) / 10 + self.text_inference_speed.update(datetime.datetime.now().timestamp() - start) return embeddings @@ -368,3 +377,27 @@ class Embeddings: totals["status"] = "completed" self.requestor.send_data(UPDATE_EMBEDDINGS_REINDEX_PROGRESS, totals) + + def start_reindex(self) -> bool: + """Start reindexing in a separate thread if not already running.""" + with self.reindex_lock: + if self.reindex_running: + logger.warning("Reindex embeddings is already running.") + return False + + # Mark as running and start the thread + self.reindex_running = True + self.reindex_thread = threading.Thread( + target=self._reindex_wrapper, daemon=True + ) + self.reindex_thread.start() + return True + + def _reindex_wrapper(self) -> None: + """Wrapper to run reindex and reset running flag when done.""" + try: + self.reindex() + finally: + with self.reindex_lock: + self.reindex_running = False + self.reindex_thread = None diff --git a/frigate/embeddings/maintainer.py b/frigate/embeddings/maintainer.py index 2fa3eeb2c..487d5dbc4 100644 --- a/frigate/embeddings/maintainer.py +++ b/frigate/embeddings/maintainer.py @@ -1,6 +1,7 @@ """Maintain embeddings in SQLite-vec.""" import base64 +import datetime import logging import os import threading @@ -13,6 +14,7 @@ import numpy as np from peewee import DoesNotExist from playhouse.sqliteq import SqliteQueueDatabase +from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum from frigate.comms.embeddings_updater import EmbeddingsRequestEnum, EmbeddingsResponder from frigate.comms.event_metadata_updater import ( EventMetadataPublisher, @@ -26,6 +28,7 @@ from frigate.comms.recordings_updater import ( RecordingsDataTypeEnum, ) from frigate.config import FrigateConfig +from frigate.config.camera.camera import CameraTypeEnum from frigate.const import ( CLIPS_DIR, UPDATE_EVENT_DESCRIPTION, @@ -97,6 +100,7 @@ class EmbeddingMaintainer(threading.Thread): self.recordings_subscriber = RecordingsDataSubscriber( RecordingsDataTypeEnum.recordings_available_through ) + self.detection_subscriber = DetectionSubscriber(DetectionTypeEnum.video) self.embeddings_responder = EmbeddingsResponder() self.frame_manager = SharedMemoryFrameManager() @@ -104,7 +108,11 @@ class EmbeddingMaintainer(threading.Thread): # model runners to share between realtime and post processors if self.config.lpr.enabled: - lpr_model_runner = LicensePlateModelRunner(self.requestor) + lpr_model_runner = LicensePlateModelRunner( + self.requestor, + device=self.config.lpr.device, + model_size=self.config.lpr.model_size, + ) # realtime processors self.realtime_processors: list[RealTimeProcessorApi] = [] @@ -112,7 +120,7 @@ class EmbeddingMaintainer(threading.Thread): if self.config.face_recognition.enabled: self.realtime_processors.append( FaceRealTimeProcessor( - self.config, self.event_metadata_publisher, metrics + self.config, self.requestor, self.event_metadata_publisher, metrics ) ) @@ -127,6 +135,7 @@ class EmbeddingMaintainer(threading.Thread): self.realtime_processors.append( LicensePlateRealTimeProcessor( self.config, + self.requestor, self.event_metadata_publisher, metrics, lpr_model_runner, @@ -141,6 +150,7 @@ class EmbeddingMaintainer(threading.Thread): self.post_processors.append( LicensePlatePostProcessor( self.config, + self.requestor, self.event_metadata_publisher, metrics, lpr_model_runner, @@ -162,12 +172,15 @@ class EmbeddingMaintainer(threading.Thread): self._process_requests() self._process_updates() self._process_recordings_updates() + self._process_dedicated_lpr() + self._expire_dedicated_lpr() self._process_finalized() self._process_event_metadata() self.event_subscriber.stop() self.event_end_subscriber.stop() self.recordings_subscriber.stop() + self.detection_subscriber.stop() self.event_metadata_publisher.stop() self.event_metadata_subscriber.stop() self.embeddings_responder.stop() @@ -199,12 +212,18 @@ class EmbeddingMaintainer(threading.Thread): self.embeddings.embed_description("", data, upsert=False), pack=False, ) + elif topic == EmbeddingsRequestEnum.reindex.value: + response = self.embeddings.start_reindex() + return "started" if response else "in_progress" + processors = [self.realtime_processors, self.post_processors] for processor_list in processors: for processor in processor_list: resp = processor.handle_request(topic, data) if resp is not None: return resp + + return None except Exception as e: logger.error(f"Unable to handle embeddings request {e}", exc_info=True) @@ -212,7 +231,7 @@ class EmbeddingMaintainer(threading.Thread): def _process_updates(self) -> None: """Process event updates""" - update = self.event_subscriber.check_for_update(timeout=0.01) + update = self.event_subscriber.check_for_update() if update is None: return @@ -222,6 +241,9 @@ class EmbeddingMaintainer(threading.Thread): if not camera or source_type != EventTypeEnum.tracked_object: return + if self.config.semantic_search.enabled: + self.embeddings.update_stats() + camera_config = self.config.cameras[camera] # no need to process updated objects if face recognition, lpr, genai are disabled @@ -302,7 +324,7 @@ class EmbeddingMaintainer(threading.Thread): def _process_finalized(self) -> None: """Process the end of an event.""" while True: - ended = self.event_end_subscriber.check_for_update(timeout=0.01) + ended = self.event_end_subscriber.check_for_update() if ended == None: break @@ -317,6 +339,7 @@ class EmbeddingMaintainer(threading.Thread): if ( recordings_available is not None and event_id in self.detected_license_plates + and self.config.cameras[camera].type != "lpr" ): processor.process_data( { @@ -336,7 +359,7 @@ class EmbeddingMaintainer(threading.Thread): # expire in realtime processors for processor in self.realtime_processors: - processor.expire_object(event_id) + processor.expire_object(event_id, camera) if updated_db: try: @@ -374,10 +397,30 @@ class EmbeddingMaintainer(threading.Thread): if event_id in self.tracked_events: del self.tracked_events[event_id] + def _expire_dedicated_lpr(self) -> None: + """Remove plates not seen for longer than expiration timeout for dedicated lpr cameras.""" + now = datetime.datetime.now().timestamp() + + to_remove = [] + + for id, data in self.detected_license_plates.items(): + last_seen = data.get("last_seen", 0) + if not last_seen: + continue + + if now - last_seen > self.config.cameras[data["camera"]].lpr.expire_time: + to_remove.append(id) + for id in to_remove: + self.event_metadata_publisher.publish( + EventMetadataTypeEnum.manual_event_end, + (id, now), + ) + self.detected_license_plates.pop(id) + def _process_recordings_updates(self) -> None: """Process recordings updates.""" while True: - recordings_data = self.recordings_subscriber.check_for_update(timeout=0.01) + recordings_data = self.recordings_subscriber.check_for_update() if recordings_data == None: break @@ -394,7 +437,7 @@ class EmbeddingMaintainer(threading.Thread): def _process_event_metadata(self): # Check for regenerate description requests - (topic, payload) = self.event_metadata_subscriber.check_for_update(timeout=0.01) + (topic, payload) = self.event_metadata_subscriber.check_for_update() if topic is None: return @@ -406,6 +449,46 @@ class EmbeddingMaintainer(threading.Thread): event_id, RegenerateDescriptionEnum(source) ) + def _process_dedicated_lpr(self) -> None: + """Process event updates""" + (topic, data) = self.detection_subscriber.check_for_update() + + if topic is None: + return + + camera, frame_name, _, _, motion_boxes, _ = data + + if not camera or not self.config.lpr.enabled or len(motion_boxes) == 0: + return + + camera_config = self.config.cameras[camera] + + if ( + camera_config.type != CameraTypeEnum.lpr + or "license_plate" in camera_config.objects.track + ): + # we're not a dedicated lpr camera or we are one but we're using frigate+ + return + + try: + yuv_frame = self.frame_manager.get( + frame_name, camera_config.frame_shape_yuv + ) + except FileNotFoundError: + pass + + if yuv_frame is None: + logger.debug( + "Unable to process dedicated LPR update because frame is unavailable." + ) + return + + for processor in self.realtime_processors: + if isinstance(processor, LicensePlateRealTimeProcessor): + processor.process_frame(camera, yuv_frame, True) + + self.frame_manager.close(frame_name) + def _create_thumbnail(self, yuv_frame, box, height=500) -> Optional[bytes]: """Return jpg thumbnail of a region of the frame.""" frame = cv2.cvtColor(yuv_frame, cv2.COLOR_YUV2BGR_I420) @@ -502,6 +585,7 @@ class EmbeddingMaintainer(threading.Thread): "type": TrackedObjectUpdateTypesEnum.description, "id": event.id, "description": description, + "camera": event.camera, }, ) diff --git a/frigate/embeddings/onnx/base_embedding.py b/frigate/embeddings/onnx/base_embedding.py index a2ea92674..7403f0ac1 100644 --- a/frigate/embeddings/onnx/base_embedding.py +++ b/frigate/embeddings/onnx/base_embedding.py @@ -69,6 +69,8 @@ class BaseEmbedding(ABC): image = Image.open(BytesIO(response.content)).convert(output) elif isinstance(image, bytes): image = Image.open(BytesIO(image)).convert(output) + elif isinstance(image, np.ndarray): + image = Image.fromarray(image) return image diff --git a/frigate/embeddings/onnx/face_embedding.py b/frigate/embeddings/onnx/face_embedding.py new file mode 100644 index 000000000..c0f35a581 --- /dev/null +++ b/frigate/embeddings/onnx/face_embedding.py @@ -0,0 +1,185 @@ +"""Facenet Embeddings.""" + +import logging +import os + +import numpy as np + +from frigate.const import MODEL_CACHE_DIR +from frigate.util.downloader import ModelDownloader + +from .base_embedding import BaseEmbedding +from .runner import ONNXModelRunner + +try: + from tflite_runtime.interpreter import Interpreter +except ModuleNotFoundError: + from tensorflow.lite.python.interpreter import Interpreter + +logger = logging.getLogger(__name__) + +ARCFACE_INPUT_SIZE = 112 +FACENET_INPUT_SIZE = 160 + + +class FaceNetEmbedding(BaseEmbedding): + def __init__(self): + super().__init__( + model_name="facedet", + model_file="facenet.tflite", + download_urls={ + "facenet.tflite": "https://github.com/NickM-27/facenet-onnx/releases/download/v1.0/facenet.tflite", + }, + ) + self.download_path = os.path.join(MODEL_CACHE_DIR, self.model_name) + self.tokenizer = None + self.feature_extractor = None + self.runner = None + files_names = list(self.download_urls.keys()) + + if not all( + os.path.exists(os.path.join(self.download_path, n)) for n in files_names + ): + logger.debug(f"starting model download for {self.model_name}") + self.downloader = ModelDownloader( + model_name=self.model_name, + download_path=self.download_path, + file_names=files_names, + download_func=self._download_model, + ) + self.downloader.ensure_model_files() + else: + self.downloader = None + self._load_model_and_utils() + logger.debug(f"models are already downloaded for {self.model_name}") + + def _load_model_and_utils(self): + if self.runner is None: + if self.downloader: + self.downloader.wait_for_download() + + self.runner = Interpreter( + model_path=os.path.join(MODEL_CACHE_DIR, "facedet/facenet.tflite"), + num_threads=2, + ) + self.runner.allocate_tensors() + self.tensor_input_details = self.runner.get_input_details() + self.tensor_output_details = self.runner.get_output_details() + + def _preprocess_inputs(self, raw_inputs): + pil = self._process_image(raw_inputs[0]) + + # handle images larger than input size + width, height = pil.size + if width != FACENET_INPUT_SIZE or height != FACENET_INPUT_SIZE: + if width > height: + new_height = int(((height / width) * FACENET_INPUT_SIZE) // 4 * 4) + pil = pil.resize((FACENET_INPUT_SIZE, new_height)) + else: + new_width = int(((width / height) * FACENET_INPUT_SIZE) // 4 * 4) + pil = pil.resize((new_width, FACENET_INPUT_SIZE)) + + og = np.array(pil).astype(np.float32) + + # Image must be FACE_EMBEDDING_SIZExFACE_EMBEDDING_SIZE + og_h, og_w, channels = og.shape + frame = np.zeros( + (FACENET_INPUT_SIZE, FACENET_INPUT_SIZE, channels), dtype=np.float32 + ) + + # compute center offset + x_center = (FACENET_INPUT_SIZE - og_w) // 2 + y_center = (FACENET_INPUT_SIZE - og_h) // 2 + + # copy img image into center of result image + frame[y_center : y_center + og_h, x_center : x_center + og_w] = og + + # run facenet normalization + frame = (frame / 127.5) - 1.0 + + frame = np.expand_dims(frame, axis=0) + return frame + + def __call__(self, inputs): + self._load_model_and_utils() + processed = self._preprocess_inputs(inputs) + self.runner.set_tensor(self.tensor_input_details[0]["index"], processed) + self.runner.invoke() + return self.runner.get_tensor(self.tensor_output_details[0]["index"]) + + +class ArcfaceEmbedding(BaseEmbedding): + def __init__(self): + super().__init__( + model_name="facedet", + model_file="arcface.onnx", + download_urls={ + "arcface.onnx": "https://github.com/NickM-27/facenet-onnx/releases/download/v1.0/arcface.onnx", + }, + ) + self.download_path = os.path.join(MODEL_CACHE_DIR, self.model_name) + self.tokenizer = None + self.feature_extractor = None + self.runner = None + files_names = list(self.download_urls.keys()) + + if not all( + os.path.exists(os.path.join(self.download_path, n)) for n in files_names + ): + logger.debug(f"starting model download for {self.model_name}") + self.downloader = ModelDownloader( + model_name=self.model_name, + download_path=self.download_path, + file_names=files_names, + download_func=self._download_model, + ) + self.downloader.ensure_model_files() + else: + self.downloader = None + self._load_model_and_utils() + logger.debug(f"models are already downloaded for {self.model_name}") + + def _load_model_and_utils(self): + if self.runner is None: + if self.downloader: + self.downloader.wait_for_download() + + self.runner = ONNXModelRunner( + os.path.join(self.download_path, self.model_file), + "GPU", + ) + + def _preprocess_inputs(self, raw_inputs): + pil = self._process_image(raw_inputs[0]) + + # handle images larger than input size + width, height = pil.size + if width != ARCFACE_INPUT_SIZE or height != ARCFACE_INPUT_SIZE: + if width > height: + new_height = int(((height / width) * ARCFACE_INPUT_SIZE) // 4 * 4) + pil = pil.resize((ARCFACE_INPUT_SIZE, new_height)) + else: + new_width = int(((width / height) * ARCFACE_INPUT_SIZE) // 4 * 4) + pil = pil.resize((new_width, ARCFACE_INPUT_SIZE)) + + og = np.array(pil).astype(np.float32) + + # Image must be FACE_EMBEDDING_SIZExFACE_EMBEDDING_SIZE + og_h, og_w, channels = og.shape + frame = np.zeros( + (ARCFACE_INPUT_SIZE, ARCFACE_INPUT_SIZE, channels), dtype=np.float32 + ) + + # compute center offset + x_center = (ARCFACE_INPUT_SIZE - og_w) // 2 + y_center = (ARCFACE_INPUT_SIZE - og_h) // 2 + + # copy img image into center of result image + frame[y_center : y_center + og_h, x_center : x_center + og_w] = og + + # run arcface normalization + frame = (frame / 127.5) - 1.0 + + frame = np.transpose(frame, (2, 0, 1)) + frame = np.expand_dims(frame, axis=0) + return [{"data": frame}] diff --git a/frigate/embeddings/onnx/jina_v1_embedding.py b/frigate/embeddings/onnx/jina_v1_embedding.py index 9924ff9e1..b448ec816 100644 --- a/frigate/embeddings/onnx/jina_v1_embedding.py +++ b/frigate/embeddings/onnx/jina_v1_embedding.py @@ -36,11 +36,12 @@ class JinaV1TextEmbedding(BaseEmbedding): requestor: InterProcessRequestor, device: str = "AUTO", ): + HF_ENDPOINT = os.environ.get("HF_ENDPOINT", "https://huggingface.co") super().__init__( model_name="jinaai/jina-clip-v1", model_file="text_model_fp16.onnx", download_urls={ - "text_model_fp16.onnx": "https://huggingface.co/jinaai/jina-clip-v1/resolve/main/onnx/text_model_fp16.onnx", + "text_model_fp16.onnx": f"{HF_ENDPOINT}/jinaai/jina-clip-v1/resolve/main/onnx/text_model_fp16.onnx", }, ) self.tokenizer_file = "tokenizer" @@ -156,12 +157,13 @@ class JinaV1ImageEmbedding(BaseEmbedding): if model_size == "large" else "vision_model_quantized.onnx" ) + HF_ENDPOINT = os.environ.get("HF_ENDPOINT", "https://huggingface.co") super().__init__( model_name="jinaai/jina-clip-v1", model_file=model_file, download_urls={ - model_file: f"https://huggingface.co/jinaai/jina-clip-v1/resolve/main/onnx/{model_file}", - "preprocessor_config.json": "https://huggingface.co/jinaai/jina-clip-v1/resolve/main/preprocessor_config.json", + model_file: f"{HF_ENDPOINT}/jinaai/jina-clip-v1/resolve/main/onnx/{model_file}", + "preprocessor_config.json": f"{HF_ENDPOINT}/jinaai/jina-clip-v1/resolve/main/preprocessor_config.json", }, ) self.requestor = requestor diff --git a/frigate/embeddings/onnx/jina_v2_embedding.py b/frigate/embeddings/onnx/jina_v2_embedding.py index be6573e50..e9def9a07 100644 --- a/frigate/embeddings/onnx/jina_v2_embedding.py +++ b/frigate/embeddings/onnx/jina_v2_embedding.py @@ -34,12 +34,13 @@ class JinaV2Embedding(BaseEmbedding): model_file = ( "model_fp16.onnx" if model_size == "large" else "model_quantized.onnx" ) + HF_ENDPOINT = os.environ.get("HF_ENDPOINT", "https://huggingface.co") super().__init__( model_name="jinaai/jina-clip-v2", model_file=model_file, download_urls={ - model_file: f"https://huggingface.co/jinaai/jina-clip-v2/resolve/main/onnx/{model_file}", - "preprocessor_config.json": "https://huggingface.co/jinaai/jina-clip-v2/resolve/main/preprocessor_config.json", + model_file: f"{HF_ENDPOINT}/jinaai/jina-clip-v2/resolve/main/onnx/{model_file}", + "preprocessor_config.json": f"{HF_ENDPOINT}/jinaai/jina-clip-v2/resolve/main/preprocessor_config.json", }, ) self.tokenizer_file = "tokenizer" diff --git a/frigate/embeddings/onnx/lpr_embedding.py b/frigate/embeddings/onnx/lpr_embedding.py index c3b9a8771..ac981da8d 100644 --- a/frigate/embeddings/onnx/lpr_embedding.py +++ b/frigate/embeddings/onnx/lpr_embedding.py @@ -31,11 +31,14 @@ class PaddleOCRDetection(BaseEmbedding): requestor: InterProcessRequestor, device: str = "AUTO", ): + model_file = ( + "detection-large.onnx" if model_size == "large" else "detection-small.onnx" + ) super().__init__( model_name="paddleocr-onnx", - model_file="detection.onnx", + model_file=model_file, download_urls={ - "detection.onnx": "https://github.com/hawkeye217/paddleocr-onnx/raw/refs/heads/master/models/detection.onnx" + model_file: f"https://github.com/hawkeye217/paddleocr-onnx/raw/refs/heads/master/models/{model_file}" }, ) self.requestor = requestor @@ -261,8 +264,8 @@ class LicensePlateDetector(BaseEmbedding): def _preprocess_inputs(self, raw_inputs): if isinstance(raw_inputs, list): raise ValueError("License plate embedding does not support batch inputs.") - # Get image as numpy array - img = self._process_image(raw_inputs) + + img = raw_inputs height, width, channels = img.shape # Resize maintaining aspect ratio diff --git a/frigate/embeddings/onnx/runner.py b/frigate/embeddings/onnx/runner.py index 7badae325..c34c97a8d 100644 --- a/frigate/embeddings/onnx/runner.py +++ b/frigate/embeddings/onnx/runner.py @@ -65,10 +65,43 @@ class ONNXModelRunner: elif self.type == "ort": return [input.name for input in self.ort.get_inputs()] + def get_input_width(self): + """Get the input width of the model regardless of backend.""" + if self.type == "ort": + return self.ort.get_inputs()[0].shape[3] + elif self.type == "ov": + input_info = self.interpreter.inputs + first_input = input_info[0] + + try: + partial_shape = first_input.get_partial_shape() + # width dimension + if len(partial_shape) >= 4 and partial_shape[3].is_static: + return partial_shape[3].get_length() + + # If width is dynamic or we can't determine it + return -1 + except Exception: + try: + # gemini says some ov versions might still allow this + input_shape = first_input.shape + return input_shape[3] if len(input_shape) >= 4 else -1 + except Exception: + return -1 + return -1 + def run(self, input: dict[str, Any]) -> Any: if self.type == "ov": infer_request = self.interpreter.create_infer_request() + try: + # This ensures the model starts with a clean state for each sequence + # Important for RNN models like PaddleOCR recognition + infer_request.reset_state() + except Exception: + # this will raise an exception for models with AUTO set as the device + pass + outputs = infer_request.infer(input) return outputs diff --git a/frigate/events/audio.py b/frigate/events/audio.py index adf45431e..024739366 100644 --- a/frigate/events/audio.py +++ b/frigate/events/audio.py @@ -29,7 +29,7 @@ from frigate.const import ( ) from frigate.ffmpeg_presets import parse_preset_input from frigate.log import LogPipe -from frigate.object_detection import load_labels +from frigate.object_detection.base import load_labels from frigate.util.builtin import get_ffmpeg_arg_list from frigate.video import start_or_restart_ffmpeg, stop_ffmpeg diff --git a/frigate/events/cleanup.py b/frigate/events/cleanup.py index ae39e3fd2..fbc7b6c3d 100644 --- a/frigate/events/cleanup.py +++ b/frigate/events/cleanup.py @@ -11,7 +11,7 @@ from frigate.config import FrigateConfig from frigate.const import CLIPS_DIR from frigate.db.sqlitevecq import SqliteVecQueueDatabase from frigate.models import Event, Timeline -from frigate.util.path import delete_event_images +from frigate.util.path import delete_event_snapshot, delete_event_thumbnail logger = logging.getLogger(__name__) @@ -98,7 +98,7 @@ class EventCleanup(threading.Thread): # delete the media from disk for expired in expired_events: - deleted = delete_event_images(expired) + deleted = delete_event_snapshot(expired) if not deleted: logger.warning( @@ -176,7 +176,7 @@ class EventCleanup(threading.Thread): # so no need to delete mp4 files for event in expired_events: events_to_update.append(event.id) - deleted = delete_event_images(event) + deleted = delete_event_snapshot(event) if not deleted: logger.warning( @@ -340,6 +340,10 @@ class EventCleanup(threading.Thread): .iterator() ) events_to_delete = [e.id for e in events] + + for e in events: + delete_event_thumbnail(e) + logger.debug(f"Found {len(events_to_delete)} events that can be expired") if len(events_to_delete) > 0: for i in range(0, len(events_to_delete), CHUNK_SIZE): diff --git a/frigate/events/maintainer.py b/frigate/events/maintainer.py index 7788c83e9..2b0fc4193 100644 --- a/frigate/events/maintainer.py +++ b/frigate/events/maintainer.py @@ -75,7 +75,7 @@ class EventProcessor(threading.Thread): ).execute() while not self.stop_event.is_set(): - update = self.event_receiver.check_for_update() + update = self.event_receiver.check_for_update(timeout=1) if update == None: continue @@ -278,6 +278,13 @@ class EventProcessor(threading.Thread): "top_score": event_data["score"], }, } + if event_data.get("recognized_license_plate") is not None: + event[Event.data]["recognized_license_plate"] = event_data[ + "recognized_license_plate" + ] + event[Event.data]["recognized_license_plate_score"] = event_data[ + "score" + ] Event.insert(event).execute() elif event_type == EventStateEnum.end: event = { diff --git a/frigate/ffmpeg_presets.py b/frigate/ffmpeg_presets.py index 3c251b3b7..77b96057b 100644 --- a/frigate/ffmpeg_presets.py +++ b/frigate/ffmpeg_presets.py @@ -283,7 +283,7 @@ PRESETS_INPUT = { "-probesize", "1000M", "-rw_timeout", - "5000000", + "10000000", ], "preset-rtmp-generic": [ "-avoid_negative_ts", @@ -297,7 +297,7 @@ PRESETS_INPUT = { "-fflags", "+genpts+discardcorrupt", "-rw_timeout", - "5000000", + "10000000", "-use_wallclock_as_timestamps", "1", "-f", @@ -312,7 +312,7 @@ PRESETS_INPUT = { "-rtsp_transport", "tcp", TIMEOUT_PARAM, - "5000000", + "10000000", "-use_wallclock_as_timestamps", "1", ], @@ -321,14 +321,14 @@ PRESETS_INPUT = { "-rtsp_transport", "tcp", TIMEOUT_PARAM, - "5000000", + "10000000", ], "preset-rtsp-restream-low-latency": _user_agent_args + [ "-rtsp_transport", "tcp", TIMEOUT_PARAM, - "5000000", + "10000000", "-fflags", "nobuffer", "-flags", @@ -343,7 +343,7 @@ PRESETS_INPUT = { "-rtsp_transport", "udp", TIMEOUT_PARAM, - "5000000", + "10000000", "-use_wallclock_as_timestamps", "1", ], @@ -362,7 +362,7 @@ PRESETS_INPUT = { "-rtsp_transport", "tcp", TIMEOUT_PARAM, - "5000000", + "10000000", "-use_wallclock_as_timestamps", "1", ], diff --git a/frigate/genai/openai.py b/frigate/genai/openai.py index 4b1926099..76ba8cb44 100644 --- a/frigate/genai/openai.py +++ b/frigate/genai/openai.py @@ -54,9 +54,13 @@ class OpenAIClient(GenAIClient): ], timeout=self.timeout, ) - except TimeoutException as e: + if ( + result is not None + and hasattr(result, "choices") + and len(result.choices) > 0 + ): + return result.choices[0].message.content.strip() + return None + except (TimeoutException, Exception) as e: logger.warning("OpenAI returned an error: %s", str(e)) return None - if len(result.choices) > 0: - return result.choices[0].message.content.strip() - return None diff --git a/frigate/motion/frigate_motion.py b/frigate/motion/frigate_motion.py index 72097667b..fd362de34 100644 --- a/frigate/motion/frigate_motion.py +++ b/frigate/motion/frigate_motion.py @@ -1,9 +1,9 @@ import cv2 -import imutils import numpy as np from frigate.config import MotionConfig from frigate.motion import MotionDetector +from frigate.util.image import grab_cv2_contours class FrigateMotionDetector(MotionDetector): @@ -103,7 +103,7 @@ class FrigateMotionDetector(MotionDetector): contours = cv2.findContours( thresh_dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE ) - contours = imutils.grab_contours(contours) + contours = grab_cv2_contours(contours) # loop over the contours for c in contours: diff --git a/frigate/motion/improved_motion.py b/frigate/motion/improved_motion.py index aae5167a4..69de6d015 100644 --- a/frigate/motion/improved_motion.py +++ b/frigate/motion/improved_motion.py @@ -1,7 +1,6 @@ import logging import cv2 -import imutils import numpy as np from scipy.ndimage import gaussian_filter @@ -9,6 +8,7 @@ from frigate.camera import PTZMetrics from frigate.comms.config_updater import ConfigSubscriber from frigate.config import MotionConfig from frigate.motion import MotionDetector +from frigate.util.image import grab_cv2_contours logger = logging.getLogger(__name__) @@ -147,7 +147,7 @@ class ImprovedMotionDetector(MotionDetector): contours = cv2.findContours( thresh_dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE ) - contours = imutils.grab_contours(contours) + contours = grab_cv2_contours(contours) # loop over the contours total_contour_area = 0 diff --git a/frigate/object_detection.py b/frigate/object_detection/base.py similarity index 88% rename from frigate/object_detection.py rename to frigate/object_detection/base.py index 8e88ae578..c77a720a0 100644 --- a/frigate/object_detection.py +++ b/frigate/object_detection/base.py @@ -6,6 +6,8 @@ import queue import signal import threading from abc import ABC, abstractmethod +from multiprocessing import Queue, Value +from multiprocessing.synchronize import Event as MpEvent import numpy as np from setproctitle import setproctitle @@ -15,12 +17,14 @@ from frigate.detectors import create_detector from frigate.detectors.detector_config import ( BaseDetectorConfig, InputDTypeEnum, - InputTensorEnum, + ModelConfig, ) from frigate.util.builtin import EventsPerSecond, load_labels from frigate.util.image import SharedMemoryFrameManager, UntrackedSharedMemory from frigate.util.services import listen +from .util import tensor_transform + logger = logging.getLogger(__name__) @@ -30,14 +34,6 @@ class ObjectDetector(ABC): pass -def tensor_transform(desired_shape: InputTensorEnum): - # Currently this function only supports BHWC permutations - if desired_shape == InputTensorEnum.nhwc: - return None - elif desired_shape == InputTensorEnum.nchw: - return (0, 3, 1, 2) - - class LocalObjectDetector(ObjectDetector): def __init__( self, @@ -84,17 +80,19 @@ class LocalObjectDetector(ObjectDetector): if self.dtype == InputDTypeEnum.float: tensor_input = tensor_input.astype(np.float32) tensor_input /= 255 + elif self.dtype == InputDTypeEnum.float_denorm: + tensor_input = tensor_input.astype(np.float32) return self.detect_api.detect_raw(tensor_input=tensor_input) def run_detector( name: str, - detection_queue: mp.Queue, - out_events: dict[str, mp.Event], - avg_speed, - start, - detector_config, + detection_queue: Queue, + out_events: dict[str, MpEvent], + avg_speed: Value, + start: Value, + detector_config: BaseDetectorConfig, ): threading.current_thread().name = f"detector:{name}" logger = logging.getLogger(f"detector.{name}") @@ -102,7 +100,7 @@ def run_detector( setproctitle(f"frigate.detector.{name}") listen() - stop_event = mp.Event() + stop_event: MpEvent = mp.Event() def receiveSignal(signalNumber, frame): stop_event.set() @@ -150,17 +148,17 @@ def run_detector( class ObjectDetectProcess: def __init__( self, - name, - detection_queue, - out_events, - detector_config, + name: str, + detection_queue: Queue, + out_events: dict[str, MpEvent], + detector_config: BaseDetectorConfig, ): self.name = name self.out_events = out_events self.detection_queue = detection_queue - self.avg_inference_speed = mp.Value("d", 0.01) - self.detection_start = mp.Value("d", 0.0) - self.detect_process = None + self.avg_inference_speed = Value("d", 0.01) + self.detection_start = Value("d", 0.0) + self.detect_process: util.Process | None = None self.detector_config = detector_config self.start_or_restart() @@ -198,7 +196,15 @@ class ObjectDetectProcess: class RemoteObjectDetector: - def __init__(self, name, labels, detection_queue, event, model_config, stop_event): + def __init__( + self, + name: str, + labels: dict[int, str], + detection_queue: Queue, + event: MpEvent, + model_config: ModelConfig, + stop_event: MpEvent, + ): self.labels = labels self.name = name self.fps = EventsPerSecond() diff --git a/frigate/object_detection/util.py b/frigate/object_detection/util.py new file mode 100644 index 000000000..ea8bd4226 --- /dev/null +++ b/frigate/object_detection/util.py @@ -0,0 +1,77 @@ +"""Object detection utilities.""" + +import queue +import threading + +from numpy import ndarray + +from frigate.detectors.detector_config import InputTensorEnum + + +class RequestStore: + """ + A thread-safe hash-based response store that handles creating requests. + """ + + def __init__(self): + self.request_counter = 0 + self.request_counter_lock = threading.Lock() + self.input_queue = queue.Queue() + + def __get_request_id(self) -> int: + with self.request_counter_lock: + request_id = self.request_counter + self.request_counter += 1 + if self.request_counter > 1000000: + self.request_counter = 0 + return request_id + + def put(self, tensor_input: ndarray) -> int: + request_id = self.__get_request_id() + self.input_queue.put((request_id, tensor_input)) + return request_id + + def get(self) -> tuple[int, ndarray] | None: + try: + return self.input_queue.get() + except Exception: + return None + + +class ResponseStore: + """ + A thread-safe hash-based response store that maps request IDs + to their results. Threads can wait on the condition variable until + their request's result appears. + """ + + def __init__(self): + self.responses = {} # Maps request_id -> (original_input, infer_results) + self.lock = threading.Lock() + self.cond = threading.Condition(self.lock) + + def put(self, request_id: int, response: ndarray): + with self.cond: + self.responses[request_id] = response + self.cond.notify_all() + + def get(self, request_id: int, timeout=None) -> ndarray: + with self.cond: + if not self.cond.wait_for( + lambda: request_id in self.responses, timeout=timeout + ): + raise TimeoutError(f"Timeout waiting for response {request_id}") + + return self.responses.pop(request_id) + + +def tensor_transform(desired_shape: InputTensorEnum): + # Currently this function only supports BHWC permutations + if desired_shape == InputTensorEnum.nhwc: + return None + elif desired_shape == InputTensorEnum.nchw: + return (0, 3, 1, 2) + elif desired_shape == InputTensorEnum.hwnc: + return (1, 2, 0, 3) + elif desired_shape == InputTensorEnum.hwcn: + return (1, 2, 3, 0) diff --git a/frigate/output/birdseye.py b/frigate/output/birdseye.py index 9bbd3abee..20cda50f7 100644 --- a/frigate/output/birdseye.py +++ b/frigate/output/birdseye.py @@ -259,7 +259,7 @@ class BroadcastThread(threading.Thread): ws.send(buf, binary=True) except ValueError: pass - except (BrokenPipeError, ConnectionResetError) as e: + except (BrokenPipeError, ConnectionResetError, OSError) as e: logger.debug(f"Websocket unexpectedly closed {e}") elif self.converter.process.poll() is not None: break @@ -754,7 +754,6 @@ class Birdseye: "birdseye", self.converter, websocket_server, stop_event ) self.birdseye_manager = BirdsEyeFrameManager(config, stop_event) - self.config_enabled_subscriber = ConfigSubscriber("config/enabled/") self.birdseye_subscriber = ConfigSubscriber("config/birdseye/") self.frame_manager = SharedMemoryFrameManager() self.stop_event = stop_event @@ -799,24 +798,13 @@ class Birdseye: updated_birdseye_config, ) = self.birdseye_subscriber.check_for_update() - ( - updated_enabled_topic, - updated_enabled_config, - ) = self.config_enabled_subscriber.check_for_update() - - if not updated_birdseye_topic and not updated_enabled_topic: + if not updated_birdseye_topic: break if updated_birdseye_config: camera_name = updated_birdseye_topic.rpartition("/")[-1] self.config.cameras[camera_name].birdseye = updated_birdseye_config - if updated_enabled_config: - camera_name = updated_enabled_topic.rpartition("/")[-1] - self.config.cameras[ - camera_name - ].enabled = updated_enabled_config.enabled - if self.birdseye_manager.update( camera, len([o for o in current_tracked_objects if not o["stationary"]]), @@ -828,6 +816,5 @@ class Birdseye: def stop(self) -> None: self.birdseye_subscriber.stop() - self.config_enabled_subscriber.stop() self.converter.join() self.broadcaster.join() diff --git a/frigate/output/output.py b/frigate/output/output.py index 30900a5ab..befb663eb 100644 --- a/frigate/output/output.py +++ b/frigate/output/output.py @@ -99,12 +99,7 @@ def output_frames( websocket_thread = threading.Thread(target=websocket_server.serve_forever) detection_subscriber = DetectionSubscriber(DetectionTypeEnum.video) - - enabled_subscribers = { - camera: ConfigSubscriber(f"config/enabled/{camera}", True) - for camera in config.cameras.keys() - if config.cameras[camera].enabled_in_config - } + config_enabled_subscriber = ConfigSubscriber("config/enabled/") jsmpeg_cameras: dict[str, JsmpegCamera] = {} birdseye: Birdseye | None = None @@ -128,16 +123,21 @@ def output_frames( websocket_thread.start() - def get_enabled_state(camera: str) -> bool: - _, config_data = enabled_subscribers[camera].check_for_update() - - if config_data: - config.cameras[camera].enabled = config_data.enabled - return config_data.enabled - - return config.cameras[camera].enabled - while not stop_event.is_set(): + # check if there is an updated config + while True: + ( + updated_enabled_topic, + updated_enabled_config, + ) = config_enabled_subscriber.check_for_update() + + if not updated_enabled_topic: + break + + if updated_enabled_config: + camera_name = updated_enabled_topic.rpartition("/")[-1] + config.cameras[camera_name].enabled = updated_enabled_config.enabled + (topic, data) = detection_subscriber.check_for_update(timeout=1) now = datetime.datetime.now().timestamp() @@ -160,7 +160,7 @@ def output_frames( _, ) = data - if not get_enabled_state(camera): + if not config.cameras[camera].enabled: continue frame = frame_manager.get(frame_name, config.cameras[camera].frame_shape_yuv) @@ -240,9 +240,7 @@ def output_frames( if birdseye is not None: birdseye.stop() - for subscriber in enabled_subscribers.values(): - subscriber.stop() - + config_enabled_subscriber.stop() websocket_server.manager.close_all() websocket_server.manager.stop() websocket_server.manager.join() diff --git a/frigate/plus.py b/frigate/plus.py index 758089b85..197b6e48d 100644 --- a/frigate/plus.py +++ b/frigate/plus.py @@ -45,7 +45,7 @@ class PlusApi: self.key = ( Path(os.path.join("/run/secrets", PLUS_ENV_VAR)).read_text().strip() ) - # check for the addon options file + # check for the add-on options file elif os.path.isfile("/data/options.json"): with open("/data/options.json") as f: raw_options = f.read() @@ -234,3 +234,11 @@ class PlusApi: raise Exception(r.text) return r.json() + + def get_models(self) -> Any: + r = self._get("model/list") + + if not r.ok: + raise Exception(r.text) + + return r.json() diff --git a/frigate/ptz/autotrack.py b/frigate/ptz/autotrack.py index 81e54c6d7..709165c24 100644 --- a/frigate/ptz/autotrack.py +++ b/frigate/ptz/autotrack.py @@ -3,11 +3,9 @@ import asyncio import copy import logging -import queue import threading import time from collections import deque -from functools import partial from multiprocessing.synchronize import Event as MpEvent import cv2 @@ -169,7 +167,12 @@ class PtzAutoTrackerThread(threading.Thread): continue if camera_config.onvif.autotracking.enabled: - self.ptz_autotracker.camera_maintenance(camera) + future = asyncio.run_coroutine_threadsafe( + self.ptz_autotracker.camera_maintenance(camera), + self.ptz_autotracker.onvif.loop, + ) + # Wait for the coroutine to complete + future.result() else: # disabled dynamically by mqtt if self.ptz_autotracker.tracked_object.get(camera): @@ -206,6 +209,7 @@ class PtzAutoTracker: self.calibrating: dict[str, object] = {} self.intercept: dict[str, object] = {} self.move_coefficients: dict[str, object] = {} + self.zoom_time: dict[str, float] = {} self.zoom_factor: dict[str, object] = {} # if cam is set to autotrack, onvif should be set up @@ -218,9 +222,13 @@ class PtzAutoTracker: camera_config.onvif.autotracking.enabled and camera_config.onvif.autotracking.enabled_in_config ): - self._autotracker_setup(camera_config, camera) + future = asyncio.run_coroutine_threadsafe( + self._autotracker_setup(camera_config, camera), self.onvif.loop + ) + # Wait for the coroutine to complete + future.result() - def _autotracker_setup(self, camera_config: CameraConfig, camera: str): + async def _autotracker_setup(self, camera_config: CameraConfig, camera: str): logger.debug(f"{camera}: Autotracker init") self.object_types[camera] = camera_config.onvif.autotracking.track @@ -241,8 +249,8 @@ class PtzAutoTracker: self.intercept[camera] = None self.move_coefficients[camera] = [] - self.move_queues[camera] = queue.Queue() - self.move_queue_locks[camera] = threading.Lock() + self.move_queues[camera] = asyncio.Queue() + self.move_queue_locks[camera] = asyncio.Lock() # handle onvif constructor failing due to no connection if camera not in self.onvif.cams: @@ -254,7 +262,7 @@ class PtzAutoTracker: return if not self.onvif.cams[camera]["init"]: - if not asyncio.run(self.onvif._init_onvif(camera)): + if not await self.onvif._init_onvif(camera): logger.warning( f"Disabling autotracking for {camera}: Unable to initialize onvif" ) @@ -270,9 +278,14 @@ class PtzAutoTracker: self.ptz_metrics[camera].autotracker_enabled.value = False return - move_status_supported = self.onvif.get_service_capabilities(camera) + move_status_supported = await self.onvif.get_service_capabilities(camera) - if move_status_supported is None or move_status_supported.lower() != "true": + if not ( + isinstance(move_status_supported, bool) and move_status_supported + ) and not ( + isinstance(move_status_supported, str) + and move_status_supported.lower() == "true" + ): logger.warning( f"Disabling autotracking for {camera}: ONVIF MoveStatus not supported" ) @@ -281,18 +294,15 @@ class PtzAutoTracker: return if self.onvif.cams[camera]["init"]: - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) - # movement thread per camera - self.move_threads[camera] = threading.Thread( - name=f"ptz_move_thread_{camera}", - target=partial(self._process_move_queue, camera), + # movement queue with asyncio on OnvifController loop + asyncio.run_coroutine_threadsafe( + self._process_move_queue(camera), self.onvif.loop ) - self.move_threads[camera].daemon = True - self.move_threads[camera].start() if camera_config.onvif.autotracking.movement_weights: - if len(camera_config.onvif.autotracking.movement_weights) == 5: + if len(camera_config.onvif.autotracking.movement_weights) == 6: camera_config.onvif.autotracking.movement_weights = [ float(val) for val in camera_config.onvif.autotracking.movement_weights @@ -311,7 +321,10 @@ class PtzAutoTracker: camera_config.onvif.autotracking.movement_weights[2] ) self.move_coefficients[camera] = ( - camera_config.onvif.autotracking.movement_weights[3:] + camera_config.onvif.autotracking.movement_weights[3:5] + ) + self.zoom_time[camera] = ( + camera_config.onvif.autotracking.movement_weights[5] ) else: camera_config.onvif.autotracking.enabled = False @@ -321,7 +334,7 @@ class PtzAutoTracker: ) if camera_config.onvif.autotracking.calibrate_on_startup: - self._calibrate_camera(camera) + await self._calibrate_camera(camera) self.ptz_metrics[camera].tracking_active.clear() self.dispatcher.publish(f"{camera}/ptz_autotracker/active", "OFF", retain=False) @@ -340,7 +353,7 @@ class PtzAutoTracker: self.config.cameras[camera].onvif.autotracking.movement_weights, ) - def _calibrate_camera(self, camera): + async def _calibrate_camera(self, camera): # move the camera from the preset in steps and measure the time it takes to move that amount # this will allow us to predict movement times with a simple linear regression # start with 0 so we can determine a baseline (to be used as the intercept in the regression calc) @@ -360,28 +373,29 @@ class PtzAutoTracker: != ZoomingModeEnum.disabled ): logger.info(f"Calibration for {camera} in progress: 0% complete") + self.zoom_time[camera] = 0 for i in range(2): # absolute move to 0 - fully zoomed out - self.onvif._zoom_absolute( + await self.onvif._zoom_absolute( camera, self.onvif.cams[camera]["absolute_zoom_range"]["XRange"]["Min"], 1, ) while not self.ptz_metrics[camera].motor_stopped.is_set(): - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) zoom_out_values.append(self.ptz_metrics[camera].zoom_level.value) - self.onvif._zoom_absolute( + await self.onvif._zoom_absolute( camera, self.onvif.cams[camera]["absolute_zoom_range"]["XRange"]["Max"], 1, ) while not self.ptz_metrics[camera].motor_stopped.is_set(): - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) zoom_in_values.append(self.ptz_metrics[camera].zoom_level.value) @@ -390,7 +404,7 @@ class PtzAutoTracker: == ZoomingModeEnum.relative ): # relative move to -0.01 - self.onvif._move_relative( + await self.onvif._move_relative( camera, 0, 0, @@ -399,12 +413,13 @@ class PtzAutoTracker: ) while not self.ptz_metrics[camera].motor_stopped.is_set(): - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) zoom_out_values.append(self.ptz_metrics[camera].zoom_level.value) + zoom_start_time = time.time() # relative move to 0.01 - self.onvif._move_relative( + await self.onvif._move_relative( camera, 0, 0, @@ -413,7 +428,39 @@ class PtzAutoTracker: ) while not self.ptz_metrics[camera].motor_stopped.is_set(): - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) + + zoom_stop_time = time.time() + + full_relative_start_time = time.time() + + await self.onvif._move_relative( + camera, + -1, + -1, + -1e-2, + 1, + ) + + while not self.ptz_metrics[camera].motor_stopped.is_set(): + await self.onvif.get_camera_status(camera) + + full_relative_stop_time = time.time() + + await self.onvif._move_relative( + camera, + 1, + 1, + 1e-2, + 1, + ) + + while not self.ptz_metrics[camera].motor_stopped.is_set(): + await self.onvif.get_camera_status(camera) + + self.zoom_time[camera] = ( + full_relative_stop_time - full_relative_start_time + ) - (zoom_stop_time - zoom_start_time) zoom_in_values.append(self.ptz_metrics[camera].zoom_level.value) @@ -421,14 +468,14 @@ class PtzAutoTracker: self.ptz_metrics[camera].min_zoom.value = min(zoom_out_values) logger.debug( - f"{camera}: Calibration values: max zoom: {self.ptz_metrics[camera].max_zoom.value}, min zoom: {self.ptz_metrics[camera].min_zoom.value}" + f"{camera}: Calibration values: max zoom: {self.ptz_metrics[camera].max_zoom.value}, min zoom: {self.ptz_metrics[camera].min_zoom.value}, zoom time: {self.zoom_time[camera]}" ) else: self.ptz_metrics[camera].max_zoom.value = 1 self.ptz_metrics[camera].min_zoom.value = 0 - self.onvif._move_to_preset( + await self.onvif._move_to_preset( camera, self.config.cameras[camera].onvif.autotracking.return_preset.lower(), ) @@ -437,18 +484,18 @@ class PtzAutoTracker: # Wait until the camera finishes moving while not self.ptz_metrics[camera].motor_stopped.is_set(): - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) for step in range(num_steps): pan = step_sizes[step] tilt = step_sizes[step] start_time = time.time() - self.onvif._move_relative(camera, pan, tilt, 0, 1) + await self.onvif._move_relative(camera, pan, tilt, 0, 1) # Wait until the camera finishes moving while not self.ptz_metrics[camera].motor_stopped.is_set(): - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) stop_time = time.time() self.move_metrics[camera].append( @@ -460,7 +507,7 @@ class PtzAutoTracker: } ) - self.onvif._move_to_preset( + await self.onvif._move_to_preset( camera, self.config.cameras[camera].onvif.autotracking.return_preset.lower(), ) @@ -469,7 +516,7 @@ class PtzAutoTracker: # Wait until the camera finishes moving while not self.ptz_metrics[camera].motor_stopped.is_set(): - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) logger.info( f"Calibration for {camera} in progress: {round((step / num_steps) * 100)}% complete" @@ -537,6 +584,7 @@ class PtzAutoTracker: self.ptz_metrics[camera].max_zoom.value, self.intercept[camera], *self.move_coefficients[camera], + self.zoom_time[camera], ] ) @@ -665,18 +713,17 @@ class PtzAutoTracker: centroid_distance < self.tracked_object_metrics[camera]["distance"] ) - def _process_move_queue(self, camera): - camera_config = self.config.cameras[camera] - camera_config.frame_shape[1] - camera_config.frame_shape[0] + async def _process_move_queue(self, camera): + move_queue = self.move_queues[camera] while not self.stop_event.is_set(): try: - move_data = self.move_queues[camera].get(True, 0.1) - except queue.Empty: + # Asynchronously wait for move data with a timeout + move_data = await asyncio.wait_for(move_queue.get(), timeout=0.1) + except asyncio.TimeoutError: continue - with self.move_queue_locks[camera]: + async with self.move_queue_locks[camera]: frame_time, pan, tilt, zoom = move_data # if we're receiving move requests during a PTZ move, ignore them @@ -685,8 +732,6 @@ class PtzAutoTracker: self.ptz_metrics[camera].start_time.value, self.ptz_metrics[camera].stop_time.value, ): - # instead of dequeueing this might be a good place to preemptively move based - # on an estimate - for fast moving objects, etc. logger.debug( f"{camera}: Move queue: PTZ moving, dequeueing move request - frame time: {frame_time}, final pan: {pan}, final tilt: {tilt}, final zoom: {zoom}" ) @@ -697,25 +742,24 @@ class PtzAutoTracker: self.config.cameras[camera].onvif.autotracking.zooming == ZoomingModeEnum.relative ): - self.onvif._move_relative(camera, pan, tilt, zoom, 1) - + await self.onvif._move_relative(camera, pan, tilt, zoom, 1) else: if pan != 0 or tilt != 0: - self.onvif._move_relative(camera, pan, tilt, 0, 1) + await self.onvif._move_relative(camera, pan, tilt, 0, 1) # Wait until the camera finishes moving while not self.ptz_metrics[camera].motor_stopped.is_set(): - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) if ( zoom > 0 and self.ptz_metrics[camera].zoom_level.value != zoom ): - self.onvif._zoom_absolute(camera, zoom, 1) + await self.onvif._zoom_absolute(camera, zoom, 1) # Wait until the camera finishes moving while not self.ptz_metrics[camera].motor_stopped.is_set(): - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) if self.config.cameras[camera].onvif.autotracking.movement_weights: logger.debug( @@ -752,6 +796,10 @@ class PtzAutoTracker: # calculate new coefficients if we have enough data self._calculate_move_coefficients(camera) + # Clean up the queue on exit + while not move_queue.empty(): + await move_queue.get() + def _enqueue_move(self, camera, frame_time, pan, tilt, zoom): def split_value(value, suppress_diff=True): clipped = np.clip(value, -1, 1) @@ -780,7 +828,9 @@ class PtzAutoTracker: f"{camera}: Enqueue movement for frame time: {frame_time} pan: {pan}, tilt: {tilt}, zoom: {zoom}" ) move_data = (frame_time, pan, tilt, zoom) - self.move_queues[camera].put(move_data) + self.onvif.loop.call_soon_threadsafe( + self.move_queues[camera].put_nowait, move_data + ) # reset values to not split up large movements pan = 0 @@ -1061,6 +1111,7 @@ class PtzAutoTracker: average_velocity = np.zeros((4,)) predicted_box = obj.obj_data["box"] + zoom_predicted_box = obj.obj_data["box"] centroid_x = obj.obj_data["centroid"][0] centroid_y = obj.obj_data["centroid"][1] @@ -1069,20 +1120,20 @@ class PtzAutoTracker: pan = ((centroid_x / camera_width) - 0.5) * 2 tilt = (0.5 - (centroid_y / camera_height)) * 2 + _, average_velocity = ( + self._get_valid_velocity(camera, obj) + if "velocity" not in self.tracked_object_metrics[camera] + else ( + self.tracked_object_metrics[camera]["valid_velocity"], + self.tracked_object_metrics[camera]["velocity"], + ) + ) + if ( camera_config.onvif.autotracking.movement_weights ): # use estimates if we have available coefficients predicted_movement_time = self._predict_movement_time(camera, pan, tilt) - _, average_velocity = ( - self._get_valid_velocity(camera, obj) - if "velocity" not in self.tracked_object_metrics[camera] - else ( - self.tracked_object_metrics[camera]["valid_velocity"], - self.tracked_object_metrics[camera]["velocity"], - ) - ) - if np.any(average_velocity): # this box could exceed the frame boundaries if velocity is high # but we'll handle that in _enqueue_move() as two separate moves @@ -1111,6 +1162,34 @@ class PtzAutoTracker: camera, obj, predicted_box, predicted_movement_time, debug_zoom=True ) + if ( + camera_config.onvif.autotracking.movement_weights + and camera_config.onvif.autotracking.zooming == ZoomingModeEnum.relative + and zoom != 0 + ): + zoom_predicted_movement_time = 0 + + if np.any(average_velocity): + zoom_predicted_movement_time = abs(zoom) * self.zoom_time[camera] + + zoom_predicted_box = ( + predicted_box + + camera_fps * zoom_predicted_movement_time * average_velocity + ) + + zoom_predicted_box = np.round(zoom_predicted_box).astype(int) + + centroid_x = round((zoom_predicted_box[0] + zoom_predicted_box[2]) / 2) + centroid_y = round((zoom_predicted_box[1] + zoom_predicted_box[3]) / 2) + + # recalculate pan and tilt with new centroid + pan = ((centroid_x / camera_width) - 0.5) * 2 + tilt = (0.5 - (centroid_y / camera_height)) * 2 + + logger.debug( + f"{camera}: Zoom amount: {zoom}, zoom predicted time: {zoom_predicted_movement_time}, zoom predicted box: {tuple(zoom_predicted_box)}" + ) + self._enqueue_move(camera, obj.obj_data["frame_time"], pan, tilt, zoom) def _autotrack_move_zoom_only(self, camera, obj): @@ -1242,7 +1321,7 @@ class PtzAutoTracker: return # this is a brand new object that's on our camera, has our label, entered the zone, - # is not a false positive, and is not initially motionless + # is not a false positive, and is active if ( # new object self.tracked_object[camera] is None @@ -1252,7 +1331,7 @@ class PtzAutoTracker: and not obj.previous["false_positive"] and not obj.false_positive and not self.tracked_object_history[camera] - and obj.obj_data["motionless_count"] == 0 + and obj.active ): logger.debug( f"{camera}: New object: {obj.obj_data['id']} {obj.obj_data['box']} {obj.obj_data['frame_time']}" @@ -1347,7 +1426,7 @@ class PtzAutoTracker: ** (1 / self.zoom_factor[camera]) } - def camera_maintenance(self, camera): + async def camera_maintenance(self, camera): # bail and don't check anything if we're calibrating or tracking an object if ( not self.autotracker_init[camera] @@ -1364,7 +1443,7 @@ class PtzAutoTracker: self._autotracker_setup(self.config.cameras[camera], camera) # regularly update camera status if not self.ptz_metrics[camera].motor_stopped.is_set(): - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) # return to preset if tracking is over if ( @@ -1382,22 +1461,18 @@ class PtzAutoTracker: self.tracked_object[camera] = None self.tracked_object_history[camera].clear() - # empty move queue - while not self.move_queues[camera].empty(): - self.move_queues[camera].get() - self.ptz_metrics[camera].motor_stopped.wait() logger.debug( f"{camera}: Time is {self.ptz_metrics[camera].frame_time.value}, returning to preset: {autotracker_config.return_preset}" ) - self.onvif._move_to_preset( + await self.onvif._move_to_preset( camera, autotracker_config.return_preset.lower(), ) # update stored zoom level from preset if not self.ptz_metrics[camera].motor_stopped.is_set(): - self.onvif.get_camera_status(camera) + await self.onvif.get_camera_status(camera) self.ptz_metrics[camera].tracking_active.clear() self.dispatcher.publish( diff --git a/frigate/ptz/onvif.py b/frigate/ptz/onvif.py index dea7f5b77..b01d9ed96 100644 --- a/frigate/ptz/onvif.py +++ b/frigate/ptz/onvif.py @@ -2,6 +2,7 @@ import asyncio import logging +import threading import time from enum import Enum from importlib.util import find_spec @@ -39,27 +40,56 @@ class OnvifController: def __init__( self, config: FrigateConfig, ptz_metrics: dict[str, PTZMetrics] ) -> None: - self.cams: dict[str, ONVIFCamera] = {} + self.cams: dict[str, dict] = {} self.failed_cams: dict[str, dict] = {} self.max_retries = 5 self.reset_timeout = 900 # 15 minutes - self.config = config self.ptz_metrics = ptz_metrics + # Create a dedicated event loop and run it in a separate thread + self.loop = asyncio.new_event_loop() + self.loop_thread = threading.Thread(target=self._run_event_loop, daemon=True) + self.loop_thread.start() + + self.camera_configs = {} for cam_name, cam in config.cameras.items(): if not cam.enabled: continue - if cam.onvif.host: - result = self._create_onvif_camera(cam_name, cam) - if result: - self.cams[cam_name] = result + self.camera_configs[cam_name] = cam - def _create_onvif_camera(self, cam_name: str, cam) -> dict | None: - """Create an ONVIF camera instance and handle failures.""" + asyncio.run_coroutine_threadsafe(self._init_cameras(), self.loop) + + def _run_event_loop(self) -> None: + """Run the event loop in a separate thread.""" + asyncio.set_event_loop(self.loop) try: - return { + self.loop.run_forever() + except Exception as e: + logger.error(f"Onvif event loop terminated unexpectedly: {e}") + + async def _init_cameras(self) -> None: + """Initialize all configured cameras.""" + for cam_name in self.camera_configs: + await self._init_single_camera(cam_name) + + async def _init_single_camera(self, cam_name: str) -> bool: + """Initialize a single camera by name. + + Args: + cam_name: The name of the camera to initialize + + Returns: + bool: True if initialization succeeded, False otherwise + """ + if cam_name not in self.camera_configs: + logger.error(f"No configuration found for camera {cam_name}") + return False + + cam = self.camera_configs[cam_name] + try: + self.cams[cam_name] = { "onvif": ONVIFCamera( cam.onvif.host, cam.onvif.port, @@ -74,7 +104,8 @@ class OnvifController: "features": [], "presets": {}, } - except ONVIFError as e: + return True + except (Fault, ONVIFError, TransportError, Exception) as e: logger.error(f"Failed to create ONVIF camera instance for {cam_name}: {e}") # track initial failures self.failed_cams[cam_name] = { @@ -82,11 +113,15 @@ class OnvifController: "last_error": str(e), "last_attempt": time.time(), } - return None + return False async def _init_onvif(self, camera_name: str) -> bool: onvif: ONVIFCamera = self.cams[camera_name]["onvif"] - await onvif.update_xaddrs() + try: + await onvif.update_xaddrs() + except Exception as e: + logger.error(f"Onvif connection failed for {camera_name}: {e}") + return False # create init services media: ONVIFService = await onvif.create_media_service() @@ -96,7 +131,7 @@ class OnvifController: # this will fire an exception if camera is not a ptz capabilities = onvif.get_definition("ptz") logger.debug(f"Onvif capabilities for {camera_name}: {capabilities}") - except (ONVIFError, Fault, TransportError) as e: + except (Fault, ONVIFError, TransportError, Exception) as e: logger.error( f"Unable to get Onvif capabilities for camera: {camera_name}: {e}" ) @@ -105,7 +140,7 @@ class OnvifController: try: profiles = await media.GetProfiles() logger.debug(f"Onvif profiles for {camera_name}: {profiles}") - except (ONVIFError, Fault, TransportError) as e: + except (Fault, ONVIFError, TransportError, Exception) as e: logger.error( f"Unable to get Onvif media profiles for camera: {camera_name}: {e}" ) @@ -236,12 +271,12 @@ class OnvifController: logger.debug( f"{camera_name}: Relative move request after deleting zoom: {move_request}" ) - except Exception: + except Exception as e: self.config.cameras[ camera_name ].onvif.autotracking.zooming = ZoomingModeEnum.disabled logger.warning( - f"Disabling autotracking zooming for {camera_name}: Relative zoom not supported" + f"Disabling autotracking zooming for {camera_name}: Relative zoom not supported. Exception: {e}" ) if move_request.Speed is None: @@ -259,7 +294,7 @@ class OnvifController: # setup existing presets try: presets: list[dict] = await ptz.GetPresets({"ProfileToken": profile.token}) - except ONVIFError as e: + except (Fault, ONVIFError, TransportError, Exception) as e: logger.warning(f"Unable to get presets from camera: {camera_name}: {e}") presets = [] @@ -291,7 +326,7 @@ class OnvifController: self.cams[camera_name]["relative_zoom_range"] = ( ptz_config.Spaces.RelativeZoomTranslationSpace[0] ) - except Exception: + except Exception as e: if ( self.config.cameras[camera_name].onvif.autotracking.zooming == ZoomingModeEnum.relative @@ -300,7 +335,7 @@ class OnvifController: camera_name ].onvif.autotracking.zooming = ZoomingModeEnum.disabled logger.warning( - f"Disabling autotracking zooming for {camera_name}: Relative zoom not supported" + f"Disabling autotracking zooming for {camera_name}: Relative zoom not supported. Exception: {e}" ) if configs.DefaultAbsoluteZoomPositionSpace: @@ -315,13 +350,13 @@ class OnvifController: ptz_config.Spaces.AbsoluteZoomPositionSpace[0] ) self.cams[camera_name]["zoom_limits"] = configs.ZoomLimits - except Exception: + except Exception as e: if self.config.cameras[camera_name].onvif.autotracking.zooming: self.config.cameras[ camera_name ].onvif.autotracking.zooming = ZoomingModeEnum.disabled logger.warning( - f"Disabling autotracking zooming for {camera_name}: Absolute zoom not supported" + f"Disabling autotracking zooming for {camera_name}: Absolute zoom not supported. Exception: {e}" ) # set relative pan/tilt space for autotracker @@ -340,25 +375,23 @@ class OnvifController: self.cams[camera_name]["init"] = True return True - def _stop(self, camera_name: str) -> None: + async def _stop(self, camera_name: str) -> None: move_request = self.cams[camera_name]["move_request"] - asyncio.run( - self.cams[camera_name]["ptz"].Stop( - { - "ProfileToken": move_request.ProfileToken, - "PanTilt": True, - "Zoom": True, - } - ) + await self.cams[camera_name]["ptz"].Stop( + { + "ProfileToken": move_request.ProfileToken, + "PanTilt": True, + "Zoom": True, + } ) self.cams[camera_name]["active"] = False - def _move(self, camera_name: str, command: OnvifCommandEnum) -> None: + async def _move(self, camera_name: str, command: OnvifCommandEnum) -> None: if self.cams[camera_name]["active"]: logger.warning( f"{camera_name} is already performing an action, stopping..." ) - self._stop(camera_name) + await self._stop(camera_name) if "pt" not in self.cams[camera_name]["features"]: logger.error(f"{camera_name} does not support ONVIF pan/tilt movement.") @@ -387,11 +420,11 @@ class OnvifController: } try: - asyncio.run(self.cams[camera_name]["ptz"].ContinuousMove(move_request)) - except ONVIFError as e: + await self.cams[camera_name]["ptz"].ContinuousMove(move_request) + except (Fault, ONVIFError, TransportError, Exception) as e: logger.warning(f"Onvif sending move request to {camera_name} failed: {e}") - def _move_relative(self, camera_name: str, pan, tilt, zoom, speed) -> None: + async def _move_relative(self, camera_name: str, pan, tilt, zoom, speed) -> None: if "pt-r-fov" not in self.cams[camera_name]["features"]: logger.error(f"{camera_name} does not support ONVIF RelativeMove (FOV).") return @@ -460,7 +493,7 @@ class OnvifController: } move_request.Translation.Zoom.x = zoom - asyncio.run(self.cams[camera_name]["ptz"].RelativeMove(move_request)) + await self.cams[camera_name]["ptz"].RelativeMove(move_request) # reset after the move request move_request.Translation.PanTilt.x = 0 @@ -475,7 +508,7 @@ class OnvifController: self.cams[camera_name]["active"] = False - def _move_to_preset(self, camera_name: str, preset: str) -> None: + async def _move_to_preset(self, camera_name: str, preset: str) -> None: if preset not in self.cams[camera_name]["presets"]: logger.error(f"{preset} is not a valid preset for {camera_name}") return @@ -485,23 +518,22 @@ class OnvifController: self.ptz_metrics[camera_name].stop_time.value = 0 move_request = self.cams[camera_name]["move_request"] preset_token = self.cams[camera_name]["presets"][preset] - asyncio.run( - self.cams[camera_name]["ptz"].GotoPreset( - { - "ProfileToken": move_request.ProfileToken, - "PresetToken": preset_token, - } - ) + + await self.cams[camera_name]["ptz"].GotoPreset( + { + "ProfileToken": move_request.ProfileToken, + "PresetToken": preset_token, + } ) self.cams[camera_name]["active"] = False - def _zoom(self, camera_name: str, command: OnvifCommandEnum) -> None: + async def _zoom(self, camera_name: str, command: OnvifCommandEnum) -> None: if self.cams[camera_name]["active"]: logger.warning( f"{camera_name} is already performing an action, stopping..." ) - self._stop(camera_name) + await self._stop(camera_name) if "zoom" not in self.cams[camera_name]["features"]: logger.error(f"{camera_name} does not support ONVIF zooming.") @@ -515,9 +547,9 @@ class OnvifController: elif command == OnvifCommandEnum.zoom_out: move_request.Velocity = {"Zoom": {"x": -0.5}} - asyncio.run(self.cams[camera_name]["ptz"].ContinuousMove(move_request)) + await self.cams[camera_name]["ptz"].ContinuousMove(move_request) - def _zoom_absolute(self, camera_name: str, zoom, speed) -> None: + async def _zoom_absolute(self, camera_name: str, zoom, speed) -> None: if "zoom-a" not in self.cams[camera_name]["features"]: logger.error(f"{camera_name} does not support ONVIF AbsoluteMove zooming.") return @@ -556,19 +588,20 @@ class OnvifController: logger.debug(f"{camera_name}: Absolute zoom: {zoom}") - asyncio.run(self.cams[camera_name]["ptz"].AbsoluteMove(move_request)) + await self.cams[camera_name]["ptz"].AbsoluteMove(move_request) self.cams[camera_name]["active"] = False - def handle_command( + async def handle_command_async( self, camera_name: str, command: OnvifCommandEnum, param: str = "" ) -> None: + """Handle ONVIF commands asynchronously""" if camera_name not in self.cams.keys(): logger.error(f"ONVIF is not configured for {camera_name}") return if not self.cams[camera_name]["init"]: - if not asyncio.run(self._init_onvif(camera_name)): + if not await self._init_onvif(camera_name): return try: @@ -576,22 +609,43 @@ class OnvifController: # already init return elif command == OnvifCommandEnum.stop: - self._stop(camera_name) + await self._stop(camera_name) elif command == OnvifCommandEnum.preset: - self._move_to_preset(camera_name, param) + await self._move_to_preset(camera_name, param) elif command == OnvifCommandEnum.move_relative: _, pan, tilt = param.split("_") - self._move_relative(camera_name, float(pan), float(tilt), 0, 1) + await self._move_relative(camera_name, float(pan), float(tilt), 0, 1) elif ( command == OnvifCommandEnum.zoom_in or command == OnvifCommandEnum.zoom_out ): - self._zoom(camera_name, command) + await self._zoom(camera_name, command) else: - self._move(camera_name, command) - except ONVIFError as e: + await self._move(camera_name, command) + except (Fault, ONVIFError, TransportError, Exception) as e: logger.error(f"Unable to handle onvif command: {e}") + def handle_command( + self, camera_name: str, command: OnvifCommandEnum, param: str = "" + ) -> None: + """ + Handle ONVIF commands by scheduling them in the event loop. + This is the synchronous interface that schedules async work. + """ + future = asyncio.run_coroutine_threadsafe( + self.handle_command_async(camera_name, command, param), self.loop + ) + + try: + # Wait with a timeout to prevent blocking indefinitely + future.result(timeout=10) + except asyncio.TimeoutError: + logger.error(f"Command {command} timed out for camera {camera_name}") + except Exception as e: + logger.error( + f"Error executing command {command} for camera {camera_name}: {e}" + ) + async def get_camera_info(self, camera_name: str) -> dict[str, any]: """ Get ptz capabilities and presets, attempting to reconnect if ONVIF is configured @@ -605,26 +659,23 @@ class OnvifController: ) return {} - if camera_name not in self.cams and ( + if camera_name not in self.cams.keys() and ( camera_name not in self.config.cameras or not self.config.cameras[camera_name].onvif.host ): logger.debug(f"ONVIF is not configured for {camera_name}") return {} - if camera_name in self.cams and self.cams[camera_name]["init"]: + if camera_name in self.cams.keys() and self.cams[camera_name]["init"]: return { "name": camera_name, "features": self.cams[camera_name]["features"], "presets": list(self.cams[camera_name]["presets"].keys()), } - if camera_name not in self.cams and camera_name in self.config.cameras: - cam = self.config.cameras[camera_name] - result = self._create_onvif_camera(camera_name, cam) - if result: - self.cams[camera_name] = result - else: + if camera_name not in self.cams.keys() and camera_name in self.config.cameras: + success = await self._init_single_camera(camera_name) + if not success: return {} # Reset retry count after timeout @@ -677,23 +728,21 @@ class OnvifController: logger.debug(f"Could not initialize ONVIF for {camera_name}") return {} - def get_service_capabilities(self, camera_name: str) -> None: + async def get_service_capabilities(self, camera_name: str) -> None: if camera_name not in self.cams.keys(): logger.error(f"ONVIF is not configured for {camera_name}") return {} if not self.cams[camera_name]["init"]: - asyncio.run(self._init_onvif(camera_name)) + await self._init_onvif(camera_name) service_capabilities_request = self.cams[camera_name][ "service_capabilities_request" ] try: - service_capabilities = asyncio.run( - self.cams[camera_name]["ptz"].GetServiceCapabilities( - service_capabilities_request - ) - ) + service_capabilities = await self.cams[camera_name][ + "ptz" + ].GetServiceCapabilities(service_capabilities_request) logger.debug( f"Onvif service capabilities for {camera_name}: {service_capabilities}" @@ -701,25 +750,24 @@ class OnvifController: # MoveStatus is required for autotracking - should return "true" if supported return find_by_key(vars(service_capabilities), "MoveStatus") - except Exception: + except Exception as e: logger.warning( - f"Camera {camera_name} does not support the ONVIF GetServiceCapabilities method. Autotracking will not function correctly and must be disabled in your config." + f"Camera {camera_name} does not support the ONVIF GetServiceCapabilities method. Autotracking will not function correctly and must be disabled in your config. Exception: {e}" ) return False - def get_camera_status(self, camera_name: str) -> None: + async def get_camera_status(self, camera_name: str) -> None: if camera_name not in self.cams.keys(): logger.error(f"ONVIF is not configured for {camera_name}") - return {} + return if not self.cams[camera_name]["init"]: - asyncio.run(self._init_onvif(camera_name)) + if not await self._init_onvif(camera_name): + return status_request = self.cams[camera_name]["status_request"] try: - status = asyncio.run( - self.cams[camera_name]["ptz"].GetStatus(status_request) - ) + status = await self.cams[camera_name]["ptz"].GetStatus(status_request) except Exception: pass # We're unsupported, that'll be reported in the next check. @@ -803,3 +851,22 @@ class OnvifController: camera_name ].frame_time.value logger.warning(f"Camera {camera_name} is still in ONVIF 'MOVING' status.") + + def close(self) -> None: + """Gracefully shut down the ONVIF controller.""" + if not hasattr(self, "loop") or self.loop.is_closed(): + logger.debug("ONVIF controller already closed") + return + + logger.info("Exiting ONVIF controller...") + + def stop_and_cleanup(): + try: + self.loop.stop() + except Exception as e: + logger.error(f"Error during loop cleanup: {e}") + + # Schedule stop and cleanup in the loop thread + self.loop.call_soon_threadsafe(stop_and_cleanup) + + self.loop_thread.join() diff --git a/frigate/record/export.py b/frigate/record/export.py index 0e64021b4..4eadbf1bd 100644 --- a/frigate/record/export.py +++ b/frigate/record/export.py @@ -19,7 +19,6 @@ from frigate.const import ( CACHE_DIR, CLIPS_DIR, EXPORT_DIR, - FFMPEG_HVC1_ARGS, MAX_PLAYLIST_SECONDS, PREVIEW_FRAME_TYPE, ) @@ -233,9 +232,6 @@ class RecordingExporter(threading.Thread): ) ).split(" ") - if self.config.ffmpeg.apple_compatibility: - ffmpeg_cmd += FFMPEG_HVC1_ARGS - # add metadata title = f"Frigate Recording for {self.camera}, {self.get_datetime_from_timestamp(self.start_time)} - {self.get_datetime_from_timestamp(self.end_time)}" ffmpeg_cmd.extend(["-metadata", f"title={title}"]) diff --git a/frigate/record/maintainer.py b/frigate/record/maintainer.py index 1cabbfdda..25783965c 100644 --- a/frigate/record/maintainer.py +++ b/frigate/record/maintainer.py @@ -27,6 +27,7 @@ from frigate.config import FrigateConfig, RetainModeEnum from frigate.const import ( CACHE_DIR, CACHE_SEGMENT_FORMAT, + FAST_QUEUE_TIMEOUT, INSERT_MANY_RECORDINGS, MAX_SEGMENT_DURATION, MAX_SEGMENTS_IN_CACHE, @@ -38,8 +39,6 @@ from frigate.util.services import get_video_properties logger = logging.getLogger(__name__) -QUEUE_READ_TIMEOUT = 0.00001 # seconds - class SegmentInfo: def __init__( @@ -536,7 +535,7 @@ class RecordingMaintainer(threading.Thread): # empty the object recordings info queue while True: (topic, data) = self.detection_subscriber.check_for_update( - timeout=QUEUE_READ_TIMEOUT + timeout=FAST_QUEUE_TIMEOUT ) if not topic: @@ -577,7 +576,7 @@ class RecordingMaintainer(threading.Thread): audio_detections, ) ) - elif topic == DetectionTypeEnum.api: + elif topic == DetectionTypeEnum.api or DetectionTypeEnum.lpr: continue if frame_time < run_start - stale_frame_count_threshold: diff --git a/frigate/review/maintainer.py b/frigate/review/maintainer.py index 3541fef3b..6b5c32956 100644 --- a/frigate/review/maintainer.py +++ b/frigate/review/maintainer.py @@ -1,5 +1,6 @@ """Maintain review segments in db.""" +import copy import json import logging import os @@ -119,21 +120,23 @@ class PendingReviewSegment: ) def get_data(self, ended: bool) -> dict: - return { - ReviewSegment.id.name: self.id, - ReviewSegment.camera.name: self.camera, - ReviewSegment.start_time.name: self.start_time, - ReviewSegment.end_time.name: self.last_update if ended else None, - ReviewSegment.severity.name: self.severity.value, - ReviewSegment.thumb_path.name: self.frame_path, - ReviewSegment.data.name: { - "detections": list(set(self.detections.keys())), - "objects": list(set(self.detections.values())), - "sub_labels": list(self.sub_labels.values()), - "zones": self.zones, - "audio": list(self.audio), - }, - }.copy() + return copy.deepcopy( + { + ReviewSegment.id.name: self.id, + ReviewSegment.camera.name: self.camera, + ReviewSegment.start_time.name: self.start_time, + ReviewSegment.end_time.name: self.last_update if ended else None, + ReviewSegment.severity.name: self.severity.value, + ReviewSegment.thumb_path.name: self.frame_path, + ReviewSegment.data.name: { + "detections": list(set(self.detections.keys())), + "objects": list(set(self.detections.values())), + "sub_labels": list(self.sub_labels.values()), + "zones": self.zones, + "audio": list(self.audio), + }, + } + ) class ReviewSegmentMaintainer(threading.Thread): @@ -181,6 +184,9 @@ class ReviewSegmentMaintainer(threading.Thread): } ), ) + self.requestor.send_data( + f"{segment.camera}/review_status", segment.severity.value.upper() + ) def _publish_segment_update( self, @@ -206,6 +212,9 @@ class ReviewSegmentMaintainer(threading.Thread): } ), ) + self.requestor.send_data( + f"{segment.camera}/review_status", segment.severity.value.upper() + ) def _publish_segment_end( self, @@ -225,6 +234,7 @@ class ReviewSegmentMaintainer(threading.Thread): } ), ) + self.requestor.send_data(f"{segment.camera}/review_status", "NONE") self.active_review_segments[segment.camera] = None def end_segment(self, camera: str) -> None: @@ -253,7 +263,8 @@ class ReviewSegmentMaintainer(threading.Thread): if len(active_objects) > 0: has_activity = True - should_update = False + should_update_image = False + should_update_state = False if frame_time > segment.last_update: segment.last_update = frame_time @@ -284,7 +295,8 @@ class ReviewSegmentMaintainer(threading.Thread): and camera_config.review.alerts.enabled ): segment.severity = SeverityEnum.alert - should_update = True + should_update_state = True + should_update_image = True # keep zones up to date if len(object["current_zones"]) > 0: @@ -293,17 +305,24 @@ class ReviewSegmentMaintainer(threading.Thread): segment.zones.append(zone) if len(active_objects) > segment.frame_active_count: - should_update = True + should_update_state = True + should_update_image = True - if should_update: + if prev_data["data"]["sub_labels"] != list(segment.sub_labels.values()): + should_update_state = True + + if should_update_state: try: - yuv_frame = self.frame_manager.get( - frame_name, camera_config.frame_shape_yuv - ) + if should_update_image: + yuv_frame = self.frame_manager.get( + frame_name, camera_config.frame_shape_yuv + ) - if yuv_frame is None: - logger.debug(f"Failed to get frame {frame_name} from SHM") - return + if yuv_frame is None: + logger.debug(f"Failed to get frame {frame_name} from SHM") + return + else: + yuv_frame = None self._publish_segment_update( segment, camera_config, yuv_frame, active_objects, prev_data @@ -466,6 +485,10 @@ class ReviewSegmentMaintainer(threading.Thread): camera_name = updated_record_topic.rpartition("/")[-1] self.config.cameras[camera_name].record = updated_record_config + # immediately end segment + if not updated_record_config.enabled: + self.end_segment(camera_name) + if updated_review_topic: camera_name = updated_review_topic.rpartition("/")[-1] self.config.cameras[camera_name].review = updated_review_config @@ -476,6 +499,10 @@ class ReviewSegmentMaintainer(threading.Thread): camera_name ].enabled = updated_enabled_config.enabled + # immediately end segment as we may not get another update + if not updated_enabled_config.enabled: + self.end_segment(camera_name) + (topic, data) = self.detection_subscriber.check_for_update(timeout=1) if not topic: @@ -497,7 +524,7 @@ class ReviewSegmentMaintainer(threading.Thread): _, audio_detections, ) = data - elif topic == DetectionTypeEnum.api: + elif topic == DetectionTypeEnum.api or DetectionTypeEnum.lpr: ( camera, frame_time, @@ -507,16 +534,14 @@ class ReviewSegmentMaintainer(threading.Thread): if camera not in self.indefinite_events: self.indefinite_events[camera] = {} - current_segment = self.active_review_segments.get(camera) - if ( not self.config.cameras[camera].enabled or not self.config.cameras[camera].record.enabled ): - if current_segment: - self.end_segment(camera) continue + current_segment = self.active_review_segments.get(camera) + # Check if the current segment should be processed based on enabled settings if current_segment: if ( @@ -556,13 +581,21 @@ class ReviewSegmentMaintainer(threading.Thread): or audio in camera_config.review.detections.labels ) and camera_config.review.detections.enabled: current_segment.audio.add(audio) - elif topic == DetectionTypeEnum.api: + elif topic == DetectionTypeEnum.api or topic == DetectionTypeEnum.lpr: if manual_info["state"] == ManualEventState.complete: current_segment.detections[manual_info["event_id"]] = ( manual_info["label"] ) - if self.config.cameras[camera].review.alerts.enabled: + if ( + topic == DetectionTypeEnum.api + and self.config.cameras[camera].review.alerts.enabled + ): current_segment.severity = SeverityEnum.alert + elif ( + topic == DetectionTypeEnum.lpr + and self.config.cameras[camera].review.detections.enabled + ): + current_segment.severity = SeverityEnum.detection current_segment.last_update = manual_info["end_time"] elif manual_info["state"] == ManualEventState.start: self.indefinite_events[camera][manual_info["event_id"]] = ( @@ -571,8 +604,16 @@ class ReviewSegmentMaintainer(threading.Thread): current_segment.detections[manual_info["event_id"]] = ( manual_info["label"] ) - if self.config.cameras[camera].review.alerts.enabled: + if ( + topic == DetectionTypeEnum.api + and self.config.cameras[camera].review.alerts.enabled + ): current_segment.severity = SeverityEnum.alert + elif ( + topic == DetectionTypeEnum.lpr + and self.config.cameras[camera].review.detections.enabled + ): + current_segment.severity = SeverityEnum.detection # temporarily make it so this event can not end current_segment.last_update = sys.maxsize @@ -660,6 +701,34 @@ class ReviewSegmentMaintainer(threading.Thread): logger.warning( f"Manual event API has been called for {camera}, but alerts are disabled. This manual event will not appear as an alert." ) + elif topic == DetectionTypeEnum.lpr: + if self.config.cameras[camera].review.detections.enabled: + self.active_review_segments[camera] = PendingReviewSegment( + camera, + frame_time, + SeverityEnum.detection, + {manual_info["event_id"]: manual_info["label"]}, + {}, + [], + set(), + ) + + if manual_info["state"] == ManualEventState.start: + self.indefinite_events[camera][manual_info["event_id"]] = ( + manual_info["label"] + ) + # temporarily make it so this event can not end + self.active_review_segments[ + camera + ].last_update = sys.maxsize + elif manual_info["state"] == ManualEventState.complete: + self.active_review_segments[ + camera + ].last_update = manual_info["end_time"] + else: + logger.warning( + f"Dedicated LPR camera API has been called for {camera}, but detections are disabled. LPR events will not appear as a detection." + ) self.record_config_subscriber.stop() self.review_config_subscriber.stop() diff --git a/frigate/stats/prometheus.py b/frigate/stats/prometheus.py index 015e551af..bc545f21d 100644 --- a/frigate/stats/prometheus.py +++ b/frigate/stats/prometheus.py @@ -12,7 +12,8 @@ from prometheus_client.core import ( class CustomCollector(object): def __init__(self, _url): - self.process_stats = {} + self.complete_stats = {} # Store complete stats data + self.process_stats = {} # Keep for CPU processing self.previous_event_id = None self.previous_event_start_time = None self.all_events = {} @@ -34,30 +35,34 @@ class CustomCollector(object): process_name, cpu_or_memory, process_type, + cpu_usages, ): try: pid = str(camera_stats[pid_name]) label_values = [pid, camera_name, process_name, process_type] try: # new frigate:0.13.0-beta3 stat 'cmdline' - label_values.append(self.process_stats[pid]["cmdline"]) + label_values.append(cpu_usages[pid]["cmdline"]) except KeyError: pass - metric.add_metric(label_values, self.process_stats[pid][cpu_or_memory]) - del self.process_stats[pid][cpu_or_memory] + metric.add_metric(label_values, cpu_usages[pid][cpu_or_memory]) + # Don't modify the original data except (KeyError, TypeError, IndexError): pass def collect(self): - stats = self.process_stats # Assign self.process_stats to local variable stats + # Work with a copy of the complete stats + stats = self.complete_stats.copy() + # Create a local copy of CPU usages to work with + cpu_usages = {} try: - self.process_stats = stats["cpu_usages"] - except KeyError: + cpu_usages = stats.get("cpu_usages", {}).copy() + except (KeyError, AttributeError): pass # process stats for cameras, detectors and other - cpu_usages = GaugeMetricFamily( + cpu_usages_metric = GaugeMetricFamily( "frigate_cpu_usage_percent", "Process CPU usage %", labels=["pid", "name", "process", "type", "cmdline"], @@ -121,25 +126,34 @@ class CustomCollector(object): self.add_metric(skipped_fps, [camera_name], camera_stats, "skipped_fps") self.add_metric_process( - cpu_usages, + cpu_usages_metric, camera_stats, camera_name, "ffmpeg_pid", "ffmpeg", "cpu", "Camera", + cpu_usages, ) self.add_metric_process( - cpu_usages, + cpu_usages_metric, camera_stats, camera_name, "capture_pid", "capture", "cpu", "Camera", + cpu_usages, ) self.add_metric_process( - cpu_usages, camera_stats, camera_name, "pid", "detect", "cpu", "Camera" + cpu_usages_metric, + camera_stats, + camera_name, + "pid", + "detect", + "cpu", + "Camera", + cpu_usages, ) self.add_metric_process( @@ -150,6 +164,7 @@ class CustomCollector(object): "ffmpeg", "mem", "Camera", + cpu_usages, ) self.add_metric_process( mem_usages, @@ -159,9 +174,17 @@ class CustomCollector(object): "capture", "mem", "Camera", + cpu_usages, ) self.add_metric_process( - mem_usages, camera_stats, camera_name, "pid", "detect", "mem", "Camera" + mem_usages, + camera_stats, + camera_name, + "pid", + "detect", + "mem", + "Camera", + cpu_usages, ) yield audio_dBFS @@ -239,13 +262,14 @@ class CustomCollector(object): "detection_start", ) self.add_metric_process( - cpu_usages, + cpu_usages_metric, stats["detectors"], detector_name, "pid", "detect", "cpu", "Detector", + cpu_usages, ) self.add_metric_process( mem_usages, @@ -255,6 +279,7 @@ class CustomCollector(object): "detect", "mem", "Detector", + cpu_usages, ) except KeyError: pass @@ -272,10 +297,10 @@ class CustomCollector(object): label.append(detector_name) # name label label.append(detector_name) # process label label.append("detectors") # type label - label.append(self.process_stats[p_pid]["cmdline"]) # cmdline label - self.add_metric(cpu_usages, label, self.process_stats[p_pid], "cpu") - self.add_metric(mem_usages, label, self.process_stats[p_pid], "mem") - del self.process_stats[p_pid] + label.append(cpu_usages[p_pid]["cmdline"]) # cmdline label + self.add_metric(cpu_usages_metric, label, cpu_usages[p_pid], "cpu") + self.add_metric(mem_usages, label, cpu_usages[p_pid], "mem") + # Don't modify the original data except KeyError: pass @@ -292,10 +317,10 @@ class CustomCollector(object): label.append(process_name) # name label label.append(process_name) # process label label.append(process_name) # type label - label.append(self.process_stats[p_pid]["cmdline"]) # cmdline label - self.add_metric(cpu_usages, label, self.process_stats[p_pid], "cpu") - self.add_metric(mem_usages, label, self.process_stats[p_pid], "mem") - del self.process_stats[p_pid] + label.append(cpu_usages[p_pid]["cmdline"]) # cmdline label + self.add_metric(cpu_usages_metric, label, cpu_usages[p_pid], "cpu") + self.add_metric(mem_usages, label, cpu_usages[p_pid], "mem") + # Don't modify the original data except KeyError: pass @@ -304,7 +329,7 @@ class CustomCollector(object): # remaining process stats try: - for process_id, pid_stats in self.process_stats.items(): + for process_id, pid_stats in cpu_usages.items(): label = [process_id] # pid label try: # new frigate:0.13.0-beta3 stat 'cmdline' @@ -314,12 +339,12 @@ class CustomCollector(object): label.append(pid_stats["cmdline"]) # cmdline label except KeyError: pass - self.add_metric(cpu_usages, label, pid_stats, "cpu") + self.add_metric(cpu_usages_metric, label, pid_stats, "cpu") self.add_metric(mem_usages, label, pid_stats, "mem") except KeyError: pass - yield cpu_usages + yield cpu_usages_metric yield mem_usages # gpu stats @@ -481,10 +506,13 @@ REGISTRY.register(collector) def update_metrics(stats): """Updates the Prometheus metrics with the given stats data.""" try: - collector.process_stats = stats # Directly assign the stats data - # Important: Since we are not fetching from URL, we need to manually call collect - for _ in collector.collect(): - pass + # Store the complete stats for later use by collect() + collector.complete_stats = stats.copy() + + # For backwards compatibility + collector.process_stats = stats.copy() + + # No need to call collect() here - it will be called by get_metrics() except Exception as e: logging.error(f"Error updating metrics: {e}") diff --git a/frigate/stats/util.py b/frigate/stats/util.py index 287c384cd..72f76c07e 100644 --- a/frigate/stats/util.py +++ b/frigate/stats/util.py @@ -15,7 +15,7 @@ from frigate.camera import CameraMetrics from frigate.config import FrigateConfig from frigate.const import CACHE_DIR, CLIPS_DIR, RECORD_DIR from frigate.data_processing.types import DataProcessorMetrics -from frigate.object_detection import ObjectDetectProcess +from frigate.object_detection.base import ObjectDetectProcess from frigate.types import StatsTrackingTypes from frigate.util.services import ( get_amd_gpu_stats, @@ -24,6 +24,8 @@ from frigate.util.services import ( get_intel_gpu_stats, get_jetson_stats, get_nvidia_gpu_stats, + get_rockchip_gpu_stats, + get_rockchip_npu_stats, is_vaapi_amd_driver, ) from frigate.version import VERSION @@ -109,6 +111,7 @@ def get_processing_stats( stats_tasks = [ asyncio.create_task(set_gpu_stats(config, stats, hwaccel_errors)), asyncio.create_task(set_cpu_stats(stats)), + asyncio.create_task(set_npu_usages(config, stats)), ] if config.telemetry.stats.network_bandwidth: @@ -230,6 +233,11 @@ async def set_gpu_stats( else: stats["intel-vaapi"] = {"gpu": "", "mem": ""} hwaccel_errors.append(args) + elif "preset-rk" in args: + rga_usage = get_rockchip_gpu_stats() + + if rga_usage: + stats["rockchip"] = rga_usage elif "v4l2m2m" in args or "rpi" in args: # RPi v4l2m2m is currently not able to get usage stats stats["rpi-v4l2m2m"] = {"gpu": "", "mem": ""} @@ -238,6 +246,19 @@ async def set_gpu_stats( all_stats["gpu_usages"] = stats +async def set_npu_usages(config: FrigateConfig, all_stats: dict[str, Any]) -> None: + stats: dict[str, dict] = {} + + for detector in config.detectors.values(): + if detector.type == "rknn": + # Rockchip NPU usage + rk_usage = get_rockchip_npu_stats() + stats["rockchip"] = rk_usage + + if stats: + all_stats["npu_usages"] = stats + + def stats_snapshot( config: FrigateConfig, stats_tracking: StatsTrackingTypes, hwaccel_errors: list[str] ) -> dict[str, Any]: @@ -293,27 +314,42 @@ def stats_snapshot( stats["embeddings"].update( { "image_embedding_speed": round( - embeddings_metrics.image_embeddings_fps.value * 1000, 2 + embeddings_metrics.image_embeddings_speed.value * 1000, 2 + ), + "image_embedding": round( + embeddings_metrics.image_embeddings_eps.value, 2 ), "text_embedding_speed": round( - embeddings_metrics.text_embeddings_sps.value * 1000, 2 + embeddings_metrics.text_embeddings_speed.value * 1000, 2 + ), + "text_embedding": round( + embeddings_metrics.text_embeddings_eps.value, 2 ), } ) if config.face_recognition.enabled: stats["embeddings"]["face_recognition_speed"] = round( - embeddings_metrics.face_rec_fps.value * 1000, 2 + embeddings_metrics.face_rec_speed.value * 1000, 2 + ) + stats["embeddings"]["face_recognition"] = round( + embeddings_metrics.face_rec_fps.value, 2 ) if config.lpr.enabled: stats["embeddings"]["plate_recognition_speed"] = round( - embeddings_metrics.alpr_pps.value * 1000, 2 + embeddings_metrics.alpr_speed.value * 1000, 2 + ) + stats["embeddings"]["plate_recognition"] = round( + embeddings_metrics.alpr_pps.value, 2 ) - if "license_plate" not in config.objects.all_objects: + if embeddings_metrics.yolov9_lpr_pps.value > 0.0: stats["embeddings"]["yolov9_plate_detection_speed"] = round( - embeddings_metrics.yolov9_lpr_fps.value * 1000, 2 + embeddings_metrics.yolov9_lpr_speed.value * 1000, 2 + ) + stats["embeddings"]["yolov9_plate_detection"] = round( + embeddings_metrics.yolov9_lpr_pps.value, 2 ) get_processing_stats(config, stats, hwaccel_errors) diff --git a/frigate/test/http_api/test_http_review.py b/frigate/test/http_api/test_http_review.py index 19c589a67..9fd0d1ea7 100644 --- a/frigate/test/http_api/test_http_review.py +++ b/frigate/test/http_api/test_http_review.py @@ -280,82 +280,6 @@ class TestHttpReview(BaseTestHttp): } self.assertEqual(response_json, expected_response) - def test_get_review_summary_multiple_days_edge_cases(self): - now = datetime.now() - five_days_ago = datetime.today() - timedelta(days=5) - twenty_days_ago = datetime.today() - timedelta(days=20) - one_month_ago = datetime.today() - timedelta(days=30) - one_month_ago_ts = one_month_ago.timestamp() - - with TestClient(self.app) as client: - super().insert_mock_review_segment("123456.random", now.timestamp()) - super().insert_mock_review_segment( - "123457.random", five_days_ago.timestamp() - ) - super().insert_mock_review_segment( - "123458.random", - twenty_days_ago.timestamp(), - None, - SeverityEnum.detection, - ) - # One month ago plus 5 seconds fits within the condition (review.start_time > month_ago). Assuming that the endpoint does not take more than 5 seconds to be invoked - super().insert_mock_review_segment( - "123459.random", - one_month_ago_ts + 5, - None, - SeverityEnum.detection, - ) - # This won't appear in the output since it's not within last month start_time clause (review.start_time > month_ago) - super().insert_mock_review_segment("123450.random", one_month_ago_ts) - response = client.get("/review/summary") - assert response.status_code == 200 - response_json = response.json() - # e.g. '2024-11-24' - today_formatted = now.strftime("%Y-%m-%d") - # e.g. '2024-11-19' - five_days_ago_formatted = five_days_ago.strftime("%Y-%m-%d") - # e.g. '2024-11-04' - twenty_days_ago_formatted = twenty_days_ago.strftime("%Y-%m-%d") - # e.g. '2024-10-24' - one_month_ago_formatted = one_month_ago.strftime("%Y-%m-%d") - expected_response = { - "last24Hours": { - "reviewed_alert": 0, - "reviewed_detection": 0, - "total_alert": 1, - "total_detection": 0, - }, - today_formatted: { - "day": today_formatted, - "reviewed_alert": 0, - "reviewed_detection": 0, - "total_alert": 1, - "total_detection": 0, - }, - five_days_ago_formatted: { - "day": five_days_ago_formatted, - "reviewed_alert": 0, - "reviewed_detection": 0, - "total_alert": 1, - "total_detection": 0, - }, - twenty_days_ago_formatted: { - "day": twenty_days_ago_formatted, - "reviewed_alert": 0, - "reviewed_detection": 0, - "total_alert": 0, - "total_detection": 1, - }, - one_month_ago_formatted: { - "day": one_month_ago_formatted, - "reviewed_alert": 0, - "reviewed_detection": 0, - "total_alert": 0, - "total_detection": 1, - }, - } - self.assertEqual(response_json, expected_response) - def test_get_review_summary_multiple_in_same_day(self): now = datetime.now() five_days_ago = datetime.today() - timedelta(days=5) diff --git a/frigate/test/test_config.py b/frigate/test/test_config.py index 5a3deefda..02f5d5e74 100644 --- a/frigate/test/test_config.py +++ b/frigate/test/test_config.py @@ -1491,7 +1491,9 @@ class TestConfig(unittest.TestCase): "fps": 5, }, "onvif": { - "autotracking": {"movement_weights": "0, 1, 1.23, 2.34, 0.50"} + "autotracking": { + "movement_weights": "0, 1, 1.23, 2.34, 0.50, 1" + } }, } }, @@ -1504,6 +1506,7 @@ class TestConfig(unittest.TestCase): "1.23", "2.34", "0.5", + "1.0", ] def test_fails_invalid_movement_weights(self): diff --git a/frigate/test/test_object_detector.py b/frigate/test/test_object_detector.py index 40a9fac14..dc15b2351 100644 --- a/frigate/test/test_object_detector.py +++ b/frigate/test/test_object_detector.py @@ -5,7 +5,7 @@ import numpy as np from pydantic import parse_obj_as import frigate.detectors as detectors -import frigate.object_detection +import frigate.object_detection.base from frigate.config import DetectorConfig, ModelConfig from frigate.detectors import DetectorTypeEnum from frigate.detectors.detector_config import InputTensorEnum @@ -23,7 +23,7 @@ class TestLocalObjectDetector(unittest.TestCase): DetectorConfig, ({"type": det_type, "model": {}}) ) test_cfg.model.path = "/test/modelpath" - test_obj = frigate.object_detection.LocalObjectDetector( + test_obj = frigate.object_detection.base.LocalObjectDetector( detector_config=test_cfg ) @@ -43,7 +43,7 @@ class TestLocalObjectDetector(unittest.TestCase): TEST_DATA = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] TEST_DETECT_RESULT = np.ndarray([1, 2, 4, 8, 16, 32]) - test_obj_detect = frigate.object_detection.LocalObjectDetector( + test_obj_detect = frigate.object_detection.base.LocalObjectDetector( detector_config=parse_obj_as(DetectorConfig, {"type": "cpu", "model": {}}) ) @@ -70,7 +70,7 @@ class TestLocalObjectDetector(unittest.TestCase): test_cfg = parse_obj_as(DetectorConfig, {"type": "cpu", "model": {}}) test_cfg.model.input_tensor = InputTensorEnum.nchw - test_obj_detect = frigate.object_detection.LocalObjectDetector( + test_obj_detect = frigate.object_detection.base.LocalObjectDetector( detector_config=test_cfg ) @@ -91,7 +91,7 @@ class TestLocalObjectDetector(unittest.TestCase): "frigate.detectors.api_types", {det_type: Mock() for det_type in DetectorTypeEnum}, ) - @patch("frigate.object_detection.load_labels") + @patch("frigate.object_detection.base.load_labels") def test_detect_given_tensor_input_should_return_lfiltered_detections( self, mock_load_labels ): @@ -118,7 +118,7 @@ class TestLocalObjectDetector(unittest.TestCase): test_cfg = parse_obj_as(DetectorConfig, {"type": "cpu", "model": {}}) test_cfg.model = ModelConfig() - test_obj_detect = frigate.object_detection.LocalObjectDetector( + test_obj_detect = frigate.object_detection.base.LocalObjectDetector( detector_config=test_cfg, labels=TEST_LABEL_FILE, ) diff --git a/frigate/track/norfair_tracker.py b/frigate/track/norfair_tracker.py index db17f9313..ec2bdfa7d 100644 --- a/frigate/track/norfair_tracker.py +++ b/frigate/track/norfair_tracker.py @@ -129,6 +129,11 @@ class NorfairTracker(ObjectTracker): "distance_function": frigate_distance, "distance_threshold": 2.5, }, + "license_plate": { + "filter_factory": OptimizedKalmanFilterFactory(R=2.5, Q=0.05), + "distance_function": frigate_distance, + "distance_threshold": 3.75, + }, } # Define autotracking PTZ-specific configurations @@ -246,6 +251,7 @@ class NorfairTracker(ObjectTracker): "ptz" if self.camera_config.onvif.autotracking.enabled_in_config and object_type in self.camera_config.onvif.autotracking.track + and object_type in self.ptz_object_type_configs.keys() else "static" ) if object_type in self.trackers: @@ -272,17 +278,24 @@ class NorfairTracker(ObjectTracker): ) self.tracked_objects[id] = obj self.disappeared[id] = 0 + if obj_match: + boxes = [p.data["box"] for p in obj_match.past_detections] + else: + boxes = [obj["box"]] + + xmins, ymins, xmaxs, ymaxs = zip(*boxes) + self.positions[id] = { - "xmins": [], - "ymins": [], - "xmaxs": [], - "ymaxs": [], + "xmins": list(xmins), + "ymins": list(ymins), + "xmaxs": list(xmaxs), + "ymaxs": list(ymaxs), "xmin": 0, "ymin": 0, "xmax": self.detect_config.width, "ymax": self.detect_config.height, } - self.stationary_box_history[id] = [] + self.stationary_box_history[id] = boxes def deregister(self, id, track_id): obj = self.tracked_objects[id] @@ -368,9 +381,9 @@ class NorfairTracker(ObjectTracker): } return False - # if there are less than 10 entries for the position, add the bounding box + # if there are more than 5 and less than 10 entries for the position, add the bounding box # and recompute the position box - if len(position["xmins"]) < 10: + if 5 <= len(position["xmins"]) < 10: position["xmins"].append(xmin) position["ymins"].append(ymin) position["xmaxs"].append(xmax) @@ -598,7 +611,10 @@ class NorfairTracker(ObjectTracker): # print a table to the console with norfair tracked object info if False: - self.print_objects_as_table(self.trackers["person"]["ptz"].tracked_objects) + if len(self.trackers["license_plate"]["static"].tracked_objects) > 0: + self.print_objects_as_table( + self.trackers["license_plate"]["static"].tracked_objects + ) # Get tracked objects from type-specific trackers for object_trackers in self.trackers.values(): @@ -643,3 +659,20 @@ class NorfairTracker(ObjectTracker): color=(255, 0, 0), thickness=None, ) + + if False: + # draw the current formatted time on the frame + from datetime import datetime + + formatted_time = datetime.fromtimestamp(frame_time).strftime( + "%m/%d/%Y %I:%M:%S %p" + ) + + frame = Drawer.text( + frame, + formatted_time, + position=(10, 50), + size=1.5, + color=(255, 255, 255), + thickness=None, + ) diff --git a/frigate/track/object_processing.py b/frigate/track/object_processing.py index b18ad97fa..702df32bd 100644 --- a/frigate/track/object_processing.py +++ b/frigate/track/object_processing.py @@ -1,3 +1,4 @@ +import base64 import datetime import json import logging @@ -7,6 +8,7 @@ from collections import defaultdict from enum import Enum from multiprocessing.synchronize import Event as MpEvent +import cv2 import numpy as np from peewee import DoesNotExist @@ -26,7 +28,7 @@ from frigate.config import ( RecordConfig, SnapshotsConfig, ) -from frigate.const import UPDATE_CAMERA_ACTIVITY +from frigate.const import FAST_QUEUE_TIMEOUT, UPDATE_CAMERA_ACTIVITY from frigate.events.types import EventStateEnum, EventTypeEnum from frigate.models import Event, Timeline from frigate.track.tracked_object import TrackedObject @@ -172,6 +174,16 @@ class TrackedObjectProcessor(threading.Thread): retain=True, ) + if obj.obj_data.get("sub_label"): + sub_label = obj.obj_data["sub_label"][0] + + if sub_label in self.config.model.all_attribute_logos: + self.dispatcher.publish( + f"{camera}/{sub_label}/snapshot", + jpg_bytes, + retain=True, + ) + def camera_activity(camera, activity): last_activity = self.camera_activity.get(camera) @@ -384,6 +396,19 @@ class TrackedObjectProcessor(threading.Thread): return True + def save_lpr_snapshot(self, payload: tuple) -> None: + # save the snapshot image + (frame, event_id, camera) = payload + + img = cv2.imdecode( + np.frombuffer(base64.b64decode(frame), dtype=np.uint8), + cv2.IMREAD_COLOR, + ) + + self.camera_states[camera].save_manual_event_image( + img, event_id, "license_plate", {} + ) + def create_manual_event(self, payload: tuple) -> None: ( frame_time, @@ -399,7 +424,9 @@ class TrackedObjectProcessor(threading.Thread): ) = payload # save the snapshot image - self.camera_states[camera_name].save_manual_event_image(event_id, label, draw) + self.camera_states[camera_name].save_manual_event_image( + None, event_id, label, draw + ) end_time = frame_time + duration if duration is not None else None # send event to event maintainer @@ -446,6 +473,59 @@ class TrackedObjectProcessor(threading.Thread): DetectionTypeEnum.api.value, ) + def create_lpr_event(self, payload: tuple) -> None: + ( + frame_time, + camera_name, + label, + event_id, + include_recording, + score, + sub_label, + plate, + ) = payload + + # send event to event maintainer + self.event_sender.publish( + ( + EventTypeEnum.api, + EventStateEnum.start, + camera_name, + "", + { + "id": event_id, + "label": label, + "sub_label": sub_label, + "score": score, + "camera": camera_name, + "start_time": frame_time + - self.config.cameras[camera_name].record.event_pre_capture, + "end_time": None, + "has_clip": self.config.cameras[camera_name].record.enabled + and include_recording, + "has_snapshot": True, + "type": "api", + "recognized_license_plate": plate, + "recognized_license_plate_score": score, + }, + ) + ) + + self.ongoing_manual_events[event_id] = camera_name + self.detection_publisher.publish( + ( + camera_name, + frame_time, + { + "state": ManualEventState.start, + "label": f"{label}: {sub_label}" if sub_label else label, + "event_id": event_id, + "end_time": None, + }, + ), + DetectionTypeEnum.lpr.value, + ) + def end_manual_event(self, payload: tuple) -> None: (event_id, end_time) = payload @@ -550,6 +630,10 @@ class TrackedObjectProcessor(threading.Thread): self.set_recognized_license_plate( event_id, recognized_license_plate, score ) + elif topic.endswith(EventMetadataTypeEnum.lpr_event_create.value): + self.create_lpr_event(payload) + elif topic.endswith(EventMetadataTypeEnum.save_lpr_snapshot.value): + self.save_lpr_snapshot(payload) elif topic.endswith(EventMetadataTypeEnum.manual_event_create.value): self.create_manual_event(payload) elif topic.endswith(EventMetadataTypeEnum.manual_event_end.value): @@ -598,7 +682,9 @@ class TrackedObjectProcessor(threading.Thread): # cleanup event finished queue while not self.stop_event.is_set(): - update = self.event_end_subscriber.check_for_update(timeout=0.01) + update = self.event_end_subscriber.check_for_update( + timeout=FAST_QUEUE_TIMEOUT + ) if not update: break diff --git a/frigate/track/tracked_object.py b/frigate/track/tracked_object.py index 7a4829c2a..77ebc6646 100644 --- a/frigate/track/tracked_object.py +++ b/frigate/track/tracked_object.py @@ -117,6 +117,7 @@ class TrackedObject: def update(self, current_frame_time: float, obj_data, has_valid_frame: bool): thumb_update = False significant_change = False + path_update = False autotracker_update = False # if the object is not in the current frame, add a 0.0 to the score history if obj_data["frame_time"] != current_frame_time: @@ -143,24 +144,29 @@ class TrackedObject: obj_data, self.camera_config.frame_shape, ): - self.thumbnail_data = { - "frame_time": current_frame_time, - "box": obj_data["box"], - "area": obj_data["area"], - "region": obj_data["region"], - "score": obj_data["score"], - "attributes": obj_data["attributes"], - "current_estimated_speed": self.current_estimated_speed, - "velocity_angle": self.velocity_angle, - "path_data": self.path_data, - "recognized_license_plate": obj_data.get( - "recognized_license_plate" - ), - "recognized_license_plate_score": obj_data.get( - "recognized_license_plate_score" - ), - } - thumb_update = True + if obj_data["frame_time"] == current_frame_time: + self.thumbnail_data = { + "frame_time": obj_data["frame_time"], + "box": obj_data["box"], + "area": obj_data["area"], + "region": obj_data["region"], + "score": obj_data["score"], + "attributes": obj_data["attributes"], + "current_estimated_speed": self.current_estimated_speed, + "velocity_angle": self.velocity_angle, + "path_data": self.path_data.copy(), + "recognized_license_plate": obj_data.get( + "recognized_license_plate" + ), + "recognized_license_plate_score": obj_data.get( + "recognized_license_plate_score" + ), + } + thumb_update = True + else: + logger.debug( + f"{self.camera_config.name}: Object frame time {obj_data['frame_time']} is not equal to the current frame time {current_frame_time}, not updating thumbnail" + ) # check zones current_zones = [] @@ -272,7 +278,7 @@ class TrackedObject: self.attributes[attr["label"]] = attr["score"] # populate the sub_label for object with highest scoring logo - if self.obj_data["label"] in ["car", "package", "person"]: + if self.obj_data["label"] in ["car", "motorcycle", "package", "person"]: recognized_logos = { k: self.attributes[k] for k in self.logos if k in self.attributes } @@ -324,19 +330,21 @@ class TrackedObject: if not self.path_data: self.path_data.append((bottom_center, obj_data["frame_time"])) + path_update = True elif ( math.dist(self.path_data[-1][0], bottom_center) >= threshold or len(self.path_data) == 1 ): # check Euclidean distance before appending self.path_data.append((bottom_center, obj_data["frame_time"])) + path_update = True logger.debug( f"Point tracking: {obj_data['id']}, {bottom_center}, {obj_data['frame_time']}" ) self.obj_data.update(obj_data) self.current_zones = current_zones - return (thumb_update, significant_change, autotracker_update) + return (thumb_update, significant_change, path_update, autotracker_update) def to_dict(self): event = { @@ -370,7 +378,7 @@ class TrackedObject: "current_estimated_speed": self.current_estimated_speed, "average_estimated_speed": self.average_estimated_speed, "velocity_angle": self.velocity_angle, - "path_data": self.path_data, + "path_data": self.path_data.copy(), "recognized_license_plate": self.obj_data.get("recognized_license_plate"), } @@ -442,7 +450,7 @@ class TrackedObject: if bounding_box: thickness = 2 - color = self.colormap[self.obj_data["label"]] + color = self.colormap.get(self.obj_data["label"], (255, 255, 255)) # draw the bounding boxes on the frame box = self.thumbnail_data["box"] diff --git a/frigate/types.py b/frigate/types.py index 4d3fe96b3..ee48cc02b 100644 --- a/frigate/types.py +++ b/frigate/types.py @@ -3,7 +3,7 @@ from typing import TypedDict from frigate.camera import CameraMetrics from frigate.data_processing.types import DataProcessorMetrics -from frigate.object_detection import ObjectDetectProcess +from frigate.object_detection.base import ObjectDetectProcess class StatsTrackingTypes(TypedDict): @@ -25,3 +25,5 @@ class ModelStatusTypesEnum(str, Enum): class TrackedObjectUpdateTypesEnum(str, Enum): description = "description" + face = "face" + lpr = "lpr" diff --git a/frigate/util/builtin.py b/frigate/util/builtin.py index 5f573ef78..0f245107a 100644 --- a/frigate/util/builtin.py +++ b/frigate/util/builtin.py @@ -11,6 +11,7 @@ import shlex import struct import urllib.parse from collections.abc import Mapping +from multiprocessing.sharedctypes import Synchronized from pathlib import Path from typing import Any, Optional, Tuple, Union from zoneinfo import ZoneInfoNotFoundError @@ -26,16 +27,16 @@ logger = logging.getLogger(__name__) class EventsPerSecond: - def __init__(self, max_events=1000, last_n_seconds=10): + def __init__(self, max_events=1000, last_n_seconds=10) -> None: self._start = None self._max_events = max_events self._last_n_seconds = last_n_seconds self._timestamps = [] - def start(self): + def start(self) -> None: self._start = datetime.datetime.now().timestamp() - def update(self): + def update(self) -> None: now = datetime.datetime.now().timestamp() if self._start is None: self._start = now @@ -45,7 +46,7 @@ class EventsPerSecond: self._timestamps = self._timestamps[(1 - self._max_events) :] self.expire_timestamps(now) - def eps(self): + def eps(self) -> float: now = datetime.datetime.now().timestamp() if self._start is None: self._start = now @@ -58,12 +59,29 @@ class EventsPerSecond: return len(self._timestamps) / seconds # remove aged out timestamps - def expire_timestamps(self, now): + def expire_timestamps(self, now: float) -> None: threshold = now - self._last_n_seconds while self._timestamps and self._timestamps[0] < threshold: del self._timestamps[0] +class InferenceSpeed: + def __init__(self, metric: Synchronized) -> None: + self.__metric = metric + self.__initialized = False + + def update(self, inference_time: float) -> None: + if not self.__initialized: + self.__metric.value = inference_time + self.__initialized = True + return + + self.__metric.value = (self.__metric.value * 9 + inference_time) / 10 + + def current(self) -> float: + return self.__metric.value + + def deep_merge(dct1: dict, dct2: dict, override=False, merge_lists=False) -> dict: """ :param dct1: First dict to merge diff --git a/frigate/util/config.py b/frigate/util/config.py index 7bdc0c3d6..59d704b9e 100644 --- a/frigate/util/config.py +++ b/frigate/util/config.py @@ -319,6 +319,21 @@ def migrate_016_0(config: dict[str, dict[str, any]]) -> dict[str, dict[str, any] camera_config["live"] = live_config + # add another value to movement_weights for autotracking cams + onvif_config = camera_config.get("onvif", {}) + if "autotracking" in onvif_config: + movement_weights = ( + camera_config.get("onvif", {}) + .get("autotracking") + .get("movement_weights", {}) + ) + + if movement_weights and len(movement_weights.split(",")) == 5: + onvif_config["autotracking"]["movement_weights"] = ( + movement_weights + ", 0" + ) + camera_config["onvif"] = onvif_config + new_config["cameras"][name] = camera_config new_config["version"] = "0.16-0" diff --git a/frigate/util/image.py b/frigate/util/image.py index 0b80efe88..5abbfb943 100644 --- a/frigate/util/image.py +++ b/frigate/util/image.py @@ -80,7 +80,7 @@ def is_better_thumbnail(label, current_thumb, new_obj, frame_shape) -> bool: return False # check license_plate on car - if label == "car": + if label in ["car", "motorcycle"]: if has_better_attr(current_thumb, new_obj, "license_plate"): return True # if the current thumb has a license_plate attr, dont update unless it gets better @@ -265,6 +265,19 @@ def draw_box_with_label( ) +def grab_cv2_contours(cnts): + # if the length the contours tuple returned by cv2.findContours + # is '2' then we are using either OpenCV v2.4, v4-beta, or + # v4-official + if len(cnts) == 2: + return cnts[0] + + # if the length of the contours tuple is '3' then we are using + # either OpenCV v3, v4-pre, or v4-alpha + elif len(cnts) == 3: + return cnts[1] + + def is_label_printable(label) -> bool: """Check if label is printable.""" return not bool(set(label) - set(printable)) diff --git a/frigate/util/model.py b/frigate/util/model.py index d96493ee6..5528c15ca 100644 --- a/frigate/util/model.py +++ b/frigate/util/model.py @@ -13,7 +13,11 @@ logger = logging.getLogger(__name__) ### Post Processing -def post_process_dfine(tensor_output: np.ndarray, width, height) -> np.ndarray: + + +def post_process_dfine( + tensor_output: np.ndarray, width: int, height: int +) -> np.ndarray: class_ids = tensor_output[0][tensor_output[2] > 0.4] boxes = tensor_output[1][tensor_output[2] > 0.4] scores = tensor_output[2][tensor_output[2] > 0.4] @@ -41,8 +45,151 @@ def post_process_dfine(tensor_output: np.ndarray, width, height) -> np.ndarray: return detections -def post_process_yolov9(predictions: np.ndarray, width, height) -> np.ndarray: - predictions = np.squeeze(predictions).T +def post_process_rfdetr(tensor_output: list[np.ndarray, np.ndarray]) -> np.ndarray: + boxes = tensor_output[0] + raw_scores = tensor_output[1] + + # apply soft max to scores + exp = np.exp(raw_scores - np.max(raw_scores, axis=-1, keepdims=True)) + all_scores = exp / np.sum(exp, axis=-1, keepdims=True) + + # get highest scoring class from every detection + scores = np.max(all_scores[0, :, 1:], axis=-1) + labels = np.argmax(all_scores[0, :, 1:], axis=-1) + + idxs = scores > 0.4 + filtered_boxes = boxes[0, idxs] + filtered_scores = scores[idxs] + filtered_labels = labels[idxs] + + # convert boxes from [x_center, y_center, width, height] + x_center, y_center, w, h = ( + filtered_boxes[:, 0], + filtered_boxes[:, 1], + filtered_boxes[:, 2], + filtered_boxes[:, 3], + ) + x_min = x_center - w / 2 + y_min = y_center - h / 2 + x_max = x_center + w / 2 + y_max = y_center + h / 2 + filtered_boxes = np.stack([x_min, y_min, x_max, y_max], axis=-1) + + # apply nms + indices = cv2.dnn.NMSBoxes( + filtered_boxes, filtered_scores, score_threshold=0.4, nms_threshold=0.4 + ) + detections = np.zeros((20, 6), np.float32) + + for i, (bbox, confidence, class_id) in enumerate( + zip(filtered_boxes[indices], filtered_scores[indices], filtered_labels[indices]) + ): + if i == 20: + break + + detections[i] = [ + class_id, + confidence, + bbox[1], + bbox[0], + bbox[3], + bbox[2], + ] + + return detections + + +def __post_process_multipart_yolo( + output_list, + width, + height, +): + anchors = [ + [(12, 16), (19, 36), (40, 28)], + [(36, 75), (76, 55), (72, 146)], + [(142, 110), (192, 243), (459, 401)], + ] + + stride_map = {0: 8, 1: 16, 2: 32} + + all_boxes = [] + all_scores = [] + all_class_ids = [] + + for i, output in enumerate(output_list): + bs, _, ny, nx = output.shape + stride = stride_map[i] + anchor_set = anchors[i] + + num_anchors = len(anchor_set) + output = output.reshape(bs, num_anchors, 85, ny, nx) + output = output.transpose(0, 1, 3, 4, 2) + output = output[0] + + for a_idx, (anchor_w, anchor_h) in enumerate(anchor_set): + for y in range(ny): + for x in range(nx): + pred = output[a_idx, y, x] + class_probs = pred[5:] + class_id = np.argmax(class_probs) + class_conf = class_probs[class_id] + conf = class_conf * pred[4] + + if conf < 0.4: + continue + + dx = pred[0] + dy = pred[1] + dw = pred[2] + dh = pred[3] + + bx = ((dx * 2.0 - 0.5) + x) * stride + by = ((dy * 2.0 - 0.5) + y) * stride + bw = ((dw * 2.0) ** 2) * anchor_w + bh = ((dh * 2.0) ** 2) * anchor_h + + x1 = max(0, bx - bw / 2) + y1 = max(0, by - bh / 2) + x2 = min(width, bx + bw / 2) + y2 = min(height, by + bh / 2) + + all_boxes.append([x1, y1, x2, y2]) + all_scores.append(conf) + all_class_ids.append(class_id) + + indices = cv2.dnn.NMSBoxes( + bboxes=all_boxes, + scores=all_scores, + score_threshold=0.4, + nms_threshold=0.4, + ) + + results = np.zeros((20, 6), np.float32) + + if len(indices) > 0: + for i, idx in enumerate(indices.flatten()[:20]): + class_id = all_class_ids[idx] + conf = all_scores[idx] + x1, y1, x2, y2 = all_boxes[idx] + results[i] = [ + class_id, + conf, + y1 / height, + x1 / width, + y2 / height, + x2 / width, + ] + + return results + + +def __post_process_nms_yolo(predictions: np.ndarray, width, height) -> np.ndarray: + predictions = np.squeeze(predictions) + + # transpose the output so it has order (inferences, class_ids) + if predictions.shape[0] < predictions.shape[1]: + predictions = predictions.T + scores = np.max(predictions[:, 4:], axis=1) predictions = predictions[scores > 0.4, :] scores = scores[scores > 0.4] @@ -50,9 +197,14 @@ def post_process_yolov9(predictions: np.ndarray, width, height) -> np.ndarray: # Rescale box boxes = predictions[:, :4] + boxes_xyxy = np.ones_like(boxes) + boxes_xyxy[:, 0] = boxes[:, 0] - boxes[:, 2] / 2 + boxes_xyxy[:, 1] = boxes[:, 1] - boxes[:, 3] / 2 + boxes_xyxy[:, 2] = boxes[:, 0] + boxes[:, 2] / 2 + boxes_xyxy[:, 3] = boxes[:, 1] + boxes[:, 3] / 2 + boxes = boxes_xyxy - input_shape = np.array([width, height, width, height]) - boxes = np.divide(boxes, input_shape, dtype=np.float32) + # run NMS indices = cv2.dnn.NMSBoxes(boxes, scores, score_threshold=0.4, nms_threshold=0.4) detections = np.zeros((20, 6), np.float32) for i, (bbox, confidence, class_id) in enumerate( @@ -64,10 +216,64 @@ def post_process_yolov9(predictions: np.ndarray, width, height) -> np.ndarray: detections[i] = [ class_id, confidence, - bbox[1] - bbox[3] / 2, - bbox[0] - bbox[2] / 2, - bbox[1] + bbox[3] / 2, - bbox[0] + bbox[2] / 2, + bbox[1] / height, + bbox[0] / width, + bbox[3] / height, + bbox[2] / width, + ] + + return detections + + +def post_process_yolo(output: list[np.ndarray], width: int, height: int) -> np.ndarray: + if len(output) > 1: + return __post_process_multipart_yolo(output, width, height) + else: + return __post_process_nms_yolo(output[0], width, height) + + +def post_process_yolox( + predictions: np.ndarray, + width: int, + height: int, + grids: np.ndarray, + expanded_strides: np.ndarray, +) -> np.ndarray: + predictions[..., :2] = (predictions[..., :2] + grids) * expanded_strides + predictions[..., 2:4] = np.exp(predictions[..., 2:4]) * expanded_strides + + # process organized predictions + predictions = predictions[0] + boxes = predictions[:, :4] + scores = predictions[:, 4:5] * predictions[:, 5:] + + boxes_xyxy = np.ones_like(boxes) + boxes_xyxy[:, 0] = boxes[:, 0] - boxes[:, 2] / 2 + boxes_xyxy[:, 1] = boxes[:, 1] - boxes[:, 3] / 2 + boxes_xyxy[:, 2] = boxes[:, 0] + boxes[:, 2] / 2 + boxes_xyxy[:, 3] = boxes[:, 1] + boxes[:, 3] / 2 + + cls_inds = scores.argmax(1) + scores = scores[np.arange(len(cls_inds)), cls_inds] + + indices = cv2.dnn.NMSBoxes( + boxes_xyxy, scores, score_threshold=0.4, nms_threshold=0.4 + ) + + detections = np.zeros((20, 6), np.float32) + for i, (bbox, confidence, class_id) in enumerate( + zip(boxes_xyxy[indices], scores[indices], cls_inds[indices]) + ): + if i == 20: + break + + detections[i] = [ + class_id, + confidence, + bbox[1] / height, + bbox[0] / width, + bbox[3] / height, + bbox[2] / width, ] return detections @@ -134,7 +340,6 @@ def get_ort_providers( providers.append(provider) options.append( { - "arena_extend_strategy": "kSameAsRequested", "cache_dir": os.path.join(MODEL_CACHE_DIR, "openvino/ort"), "device_type": device, } diff --git a/frigate/util/path.py b/frigate/util/path.py index dbe51abe5..565f5a357 100644 --- a/frigate/util/path.py +++ b/frigate/util/path.py @@ -4,6 +4,9 @@ import base64 import os from pathlib import Path +import cv2 +from numpy import ndarray + from frigate.const import CLIPS_DIR, THUMB_DIR from frigate.models import Event @@ -21,6 +24,11 @@ def get_event_thumbnail_bytes(event: Event) -> bytes | None: return None +def get_event_snapshot(event: Event) -> ndarray: + media_name = f"{event.camera}-{event.id}" + return cv2.imread(f"{os.path.join(CLIPS_DIR, media_name)}.jpg") + + ### Deletion diff --git a/frigate/util/services.py b/frigate/util/services.py index ce7041c26..1c778bac4 100644 --- a/frigate/util/services.py +++ b/frigate/util/services.py @@ -382,6 +382,50 @@ def get_intel_gpu_stats(sriov: bool) -> dict[str, str]: return results +def get_rockchip_gpu_stats() -> dict[str, str]: + """Get GPU stats using rk.""" + try: + with open("/sys/kernel/debug/rkrga/load", "r") as f: + content = f.read() + except FileNotFoundError: + return None + + load_values = [] + for line in content.splitlines(): + match = re.search(r"load = (\d+)%", line) + if match: + load_values.append(int(match.group(1))) + + if not load_values: + return None + + average_load = f"{round(sum(load_values) / len(load_values), 2)}%" + return {"gpu": average_load, "mem": "-"} + + +def get_rockchip_npu_stats() -> dict[str, str]: + """Get NPU stats using rk.""" + try: + with open("/sys/kernel/debug/rknpu/load", "r") as f: + npu_output = f.read() + + if "Core0:" in npu_output: + # multi core NPU + core_loads = re.findall(r"Core\d+:\s*(\d+)%", npu_output) + else: + # single core NPU + core_loads = re.findall(r"NPU load:\s+(\d+)%", npu_output) + except FileNotFoundError: + core_loads = None + + if not core_loads: + return None + + percentages = [int(load) for load in core_loads] + mean = round(sum(percentages) / len(percentages), 2) + return {"npu": mean, "mem": "-"} + + def try_get_info(f, h, default="N/A"): try: if h: diff --git a/frigate/video.py b/frigate/video.py index abf490a72..e6243295c 100755 --- a/frigate/video.py +++ b/frigate/video.py @@ -7,6 +7,9 @@ import signal import subprocess as sp import threading import time +from multiprocessing import Queue, Value +from multiprocessing.synchronize import Event as MpEvent +from typing import Any import cv2 from setproctitle import setproctitle @@ -15,6 +18,7 @@ from frigate.camera import CameraMetrics, PTZMetrics from frigate.comms.config_updater import ConfigSubscriber from frigate.comms.inter_process import InterProcessRequestor from frigate.config import CameraConfig, DetectConfig, ModelConfig +from frigate.config.camera.camera import CameraTypeEnum from frigate.const import ( CACHE_DIR, CACHE_SEGMENT_FORMAT, @@ -23,7 +27,7 @@ from frigate.const import ( from frigate.log import LogPipe from frigate.motion import MotionDetector from frigate.motion.improved_motion import ImprovedMotionDetector -from frigate.object_detection import RemoteObjectDetector +from frigate.object_detection.base import RemoteObjectDetector from frigate.ptz.autotrack import ptz_moving_at_frame_time from frigate.track import ObjectTracker from frigate.track.norfair_tracker import NorfairTracker @@ -98,10 +102,10 @@ def capture_frames( frame_shape: tuple[int, int], frame_manager: FrameManager, frame_queue, - fps: mp.Value, - skipped_fps: mp.Value, - current_frame: mp.Value, - stop_event: mp.Event, + fps: Value, + skipped_fps: Value, + current_frame: Value, + stop_event: MpEvent, ): frame_size = frame_shape[0] * frame_shape[1] frame_rate = EventsPerSecond() @@ -113,8 +117,10 @@ def capture_frames( def get_enabled_state(): """Fetch the latest enabled state from ZMQ.""" _, config_data = config_subscriber.check_for_update() + if config_data: - return config_data.enabled + config.enabled = config_data.enabled + return config.enabled while not stop_event.is_set(): @@ -164,7 +170,7 @@ class CameraWatchdog(threading.Thread): camera_name, config: CameraConfig, shm_frame_count: int, - frame_queue: mp.Queue, + frame_queue: Queue, camera_fps, skipped_fps, ffmpeg_pid, @@ -399,10 +405,10 @@ class CameraCapture(threading.Thread): frame_index: int, ffmpeg_process, frame_shape: tuple[int, int], - frame_queue: mp.Queue, - fps, - skipped_fps, - stop_event, + frame_queue: Queue, + fps: Value, + skipped_fps: Value, + stop_event: MpEvent, ): threading.Thread.__init__(self) self.name = f"capture:{config.name}" @@ -416,7 +422,7 @@ class CameraCapture(threading.Thread): self.skipped_fps = skipped_fps self.frame_manager = SharedMemoryFrameManager() self.ffmpeg_process = ffmpeg_process - self.current_frame = mp.Value("d", 0.0) + self.current_frame = Value("d", 0.0) self.last_frame = 0 def run(self): @@ -466,14 +472,14 @@ def capture_camera( def track_camera( name, config: CameraConfig, - model_config, - labelmap, - detection_queue, - result_connection, + model_config: ModelConfig, + labelmap: dict[int, str], + detection_queue: Queue, + result_connection: MpEvent, detected_objects_queue, camera_metrics: CameraMetrics, ptz_metrics: PTZMetrics, - region_grid, + region_grid: list[list[dict[str, Any]]], ): stop_event = mp.Event() @@ -517,6 +523,7 @@ def track_camera( frame_queue, frame_shape, model_config, + config, config.detect, frame_manager, motion_detector, @@ -580,21 +587,22 @@ def detect( def process_frames( camera_name: str, requestor: InterProcessRequestor, - frame_queue: mp.Queue, - frame_shape, + frame_queue: Queue, + frame_shape: tuple[int, int], model_config: ModelConfig, + camera_config: CameraConfig, detect_config: DetectConfig, frame_manager: FrameManager, motion_detector: MotionDetector, object_detector: RemoteObjectDetector, object_tracker: ObjectTracker, - detected_objects_queue: mp.Queue, + detected_objects_queue: Queue, camera_metrics: CameraMetrics, objects_to_track: list[str], object_filters, - stop_event, + stop_event: MpEvent, ptz_metrics: PTZMetrics, - region_grid, + region_grid: list[list[dict[str, Any]]], exit_on_empty: bool = False, ): next_region_update = get_tomorrow_at_time(2) @@ -610,6 +618,29 @@ def process_frames( region_min_size = get_min_region_size(model_config) + attributes_map = model_config.attributes_map + all_attributes = model_config.all_attributes + + # remove license_plate from attributes if this camera is a dedicated LPR cam + if camera_config.type == CameraTypeEnum.lpr: + modified_attributes_map = model_config.attributes_map.copy() + + if ( + "car" in modified_attributes_map + and "license_plate" in modified_attributes_map["car"] + ): + modified_attributes_map["car"] = [ + attr + for attr in modified_attributes_map["car"] + if attr != "license_plate" + ] + + attributes_map = modified_attributes_map + + all_attributes = [ + attr for attr in model_config.all_attributes if attr != "license_plate" + ] + while not stop_event.is_set(): _, updated_enabled_config = enabled_config_subscriber.check_for_update() @@ -803,9 +834,7 @@ def process_frames( # if detection was run on this frame, consolidate if len(regions) > 0: tracked_detections = [ - d - for d in consolidated_detections - if d[0] not in model_config.all_attributes + d for d in consolidated_detections if d[0] not in all_attributes ] # now that we have refined our detections, we need to track objects object_tracker.match_and_update( @@ -817,7 +846,7 @@ def process_frames( # group the attribute detections based on what label they apply to attribute_detections: dict[str, list[TrackedObjectAttribute]] = {} - for label, attribute_labels in model_config.attributes_map.items(): + for label, attribute_labels in attributes_map.items(): attribute_detections[label] = [ TrackedObjectAttribute(d) for d in consolidated_detections @@ -834,8 +863,7 @@ def process_frames( for attributes in attribute_detections.values(): for attribute in attributes: filtered_objects = filter( - lambda o: attribute.label - in model_config.attributes_map.get(o["label"], []), + lambda o: attribute.label in attributes_map.get(o["label"], []), all_objects, ) selected_object_id = attribute.find_best_object(filtered_objects) @@ -883,7 +911,7 @@ def process_frames( for obj in object_tracker.tracked_objects.values(): if obj["frame_time"] == frame_time: thickness = 2 - color = model_config.colormap[obj["label"]] + color = model_config.colormap.get(obj["label"], (255, 255, 255)) else: thickness = 1 color = (255, 0, 0) diff --git a/frigate/watchdog.py b/frigate/watchdog.py index d7cdec796..4c49de1a0 100644 --- a/frigate/watchdog.py +++ b/frigate/watchdog.py @@ -4,7 +4,7 @@ import threading import time from multiprocessing.synchronize import Event as MpEvent -from frigate.object_detection import ObjectDetectProcess +from frigate.object_detection.base import ObjectDetectProcess from frigate.util.services import restart_frigate logger = logging.getLogger(__name__) diff --git a/migrations/030_create_user_review_status.py b/migrations/030_create_user_review_status.py index d24738438..17f2b36b9 100644 --- a/migrations/030_create_user_review_status.py +++ b/migrations/030_create_user_review_status.py @@ -62,11 +62,13 @@ def migrate(migrator, database, fake=False, **kwargs): 'SELECT "id" FROM "reviewsegment" WHERE "has_been_reviewed" = 1' ) reviewed_segment_ids = [row[0] for row in cursor.fetchall()] + # also migrate for anonymous (unauthenticated users) + usernames = [user.username for user in all_users] + ["anonymous"] for segment_id in reviewed_segment_ids: - for user in all_users: + for username in usernames: UserReviewStatus.create( - user_id=user.username, + user_id=username, review_segment=segment_id, has_been_reviewed=True, ) diff --git a/notebooks/YOLO_NAS_Pretrained_Export.ipynb b/notebooks/YOLO_NAS_Pretrained_Export.ipynb index e4e2222da..4e0439e9e 100644 --- a/notebooks/YOLO_NAS_Pretrained_Export.ipynb +++ b/notebooks/YOLO_NAS_Pretrained_Export.ipynb @@ -8,20 +8,20 @@ }, "outputs": [], "source": [ - "! pip install -q super_gradients==3.7.1" + "! pip install -q git+https://github.com/Deci-AI/super-gradients.git" ] }, { "cell_type": "code", - "source": [ - "! sed -i 's/sghub.deci.ai/sg-hub-nv.s3.amazonaws.com/' /usr/local/lib/python3.10/dist-packages/super_gradients/training/pretrained_models.py\n", - "! sed -i 's/sghub.deci.ai/sg-hub-nv.s3.amazonaws.com/' /usr/local/lib/python3.10/dist-packages/super_gradients/training/utils/checkpoint_utils.py" - ], + "execution_count": null, "metadata": { "id": "NiRCt917KKcL" }, - "execution_count": null, - "outputs": [] + "outputs": [], + "source": [ + "! sed -i 's/sghub.deci.ai/sg-hub-nv.s3.amazonaws.com/' /usr/local/lib/python3.11/dist-packages/super_gradients/training/pretrained_models.py\n", + "! sed -i 's/sghub.deci.ai/sg-hub-nv.s3.amazonaws.com/' /usr/local/lib/python3.11/dist-packages/super_gradients/training/utils/checkpoint_utils.py" + ] }, { "cell_type": "code", @@ -51,6 +51,7 @@ "model.export(\"yolo_nas_s.onnx\",\n", " output_predictions_format=DetectionOutputFormatMode.FLAT_FORMAT,\n", " max_predictions_per_image=20,\n", + " num_pre_nms_predictions=300,\n", " confidence_threshold=0.4,\n", " input_image_shape=(320,320),\n", " )" @@ -84,4 +85,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/process_clip.py b/process_clip.py index 46bbc2c91..6f474de68 100644 --- a/process_clip.py +++ b/process_clip.py @@ -14,7 +14,7 @@ sys.path.append("/workspace/frigate") from frigate.config import FrigateConfig # noqa: E402 from frigate.motion import MotionDetector # noqa: E402 -from frigate.object_detection import LocalObjectDetector # noqa: E402 +from frigate.object_detection.base import LocalObjectDetector # noqa: E402 from frigate.track.centroid_tracker import CentroidTracker # noqa: E402 from frigate.track.object_processing import CameraState # noqa: E402 from frigate.util import ( # noqa: E402 diff --git a/web/package-lock.json b/web/package-lock.json index 97a0d991b..96913785b 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -38,9 +38,12 @@ "cmdk": "^1.0.0", "copy-to-clipboard": "^3.3.3", "date-fns": "^3.6.0", + "date-fns-tz": "^3.2.0", "embla-carousel-react": "^8.2.0", "framer-motion": "^11.5.4", "hls.js": "^1.5.20", + "i18next": "^24.2.0", + "i18next-http-backend": "^3.0.1", "idb-keyval": "^6.2.1", "immer": "^10.1.1", "konva": "^9.3.18", @@ -54,8 +57,10 @@ "react-day-picker": "^8.10.1", "react-device-detect": "^2.2.3", "react-dom": "^18.3.1", + "react-dropzone": "^14.3.8", "react-grid-layout": "^1.5.0", "react-hook-form": "^7.52.1", + "react-i18next": "^15.2.0", "react-icons": "^5.5.0", "react-konva": "^18.2.10", "react-router-dom": "^6.26.0", @@ -192,9 +197,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", - "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -3522,6 +3528,15 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/attr-accept": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz", + "integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/autoprefixer": { "version": "10.4.20", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", @@ -4306,6 +4321,15 @@ "toggle-selection": "^1.0.6" } }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -4376,6 +4400,15 @@ "url": "https://github.com/sponsors/kossnocorp" } }, + "node_modules/date-fns-tz": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.2.0.tgz", + "integrity": "sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==", + "license": "MIT", + "peerDependencies": { + "date-fns": "^3.0.0 || ^4.0.0" + } + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -5099,6 +5132,18 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-selector": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-2.1.2.tgz", + "integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==", + "license": "MIT", + "dependencies": { + "tslib": "^2.7.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -5427,6 +5472,15 @@ "dev": true, "license": "MIT" }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -5455,6 +5509,46 @@ "node": ">= 14" } }, + "node_modules/i18next": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-24.2.0.tgz", + "integrity": "sha512-ArJJTS1lV6lgKH7yEf4EpgNZ7+THl7bsGxxougPYiXRTJ/Fe1j08/TBpV9QsXCIYVfdE/HWG/xLezJ5DOlfBOA==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/i18next-http-backend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.1.tgz", + "integrity": "sha512-XT2lYSkbAtDE55c6m7CtKxxrsfuRQO3rUfHzj8ZyRtY9CkIX3aRGwXGTkUhpGWce+J8n7sfu3J0f2wTzo7Lw0A==", + "license": "MIT", + "dependencies": { + "cross-fetch": "4.0.0" + } + }, "node_modules/idb-keyval": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", @@ -6359,6 +6453,48 @@ "react-dom": "^16.8 || ^17 || ^18" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", @@ -7117,6 +7253,23 @@ "node": ">=6" } }, + "node_modules/react-dropzone": { + "version": "14.3.8", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.3.8.tgz", + "integrity": "sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==", + "license": "MIT", + "dependencies": { + "attr-accept": "^2.2.4", + "file-selector": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, "node_modules/react-grid-layout": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/react-grid-layout/-/react-grid-layout-1.5.0.tgz", @@ -7151,6 +7304,28 @@ "react": "^16.8.0 || ^17 || ^18 || ^19" } }, + "node_modules/react-i18next": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.2.0.tgz", + "integrity": "sha512-iJNc8111EaDtVTVMKigvBtPHyrJV+KblWG73cUxqp+WmJCcwkzhWNFXmkAD5pwP2Z4woeDj/oXDdbjDsb3Gutg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-icons": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", @@ -8422,9 +8597,10 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", @@ -8455,7 +8631,7 @@ "version": "5.8.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -8881,6 +9057,15 @@ } } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", diff --git a/web/package.json b/web/package.json index 59a0a5d03..b23bcdba8 100644 --- a/web/package.json +++ b/web/package.json @@ -44,9 +44,12 @@ "cmdk": "^1.0.0", "copy-to-clipboard": "^3.3.3", "date-fns": "^3.6.0", + "date-fns-tz": "^3.2.0", "embla-carousel-react": "^8.2.0", "framer-motion": "^11.5.4", "hls.js": "^1.5.20", + "i18next": "^24.2.0", + "i18next-http-backend": "^3.0.1", "idb-keyval": "^6.2.1", "immer": "^10.1.1", "konva": "^9.3.18", @@ -60,8 +63,10 @@ "react-day-picker": "^8.10.1", "react-device-detect": "^2.2.3", "react-dom": "^18.3.1", + "react-dropzone": "^14.3.8", "react-grid-layout": "^1.5.0", "react-hook-form": "^7.52.1", + "react-i18next": "^15.2.0", "react-icons": "^5.5.0", "react-konva": "^18.2.10", "react-router-dom": "^6.26.0", diff --git a/web/public/locales/ab/audio.json b/web/public/locales/ab/audio.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/audio.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/common.json b/web/public/locales/ab/common.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/common.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/components/auth.json b/web/public/locales/ab/components/auth.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/components/auth.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/components/camera.json b/web/public/locales/ab/components/camera.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/components/camera.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/components/dialog.json b/web/public/locales/ab/components/dialog.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/components/dialog.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/components/filter.json b/web/public/locales/ab/components/filter.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/components/filter.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/components/icons.json b/web/public/locales/ab/components/icons.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/components/icons.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/components/input.json b/web/public/locales/ab/components/input.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/components/input.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/components/player.json b/web/public/locales/ab/components/player.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/components/player.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/objects.json b/web/public/locales/ab/objects.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/objects.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/views/configEditor.json b/web/public/locales/ab/views/configEditor.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/views/configEditor.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/views/events.json b/web/public/locales/ab/views/events.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/views/events.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/views/explore.json b/web/public/locales/ab/views/explore.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/views/explore.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/views/exports.json b/web/public/locales/ab/views/exports.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/views/exports.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/views/faceLibrary.json b/web/public/locales/ab/views/faceLibrary.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/views/faceLibrary.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/views/live.json b/web/public/locales/ab/views/live.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/views/live.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/views/recording.json b/web/public/locales/ab/views/recording.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/views/recording.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/views/search.json b/web/public/locales/ab/views/search.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/views/search.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/views/settings.json b/web/public/locales/ab/views/settings.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/views/settings.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ab/views/system.json b/web/public/locales/ab/views/system.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ab/views/system.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/audio.json b/web/public/locales/ar/audio.json new file mode 100644 index 000000000..5477a3fda --- /dev/null +++ b/web/public/locales/ar/audio.json @@ -0,0 +1,71 @@ +{ + "bark": "نُبَاح", + "snort": "نَفْخَة", + "heartbeat": "نَبْض القَلْب", + "pets": "حَيَوَانَات أَلِيفَة", + "whoop": "هُتَاف", + "humming": "هَمْهَمَة", + "chewing": "مَضْغ", + "yodeling": "تَزَلْغُط", + "howl": "عُوَاء", + "speech": "كَلَام", + "hiccup": "فُوَاق", + "dog": "كَلْب", + "yip": "نُبَيْحَة", + "babbling": "ثَرْثَرَة", + "yell": "صُرَاخ", + "bellow": "خُوَار", + "whispering": "هَمْس", + "laughter": "ضَحِك", + "snicker": "تَضَاحُك", + "crying": "بُكَاء", + "sigh": "تَنَهُّد", + "singing": "غِنَاء", + "choir": "جَوْقَة", + "chant": "تَرْنِيم", + "mantra": "تَرْنِيمَة", + "child_singing": "غِنَاء طِفْل", + "synthetic_singing": "غِنَاء اِصْطِنَاعِيّ", + "rapping": "رَاب", + "groan": "أَنِين", + "grunt": "خَنِين", + "whistling": "صَفِير", + "breathing": "تَنَفُّس", + "wheeze": "أَزِيز", + "snoring": "شَخِير", + "gasp": "شَهْقَة", + "pant": "لَهَث", + "cough": "سُعَال", + "throat_clearing": "تَنْحِيم", + "sneeze": "عُطَاس", + "sniff": "شَمَّ", + "run": "رَكْض", + "shuffle": "خَلْط", + "footsteps": "خُطُوَات", + "biting": "عَضّ", + "gargling": "غَرْغَرَة", + "stomach_rumble": "قَرْقَرَة المَعِدَة", + "burping": "تَجَشُّؤ", + "fart": "ضُرَاط", + "hands": "أَيْدِي", + "finger_snapping": "طَقْطَقَة الأَصَابِع", + "clapping": "تَصْفِيق", + "heart_murmur": "لَغَط القَلْب", + "cheering": "صِيَاح", + "applause": "تَصْفِيق", + "chatter": "حَدِيث", + "crowd": "جُمْهُور", + "children_playing": "لَعِب الأَطْفَال", + "animal": "حَيَوَان", + "bow_wow": "نُبَاح الكَلْب", + "growling": "زَمْجَرَ", + "whimper_dog": "أَنِين الكَلْب", + "cat": "قِطّ", + "purr": "خَرْخَرَة", + "meow": "مُوَاء", + "hiss": "فَحِيح", + "caterwaul": "صُرَاخ مُتَوَاصِل", + "livestock": "مَاشِيَة", + "horse": "حِصَان", + "clip_clop": "حَوَافِر الخَيْل" +} diff --git a/web/public/locales/ar/common.json b/web/public/locales/ar/common.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/common.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/components/auth.json b/web/public/locales/ar/components/auth.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/components/auth.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/components/camera.json b/web/public/locales/ar/components/camera.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/components/camera.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/components/dialog.json b/web/public/locales/ar/components/dialog.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/components/dialog.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/components/filter.json b/web/public/locales/ar/components/filter.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/components/filter.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/components/icons.json b/web/public/locales/ar/components/icons.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/components/icons.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/components/input.json b/web/public/locales/ar/components/input.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/components/input.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/components/player.json b/web/public/locales/ar/components/player.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/components/player.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/objects.json b/web/public/locales/ar/objects.json new file mode 100644 index 000000000..be6a702ac --- /dev/null +++ b/web/public/locales/ar/objects.json @@ -0,0 +1,7 @@ +{ + "dog": "كَلْب", + "cat": "قِطّ", + "horse": "حِصَان", + "animal": "حَيَوَان", + "bark": "نُبَاح" +} diff --git a/web/public/locales/ar/views/configEditor.json b/web/public/locales/ar/views/configEditor.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/views/configEditor.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/views/events.json b/web/public/locales/ar/views/events.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/views/events.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/views/explore.json b/web/public/locales/ar/views/explore.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/views/explore.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/views/exports.json b/web/public/locales/ar/views/exports.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/views/exports.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/views/faceLibrary.json b/web/public/locales/ar/views/faceLibrary.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/views/faceLibrary.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/views/live.json b/web/public/locales/ar/views/live.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/views/live.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/views/recording.json b/web/public/locales/ar/views/recording.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/views/recording.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/views/search.json b/web/public/locales/ar/views/search.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/views/search.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/views/settings.json b/web/public/locales/ar/views/settings.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/views/settings.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ar/views/system.json b/web/public/locales/ar/views/system.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ar/views/system.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/audio.json b/web/public/locales/ca/audio.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/audio.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/common.json b/web/public/locales/ca/common.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/common.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/components/auth.json b/web/public/locales/ca/components/auth.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/components/auth.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/components/camera.json b/web/public/locales/ca/components/camera.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/components/camera.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/components/dialog.json b/web/public/locales/ca/components/dialog.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/components/dialog.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/components/filter.json b/web/public/locales/ca/components/filter.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/components/filter.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/components/icons.json b/web/public/locales/ca/components/icons.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/components/icons.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/components/input.json b/web/public/locales/ca/components/input.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/components/input.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/components/player.json b/web/public/locales/ca/components/player.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/components/player.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/objects.json b/web/public/locales/ca/objects.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/objects.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/views/configEditor.json b/web/public/locales/ca/views/configEditor.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/views/configEditor.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/views/events.json b/web/public/locales/ca/views/events.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/views/events.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/views/explore.json b/web/public/locales/ca/views/explore.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/views/explore.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/views/exports.json b/web/public/locales/ca/views/exports.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/views/exports.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/views/faceLibrary.json b/web/public/locales/ca/views/faceLibrary.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/views/faceLibrary.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/views/live.json b/web/public/locales/ca/views/live.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/views/live.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/views/recording.json b/web/public/locales/ca/views/recording.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/views/recording.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/views/search.json b/web/public/locales/ca/views/search.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/views/search.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/views/settings.json b/web/public/locales/ca/views/settings.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/views/settings.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/ca/views/system.json b/web/public/locales/ca/views/system.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/ca/views/system.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/cs/audio.json b/web/public/locales/cs/audio.json new file mode 100644 index 000000000..8a2d91691 --- /dev/null +++ b/web/public/locales/cs/audio.json @@ -0,0 +1,315 @@ +{ + "yell": "Křik", + "child_singing": "Dětský zpěv", + "speech": "Řeč", + "babbling": "Blábolení", + "bellow": "Řev", + "whoop": "Výskání", + "whispering": "Šeptání", + "snicker": "Chichotání", + "crying": "Pláč", + "sigh": "Povzdech", + "singing": "Zpěv", + "choir": "Sbor", + "yodeling": "Jódlování", + "synthetic_singing": "Umělý zpěv", + "humming": "Bzukot", + "groan": "Sténání", + "whistling": "Pískot", + "breathing": "Dech", + "wheeze": "Sípání", + "snoring": "Chrapot", + "snort": "Funění", + "cough": "Kašel", + "throat_clearing": "Odkašlávání", + "sneeze": "Kýchání", + "footsteps": "Kroky", + "chewing": "Žvýkání", + "biting": "Kousání", + "burping": "Krkání", + "hiccup": "Škytání", + "fart": "Prdění", + "hands": "Ruce", + "finger_snapping": "Luskání prstem", + "clapping": "Tleskání", + "heartbeat": "Tluk srdce", + "cheering": "Jásání", + "applause": "Potlesk", + "chatter": "Klábosení", + "crowd": "Dav", + "children_playing": "Hrající si děti", + "bark": "Štěkot", + "howl": "Vytí", + "growling": "Vrkot", + "whimper_dog": "Psí kníkot", + "cat": "Kočka", + "purr": "Předení", + "meow": "Mňouk", + "hiss": "Sykot", + "livestock": "Hospodářská zvířata", + "horse": "Kůň", + "neigh": "Řehtání", + "cattle": "Dobytek", + "moo": "Bučení", + "cowbell": "Kravský zvonec", + "pig": "Prase", + "oink": "Chrochtání", + "fowl": "Drůbež", + "chicken": "Slepice", + "cluck": "Kvokání", + "cock_a_doodle_doo": "Kykyryký", + "turkey": "Krocan", + "gobble": "Hudrování", + "duck": "Kachna", + "quack": "Kvákání", + "goose": "Husa", + "honk": "Kejhání", + "wild_animals": "Divoká zvířata", + "roaring_cats": "Řvoucí kočky", + "roar": "Řev", + "bird": "Pták", + "chirp": "Cvrlikání", + "pigeon": "Holub", + "coo": "Vrkání", + "squawk": "Skřekání", + "crow": "Vrána", + "caw": "Krákání", + "hoot": "Houkání", + "flapping_wings": "Mávání křídel", + "dogs": "Psi", + "mouse": "Myš", + "insect": "Hmyz", + "fly": "Moucha", + "buzz": "Bzučení", + "frog": "Žába", + "snake": "Had", + "croak": "Kvákání žáby", + "rattle": "Chrastění", + "whale_vocalization": "Velrybí zpěv", + "music": "Hudba", + "guitar": "Kytara", + "bass_guitar": "Basová kytara", + "steel_guitar": "Ocelová kytara", + "tapping": "Ťukání", + "banjo": "Banjo", + "sitar": "Sitar", + "mandolin": "Mandolína", + "zither": "Citera", + "ukulele": "Ukulele", + "keyboard": "Klávesnice", + "electric_piano": "Elektrický klavír", + "electronic_organ": "Elektronické varhany", + "hammond_organ": "Hammondovy varhany", + "synthesizer": "Syntezátor", + "sampler": "Sampler", + "harpsichord": "Cembalo", + "percussion": "Perkuse", + "drum_kit": "Bubny", + "drum_machine": "Bicí automat", + "drum": "Buben", + "snare_drum": "Malý buben", + "rimshot": "Rána na obruč", + "drum_roll": "Víření", + "timpani": "Tympány", + "tabla": "Tabla", + "cymbal": "Činel", + "hi_hat": "Hi-hat", + "wood_block": "Dřevěný blok", + "tambourine": "Tamburína", + "maraca": "Maraka", + "gong": "Gong", + "marimba": "Marimba", + "vibraphone": "Vibrafon", + "steelpan": "Ocelový buben", + "orchestra": "Orchestr", + "brass_instrument": "Žesťový nástroj", + "french_horn": "Lesní roh", + "trumpet": "Trubka", + "trombone": "Trombón", + "violin": "Housle", + "saxophone": "Saxofon", + "church_bell": "Kostelní zvon", + "bicycle_bell": "Cyklistický zvonek", + "tuning_fork": "Ladička", + "chime": "Zvonění", + "harmonica": "Harmonika", + "accordion": "Akordeon", + "bagpipes": "Dudy", + "didgeridoo": "Didžeridu", + "theremin": "Theremin", + "scratching": "Škrábání", + "pop_music": "Popová muzika", + "hip_hop_music": "Hip-hopová muzika", + "rock_music": "Rocková muzika", + "heavy_metal": "Heavy metal", + "music_for_children": "Hudba pro děti", + "song": "Píseň", + "thunderstorm": "Bouře", + "wind": "Vítr", + "rustling_leaves": "Šustění listů", + "wind_noise": "Zvuk větru", + "thunder": "Hrom", + "water": "Voda", + "rain": "Déšť", + "raindrop": "Dešťové kapky", + "stream": "Potok", + "waterfall": "Vodopád", + "ocean": "Moře", + "waves": "Vlny", + "steam": "Pára", + "fire": "Oheň", + "crackle": "Praskání", + "vehicle": "Vozidlo", + "sailboat": "Plachetnice", + "boat": "Člun", + "ship": "Loď", + "rowboat": "Loďka", + "motorboat": "Motorový člun", + "motor_vehicle": "Motorové vozidlo", + "car": "Auto", + "laughter": "Smích", + "sniff": "Čichání", + "stomach_rumble": "Kručení v břiše", + "gargling": "Kloktání", + "dog": "Pes", + "run": "Běh", + "cricket": "Cvrček", + "glockenspiel": "Zvonkohra", + "cello": "Cello", + "pets": "Domácí mazlíčci", + "opera": "Opera", + "harp": "Harfa", + "animal": "Zvíře", + "electric_guitar": "Elektrická kytara", + "piano": "Klavír", + "goat": "Koza", + "bleat": "Mečení", + "sheep": "Ovce", + "owl": "Sova", + "musical_instrument": "Hudební nástroj", + "organ": "Varhany", + "rats": "Krysy", + "mosquito": "Komár", + "strum": "Brnkání", + "tubular_bells": "Trubicové zvony", + "acoustic_guitar": "Akustická kytara", + "bass_drum": "Basový buben", + "jazz": "Jazz", + "flute": "Flétna", + "clarinet": "Klarinet", + "bell": "Zvon", + "techno": "Techno", + "electronic_music": "Elektronická muzika", + "car_alarm": "Autoalarm", + "power_windows": "Elektrická okénka", + "skidding": "Smyk", + "tire_squeal": "Kvílení pneumatik", + "car_passing_by": "Projíždějící auto", + "air_brake": "Vzduchové brzdy", + "air_horn": "Vzduchový klakson", + "bus": "Autobus", + "police_car": "Policejní auto", + "ambulance": "Záchranka", + "fire_engine": "Hasiči", + "motorcycle": "Motorka", + "rail_transport": "Železnice", + "train": "Vlak", + "train_horn": "Troubení vlaku", + "railroad_car": "Železniční vagon", + "subway": "Metro", + "aircraft": "Letadlo", + "aircraft_engine": "Motor letadla", + "bicycle": "Cyklistické kolo", + "jet_engine": "Tryskový motor", + "propeller": "Vrtule", + "helicopter": "Helikoptéra", + "dental_drill's_drill": "Zubní vrtačka", + "lawn_mower": "Sekačka", + "chainsaw": "Motorová pila", + "idling": "Bežící motor", + "accelerating": "Přidávání plynu", + "door": "Dveře", + "doorbell": "Zvonek", + "sliding_door": "Posuvné dveře", + "slam": "Bouchnutí", + "knock": "Klepání", + "dishes": "Nádobí", + "cutlery": "Příbory", + "chopping": "Krájení", + "bathtub": "Vana", + "hair_dryer": "Fén", + "toilet_flush": "Spláchnutí záchodu", + "toothbrush": "Zubní kartáček", + "electric_toothbrush": "Elektrický zubní kartáček", + "vacuum_cleaner": "Vysavač", + "zipper": "Zip", + "keys_jangling": "Cinkání klíčů", + "coin": "Mince", + "scissors": "Nůžky", + "electric_shaver": "Elektrický holící strojek", + "typing": "", + "typewriter": "Psací stroj", + "computer_keyboard": "Počítačová klávesnice", + "writing": "Psaní", + "alarm": "Alarm", + "telephone": "Telefon", + "telephone_bell_ringing": "Zvonění telefonu", + "telephone_dialing": "Vytáčení", + "alarm_clock": "Budík", + "siren": "Siréna", + "smoke_detector": "Detektor kouře", + "fire_alarm": "Požární alarm", + "foghorn": "Mlhovka", + "whistle": "Píšťalka", + "mechanisms": "Mechanismy", + "clock": "Hodiny", + "tick-tock": "Ťikťak", + "tick": "Ťik", + "sewing_machine": "Šicí stroj", + "air_conditioning": "Klimatizace", + "cash_register": "Kasa", + "printer": "Tiskárna", + "camera": "Kamera", + "tools": "Nářadí", + "hammer": "Kladivo", + "jackhammer": "Zbíječka", + "sawing": "Řezání", + "power_tool": "Elektrické nářadí", + "drill": "Vrtačka", + "explosion": "Výbuch", + "gunshot": "Výstřel", + "fireworks": "Ohňostroj", + "firecracker": "Petarda", + "eruption": "Erupce", + "boom": "Třesk", + "wood": "Dřevo", + "splinter": "Tříska", + "glass": "Sklo", + "shatter": "Roztříštění", + "silence": "Ticho", + "sound_effect": "Zvukový efekt", + "environmental_noise": "Okolní hluk", + "white_noise": "Bilý šum", + "radio": "Rádio", + "scream": "Výkřik", + "microwave_oven": "Mikrovlnka", + "race_car": "Závodní auto", + "ding-dong": "Cink", + "water_tap": "Vodovodní kohoutek", + "sink": "Dřez", + "pink_noise": "Růžový šum", + "frying": "Smažení", + "television": "Televize", + "blender": "Mixér", + "train_whistle": "Houkání vlaku", + "engine": "Motor", + "engine_starting": "Startující motor", + "truck": "Nákladní auto", + "static": "Šum", + "engine_knocking": "Klepání v motoru", + "skateboard": "Skateboard", + "chant": "Skandování", + "rapping": "Rapování", + "gasp": "Zalapání po dechu", + "heart_murmur": "Srdeční šelest" +} diff --git a/web/public/locales/cs/common.json b/web/public/locales/cs/common.json new file mode 100644 index 000000000..f52b47572 --- /dev/null +++ b/web/public/locales/cs/common.json @@ -0,0 +1,86 @@ +{ + "time": { + "untilForTime": "Do {{time}}", + "untilForRestart": "Do doby, než se Frigarte restartuje.", + "untilRestart": "Do restartu", + "justNow": "Teď", + "today": "Dnes", + "yesterday": "Včera", + "last7": "Posledních 7 dní", + "last14": "Posledních 14 dní", + "last30": "Posledních 30 dní", + "thisWeek": "Tento týden", + "lastWeek": "Minulý týden", + "thisMonth": "Tento měsíc", + "lastMonth": "Minulý měsíc", + "5minutes": "5 minut", + "10minutes": "10 minut", + "30minutes": "30 minut", + "1hour": "1 hodina", + "12hours": "12 hodin", + "24hours": "24 hodin", + "pm": "odpoledne", + "am": "ráno", + "year_one": "{{time}} rok", + "year_few": "{{time}} let", + "year_other": "{{time}} let", + "month_one": "{{time}} měsíc", + "month_few": "{{time}} měsíce", + "month_other": "{{time}} měsíců", + "day_one": "{{time}} den", + "day_few": "{{time}} dny", + "day_other": "{{time}} dní", + "hour_one": "{{time}} hodina", + "hour_few": "{{time}} hodiny", + "hour_other": "{{time}} hodin", + "minute_one": "{{time}} minuta", + "minute_few": "{{time}} minuty", + "minute_other": "{{time}} minut", + "second_one": "{{time}} sekunda", + "second_few": "{{time}} sekundy", + "second_other": "{{time}} sekund" + }, + "button": { + "twoWayTalk": "Obousměrná komunikace", + "enabled": "Zapnuto", + "cameraAudio": "Zvuk kamery", + "apply": "Použij", + "reset": "Reset", + "done": "Hotovo", + "on": "Zapnuto", + "off": "Vypnuto", + "edit": "Upravit", + "enable": "Zapni", + "disabled": "Vypnuto", + "disable": "Vypni", + "save": "Uložit", + "saving": "Ukládám…", + "cancel": "Zrušit", + "close": "Zavři", + "copy": "Zkopíruj", + "back": "Zpět", + "history": "Historie", + "fullscreen": "Celá obrazovka", + "exitFullscreen": "Opustit režim celé obrazovky", + "pictureInPicture": "Obraz v obraze", + "copyCoordinates": "Zkopíruj souřadnice", + "delete": "Odstraň", + "yes": "Ano", + "no": "Ne", + "download": "Stáhnout", + "info": "Informace", + "suspended": "Pozastaveno", + "unsuspended": "Zrušit pozastavení", + "play": "Hrát", + "unselect": "Zrušit výběr" + }, + "label": { + "back": "Jdi zpět" + }, + "unit": { + "speed": { + "kph": "KM/h", + "mph": "míle/h" + } + } +} diff --git a/web/public/locales/cs/components/auth.json b/web/public/locales/cs/components/auth.json new file mode 100644 index 000000000..a3dd01b32 --- /dev/null +++ b/web/public/locales/cs/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "user": "Uživatelské jméno", + "password": "Heslo", + "login": "Přihlášení", + "errors": { + "usernameRequired": "Uživatelské jméno je povinné", + "passwordRequired": "Heslo je povinné", + "loginFailed": "Přihlášení se nezdařilo", + "unknownError": "Neznámá chyba. Zkontrolujte logy.", + "webUnknownError": "Neznámá chuba. Zkontrolujte logy konzoly.", + "rateLimit": "Limit požadavků překročen. Zkuste to znovu později." + } + } +} diff --git a/web/public/locales/cs/components/camera.json b/web/public/locales/cs/components/camera.json new file mode 100644 index 000000000..7053989df --- /dev/null +++ b/web/public/locales/cs/components/camera.json @@ -0,0 +1,5 @@ +{ + "group": { + "label": "Skupiny kamer" + } +} diff --git a/web/public/locales/cs/components/dialog.json b/web/public/locales/cs/components/dialog.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/cs/components/dialog.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/cs/components/filter.json b/web/public/locales/cs/components/filter.json new file mode 100644 index 000000000..c08a98264 --- /dev/null +++ b/web/public/locales/cs/components/filter.json @@ -0,0 +1,3 @@ +{ + "filter": "Filtrovat" +} diff --git a/web/public/locales/cs/components/icons.json b/web/public/locales/cs/components/icons.json new file mode 100644 index 000000000..a98f6d6e0 --- /dev/null +++ b/web/public/locales/cs/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "Zvolte ikonu", + "search": { + "placeholder": "Hledejte ikonu…" + } + } +} diff --git a/web/public/locales/cs/components/input.json b/web/public/locales/cs/components/input.json new file mode 100644 index 000000000..19574eb42 --- /dev/null +++ b/web/public/locales/cs/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Stáhnout video", + "toast": { + "success": "Vaše video se stahuje." + } + } + } +} diff --git a/web/public/locales/cs/components/player.json b/web/public/locales/cs/components/player.json new file mode 100644 index 000000000..6f32e403c --- /dev/null +++ b/web/public/locales/cs/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "V tomto období nebyly nalezeny žádné záznamy", + "noPreviewFound": "Náhled nenalezen", + "noPreviewFoundFor": "Náhled nenalezen pro {{cameraName}}", + "submitFrigatePlus": { + "title": "Odeslat tento snímek do služby Frigate+?", + "submit": "Odeslat" + }, + "livePlayerRequiredIOSVersion": "Pro tento typ živého přenosu je vyžadován systém iOS 17.1 nebo novější.", + "streamOffline": { + "title": "Přenos je offline", + "desc": "Žádné snímky nebyly zaznamenány na {{cameraName}} detectpřenosu, zkontrolujte logy chyb" + }, + "cameraDisabled": "Kamera je zakázaná", + "stats": { + "streamType": { + "title": "Typ přenosu:", + "short": "Typ" + }, + "bandwidth": { + "title": "Šířka pásma:", + "short": "Šířka pásma" + }, + "latency": { + "title": "Latence:", + "value": "{{seconds}} sekund", + "short": { + "title": "Latence", + "value": "{{seconds}} sek" + } + }, + "totalFrames": "Celkový počet snímků:", + "droppedFrames": { + "title": "Ztracené snímky:", + "short": { + "title": "Ztracené", + "value": "{{droppedFrames}} snímků" + } + }, + "decodedFrames": "Dekódované snímky:", + "droppedFrameRate": "Frekvence ztracených snímků:" + }, + "toast": { + "success": { + "submittedFrigatePlus": "Snimek byl úspěšně odeslán službě Frigate+" + }, + "error": { + "submitFrigatePlusFailed": "Nepodařilo se odeslat snímek službě Frigate+" + } + } +} diff --git a/web/public/locales/cs/objects.json b/web/public/locales/cs/objects.json new file mode 100644 index 000000000..4bdb6c916 --- /dev/null +++ b/web/public/locales/cs/objects.json @@ -0,0 +1,28 @@ +{ + "person": "Osoba", + "dog": "Pes", + "cat": "Kočka", + "horse": "Kůň", + "bird": "Pták", + "boat": "Člun", + "car": "Auto", + "sheep": "Ovce", + "mouse": "Myš", + "keyboard": "Klávesnice", + "animal": "Zvíře", + "vehicle": "Vozidlo", + "bark": "Štěkot", + "goat": "Koza", + "bus": "Autobus", + "motorcycle": "Motorka", + "train": "Vlak", + "bicycle": "Cyklistické kolo", + "door": "Dveře", + "blender": "Mixér", + "sink": "Dřez", + "scissors": "Nůžky", + "clock": "Hodiny", + "toothbrush": "Zubní kartáček", + "hair_dryer": "Fén", + "skateboard": "Skateboard" +} diff --git a/web/public/locales/cs/views/configEditor.json b/web/public/locales/cs/views/configEditor.json new file mode 100644 index 000000000..8bc390802 --- /dev/null +++ b/web/public/locales/cs/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "documentTitle": "Editor konfigurace - Frigate", + "configEditor": "Editor konfigurace", + "copyConfig": "Kopírovat konfiguraci", + "saveAndRestart": "Uložit a restartovat", + "saveOnly": "Jen uložit", + "toast": { + "success": { + "copyToClipboard": "Konfigurace byla zkopírovaná do schránky." + }, + "error": { + "savingError": "Chyba ukládání konfigurace" + } + } +} diff --git a/web/public/locales/cs/views/events.json b/web/public/locales/cs/views/events.json new file mode 100644 index 000000000..7345b83fa --- /dev/null +++ b/web/public/locales/cs/views/events.json @@ -0,0 +1,35 @@ +{ + "alerts": "Výstrahy", + "detections": "Detekce", + "motion": { + "label": "Pohyb", + "only": "Jen pohyb" + }, + "allCameras": "Všechny kamery", + "empty": { + "alert": "Nejsou žádné výstrahy na kontrolu", + "detection": "Nejsou žádné detekce na kontrolu", + "motion": "Nenalezena žádná data o pohybu" + }, + "timeline": "Časová osa", + "timeline.aria": "Zvolit časovou osu", + "events": { + "label": "Události", + "aria": "Zvolit události", + "noFoundForTimePeriod": "Pro toto období nebyly nalezeny žádné události." + }, + "documentTitle": "Kontrola - Frigate", + "camera": "Kamera", + "calendarFilter": { + "last24Hours": "Posledních 24 hodin" + }, + "markAsReviewed": "Označit jako zkontrolované", + "markTheseItemsAsReviewed": "Označit tyto položky jako zkontrolované", + "newReviewItems": { + "label": "Zobrazit nové položky na kontrolu", + "button": "Nové položky na kontrolu" + }, + "recordings": { + "documentTitle": "Záznamy - Frigate" + } +} diff --git a/web/public/locales/cs/views/explore.json b/web/public/locales/cs/views/explore.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/cs/views/explore.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/cs/views/exports.json b/web/public/locales/cs/views/exports.json new file mode 100644 index 000000000..d27bf05e9 --- /dev/null +++ b/web/public/locales/cs/views/exports.json @@ -0,0 +1,17 @@ +{ + "search": "Hledat", + "documentTitle": "Exportovat - Frigate", + "noExports": "Žádné exporty nenalezeny", + "deleteExport": "Smazat export", + "deleteExport.desc": "Opravdu chcete smazat {{exportName}}?", + "editExport": { + "title": "Přejmenovat export", + "desc": "Zadejte nové jméno pro tento export.", + "saveExport": "Uložit export" + }, + "toast": { + "error": { + "renameExportFailed": "Nepodařilo se přejmenovat export: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/cs/views/faceLibrary.json b/web/public/locales/cs/views/faceLibrary.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/cs/views/faceLibrary.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/cs/views/live.json b/web/public/locales/cs/views/live.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/cs/views/live.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/cs/views/recording.json b/web/public/locales/cs/views/recording.json new file mode 100644 index 000000000..80fa1f193 --- /dev/null +++ b/web/public/locales/cs/views/recording.json @@ -0,0 +1,12 @@ +{ + "export": "Exportovat", + "calendar": "Kalendář", + "filter": "Filtrovat", + "filters": "Filtry", + "toast": { + "error": { + "endTimeMustAfterStartTime": "Čas konce musí být po čase začátku", + "noValidTimeSelected": "Nebylo zvoleno platné časové období" + } + } +} diff --git a/web/public/locales/cs/views/search.json b/web/public/locales/cs/views/search.json new file mode 100644 index 000000000..500058df8 --- /dev/null +++ b/web/public/locales/cs/views/search.json @@ -0,0 +1,3 @@ +{ + "search": "Hledat" +} diff --git a/web/public/locales/cs/views/settings.json b/web/public/locales/cs/views/settings.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/cs/views/settings.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/cs/views/system.json b/web/public/locales/cs/views/system.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/cs/views/system.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/de/audio.json b/web/public/locales/de/audio.json new file mode 100644 index 000000000..eab0be28e --- /dev/null +++ b/web/public/locales/de/audio.json @@ -0,0 +1,429 @@ +{ + "speech": "Sprache", + "babbling": "Plappern", + "laughter": "Gelächter", + "bellow": "Gebrüll", + "whoop": "Jubel", + "whispering": "Gerede", + "crying": "Weinen", + "bark": "Bellen", + "goat": "Ziege", + "car": "Auto", + "skateboard": "Skateboard", + "hair_dryer": "Haartrockner", + "animal": "Tier", + "boat": "Boot", + "blender": "Mixer", + "sink": "Waschbecken", + "scissors": "Schere", + "train": "Zug", + "clock": "Uhr", + "bird": "Vogel", + "motorcycle": "Motorrad", + "toothbrush": "Zahnbürste", + "bicycle": "Fahrrad", + "door": "Tür", + "keyboard": "Klaviatur", + "bus": "Bus", + "horse": "Pferd", + "cat": "Katze", + "dog": "Hund", + "sheep": "Schaf", + "mouse": "Maus", + "vehicle": "Fahrzeug", + "yell": "Schrei", + "snicker": "Gekicher", + "sigh": "Seufzer", + "choir": "Chor", + "yodeling": "Gejodel", + "chant": "Choral", + "mantra": "Mantra", + "child_singing": "Kindergesang", + "rapping": "Rappen", + "humming": "Summen", + "groan": "Stöhnen", + "grunt": "Grunzen", + "whistling": "Pfeifen", + "breathing": "Atmen", + "wheeze": "Keuchen", + "gasp": "nach Luft schnappen", + "pant": "Hecheln", + "snort": "Schnauben", + "cough": "Husten", + "sneeze": "Niesen", + "sniff": "Schnüffeln", + "run": "Laufen", + "shuffle": "Schlurfen", + "biting": "Beißen", + "gargling": "Gurgeln", + "stomach_rumble": "Magenknurren", + "burping": "Rülpsen", + "hiccup": "Schluckauf", + "fart": "Furz", + "hands": "Hände", + "finger_snapping": "Fingerschnippen", + "heartbeat": "Herzschlag", + "heart_murmur": "Herzgeräusch", + "cheering": "Gejubel", + "applause": "Beifall", + "chatter": "Geschwätz", + "crowd": "Menge", + "children_playing": "Kinderspiel", + "pets": "Haustiere", + "yip": "Aufjaulen", + "howl": "Heulen", + "growling": "Knurren", + "whimper_dog": "Hundegewimmer", + "purr": "Schnurren", + "meow": "Miauen", + "hiss": "Zischen", + "caterwaul": "Gejaule", + "livestock": "Vieh", + "clip_clop": "Klippklapp", + "neigh": "Wiehern", + "cattle": "Rinder", + "moo": "Muhen", + "cowbell": "Kuhglocke", + "oink": "Grunz", + "bleat": "Blöken", + "cluck": "Gackern", + "cock_a_doodle_doo": "Kikeriki", + "gobble": "Kollern", + "goose": "Gans", + "honk": "Hupen", + "coo": "Gurren", + "crow": "Krähe", + "dogs": "Hunde", + "rats": "Ratten", + "insect": "Insekt", + "fly": "Fliege", + "buzz": "Surren", + "frog": "Frosch", + "snake": "Schlange", + "hammond_organ": "Hammondorgel", + "synthesizer": "Synthesizer", + "sampler": "Probennehmer", + "drum_kit": "Schlagzeug", + "drum_machine": "Trommelsynthesizer", + "snare_drum": "Kleine Trommel", + "rimshot": "Rimshot", + "drum_roll": "Trommelwirbel", + "timpani": "Timpani", + "tabla": "Tabla", + "cymbal": "Becken", + "hi_hat": "Hi-Hat", + "wood_block": "Holzblock", + "tambourine": "Tamburin", + "tubular_bells": "Glockenspiel", + "camera": "Kamera", + "roar": "Brüllen", + "owl": "Eule", + "whale_vocalization": "Walgesang", + "mandolin": "Mandoline", + "chicken": "Huhn", + "sitar": "Sitar", + "ukulele": "Ukulele", + "tapping": "Klopfen", + "flapping_wings": "Flügelschlagen", + "strum": "Herumklimpern", + "electronic_organ": "Elektrische Orgel", + "duck": "Ente", + "quack": "Quaken", + "wild_animals": "Wildtiere", + "rattle": "Klappern", + "music": "Musik", + "pig": "Schwein", + "chirp": "Zwitschern", + "guitar": "Gitarre", + "plucked_string_instrument": "Zupfinstrument", + "hoot": "Heulen", + "acoustic_guitar": "Akustikgitarre", + "electric_piano": "Elektrisches Klavier", + "cricket": "Grille", + "mosquito": "Mücke", + "musical_instrument": "Musikinstrument", + "steel_guitar": "Hawaiigitarre", + "organ": "Orgel", + "drum": "Trommel", + "roaring_cats": "Katzengeschrei", + "footsteps": "Schritte", + "chewing": "Kauen", + "caw": "Krächzen", + "piano": "Klavier", + "clapping": "Klatschen", + "patter": "Trippeln", + "percussion": "Percussion", + "singing": "Gesang", + "bass_guitar": "Bassgitarre", + "fowl": "Geflügel", + "squawk": "Kreischen", + "pigeon": "Taube", + "snoring": "Schnarchen", + "synthetic_singing": "Synthetischer Gesang", + "bow_wow": "Wau-Wau", + "turkey": "Truthahn", + "croak": "Krächzen", + "electric_guitar": "Elektrische Gitarre", + "throat_clearing": "Räuspern", + "gong": "Gong", + "banjo": "Banjo", + "zither": "Zitter", + "harpsichord": "Cembalo", + "bass_drum": "Basstrommel", + "maraca": "Maraca", + "marimba": "Marimba", + "glockenspiel": "Glockenspiel", + "vibraphone": "Vibrafon", + "steelpan": "Stahlpfanne", + "brass_instrument": "Blechblasinstrument", + "french_horn": "Waldhorn", + "string_section": "Streicher", + "violin": "Geige", + "pizzicato": "Pizzikato", + "saxophone": "Saxophon", + "clarinet": "Klarinette", + "jingle_bell": "Jingle Bell", + "chime": "Glockenspiel", + "bagpipes": "Dudelsack", + "theremin": "Theremin", + "pop_music": "Popmusik", + "bowed_string_instrument": "Streichinstrument", + "didgeridoo": "Didgeridoo", + "wind_chime": "Windspiel", + "flute": "Flöte", + "church_bell": "Kirchenglocke", + "bell": "Glocke", + "orchestra": "Orchester", + "wind_instrument": "Blasinstrument", + "trombone": "Posaune", + "bicycle_bell": "Fahrradklingel", + "trumpet": "Trompete", + "harmonica": "Mundharmonika", + "double_bass": "Kontrabass", + "cello": "Cello", + "harp": "Harfe", + "tuning_fork": "Stimmgabel", + "accordion": "Akkordeon", + "singing_bowl": "Klangschale", + "mallet_percussion": "Mallet-Schlagzeug", + "hip_hop_music": "Hip-Hop-Musik", + "beatboxing": "Beatboxen", + "punk_rock": "Punkrock", + "grunge": "Grunge", + "progressive_rock": "Progressiver Rock", + "psychedelic_rock": "Psychedelischer Rock", + "rhythm_and_blues": "Rythm and Blues", + "soul_music": "Soulmusik", + "country": "Country", + "swing_music": "Swingmusik", + "bluegrass": "Bluegrass", + "funk": "Funk", + "folk_music": "Folkmusik", + "disco": "Disco", + "classical_music": "Klassische Musik", + "opera": "Oper", + "electronic_music": "Elektronische Musik", + "house_music": "House Musik", + "dubstep": "Dubstep", + "electronica": "Elektronische Medien", + "electronic_dance_music": "Elektronische Tanzmusik", + "ambient_music": "Hintergrundmusik", + "trance_music": "Trance-Musik", + "music_of_latin_america": "Lateinamerikanische Musik", + "salsa_music": "Salsa-Musik", + "blues": "Blues", + "vocal_music": "Vokalmusik", + "a_capella": "A Capella", + "music_of_africa": "Afrikanische Musik", + "gospel_music": "Gospel-Musik", + "music_of_asia": "Asiatische Musik", + "carnatic_music": "Karnatische Musik", + "music_of_bollywood": "Bollywood-Musik", + "traditional_music": "Traditionelle Musik", + "independent_music": "Eigenständige Musik", + "song": "Lied", + "background_music": "Hintergrundmusik", + "theme_music": "Titelmusik", + "lullaby": "Schlaflied", + "christmas_music": "Weihnachtsmusik", + "dance_music": "Tanzmusik", + "happy_music": "Fröhliche Musik", + "tender_music": "Sanfte Musik", + "exciting_music": "Spannende Musik", + "scary_music": "Gruselige Musik", + "wind": "Wind", + "wind_noise": "Windrauschen", + "rain_on_surface": "Regen auf einer Oberfläche", + "stream": "Strahl", + "waterfall": "Wasserfall", + "steam": "Dampf", + "fire": "Feuer", + "crackle": "Knistern", + "sailboat": "Segelboot", + "ship": "Schiff", + "motor_vehicle": "Kraftfahrzeug", + "toot": "tuten", + "car_alarm": "Autoalarm", + "power_windows": "Elektrische Fensterheber", + "tire_squeal": "Reifenquietschen", + "car_passing_by": "Vorbeifahrendes Auto", + "air_brake": "Druckluftbremse", + "air_horn": "Autohupe", + "reversing_beeps": "Rückfahrpiepser", + "ice_cream_truck": "Eiswagen", + "emergency_vehicle": "Einsatzfahrzeug", + "police_car": "Polizeiwagen", + "ambulance": "Krankenwagen", + "fire_engine": "Feuerwehrauto", + "traffic_noise": "Verkehrslärm", + "rail_transport": "Schienentransport", + "train_whistle": "Zugpfeife", + "train_horn": "Zugsignalhorn", + "train_wheels_squealing": "Quietschende Eisenbahnräder", + "aircraft": "Flugzeug", + "aircraft_engine": "Flugzeugmotor", + "jet_engine": "Strahltriebwerk", + "propeller": "Propeller", + "helicopter": "Hubschrauber", + "engine": "Motor", + "dental_drill's_drill": "Zahnbohrer", + "lawn_mower": "Rasenmäher", + "medium_engine": "Mittlerer Motor", + "heavy_engine": "Schwerer Motor", + "engine_knocking": "Motorklopfen", + "engine_starting": "Motorstart", + "idling": "Leerlauf", + "doorbell": "Türklingel", + "ding-dong": "BimBam", + "sliding_door": "Schiebetür", + "slam": "Knall", + "knock": "Klopfen", + "tap": "Schlag", + "squeak": "Quietschen", + "drawer_open_or_close": "Schublade Öffnen oder Schließen", + "dishes": "Geschirr", + "chopping": "Kleinhacken", + "frying": "Braten", + "microwave_oven": "Mikrowelle", + "water_tap": "Wasserhahn", + "bathtub": "Badewanne", + "toilet_flush": "Toilettenspülung", + "vacuum_cleaner": "Staubsauger", + "zipper": "Reißverschluss", + "keys_jangling": "Schlüsselanhänger", + "coin": "Münze", + "electric_shaver": "Rasierapparat", + "typing": "Tippen", + "typewriter": "Schreibmaschine", + "computer_keyboard": "Computertastatur", + "telephone": "Telefon", + "telephone_bell_ringing": "Telefonklingeln", + "telephone_dialing": "Telefonwahl", + "dial_tone": "Wählton", + "alarm_clock": "Wecker", + "siren": "Sirene", + "civil_defense_siren": "Zivilschutzsirene", + "smoke_detector": "Rauchmelder", + "foghorn": "Nebelhorn", + "whistle": "Pfeife", + "steam_whistle": "Dampfpfeife", + "mechanisms": "Mechanismen", + "ratchet": "Ratsche", + "tick": "Ticken", + "gears": "Getriebe", + "mechanical_fan": "Mechanischer Lüfter", + "printer": "Drucker", + "tools": "Werkzeuge", + "hammer": "Hammer", + "jackhammer": "Presslufthammer", + "sawing": "Sägen", + "power_tool": "Elektrowerkzeug", + "drill": "Bohrer", + "explosion": "Explosion", + "gunshot": "Schuss", + "fusillade": "Gewehrfeuer", + "artillery_fire": "Artilleriefeuer", + "cap_gun": "Maschinenpistole", + "fireworks": "Feuerwerk", + "firecracker": "Feuerwerkskörper", + "eruption": "Ausbruch", + "wood": "Holz", + "splinter": "Splittern", + "crack": "Knacken", + "glass": "Glas", + "chink": "Klirren", + "shatter": "Zerspringen", + "silence": "Stille", + "environmental_noise": "Umgebungsgeräusch", + "static": "Rauschen", + "pink_noise": "Rosa Rauschen", + "television": "Fernsehgerät", + "radio": "Radio", + "scream": "Schrei", + "heavy_metal": "Heavy Metal", + "rock_music": "Rockmusik", + "techno": "Techno", + "reggae": "Reggae", + "rain": "Regen", + "gurgling": "Plätschern", + "jazz": "Jazz", + "video_game_music": "Videospielmusik", + "rock_and_roll": "Rock and Roll", + "scratching": "Scratching", + "thunderstorm": "Gewitter", + "christian_music": "Christliche Musik", + "ska": "Ska", + "rustling_leaves": "Blätterrascheln", + "jingle": "Jingle", + "middle_eastern_music": "Orientalische Musik", + "drum_and_bass": "Trommel und Bass", + "flamenco": "Flamenco", + "music_for_children": "Kindermusik", + "new-age_music": "New-Age-Musik", + "afrobeat": "Afrobeat", + "wedding_music": "Hochzeitsmusik", + "soundtrack_music": "Soundtrack Musik", + "raindrop": "Regentropfen", + "sad_music": "Traurige Musik", + "angry_music": "Wütende Musik", + "ocean": "Ozean", + "thunder": "Donner", + "water": "Wasser", + "waves": "Wellen", + "race_car": "Rennwagen", + "rowboat": "Ruderboot", + "truck": "LKW", + "motorboat": "Motorboot", + "chainsaw": "Kettensäge", + "railroad_car": "Eisenbahnwaggon", + "cupboard_open_or_close": "Schrank Öffnen oder Schließen", + "alarm": "Alarm", + "filing": "Feilen", + "chop": "Hacken", + "single-lens_reflex_camera": "Spiegelreflexkamera", + "light_engine": "Lichtmaschine", + "buzzer": "Summer", + "sound_effect": "Geräuscheffekt", + "accelerating": "Beschleunigen", + "electric_toothbrush": "Elektrische Zahnbürste", + "busy_signal": "Besetztzeichen", + "pulleys": "Riemenscheiben", + "sewing_machine": "Nähmaschine", + "air_conditioning": "Klimaanlage", + "burst": "Platzen", + "skidding": "Schleudern", + "subway": "U-Bahn", + "tick-tock": "Ticktack", + "shuffling_cards": "Karten mischen", + "cutlery": "Besteck", + "cash_register": "Kasse", + "ringtone": "Klingelton", + "writing": "Schreiben", + "fixed-wing_aircraft": "Starrflügler", + "fire_alarm": "Feueralarm", + "white_noise": "Weißes Rauschen", + "sanding": "Schleifen", + "machine_gun": "Maschinengewehr", + "boom": "Dröhnen", + "field_recording": "Außenaufnahme" +} diff --git a/web/public/locales/de/common.json b/web/public/locales/de/common.json new file mode 100644 index 000000000..b7a8cdc18 --- /dev/null +++ b/web/public/locales/de/common.json @@ -0,0 +1,258 @@ +{ + "time": { + "untilForTime": "Bis {{time}}", + "last7": "Letzte 7 Tage", + "untilForRestart": "Bis Frigate neu startet.", + "today": "Heute", + "yesterday": "Gestern", + "thisWeek": "Diese Woche", + "lastMonth": "Letzter Monat", + "5minutes": "5 Minuten", + "12hours": "12 Stunden", + "24hours": "24 Stunden", + "month_one": "{{time}} Monat", + "month_other": "{{time}} Monate", + "d": "{{time}} Tag", + "day_one": "{{time}} Tag", + "day_other": "{{time}} Tage", + "m": "{{time}} Minute", + "minute_one": "{{time}} Minute", + "minute_other": "{{time}} Minuten", + "s": "{{time}} Sekunde", + "second_one": "{{time}} Sekunde", + "second_other": "{{time}} Sekunden", + "formattedTimestamp2": { + "24hour": "%d %b %H:%M:%S", + "12hour": "%d-%m %H:%M:%S" + }, + "last30": "Letzte 30 Tage", + "10minutes": "10 Minuten", + "thisMonth": "Dieser Monat", + "yr": "{{time}}Jahr", + "year_one": "{{time}}Jahr", + "year_other": "{{time}}Jahre", + "hour_one": "{{time}} Stunde", + "hour_other": "{{time}} Stunden", + "last14": "Letzte 14 Tage", + "30minutes": "30 Minuten", + "1hour": "1 Stunde", + "lastWeek": "Letzte Woche", + "h": "{{time}} Stunde", + "ago": "{{timeAgo}} her", + "untilRestart": "Bis zum Neustart", + "justNow": "Aktuell", + "pm": "pm", + "mo": "{{time}}monat", + "formattedTimestamp": { + "12hour": "%d %b %H:%M:%S", + "24hour": "%-d %b, %H:%M:%S" + }, + "formattedTimestampWithYear": { + "24hour": "%-d %b %Y, %H:%M", + "12hour": "%-d %b %Y, %H:%M" + }, + "formattedTimestampOnlyMonthAndDay": "%-d %b", + "am": "am", + "formattedTimestampExcludeSeconds": { + "24hour": "%-d %b, %H:%M", + "12hour": "%-d %b, %H:%M" + }, + "formattedTimestampHourMinute": { + "12hour": "h:mm aaa", + "24hour": "HH:mm" + }, + "formattedTimestampHourMinuteSecond": { + "12hour": "h:mm:ss aaa", + "24hour": "HH:mm:ss" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "MMM d, h:mm aaa", + "24hour": "MMM d, HH:mm" + }, + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "MMM d yyyy, h:mm aaa", + "24hour": "MMM d yyyy, HH:mm" + }, + "formattedTimestampMonthDay": "MMM d", + "formattedTimestampFilename": { + "12hour": "MM-dd-yy-h-mm-ss-a", + "24hour": "MM-dd-yy-HH-mm-ss" + } + }, + "button": { + "save": "Speichern", + "delete": "Entfernen", + "apply": "Anwenden", + "enabled": "Aktiviert", + "enable": "Aktivieren", + "disabled": "deaktiviert", + "disable": "deaktivieren", + "saving": "Speichere…", + "close": "Schließen", + "back": "Zurück", + "history": "Historie", + "cameraAudio": "Kamera Ton", + "yes": "JA", + "info": "Info", + "play": "Abspielen", + "export": "Exportieren", + "deleteNow": "Jetzt löschen", + "next": "Nächster", + "fullscreen": "Vollbild", + "no": "Nein", + "off": "AUS", + "reset": "Zurücksetzen", + "copy": "Kopieren", + "twoWayTalk": "bidirecktionales Gespräch", + "exitFullscreen": "Vollbild verlassen", + "unselect": "Selektion aufheben", + "copyCoordinates": "Kopiere Koordinaten", + "done": "Fertig", + "edit": "Bearbeiten", + "download": "Herunterladen", + "cancel": "Abbrechen", + "pictureInPicture": "Bild in Bild", + "on": "AN", + "suspended": "Pausierte", + "unsuspended": "fortsetzen" + }, + "label": { + "back": "Zurück" + }, + "menu": { + "configurationEditor": "Konfigurationseditor", + "languages": "Sprachen", + "language": { + "withSystem": { + "label": "Sprache der Systemeinstellungen verwenden" + }, + "en": "Englisch", + "zhCN": "简体中文 (Vereinfachtes Chinesisch)", + "fr": "Französisch", + "es": "Spanisch", + "ar": "Arabisch", + "pt": "Portugiesisch", + "de": "Deutsch", + "it": "Italienisch", + "nl": "Niederländisch", + "sv": "Schwedisch", + "cs": "Tschechisch", + "ko": "Koreanisch", + "pl": "Polnisch", + "el": "Griechisch", + "ro": "Rumänisch", + "hu": "Ungarisch", + "fi": "Finnisch", + "ru": "Russisch", + "ja": "Japanisch", + "tr": "Türkisch", + "da": "Dänisch", + "hi": "Hindi", + "nb": "Norwegisch", + "vi": "Vietnamesisch", + "fa": "Persisch", + "uk": "Ukrainisch", + "he": "Hebräisch", + "sk": "Slowakisch", + "yue": "粵語 (Kantonesisch)" + }, + "appearance": "Erscheinung", + "theme": { + "label": "Thema", + "blue": "Blau", + "green": "Grün", + "default": "Standard", + "nord": "Norden", + "red": "Rot", + "contrast": "Hoher Kontrast", + "highcontrast": "Hoher Kontrast" + }, + "help": "Hilfe", + "documentation": { + "title": "Dokumentation", + "label": "Frigate Dokumentation" + }, + "live": { + "allCameras": "Alle Kameras", + "cameras": { + "title": "Kameras", + "count_one": "{{count}} Kamera", + "count_other": "{{count}} Kameras" + }, + "title": "Live" + }, + "review": "Überprüfen", + "restart": "Frigate neu starten", + "darkMode": { + "light": "Hell", + "label": "Dunkler Modus", + "dark": "Dunkel", + "withSystem": { + "label": "Verwende Systemeinstellungen fuer hell oder dunkel Modus" + } + }, + "system": "System", + "configuration": "Konfigurieren", + "withSystem": "System", + "settings": "Einstellungen", + "systemLogs": "Systemprotokoll", + "systemMetrics": "Systemstatistiken", + "explore": "Erkunden", + "faceLibrary": "Gesichterbibliothek", + "user": { + "title": "Benutzer", + "account": "Benutzerkonto", + "current": "Aktueller Benutzer: {{user}}", + "setPassword": "Passwort setzen", + "anonymous": "anonym", + "logout": "Abmelden" + }, + "uiPlayground": "Testgebiet für Benutzeroberfläche", + "export": "Exportieren" + }, + "unit": { + "speed": { + "mph": "mph", + "kph": "km/h" + } + }, + "toast": { + "copyUrlToClipboard": "URL in zwischenablage kopiert.", + "save": { + "error": { + "title": "Speichern der Konfigurationsänderungen gescheitert: {{errorMessage}}", + "noMessage": "Speichern der Konfigurationsänderungen gescheitert" + }, + "title": "Speichern" + } + }, + "role": { + "title": "Rolle", + "admin": "Administrator", + "viewer": "Zuschauer", + "desc": "Administratoren haben vollen Zugang zu allen funktionen der Frigate Benutzeroberfläche. Zuschauer können nur Kameras betrachten, erkannte Objekte überprüfen und historische Aufnahmen durchsehen." + }, + "pagination": { + "previous": { + "title": "Voherige", + "label": "Zur voherigen Seite wechseln" + }, + "next": { + "title": "Nächste", + "label": "Zur nächsten Seite wechseln" + }, + "more": "Weitere Seiten", + "label": "Seitennummerierung" + }, + "notFound": { + "title": "404", + "desc": "Seite nicht gefunden", + "documentTitle": "Nicht gefunden - Frigate" + }, + "selectItem": "Wähle {{item}}", + "accessDenied": { + "desc": "Du hast keine Berechtigung diese Seite anzuzeigen.", + "documentTitle": "Zugang verweigert - Frigate", + "title": "Zugang verweigert" + } +} diff --git a/web/public/locales/de/components/auth.json b/web/public/locales/de/components/auth.json new file mode 100644 index 000000000..8cbd1ff8c --- /dev/null +++ b/web/public/locales/de/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "login": "Anmeldung", + "errors": { + "passwordRequired": "Kennwort ist erforderlich", + "loginFailed": "Anmeldung gescheitert", + "webUnknownError": "Unbekannter Fehler. Prüfe Konsolenlogs.", + "usernameRequired": "Benutzername ist erforderlich", + "rateLimit": "Anmeldelimit überschritten. Bitte später erneut versuchen.", + "unknownError": "Unbekannter Fehler. Prüfe Logs." + }, + "user": "Benutzername", + "password": "Kennwort" + } +} diff --git a/web/public/locales/de/components/camera.json b/web/public/locales/de/components/camera.json new file mode 100644 index 000000000..fdf9dcf3b --- /dev/null +++ b/web/public/locales/de/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "delete": { + "label": "Kameragruppe löschen", + "confirm": { + "title": "Löschen bestätigen", + "desc": "Willst Du die Kameragruppe {{name}} wirklich löschen?" + } + }, + "name": { + "label": "Name", + "placeholder": "Gib einen Namen ein…", + "errorMessage": { + "exists": "Name der Kameragruppe bereits vorhanden.", + "nameMustNotPeriod": "Name einer Kameragruppe darf keinen Punkt enthalten.", + "mustLeastCharacters": "Name einer Kameragruppe muss mindestens 2 Zeichen haben.", + "invalid": "Ungültiger Name für eine Kameragruppe." + } + }, + "icon": "Icon", + "camera": { + "setting": { + "label": "Kamera Streaming Einstellungen", + "audioIsAvailable": "Audio ist für diesen Stream verfügbar", + "audioIsUnavailable": "Audio ist für diesen Stream nicht verfügbar", + "streamMethod": { + "label": "Streaming-Methode", + "method": { + "noStreaming": { + "label": "Kein Streaming", + "desc": "Kamerabilder werden nur einmal pro Minute aktualisiert und es wird kein Live Streaming geben." + }, + "smartStreaming": { + "label": "Smart Streaming (empfohlen)", + "desc": "Smart Streaming wird Deine Kamera einmal in der Minute aktualisieren, wenn sich keine erkennbare Aktivität ereignet, um Bandbreite und Ressourcen zu schonen. Sobald eine Aktivität erkannt wird, wechselt das Standbild sofort zu einem Live Stream." + }, + "continuousStreaming": { + "label": "Kontinuierliches Streaming", + "desc": { + "title": "Das auf einem Dashboard sichtbare Kamerabild ist immer ein Live Stream, selbst wenn keine Aktivität erkannt wird.", + "warning": "Kontinuierliches Streaming kann zu hoher Bandbreitenausnutzung und zu Performanceproblemen führen. Bitte behutsam nutzen." + } + } + } + }, + "title": "{{cameraName}} Streaming Einstellungen", + "compatibilityMode": { + "desc": "Aktiviere diese Option nur, falls der Live Stream Deiner Kamera Farbstörungen zeigt und eine Diagonale Linie auf der rechten Seite des Bildes hat.", + "label": "Kompatibilitätsmodus" + }, + "audio": { + "tips": { + "title": "Audio muss in der Kamera verfügbar und in go2rtc für diesen Stream konfiguriert sein.", + "document": "Lies die Dokumentation. " + } + }, + "desc": "Ändere die Live Stream Optionen für das Dashboard dieser Kameragruppe. Diese Einstellungen sind geräte-/browserspezifisch." + } + }, + "add": "Kameragruppe hinzufügen", + "cameras": { + "label": "Kameras", + "desc": "Wähle Kameras für diese Gruppe aus." + }, + "label": "Kameragruppen", + "edit": "Kameragruppe bearbeiten", + "success": "Kameragruppe {{name}} wurde gespeichert." + }, + "debug": { + "options": { + "title": "Optionen", + "hideOptions": "Verberge Optionen", + "label": "Einstellungen", + "showOptions": "Zeige Optionen" + }, + "timestamp": "Zeitstempel", + "zones": "Zonen", + "mask": "Maske", + "motion": "Bewegung", + "regions": "Regionen", + "boundingBox": "Begrenzungsrechteck" + } +} diff --git a/web/public/locales/de/components/dialog.json b/web/public/locales/de/components/dialog.json new file mode 100644 index 000000000..e7a67695d --- /dev/null +++ b/web/public/locales/de/components/dialog.json @@ -0,0 +1,119 @@ +{ + "restart": { + "title": "Sind Sie sicher, dass Sie Frigate neustarten wollen?", + "restarting": { + "title": "Frigate startet neu", + "content": "Diese Seite wird in {{countdown}} Sekunde(n) aktualisiert.", + "button": "Neuladen erzwingen" + }, + "button": "Neustarten" + }, + "explore": { + "plus": { + "review": { + "true": { + "label": "Bestätigen Sie das Label für Frigate Plus", + "true_one": "Das ist ein/eine {{label}}", + "true_other": "Dies sind {{label}}" + }, + "state": { + "submitted": "Übermittelt" + }, + "false": { + "false_one": "Das ist kein(e) {{label}}", + "false_other": "Das sind kein(e) {{label}}", + "label": "Bestätige dieses Label nicht für Frigate Plus" + }, + "question": { + "label": "Bestätige diese Beschriftung für Frigate Plus", + "ask_a": "Ist dieses Objekt ein {{label}}?", + "ask_an": "Ist dieses Objekt ein {{label}}?", + "ask_full": "Ist dieses Objekt ein {{untranslatedLabel}} ({{translatedLabel}})?" + } + }, + "submitToPlus": { + "label": "An Frigate+ übermitteln", + "desc": "Objekte an Orten die du vermeiden möchtest, sind keine Fehlalarme. Wenn du sie als Fehlalarme meldest, verwirrst du das Modell." + } + }, + "video": { + "viewInHistory": "Im Verlauf ansehen" + } + }, + "export": { + "time": { + "fromTimeline": "Aus der Zeitleiste auswählen", + "start": { + "title": "Startzeit", + "label": "Startzeit auswählen" + }, + "end": { + "label": "Endzeit auswählen", + "title": "Endzeit" + }, + "lastHour_one": "Letzte Stunde", + "lastHour_other": "Letzte {{count}} Stunden", + "custom": "Benutzerdefiniert" + }, + "name": { + "placeholder": "Export benennen" + }, + "select": "Auswählen", + "selectOrExport": "Auswählen oder Exportieren", + "toast": { + "error": { + "endTimeMustAfterStartTime": "Die Endzeit darf nicht vor der Startzeit liegen", + "failed": "Fehler beim Starten des Exports: {{error}}", + "noVaildTimeSelected": "Kein gültiger Zeitraum ausgewählt" + }, + "success": "Export erfolgreich gestartet. Die Datei befindet sich im Ordner /exports." + }, + "fromTimeline": { + "saveExport": "Export speichern", + "previewExport": "Exportvorschau" + }, + "export": "Exportieren" + }, + "streaming": { + "restreaming": { + "disabled": "Für diese Kamera ist das Restreaming nicht aktiviert.", + "desc": { + "readTheDocumentation": "Weitere Informationen in der Dokumentation", + "title": "Konfiguriere go2rtc, um erweiterte Live-Ansichtsoptionen und Audio für diese Kamera zu nutzen." + } + }, + "showStats": { + "label": "Stream-Statistiken anzeigen", + "desc": "Stream-Statistiken werden bei aktivierter Option als Overlay im Kamera-Feed eingeblendet." + }, + "debugView": "Debug-Ansicht", + "label": "Stream" + }, + "search": { + "saveSearch": { + "label": "Suche speichern", + "desc": "Gib einen Namen für diese gespeicherte Suche an.", + "placeholder": "Gib einen Namen für die Suche ein", + "overwrite": "{{searchName}} existiert bereits. Beim Speichern wird der vorhandene Wert überschrieben.", + "button": { + "save": { + "label": "Diese Suche speichern" + } + }, + "success": "Die Suche {{searchName}} wurde gespeichert." + } + }, + "recording": { + "confirmDelete": { + "title": "Bestätige Löschung", + "desc": { + "selected": "Bist du sicher, dass du alle aufgezeichneten Videos, die mit diesem Beitrag verbunden sind, löschen möchtest?

Halte Shift-Taste gedrückt, um diesen Dialog in Zukunft zu umgehen." + } + }, + "button": { + "export": "Exportieren", + "markAsReviewed": "Als geprüft markieren", + "deleteNow": "Jetzt löschen" + } + } +} diff --git a/web/public/locales/de/components/filter.json b/web/public/locales/de/components/filter.json new file mode 100644 index 000000000..f3b4882bb --- /dev/null +++ b/web/public/locales/de/components/filter.json @@ -0,0 +1,125 @@ +{ + "filter": "Filter", + "labels": { + "all": { + "short": "Labels", + "title": "Alle Labels" + }, + "label": "Labels", + "count_one": "{{count}} Label", + "count_other": "{{count}} Labels" + }, + "zones": { + "all": { + "title": "Alle Zonen", + "short": "Zonen" + }, + "label": "Zonen" + }, + "dates": { + "all": { + "title": "Alle Zeiträume", + "short": "Daten" + } + }, + "reset": { + "label": "Filter auf Standardwerte zurücksetzen" + }, + "more": "Mehr Filter", + "timeRange": "Zeitraum", + "subLabels": { + "all": "Alle Unterkategorien", + "label": "Unterkategorie" + }, + "features": { + "label": "Eigenschaften", + "hasSnapshot": "Hat einen Schnappschuss", + "hasVideoClip": "Hat einen Video-Clip", + "submittedToFrigatePlus": { + "label": "Eingereicht bei Frigate+", + "tips": "Du musst zuerst nach deine erkannten Objekten, die einen Schnappschuss haben, filtern.

Erkante Objekte ohne Schnappschuss können nicht zu Frigate+ übermittelt werden." + } + }, + "score": "Ergebnis", + "estimatedSpeed": "Geschätzte Geschwindigkeit ({{unit}})", + "sort": { + "label": "Sortieren", + "dateAsc": "Datum (Aufsteigend)", + "dateDesc": "Datum (Absteigend)", + "scoreAsc": "Objekt Wertung (Aufsteigend)", + "scoreDesc": "Objekt Wertung (Absteigend)", + "speedAsc": "Geschätzte Geschwindigkeit (Aufsteigend)", + "relevance": "Relevanz", + "speedDesc": "Geschätzte Geschwindigkeit (absteigend)" + }, + "cameras": { + "all": { + "title": "Alle Kameras", + "short": "Kameras" + }, + "label": "Kamera Filter" + }, + "motion": { + "showMotionOnly": "Zeige nur Bewegung" + }, + "review": { + "showReviewed": "Geprüfte anzeigen" + }, + "explore": { + "settings": { + "defaultView": { + "title": "Standardansicht", + "desc": "Wenn keine Filter ausgewählt sind, wird eine Zusammenfassung der zuletzt verfolgten Objekte pro Kategorie oder ein ungefiltertes Raster angezeigt.", + "summary": "Zusammenfassung", + "unfilteredGrid": "Ungefiltertes Raster" + }, + "title": "Einstellungen", + "gridColumns": { + "title": "Rasterspalten", + "desc": "Wähle die Anzahl der Spalten in der Rasteransicht." + }, + "searchSource": { + "options": { + "description": "Beschreibung", + "thumbnailImage": "Vorschaubild" + }, + "label": "Quelle der Suche", + "desc": "Wähle, ob die Miniaturansichten oder die Beschreibungen der erkannten Objekte durchsucht werden sollen." + } + }, + "date": { + "selectDateBy": { + "label": "Wähle ein Datum zum Filtern" + } + } + }, + "logSettings": { + "label": "Log-Ebene filtern", + "filterBySeverity": "Protokolle nach Schweregrad filtern", + "loading": { + "title": "Lade", + "desc": "Wenn das Protokollfenster nach unten gescrollt wird, werden neue Protokolle automatisch geladen, sobald sie hinzugefügt werden." + }, + "disableLogStreaming": "Log des Streams deaktvieren", + "allLogs": "Alle Logs" + }, + "trackedObjectDelete": { + "title": "Bestätige Löschung", + "toast": { + "success": "Erkannte Objekte erfolgreich gelöscht.", + "error": "Das Löschen von verfolgten Objekten ist fehlgeschlagen: {{errorMessage}}" + }, + "desc": "Beim Löschen dieser {{objectLength}} verfolgten Objekte werden der Schnappschuss, alle gespeicherten Einbettungen und alle zugehörigen Objektlebenszykluseinträge entfernt. Aufgezeichnetes Filmmaterial dieser verfolgten Objekte in der Verlaufsansicht wird NICHT gelöscht.

Bist du sicher, dass du fortfahren möchtest?

Halte die Shift-Taste gedrückt, um diesen Dialog in Zukunft zu umgehen." + }, + "zoneMask": { + "filterBy": "Nach Zonenmaskierung filtern" + }, + "recognizedLicensePlates": { + "noLicensePlatesFound": "Keine Kennzeichen gefunden.", + "title": "Bekannte Kennzeichen", + "loadFailed": "Bekannte Nummernschilder konnten nicht geladen werden.", + "loading": "Lade bekannte Nummernschilder…", + "placeholder": "Tippe, um Kennzeichen zu suchen…", + "selectPlatesFromList": "Wählen eine oder mehrere Kennzeichen aus der Liste aus." + } +} diff --git a/web/public/locales/de/components/icons.json b/web/public/locales/de/components/icons.json new file mode 100644 index 000000000..41d608b27 --- /dev/null +++ b/web/public/locales/de/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "search": { + "placeholder": "Suche nach einem Icon…" + }, + "selectIcon": "Wähle ein Icon" + } +} diff --git a/web/public/locales/de/components/input.json b/web/public/locales/de/components/input.json new file mode 100644 index 000000000..fcee21c6a --- /dev/null +++ b/web/public/locales/de/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Video herunterladen", + "toast": { + "success": "Das Herunterladen des überprüften Videos wurde gestartet." + } + } + } +} diff --git a/web/public/locales/de/components/player.json b/web/public/locales/de/components/player.json new file mode 100644 index 000000000..a6b251f01 --- /dev/null +++ b/web/public/locales/de/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "Keine Aufnahmen für diesen Zeitpunkt gefunden", + "noPreviewFound": "Keine Vorschau gefunden", + "submitFrigatePlus": { + "title": "Dieses Bild an Frigate+ senden?", + "submit": "Senden" + }, + "livePlayerRequiredIOSVersion": "iOS 17.1 oder höher ist für diesen Typ eines Live-Streams erforderlich.", + "streamOffline": { + "title": "Stream ist offline", + "desc": "Es wurden keine Bilder vom Erkennungsstream der Kamera {{cameraName}} empfangen, bitte Logs überprüfen" + }, + "cameraDisabled": "Kamera ist deaktiviert", + "stats": { + "streamType": { + "title": "Stream Typ:", + "short": "Typ" + }, + "bandwidth": { + "title": "Bandbreite:", + "short": "Bandbreite" + }, + "latency": { + "title": "Latenz:", + "value": "{{seconds}} Sekunden", + "short": { + "title": "Lazenz", + "value": "{{seconds}} s" + } + }, + "droppedFrames": { + "short": { + "title": "Ausgelassen", + "value": "{{droppedFrames}} Bilder" + }, + "title": "Ausgelassene Bilder:" + }, + "decodedFrames": "Dekodierte Bilder:", + "droppedFrameRate": "Verlorene Bildrate:", + "totalFrames": "Bilder insgesamt:" + }, + "toast": { + "error": { + "submitFrigatePlusFailed": "Bild an Frigate+ senden gescheitert" + }, + "success": { + "submittedFrigatePlus": "Bild erfolgreich an Frigate+ gesendet" + } + }, + "noPreviewFoundFor": "Keine Vorschau für {{cameraName}} gefunden" +} diff --git a/web/public/locales/de/objects.json b/web/public/locales/de/objects.json new file mode 100644 index 000000000..57fb35617 --- /dev/null +++ b/web/public/locales/de/objects.json @@ -0,0 +1,120 @@ +{ + "boat": "Boot", + "traffic_light": "Ampel", + "fire_hydrant": "Hydrant", + "stop_sign": "Stoppschild", + "bench": "Bank", + "bird": "Vogel", + "cow": "Kuh", + "elephant": "Elefant", + "bear": "Bär", + "zebra": "Zebra", + "giraffe": "Giraffe", + "shoe": "Schuh", + "tie": "Krawatte", + "frisbee": "Frisbee", + "skis": "Skier", + "kite": "Drachen", + "skateboard": "Skateboard", + "surfboard": "Surfbrett", + "plate": "Platte", + "cup": "Tasse", + "spoon": "Löffel", + "sandwich": "Sandwich", + "broccoli": "Brokkoli", + "carrot": "Karotte", + "pizza": "Pizza", + "donut": "Donut", + "cake": "Kuchen", + "chair": "Stuhl", + "couch": "Couch", + "bed": "Bett", + "dining_table": "Esstisch", + "toilet": "Toilette", + "door": "Tür", + "sink": "Waschbecken", + "refrigerator": "Kühlschrank", + "book": "Buch", + "bbq_grill": "BBQ Grill", + "amazon": "Amazon", + "fedex": "FedEx", + "dhl": "DHL", + "an_post": "Post", + "postnl": "PostNL", + "nzpost": "NZPost", + "purolator": "Purolator", + "postnord": "PostNord", + "dpd": "DPD", + "snowboard": "Snowboard", + "baseball_bat": "Baseballschläger", + "knife": "Messer", + "squirrel": "Eichhörnchen", + "animal": "Tier", + "blender": "Mixer", + "vase": "Vase", + "orange": "Orange", + "teddy_bear": "Teddybär", + "on_demand": "Auf Anfrage", + "scissors": "Schere", + "ups": "UPS", + "train": "Zug", + "toaster": "Toaster", + "clock": "Uhr", + "mirror": "Spiegel", + "backpack": "Rucksack", + "motorcycle": "Motorrad", + "window": "Fenster", + "toothbrush": "Zahnbürste", + "package": "Paket", + "hair_brush": "Haarbürste", + "apple": "Apfel", + "banana": "Banane", + "parking_meter": "Parkuhr", + "oven": "Ofen", + "umbrella": "Regenschirm", + "eye_glasses": "Brillen", + "robot_lawnmower": "Mähroboter", + "potted_plant": "Topfpflanze", + "waste_bin": "Abfallbehälter", + "license_plate": "Kennzeichen", + "bottle": "Flasche", + "deer": "Reh", + "usps": "USPS", + "person": "Person", + "bowl": "Schüssel", + "microwave": "Mikrowelle", + "bicycle": "Fahrrad", + "car": "Auto", + "fork": "Gabel", + "tv": "Fernseher", + "laptop": "Laptop", + "mouse": "Maus", + "goat": "Ziege", + "keyboard": "Klaviatur", + "cell_phone": "Handy", + "remote": "Fernbedienung", + "airplane": "Flugzeug", + "tennis_racket": "Tennisschläger", + "bus": "Bus", + "street_sign": "Straßenschild", + "horse": "Pferd", + "bark": "Bellen", + "cat": "Katze", + "wine_glass": "Weinglas", + "dog": "Hund", + "sheep": "Schaf", + "hat": "Hut", + "hot_dog": "Hot Dog", + "baseball_glove": "Baseballhandschuh", + "suitcase": "Koffer", + "handbag": "Handtasche", + "sports_ball": "Sportball", + "hair_dryer": "Haartrockner", + "vehicle": "Fahrzeug", + "face": "Gesicht", + "fox": "Fuchs", + "desk": "Schreibtisch", + "raccoon": "Waschbär", + "rabbit": "Kaninchen", + "gls": "GLS" +} diff --git a/web/public/locales/de/views/configEditor.json b/web/public/locales/de/views/configEditor.json new file mode 100644 index 000000000..d184f082a --- /dev/null +++ b/web/public/locales/de/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "configEditor": "Konfigurationseditor", + "copyConfig": "Konfiguration kopieren", + "saveAndRestart": "Sichern und Neustarten", + "saveOnly": "Nur Sichern", + "toast": { + "error": { + "savingError": "Fehler beim Speichern der Konfiguration" + }, + "success": { + "copyToClipboard": "Konfiguration in Zwischenablage kopiert." + } + }, + "documentTitle": "Konfigurationseditor - Frigate" +} diff --git a/web/public/locales/de/views/events.json b/web/public/locales/de/views/events.json new file mode 100644 index 000000000..b9149190b --- /dev/null +++ b/web/public/locales/de/views/events.json @@ -0,0 +1,37 @@ +{ + "alerts": "Alarme", + "detections": "Erkennungen", + "motion": { + "label": "Bewegung", + "only": "nur Bewegung" + }, + "empty": { + "alert": "Es gibt keine zu prüfende Alarme", + "detection": "Es gibt keine zu prüfende Erkennungen", + "motion": "Keine Bewegungsdaten gefunden" + }, + "timeline": "Zeitleiste", + "timeline.aria": "Zeitleiste auswählen", + "events": { + "label": "Ereignisse", + "noFoundForTimePeriod": "Keine Ereignisse für diesen Zeitraum gefunden.", + "aria": "Wähle Ereignisse aus" + }, + "documentTitle": "Überprüfung - Frigate", + "recordings": { + "documentTitle": "Aufnahmen - Frigate" + }, + "calendarFilter": { + "last24Hours": "Letzte 24 Stunden" + }, + "newReviewItems": { + "label": "Neue zu prüfende Objekte anschauen", + "button": "Neue zu prüfende Objekte" + }, + "markTheseItemsAsReviewed": "Diese Objekte als geprüft kennzeichnen", + "camera": "Kamera", + "allCameras": "Alle Kameras", + "markAsReviewed": "Als geprüft kennzeichnen", + "selected_one": "{{count}} ausgewählt", + "selected_other": "{{count}} ausgewählt" +} diff --git a/web/public/locales/de/views/explore.json b/web/public/locales/de/views/explore.json new file mode 100644 index 000000000..7758ff538 --- /dev/null +++ b/web/public/locales/de/views/explore.json @@ -0,0 +1,195 @@ +{ + "details": { + "timestamp": "Zeitstempel", + "item": { + "title": "Item-Details begutachten", + "desc": "Item-Details begutachten", + "button": { + "share": "Diese Aufnahme teilen", + "viewInExplore": "Ansicht in Erkunden" + }, + "tips": { + "hasMissingObjects": "Passe die Konfiguration an, so dass Frigate verfolgte Objekte für die folgenden Kategorien speichert: {{objects}}", + "mismatch_one": "{{count}} nicht verfügbares Objekt wurde entdeckt und in diese Überprüfung einbezogen. Dieses Objekt hat sich entweder nicht für einen Alarm oder eine Erkennung qualifiziert oder wurde bereits bereinigt/gelöscht.", + "mismatch_other": "{{count}} nicht verfügbare Objekte wurden entdeckt und in diese Überprüfung einbezogen. Diese Objekte haben sich entweder nicht für einen Alarm oder eine Erkennung qualifiziert oder wurden bereits bereinigt/gelöscht." + }, + "toast": { + "success": { + "updatedSublabel": "Unterkategorie erfolgreich aktualisiert.", + "updatedLPR": "Nummernschild erfolgreich aktualisiert.", + "regenerate": "Eine neue Beschreibung wurde von {{provider}} angefordert. Je nach Geschwindigkeit des Anbieters kann es einige Zeit dauern, bis die neue Beschreibung generiert ist." + }, + "error": { + "regenerate": "Der Aufruf von {{provider}} für eine neue Beschreibung ist fehlgeschlagen: {{errorMessage}}", + "updatedSublabelFailed": "Untekategorie konnte nicht aktualisiert werden: {{errorMessage}}", + "updatedLPRFailed": "Aktualisierung des Kennzeichens fehlgeschlagen: {{errorMessage}}" + } + } + }, + "label": "Label", + "zones": "Zonen", + "editSubLabel": { + "title": "Unterkategorie bearbeiten", + "desc": "Geben Sie eine neue Unterkategorie für dieses {{label}} ein", + "descNoLabel": "Geben Sie eine neue Unterkategorie für dieses verfolgte Objekt ein" + }, + "editLPR": { + "title": "Kennzeichen bearbeiten", + "desc": "Gib einen neuen Kennzeichenwert für dieses {{label}} ein", + "descNoLabel": "Gib einen neuen Kennzeichenwert für dieses verfolgte Objekt ein" + }, + "topScore": { + "label": "Beste Ergebnisse", + "info": "Die höchste Punktzahl ist der höchste Medianwert für das verfolgte Objekt und kann daher von der auf der Miniaturansicht des Suchergebnisses angezeigten Punktzahl abweichen." + }, + "recognizedLicensePlate": "Erkanntes Kennzeichen", + "estimatedSpeed": "Geschätzte Geschwindigkeit", + "objects": "Objekte", + "camera": "Kamera", + "button": { + "findSimilar": "Finde ähnliche", + "regenerate": { + "title": "Erneuern", + "label": "Beschreibung des verfolgten Objekts neu generieren" + } + }, + "description": { + "label": "Beschreibung", + "placeholder": "Beschreibund des verfolgten Objekts", + "aiTips": "Frigate wird erst dann eine Beschreibung vom generativen KI-Anbieter anfordern, wenn der Lebenszyklus des verfolgten Objekts beendet ist." + }, + "expandRegenerationMenu": "Erneuerungsmenü erweitern", + "regenerateFromSnapshot": "Aus Snapshot neu generieren", + "regenerateFromThumbnails": "Aus Vorschaubild neu generieren", + "tips": { + "descriptionSaved": "Erfolgreich gespeicherte Beschreibung", + "saveDescriptionFailed": "Die Aktualisierung der Beschreibung ist fehlgeschlagen: {{errorMessage}}" + }, + "snapshotScore": { + "label": "Schnappschuss Bewertung" + } + }, + "documentTitle": "Erkunden - Frigate", + "generativeAI": "Generative KI", + "exploreIsUnavailable": { + "title": "Erkunden ist nicht Verfügbar", + "embeddingsReindexing": { + "context": "Erkunden kann nach der Re-Indexierung der verfolgten Objekte verwendet werden.", + "startingUp": "Startet…", + "estimatedTime": "Voraussichtlich verbleibende Zeit:", + "finishingShortly": "Bald erledigt", + "step": { + "thumbnailsEmbedded": "Vorschaubilder eingebettet: ", + "descriptionsEmbedded": "Beschreibungen eingebettet: ", + "trackedObjectsProcessed": "Verfolgte Objekte bearbeitet: " + } + }, + "downloadingModels": { + "setup": { + "visionModel": "Vision Model", + "visionModelFeatureExtractor": "Vision Model Feature Extraktor", + "textModel": "Text Model", + "textTokenizer": "Text Tokenizer" + }, + "tips": { + "context": "Sie sollten eine Re-Indexierung der verfolgten Objekte durchführen, sobald die Modelle heruntergeladen sind.", + "documentation": "Lesen Sie die Dokumentation" + }, + "error": "Ein Fehler ist aufgetreten. Bitte prüfen Sie die Frigate Logs.", + "context": "Frigate lädt derzeit benötigte Modelle für den Support des \"Semantic Search\"-Features. Je nach der Geschwindigkeit der Netzwerkverbindung kann dies einige Minuten in Anspruch nehmen." + } + }, + "trackedObjectDetails": "Details zu verfolgtem Objekt", + "objectLifecycle": { + "noImageFound": "Kein Bild für diesen Zeitstempel gefunden.", + "createObjectMask": "Objekt-Maske erstellen", + "lifecycleItemDesc": { + "entered_zone": "{{label}} hat {{zones}} betreten", + "visible": "{{label}} erkannt", + "attribute": { + "other": "{{label}} erkannt als {{attribute}}", + "faceOrLicense_plate": "{{attribute}} erkannt für {{label}}" + }, + "external": "{{label}} erkannt", + "active": "{{label}} wurde aktiv", + "gone": "{{label}} hat verlassen", + "stationary": "{{label}} wurde stationär", + "heard": "{{label}} gehört" + }, + "annotationSettings": { + "offset": { + "documentation": "Lesen Sie die Dokumentation ", + "label": "Anmerkungen Versatz", + "desc": "Diese Daten stammen aus dem Erkennungs-Feed der Kamera, werden aber mit Bildern aus dem Aufnahme-Feed überlagert. Es ist unwahrscheinlich, dass die beiden Streams perfekt synchronisiert sind. Daher stimmen die Bounding Box und das Filmmaterial nicht perfekt überein. Das Feld annotation_offset kann jedoch verwendet werden, um dies anzupassen.", + "millisecondsToOffset": "Millisekunden, um die die Benachrichtigung zu Erkennungen verschoben werden soll. Standard: 0", + "tips": "TIPP: Stelle dir einen Ereignisclip vor, in dem eine Person von links nach rechts läuft. Wenn die Bounding Box der Ereigniszeitleiste durchgehend links von der Person liegt, sollte der Wert verringert werden. Ähnlich verhält es sich, wenn eine Person von links nach rechts geht und die Bounding Box durchgängig vor der Person liegt, dann sollte der Wert erhöht werden." + }, + "showAllZones": { + "title": "Zeige alle Zonen", + "desc": "Immer Zonen auf Rahmen anzeigen, in die Objekte eingetreten sind." + }, + "title": "Anmerkungseinstellungen" + }, + "adjustAnnotationSettings": "Anmerkungseinstellungen anpassen", + "title": "Objekt-Lebenszyklus", + "carousel": { + "next": "Nächste Anzeige", + "previous": "Vorherige Anzeige" + }, + "scrollViewTips": "Scrolle um die wichtigsten Momente dieses Objekts anzuzeigen.", + "autoTrackingTips": "Die Positionen der Bounding Box sind bei Kameras mit automatischer Verfolgung ungenau." + }, + "type": { + "details": "Details", + "video": "Video", + "object_lifecycle": "Objekt-Lebenszyklus", + "snapshot": "Snapshot" + }, + "itemMenu": { + "downloadSnapshot": { + "label": "Schnappschuss herunterladen", + "aria": "Schnappschuss herunterladen" + }, + "downloadVideo": { + "label": "Video herunterladen", + "aria": "Video herunterladen" + }, + "viewObjectLifecycle": { + "label": "Lebenszyklus von Objekten anzeigen", + "aria": "Den Lebenszyklus des Objekts anzeigen" + }, + "findSimilar": { + "label": "Ähnliches finden", + "aria": "Ähnliche verfolgte Objekte finden" + }, + "submitToPlus": { + "label": "Bei Frigate+ einreichen", + "aria": "Bei Frigate+ einreichen" + }, + "viewInHistory": { + "label": "Ansicht im Verlauf", + "aria": "Ansicht im Verlauf" + }, + "deleteTrackedObject": { + "label": "Dieses verfolgte Objekt löschen" + } + }, + "dialog": { + "confirmDelete": { + "title": "Löschen bestätigen", + "desc": "Beim Löschen dieses verfolgten Objekts werden der Schnappschuss, alle gespeicherten Einbettungen und alle zugehörigen Objektlebenszykluseinträge entfernt. Aufgezeichnetes Filmmaterial dieses verfolgten Objekts in der Verlaufsansicht wird NICHT gelöscht.

Sind Sie sicher, dass Sie fortfahren möchten?" + } + }, + "searchResult": { + "deleteTrackedObject": { + "toast": { + "success": "Verfolgtes Objekt erfolgreich gelöscht.", + "error": "Das verfolgte Objekt konnte nicht gelöscht werden: {{errorMessage}}" + } + } + }, + "noTrackedObjects": "Keine verfolgten Objekte gefunden", + "fetchingTrackedObjectsFailed": "Fehler beim Abrufen von verfolgten Objekten: {{errorMessage}}", + "trackedObjectsCount_one": "{{count}} verfolgtes Objekt ", + "trackedObjectsCount_other": "{{count}} verfolgte Objekte " +} diff --git a/web/public/locales/de/views/exports.json b/web/public/locales/de/views/exports.json new file mode 100644 index 000000000..2fb729cc2 --- /dev/null +++ b/web/public/locales/de/views/exports.json @@ -0,0 +1,17 @@ +{ + "deleteExport": "Export löschen", + "editExport": { + "title": "Export umbenennen", + "desc": "Gib einen neuen Namen für diesen Export an.", + "saveExport": "Export speichern" + }, + "documentTitle": "Exportieren - Frigate", + "deleteExport.desc": "Soll {{exportName}} wirklich gelöscht werden?", + "search": "Suche", + "noExports": "Keine Exporte gefunden", + "toast": { + "error": { + "renameExportFailed": "Umbenennen des Exports fehlgeschlagen: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/de/views/faceLibrary.json b/web/public/locales/de/views/faceLibrary.json new file mode 100644 index 000000000..96c0e8b7d --- /dev/null +++ b/web/public/locales/de/views/faceLibrary.json @@ -0,0 +1,82 @@ +{ + "description": { + "placeholder": "Gib einen Name für diese Kollektion ein", + "addFace": "Anleitung für das Hinzufügen einer neuen Kollektion zur Gesichtsbibliothek." + }, + "details": { + "person": "Person", + "confidence": "Vertrauen", + "timestamp": "Zeitstempel", + "faceDesc": "Details für das Gesicht und der zugehörigen Person", + "face": "Gesichtsdetails" + }, + "uploadFaceImage": { + "title": "Lade Gesichtsbild hoch", + "desc": "Lade ein Bild zur Gesichtserkennung hoch und füge es für {{pageToggle}} hinzu" + }, + "createFaceLibrary": { + "title": "Kollektion erstellen", + "new": "Lege ein neues Gesicht an", + "desc": "Erstelle eine neue Kollektion", + "nextSteps": "Um eine solide Grundlage zu bilden:
  • Benutze den Trainieren Tab, um Bilder für jede erkannte Person auszuwählen und zu trainieren.
  • Konzentriere dich für gute Ergebnisse auf Frontalfotos; vermeide Bilder zu Trainingszwecken, bei denen Gesichter aus einem Winkel erfasst wurden.
  • " + }, + "documentTitle": "Gesichtsbibliothek - Frigate", + "selectItem": "Wähle {{item}}", + "selectFace": "Wähle Gesicht", + "imageEntry": { + "dropActive": "Ziehe das Bild hierher…", + "dropInstructions": "Ziehe ein Bild hier her oder klicke um eines auszuwählen", + "maxSize": "Maximale Größe: {{size}} MB", + "validation": { + "selectImage": "Bitte wähle ein Bild aus." + } + }, + "button": { + "addFace": "Gesicht hinzufügen", + "uploadImage": "Bild hochladen", + "deleteFaceAttempts": "Lösche Gesichtsversuche", + "reprocessFace": "Gesichter erneut verarbeiten", + "renameFace": "Gesicht umbenennen", + "deleteFace": "Lösche Gesicht" + }, + "train": { + "title": "Trainiere", + "aria": "Wähle Training" + }, + "deleteFaceLibrary": { + "title": "Lösche Name", + "desc": "Möchtest du die Sammlung {{name}} löschen? Alle zugehörigen Gesichter werden gelöscht." + }, + "readTheDocs": "Lies die Dokumentation", + "trainFaceAs": "Trainiere Gesicht als:", + "trainFace": "Trainiere Gesicht", + "toast": { + "success": { + "uploadedImage": "Das Bild wurde erfolgreich hochgeladen.", + "deletedFace_one": "Erfolgreich {{count}} Gesicht gelöscht.", + "deletedFace_other": "Erfolgreich {{count}} Gesichter gelöscht.", + "deletedName_one": "{{count}} Gesicht wurde erfolgreich gelöscht.", + "deletedName_other": "{{count}} Gesichter wurden erfolgreich gelöscht.", + "addFaceLibrary": "{{name}} wurde erfolgreich in die Gesichtsbibliothek aufgenommen!", + "trainedFace": "Gesicht erfolgreich trainiert.", + "updatedFaceScore": "Gesichtsbewertung erfolgreich aktualisiert." + }, + "error": { + "deleteFaceFailed": "Das Löschen ist fehlgeschlagen: {{errorMessage}}", + "uploadingImageFailed": "Bild kann nicht hochgeladen werden: {{errorMessage}}", + "addFaceLibraryFailed": "Der Gesichtsname konnte nicht gesetzt werden: {{errorMessage}}", + "trainFailed": "Ausbildung fehlgeschlagen: {{errorMessage}}", + "updateFaceScoreFailed": "Aktualisierung der Gesichtsbewertung fehlgeschlagen: {{errorMessage}}", + "deleteNameFailed": "Name kann nicht gelöscht werden: {{errorMessage}}" + } + }, + "steps": { + "uploadFace": "Lade Bild des Gesichts hoch", + "nextSteps": "Nächste Schritte", + "faceName": "Gib den Namen zum Gesicht ein" + }, + "renameFace": { + "title": "Gesicht umbenennen", + "desc": "Gib den neuen Namen für das Gesicht von {{name}} ein." + } +} diff --git a/web/public/locales/de/views/live.json b/web/public/locales/de/views/live.json new file mode 100644 index 000000000..2e889b206 --- /dev/null +++ b/web/public/locales/de/views/live.json @@ -0,0 +1,158 @@ +{ + "lowBandwidthMode": "Modus für geringe Bandbreite", + "twoWayTalk": { + "enable": "Gegensprechfunktion aktivieren", + "disable": "Gegensprechfunktion ausschalten" + }, + "cameraAudio": { + "enable": "Kamera-Audio aktivieren", + "disable": "Kamera-Audio deaktivieren" + }, + "ptz": { + "move": { + "clickMove": { + "disable": "Bewegen per Klick deaktivieren", + "enable": "Bewegen per Klick aktivieren", + "label": "Zum Zentrieren der Kamera ins Bild klicken" + }, + "up": { + "label": "PTZ-Kamera nach oben bewegen" + }, + "left": { + "label": "PTZ-Kamera nach links bewegen" + }, + "down": { + "label": "PTZ-Kamera nach unten bewegen" + }, + "right": { + "label": "PTZ-Kamera nach rechts bewegen" + } + }, + "zoom": { + "in": { + "label": "PTZ-Kamera vergrößern" + }, + "out": { + "label": "PTZ-Kamera herauszoomen" + } + }, + "presets": "PTZ-Kameravoreinstellungen", + "frame": { + "center": { + "label": "Klicken Sie in den Rahmen, um die PTZ-Kamera zu zentrieren" + } + } + }, + "documentTitle": "Live - Frigate", + "documentTitle.withCamera": "{{camera}} - Live - Frigate", + "muteCameras": { + "disable": "Stumm aller Kameras aufheben", + "enable": "Alle Kameras auf stumm" + }, + "recording": { + "disable": "Aufzeichnung deaktivieren", + "enable": "Aufzeichnung aktivieren" + }, + "snapshots": { + "enable": "Snapshots aktivieren", + "disable": "Snapshots deaktivieren" + }, + "autotracking": { + "disable": "Autotracking deaktivieren", + "enable": "Autotracking aktivieren" + }, + "streamStats": { + "enable": "Stream Statistiken anzeigen", + "disable": "Stream-Statistiken ausblenden" + }, + "manualRecording": { + "title": "On-Demand Aufzeichnung", + "showStats": { + "label": "Statistiken anzeigen", + "desc": "Aktivieren Sie diese Option, um Stream-Statistiken als Overlay über dem Kamera-Feed anzuzeigen." + }, + "started": "Manuelle On-Demand Aufzeichnung gestartet.", + "failedToStart": "Manuelle On-Demand Aufzeichnung konnte nicht gestartet werden.", + "recordDisabledTips": "Da die Aufzeichnung in der Konfiguration für diese Kamera deaktiviert oder eingeschränkt ist, wird nur ein Schnappschuss gespeichert.", + "end": "On-Demand Aufzeichnung beenden", + "ended": "Manuelle On-Demand Aufzeichnung beendet.", + "playInBackground": { + "desc": "Aktivieren Sie diese Option, um das Streaming fortzusetzen, wenn der Player ausgeblendet ist.", + "label": "Im Hintergrund abspielen" + }, + "tips": "Starten Sie ein manuelles Ereignis basierend auf den Aufzeichnung Aufbewahrungseinstellungen dieser Kamera.", + "debugView": "Debug-Ansicht", + "start": "On-Demand Aufzeichnung starten", + "failedToEnd": "Die manuelle On-Demand Aufzeichnung konnte nicht beendet werden." + }, + "streamingSettings": "Streaming Einstellungen", + "notifications": "Benachrichtigungen", + "stream": { + "audio": { + "available": "Für diesen Stream ist Audio verfügbar", + "tips": { + "title": "Der Ton muss von Ihrer Kamera ausgegeben und für diesen Stream in go2rtc konfiguriert werden.", + "documentation": "Dokumentation lesen " + }, + "unavailable": "Für diesen Stream ist kein Audio verfügbar" + }, + "twoWayTalk": { + "tips": "Ihr Gerät muss die Funktion unterstützen und WebRTC muss für die bidirektionale Kommunikation konfiguriert sein.", + "tips.documentation": "Dokumentation lesen ", + "available": "Für diesen Stream ist eine Zwei-Wege-Sprechfunktion verfügbar", + "unavailable": "Für diesen Stream ist keine Zwei-Wege-Kommunikation möglich." + }, + "lowBandwidth": { + "tips": "Die Live-Ansicht befindet sich aufgrund von Puffer- oder Stream-Fehlern im Modus mit geringer Bandbreite.", + "resetStream": "Stream zurücksetzen" + }, + "title": "Strom", + "playInBackground": { + "tips": "Aktivieren Sie diese Option, um das Streaming fortzusetzen, wenn der Player ausgeblendet ist.", + "label": "Im Hintergrund abspielen" + } + }, + "effectiveRetainMode": { + "modes": { + "motion": "Bewegung", + "active_objects": "Aktive Objekte", + "all": "Alle" + }, + "notAllTips": "Dein Konfiguration zur Aufzeichnungsaufbewahrung von {{source}} ist eingestellt auf -Modus:{{effectiveRetainMode}} , daher werden in dieser On-Demand Aufzeichnung nur Segmente gespeichert mit{{effectiveRetainModeName}} ." + }, + "editLayout": { + "group": { + "label": "Kameragruppe bearbeiten" + }, + "exitEdit": "Bearbeitung beenden", + "label": "Layout bearbeiten" + }, + "camera": { + "enable": "Kamera aktivieren", + "disable": "Kamera deaktivieren" + }, + "audioDetect": { + "enable": "Audioerkennung aktivieren", + "disable": "Audioerkennung deaktivieren" + }, + "detect": { + "enable": "Erkennung aktivieren", + "disable": "Erkennung deaktivieren" + }, + "cameraSettings": { + "objectDetection": "Objekterkennung", + "recording": "Aufnahme", + "snapshots": "Schnappschüsse", + "cameraEnabled": "Kamera aktiviert", + "autotracking": "Autotracking", + "audioDetection": "Audioerkennung", + "title": "{{camera}} Einstellungen" + }, + "history": { + "label": "Historisches Filmmaterial zeigen" + }, + "audio": "Audio", + "suspend": { + "forTime": "Aussetzen für: " + } +} diff --git a/web/public/locales/de/views/recording.json b/web/public/locales/de/views/recording.json new file mode 100644 index 000000000..354cd4055 --- /dev/null +++ b/web/public/locales/de/views/recording.json @@ -0,0 +1,12 @@ +{ + "export": "Export", + "calendar": "Kalender", + "filters": "Filter", + "toast": { + "error": { + "endTimeMustAfterStartTime": "Endzeit muss nach Startzeit liegen", + "noValidTimeSelected": "Gewählter Zeitraum ist ungültig" + } + }, + "filter": "Filter" +} diff --git a/web/public/locales/de/views/search.json b/web/public/locales/de/views/search.json new file mode 100644 index 000000000..7caf23b88 --- /dev/null +++ b/web/public/locales/de/views/search.json @@ -0,0 +1,67 @@ +{ + "savedSearches": "Gespeicherte Suchen", + "searchFor": "Suche nach {{inputValue}}", + "button": { + "save": "Suche speichern", + "filterActive": "Filter aktiv", + "delete": "Gespeicherte Suche löschen", + "filterInformation": "Information filtern", + "clear": "Suche löschen" + }, + "trackedObjectId": "ID verfolgtes Objekt", + "filter": { + "label": { + "cameras": "Kameras", + "zones": "Zonen", + "search_type": "Suchtyp", + "before": "Vor", + "after": "Nach", + "min_score": "Minimalwert", + "max_score": "Maximalwert", + "recognized_license_plate": "Erkanntes Autokennzeichen", + "has_clip": "Clip vorhanden", + "has_snapshot": "Schnappschuss vorhanden", + "min_speed": "Minimalgeschwindigkeit", + "max_speed": "Maximalgeschwindigkeit", + "time_range": "Zeitraum", + "labels": "Labels", + "sub_labels": "Unterlabels" + }, + "toast": { + "error": { + "beforeDateBeLaterAfter": "Das \"Vor\" Datum muss später als das \"Nach\" Datum sein.", + "minScoreMustBeLessOrEqualMaxScore": "Der \"Minimalwert\" muss kleiner oder gleich dem \"Maximalwert\" sein.", + "afterDatebeEarlierBefore": "Das \"Nach\" Datum muss früher als das \"Vor\" Datum sein.", + "maxScoreMustBeGreaterOrEqualMinScore": "Der \"Maximalwert\" muss größer oder gleich dem \"Minimalwert\" sein.", + "minSpeedMustBeLessOrEqualMaxSpeed": "Der \"Minimalgeschwindigkeit\" muss kleiner oder gleich der \"Maximalgeschwindigkeit\" sein.", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "Der \"Maximalgeschwindigkeit\" muss größer oder gleich der \"Maximalgeschwindigkeit\" sein." + } + }, + "header": { + "currentFilterType": "Filterwerte", + "noFilters": "Filter", + "activeFilters": "Aktive Filter" + }, + "tips": { + "desc": { + "step": "
    • Gib einen Filternamen gefolgt von einem Doppelpunkt ein (z.B. \"Kameras:\").
    • Wähle einen Wert aus den Vorschlägen aus oder tippe einen individuellen ein.
    • Verwende mehrere Filter, indem Du sie nacheinander mit Leerzeichen getrennt eingibst.
    • Datumfilter (Vor: und Nach:) im Format {{DateFormat}}.
    • Zeitraumfilter im Format {{exampleTime}}.
    • Lösche Filter durch Drücken des \"x\" daneben.
    ", + "text": "Mit Filtern kannst Du Suchergebnisse eingrenzen. Hier erfährst Du, wie diese im Eingabefeld verwendet werden können:", + "example": "Beispiel: Kameras:Tor Label:Person Vor:01012024 Zeitraum:15:00-16:00" + }, + "title": "Wie man Textfilter verwendet" + }, + "searchType": { + "thumbnail": "Miniaturansicht", + "description": "Beschreibung" + } + }, + "similaritySearch": { + "title": "Ähnlichkeitssuche", + "clear": "Ähnlichkeitssuche löschen", + "active": "Aktive Ähnlichkeitssuche" + }, + "search": "Suche", + "placeholder": { + "search": "Suchen…" + } +} diff --git a/web/public/locales/de/views/settings.json b/web/public/locales/de/views/settings.json new file mode 100644 index 000000000..dabe9f48f --- /dev/null +++ b/web/public/locales/de/views/settings.json @@ -0,0 +1,237 @@ +{ + "documentTitle": { + "default": "Einstellungen - Frigate", + "authentication": "Authentifizierungseinstellungen", + "camera": "Kameraeinstellungen", + "masksAndZones": "Masken und Zonen bearbeiten", + "object": "Objekt Einstellungen - Frigate", + "general": "Allgemeine Einstellungen - Frigate", + "frigatePlus": "Frigate+ Einstellungen", + "classification": "Klassifizierungseinstellungen - Frigate", + "motionTuner": "Bewegungsanpassung – Frigate" + }, + "menu": { + "ui": "Benutzeroberfläche", + "cameras": "Kameraeinstellungen", + "classification": "Klassifizierung", + "masksAndZones": "Maskierungen / Zonen", + "motionTuner": "Bewegungsempflindlichkeit einstellen", + "debug": "Fehlerbehebung", + "frigateplus": "Frigate+", + "users": "Benutzer", + "notifications": "Benachrichtigungen" + }, + "dialog": { + "unsavedChanges": { + "title": "Du hast nicht gespeicherte Änderungen.", + "desc": "Möchtest Du deine Änderungen speichern, bevor du fortfährst?" + } + }, + "cameraSetting": { + "camera": "Kamera", + "noCamera": "Keine Kamera" + }, + "general": { + "title": "Allgemeine Einstellungen", + "liveDashboard": { + "title": "Live Übersicht", + "playAlertVideos": { + "label": "Spiele Videos mit Alarmierung", + "desc": "Standardmäßig werden die letzten Warnmeldungen auf dem Live-Dashboard als kurze Videoschleifen abgespielt. Deaktiviere diese Option, um nur ein statisches Bild der letzten Warnungen auf diesem Gerät/Browser anzuzeigen." + }, + "automaticLiveView": { + "desc": "Wechsle automatisch zur Live Ansicht der Kamera, wenn einen Aktivität erkannt wurde. Wenn du diese Option deaktivierst, werden die statischen Kamerabilder auf der Liveübersicht nur einmal pro Minute aktualisiert.", + "label": "Automatische Live Ansicht" + } + }, + "storedLayouts": { + "title": "Gespeicherte Ansichten", + "clearAll": "Lösche alle Ansichten", + "desc": "Das Layout der Kameras in einer Kameragruppe kann verschoben/geändert werden. Die Positionen werden im lokalen Cache des Browsers gespeichert." + }, + "cameraGroupStreaming": { + "title": "Einstellungen für Kamera-Gruppen-Streaming", + "clearAll": "Alle Streamingeinstellungen löschen", + "desc": "Die Streaming-Einstellungen für jede Kameragruppe werden im lokalen Cache des Browsers gespeichert." + }, + "recordingsViewer": { + "title": "Aufzeichnungsbetrachter", + "defaultPlaybackRate": { + "desc": "Standard-Wiedergabegeschwindigkeit für die Wiedergabe von Aufnahmen.", + "label": "Standard-Wiedergabegeschwindigkeit" + } + }, + "calendar": { + "title": "Kalender", + "firstWeekday": { + "label": "Erster Wochentag", + "desc": "Der Tag, an dem die Wochen des Review Kalenders beginnen.", + "sunday": "Sonntag", + "monday": "Montag" + } + }, + "toast": { + "success": { + "clearStoredLayout": "Gespeichertes Layout für {{cameraName}} gelöscht", + "clearStreamingSettings": "Streaming Einstellungen aller Kameragruppen bereinigt." + }, + "error": { + "clearStoredLayoutFailed": "Das gespeicherte Layout konnte nicht gelöscht werden: {{errorMessage}}", + "clearStreamingSettingsFailed": "Die Streaming-Einstellungen konnten nicht gelöscht werden: {{errorMessage}}" + } + } + }, + "classification": { + "title": "Klassifizierungseinstellungen", + "semanticSearch": { + "title": "Semantische Suche", + "desc": "Die semantische Suche in Frigate ermöglicht es, verfolgte Objekte innerhalb der Überprüfungselemente zu finden, indem entweder das Bild selbst, eine benutzerdefinierte Textbeschreibung oder eine automatisch generierte Beschreibung verwendet wird.", + "readTheDocumentation": "Lesen Sie die Dokumentation", + "reindexNow": { + "alreadyInProgress": "Neu-Indizierung läufts bereits.", + "label": "Neuindizieren", + "confirmTitle": "Bestätige Neu-Indizierung", + "confirmButton": "Neu-Indizieren", + "success": "Neuindizierung erfolgreich gestartet.", + "error": "Starten der Neuindizierung fehlgeschlagen: {{errorMessage}}" + }, + "modelSize": { + "large": { + "title": "groß" + }, + "label": "Model Größe", + "small": { + "title": "klein" + } + } + }, + "birdClassification": { + "desc": "Die Vogelklassifizierung identifiziert bekannte Vögel mithilfe eines quantisierten Tensorflow-Modells. Wenn ein bekannter Vogel erkannt wird, wird sein allgemeiner Name als sub_label hinzugefügt. Diese Informationen sind in der Benutzeroberfläche, in Filtern und in Benachrichtigungen enthalten.", + "title": "Vogel-Klassifizierung" + }, + "licensePlateRecognition": { + "readTheDocumentation": "Lies die Dokumentation", + "title": "Nummernschilderkennung" + }, + "faceRecognition": { + "readTheDocumentation": "Lies die Dokumentation", + "modelSize": { + "small": { + "title": "klein" + }, + "label": "Model Größe", + "large": { + "title": "groß" + } + }, + "title": "Gesichtserkennung" + }, + "toast": { + "error": "Sichern der Konfigurationsänderungen fehlgeschlagen: {{errorMessage}}" + } + }, + "camera": { + "reviewClassification": { + "toast": { + "success": "Die Konfiguration der Klassifizierung wurde gespeichert. Starte Frigate neu, um die Änderungen zu übernehmen." + }, + "title": "Überprüfung der Klassifikation", + "selectAlertsZones": "Zonen für Warnungen auswählen", + "limitDetections": "Begrenzung der Erkennungen auf bestimmte Zonen", + "readTheDocumentation": "Lies die Dokumentation", + "noDefinedZones": "Für diese Kamera sind keine Zonen definiert.", + "selectDetectionsZones": "Zonen für Erkennungen auswählen" + }, + "streams": { + "title": "Streams" + }, + "review": { + "title": "Überprüfung", + "alerts": "Warnungen ", + "detections": "Erkennungen " + }, + "title": "Kamera-Einstellungen" + }, + "masksAndZones": { + "form": { + "zoneName": { + "error": { + "hasIllegalCharacter": "Zonenname enthält unzulässige Zeichen.", + "alreadyExists": "Für diese Kamera existiert bereits eine Zone mit diesem Namen.", + "mustBeAtLeastTwoCharacters": "Der Zonenname muss aus mindestens 2 Zeichen bestehen.", + "mustNotBeSameWithCamera": "Der Zonenname darf nicht mit dem Kameranamen identisch sein.", + "mustNotContainPeriod": "Der Zonenname darf keine Punkte enthalten." + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "Die Verweildauer muss größer oder gleich 0 sein." + } + }, + "distance": { + "error": { + "text": "Der Abstand muss größer als oder gleich 0.1 sein.", + "mustBeFilled": "Alle Entfernungsfelder müssen ausgefüllt werden, um die Geschwindigkeitsschätzung zu verwenden." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "Die Trägheit muss über 0 liegen." + } + }, + "polygonDrawing": { + "removeLastPoint": "Letzten Punkt entfernen", + "reset": { + "label": "Alle Punkte löschen" + }, + "snapPoints": { + "true": "Fangpunkte" + }, + "delete": { + "title": "Löschen bestätigen", + "success": "{{name}} wurde gelöscht." + } + } + }, + "toast": { + "error": { + "copyCoordinatesFailed": "Die Koordinaten konnten nicht in die Zwischenablage kopiert werden." + }, + "success": { + "copyCoordinates": "Koordinaten von {{polyName}} wurden in die Zwischenablage kopiert." + } + }, + "filter": { + "all": "Alle Maskierungen und Zonen" + }, + "zones": { + "edit": "Zone bearbeiten", + "toast": { + "success": "Die Zone ({{zoneName}}) wurde gespeichert. Starten Sie Frigate neu, um die Änderungen zu übernehmen." + }, + "desc": { + "documentation": "Dokumentation" + }, + "allObjects": "Alle Objekte", + "speedEstimation": { + "title": "Geschwindigkeitsschätzung" + }, + "label": "Zonen", + "documentTitle": "Zone bearbeiten - Frigate", + "add": "Zone hinzufügen", + "name": { + "title": "Name", + "inputPlaceHolder": "Geben Sie einen Namen ein…", + "tips": "Der Name muss aus mindestens 2 Zeichen bestehen und sollte nicht den Namen einer Kamera oder anderen Zone entsprechen." + }, + "objects": { + "title": "Objekte" + } + }, + "motionMasks": { + "desc": { + "documentation": "Dokumentation" + } + } + } +} diff --git a/web/public/locales/de/views/system.json b/web/public/locales/de/views/system.json new file mode 100644 index 000000000..c4026463d --- /dev/null +++ b/web/public/locales/de/views/system.json @@ -0,0 +1,167 @@ +{ + "general": { + "hardwareInfo": { + "gpuInfo": { + "vainfoOutput": { + "title": "Ergebnis der Vainfo-Abfrage", + "returnCode": "Rückgabecode: {{code}}", + "processError": "Prozess Fehler:", + "processOutput": "Prozess-Output:" + }, + "nvidiaSMIOutput": { + "title": "Nvidia SMI Ausgabe", + "cudaComputerCapability": "CUDA Rechenleistung:{{cuda_compute}}", + "name": "Name: {{name}}", + "driver": "Treiber: {{driver}}", + "vbios": "VBios Info: {{vbios}}" + }, + "closeInfo": { + "label": "Schhließe GPU Info" + }, + "copyInfo": { + "label": "Kopiere GPU Info" + }, + "toast": { + "success": "GPU-Infos in die Zwischenablage kopiert" + } + }, + "title": "Hardwareinformationen", + "gpuUsage": "GPU Auslastung", + "gpuMemory": "Grafikspeicher", + "gpuDecoder": "GPU Decoder", + "gpuEncoder": "GPU Encoder", + "npuUsage": "NPU Verwendung", + "npuMemory": "NPU Speicher" + }, + "title": "Allgemein", + "detector": { + "title": "Detektoren", + "cpuUsage": "CPU-Auslastung des Detektors", + "memoryUsage": "Arbeitsspeichernutzung des Detektors", + "inferenceSpeed": "Detektoren Inferenzgeschwindigkeit", + "temperature": "Temperatur des Detektors" + }, + "otherProcesses": { + "title": "Andere Prozesse", + "processCpuUsage": "CPU Auslastung für Prozess", + "processMemoryUsage": "Prozessspeicherauslastung" + } + }, + "documentTitle": { + "cameras": "Kamerastatistiken – Frigate", + "storage": "Speicherstatistiken - Frigate", + "general": "Allgemeine Statistiken - Frigate", + "logs": { + "frigate": "Frigate Protokolle – Frigate", + "go2rtc": "Go2RTC Protokolle - Frigate", + "nginx": "Nginx Protokolle - Frigate" + }, + "enrichments": "Erweiterte Statistiken - Frigate" + }, + "title": "System", + "logs": { + "download": { + "label": "Protokolldateien herunterladen" + }, + "copy": { + "success": "Protokolle in die Zwischenablage kopiert", + "label": "In die Zwischenablage kopieren", + "error": "Protokolle konnten nicht in die Zwischenablage kopiert werden" + }, + "type": { + "message": "Nachricht", + "timestamp": "Zeitstempel", + "label": "Art", + "tag": "Tag" + }, + "toast": { + "error": { + "fetchingLogsFailed": "Fehler beim Abrufen der Protokolle: {{errorMessage}}", + "whileStreamingLogs": "Beim Übertragen der Protokolle ist ein Fehler aufgetreten: {{errorMessage}}" + } + }, + "tips": "Protokolle werden in Echtzeit vom Server übertragen" + }, + "metrics": "Systemmetriken", + "storage": { + "recordings": { + "earliestRecording": "Älteste verfügbare Aufzeichnung:", + "title": "Aufnahmen", + "tips": "Dieser Wert gibt den Gesamtspeicherplatz an, den die Aufzeichnungen in der Datenbank von Frigate belegen. Frigate erfasst nicht die Speichernutzung für alle Dateien auf Ihrer Festplatte." + }, + "cameraStorage": { + "camera": "Kamera", + "title": "Kamera Speicher", + "unused": { + "title": "Ungenutzt", + "tips": "Dieser Wert gibt möglicherweise nicht genau den freien Speicherplatz an, der Frigate zur Verfügung steht, wenn neben den Aufzeichnungen von Frigate noch andere Dateien auf der Festplatte gespeichert sind. Frigate verfolgt die Speichernutzung außerhalb der Aufzeichnungen nicht." + }, + "unusedStorageInformation": "Info zum ungenutzten Speicher", + "storageUsed": "Speicher", + "percentageOfTotalUsed": "Prozentualer Anteil am Gesamtanteil", + "bandwidth": "Bandbreite" + }, + "title": "Speicher", + "overview": "Übersicht" + }, + "cameras": { + "info": { + "stream": "Stream {{idx}}", + "video": "Video:", + "codec": "Codec:", + "fetching": "Lade Kamera Daten", + "resolution": "Auflösung:", + "fps": "FPS:", + "unknown": "Unbekannt", + "audio": "Audio:", + "error": "Fehler: {{error}}", + "cameraProbeInfo": "{{camera}} Kamera-Untersuchsungsinfo", + "streamDataFromFFPROBE": "Stream-Daten werden mit ffprobe erhalten.", + "tips": { + "title": "Kamera-Untersuchsungsinfo" + } + }, + "overview": "Übersicht", + "label": { + "detect": "erkennen", + "camera": "Kamera", + "skipped": "übersprungene", + "ffmpeg": "ffmpeg", + "capture": "aufnehmen" + }, + "title": "Kameras", + "framesAndDetections": "Bilder / Erkennungen", + "toast": { + "success": { + "copyToClipboard": "Kopiert Untersuchungsdaten in die Zwischenablage." + }, + "error": { + "unableToProbeCamera": "Die Kamera kann nicht getestet werden: {{errorMessage}}" + } + } + }, + "enrichments": { + "embeddings": { + "image_embedding_speed": "Geschwindigkeit der Bildeinbettung", + "face_embedding_speed": "Geschwindigkeit der Gesichtseinbettung", + "plate_recognition_speed": "Geschwindigkeit der Kennzeichenerkennung", + "text_embedding_speed": "Geschwindigkeit der Texteinbettung", + "plate_recognition": "Kennzeichen Erkennung", + "face_recognition_speed": "Gesichts Erkennungs Geschwindigkeit", + "text_embedding": "Einbettung von Bildern", + "face_recognition": "Gesichts Erkennung" + }, + "title": "Optimierungen", + "infPerSecond": "Rückschlüsse pro Sekunde" + }, + "stats": { + "healthy": "Das System läuft problemlos", + "ffmpegHighCpuUsage": "{{camera}} hat eine hohe FFMPEG CPU Auslastung ({{ffmpegAvg}}%)", + "detectHighCpuUsage": "{{camera}} hat eine hohe CPU Auslastung bei der Erkennung ({{detectAvg}}%)", + "reindexingEmbeddings": "Neuindizierung von Einbettungen ({{processed}}% erledigt)", + "detectIsSlow": "{{detect}} ist langsam ({{speed}} ms)", + "detectIsVerySlow": "{{detect}} ist sehr langsam ({{speed}} ms)", + "cameraIsOffline": "{{camera}} ist offline" + }, + "lastRefreshed": "Zuletzt aktualisiert: " +} diff --git a/web/public/locales/en/audio.json b/web/public/locales/en/audio.json new file mode 100644 index 000000000..de5f5638c --- /dev/null +++ b/web/public/locales/en/audio.json @@ -0,0 +1,429 @@ +{ + "speech": "Speech", + "babbling": "Babbling", + "yell": "Yell", + "bellow": "Bellow", + "whoop": "Whoop", + "whispering": "Whispering", + "laughter": "Laughter", + "snicker": "Snicker", + "crying": "Crying", + "sigh": "Sigh", + "singing": "Singing", + "choir": "Choir", + "yodeling": "Yodeling", + "chant": "Chant", + "mantra": "Mantra", + "child_singing": "Child Singing", + "synthetic_singing": "Synthetic Singing", + "rapping": "Rapping", + "humming": "Humming", + "groan": "Groan", + "grunt": "Grunt", + "whistling": "Whistling", + "breathing": "Breathing", + "wheeze": "Wheeze", + "snoring": "Snoring", + "gasp": "Gasp", + "pant": "Pant", + "snort": "Snort", + "cough": "Cough", + "throat_clearing": "Throat Clearing", + "sneeze": "Sneeze", + "sniff": "Sniff", + "run": "Run", + "shuffle": "Shuffle", + "footsteps": "Footsteps", + "chewing": "Chewing", + "biting": "Biting", + "gargling": "Gargling", + "stomach_rumble": "Stomach Rumble", + "burping": "Burping", + "hiccup": "Hiccup", + "fart": "Fart", + "hands": "Hands", + "finger_snapping": "Finger Snapping", + "clapping": "Clapping", + "heartbeat": "Heartbeat", + "heart_murmur": "Heart Murmur", + "cheering": "Cheering", + "applause": "Applause", + "chatter": "Chatter", + "crowd": "Crowd", + "children_playing": "Children Playing", + "animal": "Animal", + "pets": "Pets", + "dog": "Dog", + "bark": "Bark", + "yip": "Yip", + "howl": "Howl", + "bow_wow": "Bow Wow", + "growling": "Growling", + "whimper_dog": "Dog Whimper", + "cat": "Cat", + "purr": "Purr", + "meow": "Meow", + "hiss": "Hiss", + "caterwaul": "Caterwaul", + "livestock": "Livestock", + "horse": "Horse", + "clip_clop": "Clip Clop", + "neigh": "Neigh", + "cattle": "Cattle", + "moo": "Moo", + "cowbell": "Cowbell", + "pig": "Pig", + "oink": "Oink", + "goat": "Goat", + "bleat": "Bleat", + "sheep": "Sheep", + "fowl": "Fowl", + "chicken": "Chicken", + "cluck": "Cluck", + "cock_a_doodle_doo": "Cock-a-Doodle-Doo", + "turkey": "Turkey", + "gobble": "Gobble", + "duck": "Duck", + "quack": "Quack", + "goose": "Goose", + "honk": "Honk", + "wild_animals": "Wild Animals", + "roaring_cats": "Roaring Cats", + "roar": "Roar", + "bird": "Bird", + "chirp": "Chirp", + "squawk": "Squawk", + "pigeon": "Pigeon", + "coo": "Coo", + "crow": "Crow", + "caw": "Caw", + "owl": "Owl", + "hoot": "Hoot", + "flapping_wings": "Flapping Wings", + "dogs": "Dogs", + "rats": "Rats", + "mouse": "Mouse", + "patter": "Patter", + "insect": "Insect", + "cricket": "Cricket", + "mosquito": "Mosquito", + "fly": "Fly", + "buzz": "Buzz", + "frog": "Frog", + "croak": "Croak", + "snake": "Snake", + "rattle": "Rattle", + "whale_vocalization": "Whale Vocalization", + "music": "Music", + "musical_instrument": "Musical Instrument", + "plucked_string_instrument": "Plucked String Instrument", + "guitar": "Guitar", + "electric_guitar": "Electric Guitar", + "bass_guitar": "Bass Guitar", + "acoustic_guitar": "Acoustic Guitar", + "steel_guitar": "Steel Guitar", + "tapping": "Tapping", + "strum": "Strum", + "banjo": "Banjo", + "sitar": "Sitar", + "mandolin": "Mandolin", + "zither": "Zither", + "ukulele": "Ukulele", + "keyboard": "Keyboard", + "piano": "Piano", + "electric_piano": "Electric Piano", + "organ": "Organ", + "electronic_organ": "Electronic Organ", + "hammond_organ": "Hammond Organ", + "synthesizer": "Synthesizer", + "sampler": "Sampler", + "harpsichord": "Harpsichord", + "percussion": "Percussion", + "drum_kit": "Drum Kit", + "drum_machine": "Drum Machine", + "drum": "Drum", + "snare_drum": "Snare Drum", + "rimshot": "Rimshot", + "drum_roll": "Drum Roll", + "bass_drum": "Bass Drum", + "timpani": "Timpani", + "tabla": "Tabla", + "cymbal": "Cymbal", + "hi_hat": "Hi-Hat", + "wood_block": "Wood Block", + "tambourine": "Tambourine", + "maraca": "Maraca", + "gong": "Gong", + "tubular_bells": "Tubular Bells", + "mallet_percussion": "Mallet Percussion", + "marimba": "Marimba", + "glockenspiel": "Glockenspiel", + "vibraphone": "Vibraphone", + "steelpan": "Steelpan", + "orchestra": "Orchestra", + "brass_instrument": "Brass Instrument", + "french_horn": "French Horn", + "trumpet": "Trumpet", + "trombone": "Trombone", + "bowed_string_instrument": "Bowed String Instrument", + "string_section": "String Section", + "violin": "Violin", + "pizzicato": "Pizzicato", + "cello": "Cello", + "double_bass": "Double Bass", + "wind_instrument": "Wind Instrument", + "flute": "Flute", + "saxophone": "Saxophone", + "clarinet": "Clarinet", + "harp": "Harp", + "bell": "Bell", + "church_bell": "Church Bell", + "jingle_bell": "Jingle Bell", + "bicycle_bell": "Bicycle Bell", + "tuning_fork": "Tuning Fork", + "chime": "Chime", + "wind_chime": "Wind Chime", + "harmonica": "Harmonica", + "accordion": "Accordion", + "bagpipes": "Bagpipes", + "didgeridoo": "Didgeridoo", + "theremin": "Theremin", + "singing_bowl": "Singing Bowl", + "scratching": "Scratching", + "pop_music": "Pop Music", + "hip_hop_music": "Hip-Hop Music", + "beatboxing": "Beatboxing", + "rock_music": "Rock Music", + "heavy_metal": "Heavy Metal", + "punk_rock": "Punk Rock", + "grunge": "Grunge", + "progressive_rock": "Progressive Rock", + "rock_and_roll": "Rock and Roll", + "psychedelic_rock": "Psychedelic Rock", + "rhythm_and_blues": "Rhythm and Blues", + "soul_music": "Soul Music", + "reggae": "Reggae", + "country": "Country", + "swing_music": "Swing Music", + "bluegrass": "Bluegrass", + "funk": "Funk", + "folk_music": "Folk Music", + "middle_eastern_music": "Middle Eastern Music", + "jazz": "Jazz", + "disco": "Disco", + "classical_music": "Classical Music", + "opera": "Opera", + "electronic_music": "Electronic Music", + "house_music": "House Music", + "techno": "Techno", + "dubstep": "Dubstep", + "drum_and_bass": "Drum and Bass", + "electronica": "Electronica", + "electronic_dance_music": "Electronic Dance Music", + "ambient_music": "Ambient Music", + "trance_music": "Trance Music", + "music_of_latin_america": "Music of Latin America", + "salsa_music": "Salsa Music", + "flamenco": "Flamenco", + "blues": "Blues", + "music_for_children": "Music for Children", + "new-age_music": "New Age Music", + "vocal_music": "Vocal Music", + "a_capella": "A Capella", + "music_of_africa": "Music of Africa", + "afrobeat": "Afrobeat", + "christian_music": "Christian Music", + "gospel_music": "Gospel Music", + "music_of_asia": "Music of Asia", + "carnatic_music": "Carnatic Music", + "music_of_bollywood": "Music of Bollywood", + "ska": "Ska", + "traditional_music": "Traditional Music", + "independent_music": "Independent Music", + "song": "Song", + "background_music": "Background Music", + "theme_music": "Theme Music", + "jingle": "Jingle", + "soundtrack_music": "Soundtrack Music", + "lullaby": "Lullaby", + "video_game_music": "Video Game Music", + "christmas_music": "Christmas Music", + "dance_music": "Dance Music", + "wedding_music": "Wedding Music", + "happy_music": "Happy Music", + "sad_music": "Sad Music", + "tender_music": "Tender Music", + "exciting_music": "Exciting Music", + "angry_music": "Angry Music", + "scary_music": "Scary Music", + "wind": "Wind", + "rustling_leaves": "Rustling Leaves", + "wind_noise": "Wind Noise", + "thunderstorm": "Thunderstorm", + "thunder": "Thunder", + "water": "Water", + "rain": "Rain", + "raindrop": "Raindrop", + "rain_on_surface": "Rain on Surface", + "stream": "Stream", + "waterfall": "Waterfall", + "ocean": "Ocean", + "waves": "Waves", + "steam": "Steam", + "gurgling": "Gurgling", + "fire": "Fire", + "crackle": "Crackle", + "vehicle": "Vehicle", + "boat": "Boat", + "sailboat": "Sailboat", + "rowboat": "Rowboat", + "motorboat": "Motorboat", + "ship": "Ship", + "motor_vehicle": "Motor Vehicle", + "car": "Car", + "toot": "Toot", + "car_alarm": "Car Alarm", + "power_windows": "Power Windows", + "skidding": "Skidding", + "tire_squeal": "Tire Squeal", + "car_passing_by": "Car Passing By", + "race_car": "Race Car", + "truck": "Truck", + "air_brake": "Air Brake", + "air_horn": "Air Horn", + "reversing_beeps": "Reversing Beeps", + "ice_cream_truck": "Ice Cream Truck", + "bus": "Bus", + "emergency_vehicle": "Emergency Vehicle", + "police_car": "Police Car", + "ambulance": "Ambulance", + "fire_engine": "Fire Engine", + "motorcycle": "Motorcycle", + "traffic_noise": "Traffic Noise", + "rail_transport": "Rail Transport", + "train": "Train", + "train_whistle": "Train Whistle", + "train_horn": "Train Horn", + "railroad_car": "Railroad Car", + "train_wheels_squealing": "Train Wheels Squealing", + "subway": "Subway", + "aircraft": "Aircraft", + "aircraft_engine": "Aircraft Engine", + "jet_engine": "Jet Engine", + "propeller": "Propeller", + "helicopter": "Helicopter", + "fixed-wing_aircraft": "Fixed-Wing Aircraft", + "bicycle": "Bicycle", + "skateboard": "Skateboard", + "engine": "Engine", + "light_engine": "Light Engine", + "dental_drill's_drill": "Dental Drill", + "lawn_mower": "Lawn Mower", + "chainsaw": "Chainsaw", + "medium_engine": "Medium Engine", + "heavy_engine": "Heavy Engine", + "engine_knocking": "Engine Knocking", + "engine_starting": "Engine Starting", + "idling": "Idling", + "accelerating": "Accelerating", + "door": "Door", + "doorbell": "Doorbell", + "ding-dong": "Ding-Dong", + "sliding_door": "Sliding Door", + "slam": "Slam", + "knock": "Knock", + "tap": "Tap", + "squeak": "Squeak", + "cupboard_open_or_close": "Cupboard Open or Close", + "drawer_open_or_close": "Drawer Open or Close", + "dishes": "Dishes", + "cutlery": "Cutlery", + "chopping": "Chopping", + "frying": "Frying", + "microwave_oven": "Microwave Oven", + "blender": "Blender", + "water_tap": "Water Tap", + "sink": "Sink", + "bathtub": "Bathtub", + "hair_dryer": "Hair Dryer", + "toilet_flush": "Toilet Flush", + "toothbrush": "Toothbrush", + "electric_toothbrush": "Electric Toothbrush", + "vacuum_cleaner": "Vacuum Cleaner", + "zipper": "Zipper", + "keys_jangling": "Keys Jangling", + "coin": "Coin", + "scissors": "Scissors", + "electric_shaver": "Electric Shaver", + "shuffling_cards": "Shuffling Cards", + "typing": "Typing", + "typewriter": "Typewriter", + "computer_keyboard": "Computer Keyboard", + "writing": "Writing", + "alarm": "Alarm", + "telephone": "Telephone", + "telephone_bell_ringing": "Telephone Bell Ringing", + "ringtone": "Ringtone", + "telephone_dialing": "Telephone Dialing", + "dial_tone": "Dial Tone", + "busy_signal": "Busy Signal", + "alarm_clock": "Alarm Clock", + "siren": "Siren", + "civil_defense_siren": "Civil Defense Siren", + "buzzer": "Buzzer", + "smoke_detector": "Smoke Detector", + "fire_alarm": "Fire Alarm", + "foghorn": "Foghorn", + "whistle": "Whistle", + "steam_whistle": "Steam Whistle", + "mechanisms": "Mechanisms", + "ratchet": "Ratchet", + "clock": "Clock", + "tick": "Tick", + "tick-tock": "Tick-Tock", + "gears": "Gears", + "pulleys": "Pulleys", + "sewing_machine": "Sewing Machine", + "mechanical_fan": "Mechanical Fan", + "air_conditioning": "Air Conditioning", + "cash_register": "Cash Register", + "printer": "Printer", + "camera": "Camera", + "single-lens_reflex_camera": "Single-Lens Reflex Camera", + "tools": "Tools", + "hammer": "Hammer", + "jackhammer": "Jackhammer", + "sawing": "Sawing", + "filing": "Filing", + "sanding": "Sanding", + "power_tool": "Power Tool", + "drill": "Drill", + "explosion": "Explosion", + "gunshot": "Gunshot", + "machine_gun": "Machine Gun", + "fusillade": "Fusillade", + "artillery_fire": "Artillery Fire", + "cap_gun": "Cap Gun", + "fireworks": "Fireworks", + "firecracker": "Firecracker", + "burst": "Burst", + "eruption": "Eruption", + "boom": "Boom", + "wood": "Wood", + "chop": "Chop", + "splinter": "Splinter", + "crack": "Crack", + "glass": "Glass", + "chink": "Chink", + "shatter": "Shatter", + "silence": "Silence", + "sound_effect": "Sound Effect", + "environmental_noise": "Environmental Noise", + "static": "Static", + "white_noise": "White Noise", + "pink_noise": "Pink Noise", + "television": "Television", + "radio": "Radio", + "field_recording": "Field Recording", + "scream": "Scream" +} diff --git a/web/public/locales/en/common.json b/web/public/locales/en/common.json new file mode 100644 index 000000000..56aa659e6 --- /dev/null +++ b/web/public/locales/en/common.json @@ -0,0 +1,252 @@ +{ + "time": { + "untilForTime": "Until {{time}}", + "untilForRestart": "Until Frigate restarts.", + "untilRestart": "Until restart", + "ago": "{{timeAgo}} ago", + "justNow": "Just now", + "today": "Today", + "yesterday": "Yesterday", + "last7": "Last 7 days", + "last14": "Last 14 days", + "last30": "Last 30 days", + "thisWeek": "This Week", + "lastWeek": "Last Week", + "thisMonth": "This Month", + "lastMonth": "Last Month", + "5minutes": "5 minutes", + "10minutes": "10 minutes", + "30minutes": "30 minutes", + "1hour": "1 hour", + "12hours": "12 hours", + "24hours": "24 hours", + "pm": "pm", + "am": "am", + "yr": "{{time}}yr", + "year_one": "{{time}} year", + "year_other": "{{time}} years", + "mo": "{{time}}mo", + "month_one": "{{time}} month", + "month_other": "{{time}} months", + "d": "{{time}}d", + "day_one": "{{time}} day", + "day_other": "{{time}} days", + "h": "{{time}}h", + "hour_one": "{{time}} hour", + "hour_other": "{{time}} hours", + "m": "{{time}}m", + "minute_one": "{{time}} minute", + "minute_other": "{{time}} minutes", + "s": "{{time}}s", + "second_one": "{{time}} second", + "second_other": "{{time}} seconds", + "formattedTimestamp": { + "12hour": "MMM d, h:mm:ss aaa", + "24hour": "MMM d, HH:mm:ss" + }, + "formattedTimestamp2": { + "12hour": "MM/dd h:mm:ssa", + "24hour": "d MMM HH:mm:ss" + }, + "formattedTimestampHourMinute": { + "12hour": "h:mm aaa", + "24hour": "HH:mm" + }, + "formattedTimestampHourMinuteSecond": { + "12hour": "h:mm:ss aaa", + "24hour": "HH:mm:ss" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "MMM d, h:mm aaa", + "24hour": "MMM d, HH:mm" + }, + "formattedTimestampMonthDayYear": { + "12hour": "MMM d, yyyy", + "24hour": "MMM d, yyyy" + }, + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "MMM d yyyy, h:mm aaa", + "24hour": "MMM d yyyy, HH:mm" + }, + "formattedTimestampMonthDay": "MMM d", + "formattedTimestampFilename": { + "12hour": "MM-dd-yy-h-mm-ss-a", + "24hour": "MM-dd-yy-HH-mm-ss" + } + }, + "unit": { + "speed": { + "mph": "mph", + "kph": "kph" + } + }, + "label": { + "back": "Go back" + }, + "button": { + "apply": "Apply", + "reset": "Reset", + "done": "Done", + "enabled": "Enabled", + "enable": "Enable", + "disabled": "Disabled", + "disable": "Disable", + "save": "Save", + "saving": "Saving…", + "cancel": "Cancel", + "close": "Close", + "copy": "Copy", + "back": "Back", + "history": "History", + "fullscreen": "Fullscreen", + "exitFullscreen": "Exit Fullscreen", + "pictureInPicture": "Picture in Picture", + "twoWayTalk": "Two Way Talk", + "cameraAudio": "Camera Audio", + "on": "ON", + "off": "OFF", + "edit": "Edit", + "copyCoordinates": "Copy coordinates", + "delete": "Delete", + "yes": "Yes", + "no": "No", + "download": "Download", + "info": "Info", + "suspended": "Suspended", + "unsuspended": "Unsuspend", + "play": "Play", + "unselect": "Unselect", + "export": "Export", + "deleteNow": "Delete Now", + "next": "Next" + }, + "menu": { + "system": "System", + "systemMetrics": "System metrics", + "configuration": "Configuration", + "systemLogs": "System logs", + "settings": "Settings", + "configurationEditor": "Configuration Editor", + "languages": "Languages", + "language": { + "en": "English (English)", + "es": "Español (Spanish)", + "zhCN": "简体中文 (Simplified Chinese)", + "hi": "हिन्दी (Hindi)", + "fr": "Français (French)", + "ar": "العربية (Arabic)", + "pt": "Português (Portuguese)", + "ru": "Русский (Russian)", + "de": "Deutsch (German)", + "ja": "日本語 (Japanese)", + "tr": "Türkçe (Turkish)", + "it": "Italiano (Italian)", + "nl": "Nederlands (Dutch)", + "sv": "Svenska (Swedish)", + "cs": "Čeština (Czech)", + "nb": "Norsk Bokmål (Norwegian Bokmål)", + "ko": "한국어 (Korean)", + "vi": "Tiếng Việt (Vietnamese)", + "fa": "فارسی (Persian)", + "pl": "Polski (Polish)", + "uk": "Українська (Ukrainian)", + "he": "עברית (Hebrew)", + "el": "Ελληνικά (Greek)", + "ro": "Română (Romanian)", + "hu": "Magyar (Hungarian)", + "fi": "Suomi (Finnish)", + "da": "Dansk (Danish)", + "sk": "Slovenčina (Slovak)", + "yue": "粵語 (Cantonese)", + "withSystem": { + "label": "Use the system settings for language" + } + }, + "appearance": "Appearance", + "darkMode": { + "label": "Dark Mode", + "light": "Light", + "dark": "Dark", + "withSystem": { + "label": "Use the system settings for light or dark mode" + } + }, + "withSystem": "System", + "theme": { + "label": "Theme", + "blue": "Blue", + "green": "Green", + "nord": "Nord", + "red": "Red", + "highcontrast": "High Contrast", + "default": "Default" + }, + "help": "Help", + "documentation": { + "title": "Documentation", + "label": "Frigate documentation" + }, + "restart": "Restart Frigate", + "live": { + "title": "Live", + "allCameras": "All Cameras", + "cameras": { + "title": "Cameras", + "count_one": "{{count}} Camera", + "count_other": "{{count}} Cameras" + } + }, + "review": "Review", + "explore": "Explore", + "export": "Export", + "uiPlayground": "UI Playground", + "faceLibrary": "Face Library", + "user": { + "title": "User", + "account": "Account", + "current": "Current User: {{user}}", + "anonymous": "anonymous", + "logout": "Logout", + "setPassword": "Set Password" + } + }, + "toast": { + "copyUrlToClipboard": "Copied URL to clipboard.", + "save": { + "title": "Save", + "error": { + "title": "Failed to save config changes: {{errorMessage}}", + "noMessage": "Failed to save config changes" + } + } + }, + "role": { + "title": "Role", + "admin": "Admin", + "viewer": "Viewer", + "desc": "Admins have full access to all features in the Frigate UI. Viewers are limited to viewing cameras, review items, and historical footage in the UI." + }, + "pagination": { + "label": "pagination", + "previous": { + "title": "Previous", + "label": "Go to previous page" + }, + "next": { + "title": "Next", + "label": "Go to next page" + }, + "more": "More pages" + }, + "accessDenied": { + "documentTitle": "Access Denied - Frigate", + "title": "Access Denied", + "desc": "You don't have permission to view this page." + }, + "notFound": { + "documentTitle": "Not Found - Frigate", + "title": "404", + "desc": "Page not found" + }, + "selectItem": "Select {{item}}" +} diff --git a/web/public/locales/en/components/auth.json b/web/public/locales/en/components/auth.json new file mode 100644 index 000000000..05c2a779f --- /dev/null +++ b/web/public/locales/en/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "user": "Username", + "password": "Password", + "login": "Login", + "errors": { + "usernameRequired": "Username is required", + "passwordRequired": "Password is required", + "rateLimit": "Exceeded rate limit. Try again later.", + "loginFailed": "Login failed", + "unknownError": "Unknown error. Check logs.", + "webUnknownError": "Unknown error. Check console logs." + } + } +} diff --git a/web/public/locales/en/components/camera.json b/web/public/locales/en/components/camera.json new file mode 100644 index 000000000..4a1495326 --- /dev/null +++ b/web/public/locales/en/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "label": "Camera Groups", + "add": "Add Camera Group", + "edit": "Edit Camera Group", + "delete": { + "label": "Delete Camera Group", + "confirm": { + "title": "Confirm Delete", + "desc": "Are you sure you want to delete the camera group {{name}}?" + } + }, + "name": { + "label": "Name", + "placeholder": "Enter a name…", + "errorMessage": { + "mustLeastCharacters": "Camera group name must be at least 2 characters.", + "exists": "Camera group name already exists.", + "nameMustNotPeriod": "Camera group name must not contain a period.", + "invalid": "Invalid camera group name." + } + }, + "cameras": { + "label": "Cameras", + "desc": "Select cameras for this group." + }, + "icon": "Icon", + "success": "Camera group ({{name}}) has been saved.", + "camera": { + "setting": { + "label": "Camera Streaming Settings", + "title": "{{cameraName}} Streaming Settings", + "desc": "Change the live streaming options for this camera group's dashboard. These settings are device/browser-specific.", + "audioIsAvailable": "Audio is available for this stream", + "audioIsUnavailable": "Audio is unavailable for this stream", + "audio": { + "tips": { + "title": "Audio must be output from your camera and configured in go2rtc for this stream.", + "document": "Read the documentation " + } + }, + "streamMethod": { + "label": "Streaming Method", + "method": { + "noStreaming": { + "label": "No Streaming", + "desc": "Camera images will only update once per minute and no live streaming will occur." + }, + "smartStreaming": { + "label": "Smart Streaming (recommended)", + "desc": "Smart streaming will update your camera image once per minute when no detectable activity is occurring to conserve bandwidth and resources. When activity is detected, the image seamlessly switches to a live stream." + }, + "continuousStreaming": { + "label": "Continuous Streaming", + "desc": { + "title": "Camera image will always be a live stream when visible on the dashboard, even if no activity is being detected.", + "warning": "Continuous streaming may cause high bandwidth usage and performance issues. Use with caution." + } + } + } + }, + "compatibilityMode": { + "label": "Compatibility mode", + "desc": "Enable this option only if your camera's live stream is displaying color artifacts and has a diagonal line on the right side of the image." + } + } + } + }, + "debug": { + "options": { + "label": "Settings", + "title": "Options", + "showOptions": "Show Options", + "hideOptions": "Hide Options" + }, + "boundingBox": "Bounding Box", + "timestamp": "Timestamp", + "zones": "Zones", + "mask": "Mask", + "motion": "Motion", + "regions": "Regions" + } +} diff --git a/web/public/locales/en/components/dialog.json b/web/public/locales/en/components/dialog.json new file mode 100644 index 000000000..8b2dc0b88 --- /dev/null +++ b/web/public/locales/en/components/dialog.json @@ -0,0 +1,113 @@ +{ + "restart": { + "title": "Are you sure you want to restart Frigate?", + "button": "Restart", + "restarting": { + "title": "Frigate is Restarting", + "content": "This page will reload in {{countdown}} seconds.", + "button": "Force Reload Now" + } + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "Submit To Frigate+", + "desc": "Objects in locations you want to avoid are not false positives. Submitting them as false positives will confuse the model." + }, + "review": { + "question": { + "label": "Confirm this label for Frigate Plus", + "ask_a": "Is this object a {{label}}?", + "ask_an": "Is this object an {{label}}?", + "ask_full": "Is this object a {{untranslatedLabel}} ({{translatedLabel}})?" + }, + "state": { + "submitted": "Submitted" + } + } + }, + "video": { + "viewInHistory": "View in History" + } + }, + "export": { + "time": { + "fromTimeline": "Select from Timeline", + "lastHour_one": "Last Hour", + "lastHour_other": "Last {{count}} Hours", + "custom": "Custom", + "start": { + "title": "Start Time", + "label": "Select Start Time" + }, + "end": { + "title": "End Time", + "label": "Select End Time" + } + }, + "name": { + "placeholder": "Name the Export" + }, + "select": "Select", + "export": "Export", + "selectOrExport": "Select or Export", + "toast": { + "success": "Successfully started export. View the file in the /exports folder.", + "error": { + "failed": "Failed to start export: {{error}}", + "endTimeMustAfterStartTime": "End time must be after start time", + "noVaildTimeSelected": "No valid time range selected" + } + }, + "fromTimeline": { + "saveExport": "Save Export", + "previewExport": "Preview Export" + } + }, + "streaming": { + "label": "Stream", + "restreaming": { + "disabled": "Restreaming is not enabled for this camera.", + "desc": { + "title": "Set up go2rtc for additional live view options and audio for this camera.", + "readTheDocumentation": "Read the documentation" + } + }, + "showStats": { + "label": "Show stream stats", + "desc": "Enable this option to show stream statistics as an overlay on the camera feed." + }, + "debugView": "Debug View" + }, + "search": { + "saveSearch": { + "label": "Save Search", + "desc": "Provide a name for this saved search.", + "placeholder": "Enter a name for your search", + "overwrite": "{{searchName}} already exists. Saving will overwrite the existing value.", + "success": "Search ({{searchName}}) has been saved.", + "button": { + "save": { + "label": "Save this search" + } + } + } + }, + "recording": { + "confirmDelete": { + "title": "Confirm Delete", + "desc": { + "selected": "Are you sure you want to delete all recorded video associated with this review item?

    Hold the Shift key to bypass this dialog in the future." + }, + "toast": { + "success": "Video footage associated with the selected review items has been deleted successfully.", + "error": "Failed to delete: {{error}}" + } + }, + "button": { + "export": "Export", + "markAsReviewed": "Mark as reviewed", + "deleteNow": "Delete Now" + } + } +} diff --git a/web/public/locales/en/components/filter.json b/web/public/locales/en/components/filter.json new file mode 100644 index 000000000..7ec5c752e --- /dev/null +++ b/web/public/locales/en/components/filter.json @@ -0,0 +1,125 @@ +{ + "filter": "Filter", + "labels": { + "label": "Labels", + "all": { + "title": "All Labels", + "short": "Labels" + }, + "count_one": "{{count}} Label", + "count_other": "{{count}} Labels" + }, + "zones": { + "label": "Zones", + "all": { + "title": "All Zones", + "short": "Zones" + } + }, + "dates": { + "all": { + "title": "All Dates", + "short": "Dates" + } + }, + "more": "More Filters", + "reset": { + "label": "Reset filters to default values" + }, + "timeRange": "Time Range", + "subLabels": { + "label": "Sub Labels", + "all": "All Sub Labels" + }, + "score": "Score", + "estimatedSpeed": "Estimated Speed ({{unit}})", + "features": { + "label": "Features", + "hasSnapshot": "Has a snapshot", + "hasVideoClip": "Has a video clip", + "submittedToFrigatePlus": { + "label": "Submitted to Frigate+", + "tips": "You must first filter on tracked objects that have a snapshot.

    Tracked objects without a snapshot cannot be submitted to Frigate+." + } + }, + "sort": { + "label": "Sort", + "dateAsc": "Date (Ascending)", + "dateDesc": "Date (Descending)", + "scoreAsc": "Object Score (Ascending)", + "scoreDesc": "Object Score (Descending)", + "speedAsc": "Estimated Speed (Ascending)", + "speedDesc": "Estimated Speed (Descending)", + "relevance": "Relevance" + }, + "cameras": { + "label": "Cameras Filter", + "all": { + "title": "All Cameras", + "short": "Cameras" + } + }, + "review": { + "showReviewed": "Show Reviewed" + }, + "motion": { + "showMotionOnly": "Show Motion Only" + }, + "explore": { + "settings": { + "title": "Settings", + "defaultView": { + "title": "Default View", + "desc": "When no filters are selected, display a summary of the most recent tracked objects per label, or display an unfiltered grid.", + "summary": "Summary", + "unfilteredGrid": "Unfiltered Grid" + }, + "gridColumns": { + "title": "Grid Columns", + "desc": "Select the number of columns in the grid view." + }, + "searchSource": { + "label": "Search Source", + "desc": "Choose whether to search the thumbnails or descriptions of your tracked objects.", + "options": { + "thumbnailImage": "Thumbnail Image", + "description": "Description" + } + } + }, + "date": { + "selectDateBy": { + "label": "Select a date to filter by" + } + } + }, + "logSettings": { + "label": "Filter log level", + "filterBySeverity": "Filter logs by severity", + "loading": { + "title": "Loading", + "desc": "When the log pane is scrolled to the bottom, new logs automatically stream as they are added." + }, + "disableLogStreaming": "Disable log streaming", + "allLogs": "All logs" + }, + "trackedObjectDelete": { + "title": "Confirm Delete", + "desc": "Deleting these {{objectLength}} tracked objects removes the snapshot, any saved embeddings, and any associated object lifecycle entries. Recorded footage of these tracked objects in History view will NOT be deleted.

    Are you sure you want to proceed?

    Hold the Shift key to bypass this dialog in the future.", + "toast": { + "success": "Tracked objects deleted successfully.", + "error": "Failed to delete tracked objects: {{errorMessage}}" + } + }, + "zoneMask": { + "filterBy": "Filter by zone mask" + }, + "recognizedLicensePlates": { + "title": "Recognized License Plates", + "loadFailed": "Failed to load recognized license plates.", + "loading": "Loading recognized license plates…", + "placeholder": "Type to search license plates…", + "noLicensePlatesFound": "No license plates found.", + "selectPlatesFromList": "Select one or more plates from the list." + } +} diff --git a/web/public/locales/en/components/icons.json b/web/public/locales/en/components/icons.json new file mode 100644 index 000000000..e7a35a737 --- /dev/null +++ b/web/public/locales/en/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "Select an icon", + "search": { + "placeholder": "Search for an icon…" + } + } +} diff --git a/web/public/locales/en/components/input.json b/web/public/locales/en/components/input.json new file mode 100644 index 000000000..7a9e35942 --- /dev/null +++ b/web/public/locales/en/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Download Video", + "toast": { + "success": "Your review item video has started downloading." + } + } + } +} diff --git a/web/public/locales/en/components/player.json b/web/public/locales/en/components/player.json new file mode 100644 index 000000000..3b50ff5ed --- /dev/null +++ b/web/public/locales/en/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "No recordings found for this time", + "noPreviewFound": "No Preview Found", + "noPreviewFoundFor": "No Preview Found for {{cameraName}}", + "submitFrigatePlus": { + "title": "Submit this frame to Frigate+?", + "submit": "Submit" + }, + "livePlayerRequiredIOSVersion": "iOS 17.1 or greater is required for this live stream type.", + "streamOffline": { + "title": "Stream Offline", + "desc": "No frames have been received on the {{cameraName}} detect stream, check error logs" + }, + "cameraDisabled": "Camera is disabled", + "stats": { + "streamType": { + "title": "Stream Type:", + "short": "Type" + }, + "bandwidth": { + "title": "Bandwidth:", + "short": "Bandwidth" + }, + "latency": { + "title": "Latency:", + "value": "{{seconds}} seconds", + "short": { + "title": "Latency", + "value": "{{seconds}} sec" + } + }, + "totalFrames": "Total Frames:", + "droppedFrames": { + "title": "Dropped Frames:", + "short": { + "title": "Dropped", + "value": "{{droppedFrames}} frames" + } + }, + "decodedFrames": "Decoded Frames:", + "droppedFrameRate": "Dropped Frame Rate:" + }, + "toast": { + "success": { + "submittedFrigatePlus": "Successfully submitted frame to Frigate+" + }, + "error": { + "submitFrigatePlusFailed": "Failed to submit frame to Frigate+" + } + } +} diff --git a/web/public/locales/en/objects.json b/web/public/locales/en/objects.json new file mode 100644 index 000000000..130bfcc53 --- /dev/null +++ b/web/public/locales/en/objects.json @@ -0,0 +1,120 @@ +{ + "person": "Person", + "bicycle": "Bicycle", + "car": "Car", + "motorcycle": "Motorcycle", + "airplane": "Airplane", + "bus": "Bus", + "train": "Train", + "boat": "Boat", + "traffic_light": "Traffic Light", + "fire_hydrant": "Fire Hydrant", + "street_sign": "Street Sign", + "stop_sign": "Stop Sign", + "parking_meter": "Parking Meter", + "bench": "Bench", + "bird": "Bird", + "cat": "Cat", + "dog": "Dog", + "horse": "Horse", + "sheep": "Sheep", + "cow": "Cow", + "elephant": "Elephant", + "bear": "Bear", + "zebra": "Zebra", + "giraffe": "Giraffe", + "hat": "Hat", + "backpack": "Backpack", + "umbrella": "Umbrella", + "shoe": "Shoe", + "eye_glasses": "Eye Glasses", + "handbag": "Handbag", + "tie": "Tie", + "suitcase": "Suitcase", + "frisbee": "Frisbee", + "skis": "Skis", + "snowboard": "Snowboard", + "sports_ball": "Sports Ball", + "kite": "Kite", + "baseball_bat": "Baseball Bat", + "baseball_glove": "Baseball Glove", + "skateboard": "Skateboard", + "surfboard": "Surfboard", + "tennis_racket": "Tennis Racket", + "bottle": "Bottle", + "plate": "Plate", + "wine_glass": "Wine Glass", + "cup": "Cup", + "fork": "Fork", + "knife": "Knife", + "spoon": "Spoon", + "bowl": "Bowl", + "banana": "Banana", + "apple": "Apple", + "sandwich": "Sandwich", + "orange": "Orange", + "broccoli": "Broccoli", + "carrot": "Carrot", + "hot_dog": "Hot Dog", + "pizza": "Pizza", + "donut": "Donut", + "cake": "Cake", + "chair": "Chair", + "couch": "Couch", + "potted_plant": "Potted Plant", + "bed": "Bed", + "mirror": "Mirror", + "dining_table": "Dining Table", + "window": "Window", + "desk": "Desk", + "toilet": "Toilet", + "door": "Door", + "tv": "TV", + "laptop": "Laptop", + "mouse": "Mouse", + "remote": "Remote", + "keyboard": "Keyboard", + "cell_phone": "Cell Phone", + "microwave": "Microwave", + "oven": "Oven", + "toaster": "Toaster", + "sink": "Sink", + "refrigerator": "Refrigerator", + "blender": "Blender", + "book": "Book", + "clock": "Clock", + "vase": "Vase", + "scissors": "Scissors", + "teddy_bear": "Teddy Bear", + "hair_dryer": "Hair Dryer", + "toothbrush": "Toothbrush", + "hair_brush": "Hair Brush", + "vehicle": "Vehicle", + "squirrel": "Squirrel", + "deer": "Deer", + "animal": "Animal", + "bark": "Bark", + "fox": "Fox", + "goat": "Goat", + "rabbit": "Rabbit", + "raccoon": "Raccoon", + "robot_lawnmower": "Robot Lawnmower", + "waste_bin": "Waste Bin", + "on_demand": "On Demand", + "face": "Face", + "license_plate": "License Plate", + "package": "Package", + "bbq_grill": "BBQ Grill", + "amazon": "Amazon", + "usps": "USPS", + "ups": "UPS", + "fedex": "FedEx", + "dhl": "DHL", + "an_post": "An Post", + "purolator": "Purolator", + "postnl": "PostNL", + "nzpost": "NZPost", + "postnord": "PostNord", + "gls": "GLS", + "dpd": "DPD" +} diff --git a/web/public/locales/en/views/configEditor.json b/web/public/locales/en/views/configEditor.json new file mode 100644 index 000000000..8d319bbc2 --- /dev/null +++ b/web/public/locales/en/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "documentTitle": "Config Editor - Frigate", + "configEditor": "Config Editor", + "copyConfig": "Copy Config", + "saveAndRestart": "Save & Restart", + "saveOnly": "Save Only", + "toast": { + "success": { + "copyToClipboard": "Config copied to clipboard." + }, + "error": { + "savingError": "Error saving config" + } + } +} diff --git a/web/public/locales/en/views/events.json b/web/public/locales/en/views/events.json new file mode 100644 index 000000000..98bc7c422 --- /dev/null +++ b/web/public/locales/en/views/events.json @@ -0,0 +1,38 @@ +{ + "alerts": "Alerts", + "detections": "Detections", + "motion": { + "label": "Motion", + "only": "Motion only" + }, + "allCameras": "All Cameras", + "empty": { + "alert": "There are no alerts to review", + "detection": "There are no detections to review", + "motion": "No motion data found" + }, + "timeline": "Timeline", + "timeline.aria": "Select timeline", + "events": { + "label": "Events", + "aria": "Select events", + "noFoundForTimePeriod": "No events found for this time period." + }, + "documentTitle": "Review - Frigate", + "recordings": { + "documentTitle": "Recordings - Frigate" + }, + "calendarFilter": { + "last24Hours": "Last 24 Hours" + }, + "markAsReviewed": "Mark as Reviewed", + "markTheseItemsAsReviewed": "Mark these items as reviewed", + "newReviewItems": { + "label": "View new review items", + "button": "New Items To Review" + }, + "selected_one": "{{count}} selected", + "selected_other": "{{count}} selected", + "camera": "Camera", + "detected": "detected" +} diff --git a/web/public/locales/en/views/explore.json b/web/public/locales/en/views/explore.json new file mode 100644 index 000000000..e8a5153ee --- /dev/null +++ b/web/public/locales/en/views/explore.json @@ -0,0 +1,201 @@ +{ + "documentTitle": "Explore - Frigate", + "generativeAI": "Generative AI", + "exploreIsUnavailable": { + "title": "Explore is Unavailable", + "embeddingsReindexing": { + "context": "Explore can be used after tracked object embeddings have finished reindexing.", + "startingUp": "Starting up…", + "estimatedTime": "Estimated time remaining:", + "finishingShortly": "Finishing shortly", + "step": { + "thumbnailsEmbedded": "Thumbnails embedded: ", + "descriptionsEmbedded": "Descriptions embedded: ", + "trackedObjectsProcessed": "Tracked objects processed: " + } + }, + "downloadingModels": { + "context": "Frigate is downloading the necessary embeddings models to support the Semantic Search feature. This may take several minutes depending on the speed of your network connection.", + "setup": { + "visionModel": "Vision model", + "visionModelFeatureExtractor": "Vision model feature extractor", + "textModel": "Text model", + "textTokenizer": "Text tokenizer" + }, + "tips": { + "context": "You may want to reindex the embeddings of your tracked objects once the models are downloaded.", + "documentation": "Read the documentation" + }, + "error": "An error has occurred. Check Frigate logs." + } + }, + "trackedObjectDetails": "Tracked Object Details", + "type": { + "details": "details", + "snapshot": "snapshot", + "video": "video", + "object_lifecycle": "object lifecycle" + }, + "objectLifecycle": { + "title": "Object Lifecycle", + "noImageFound": "No image found for this timestamp.", + "createObjectMask": "Create Object Mask", + "adjustAnnotationSettings": "Adjust annotation settings", + "scrollViewTips": "Scroll to view the significant moments of this object's lifecycle.", + "autoTrackingTips": "Bounding box positions will be inaccurate for autotracking cameras.", + "lifecycleItemDesc": { + "visible": "{{label}} detected", + "entered_zone": "{{label}} entered {{zones}}", + "active": "{{label}} became active", + "stationary": "{{label}} became stationary", + "attribute": { + "faceOrLicense_plate": "{{attribute}} detected for {{label}}", + "other": "{{label}} recognized as {{attribute}}" + }, + "gone": "{{label}} left", + "heard": "{{label}} heard", + "external": "{{label}} detected", + "header": { + "zones": "Zones", + "ratio": "Ratio", + "area": "Area" + } + }, + "annotationSettings": { + "title": "Annotation Settings", + "showAllZones": { + "title": "Show All Zones", + "desc": "Always show zones on frames where objects have entered a zone." + }, + "offset": { + "label": "Annotation Offset", + "desc": "This data comes from your camera's detect feed but is overlayed on images from the the record feed. It is unlikely that the two streams are perfectly in sync. As a result, the bounding box and the footage will not line up perfectly. However, the annotation_offset field can be used to adjust this.", + "documentation": "Read the documentation ", + "millisecondsToOffset": "Milliseconds to offset detect annotations by. Default: 0", + "tips": "TIP: Imagine there is an event clip with a person walking from left to right. If the event timeline bounding box is consistently to the left of the person then the value should be decreased. Similarly, if a person is walking from left to right and the bounding box is consistently ahead of the person then the value should be increased." + } + }, + "carousel": { + "previous": "Previous slide", + "next": "Next slide" + } + }, + "details": { + "item": { + "title": "Review Item Details", + "desc": "Review item details", + "button": { + "share": "Share this review item", + "viewInExplore": "View in Explore" + }, + "tips": { + "mismatch_one": "{{count}} unavailable object was detected and included in this review item. Those objects either did not qualify as an alert or detection or have already been cleaned up/deleted.", + "mismatch_other": "{{count}} unavailable objects were detected and included in this review item. Those objects either did not qualify as an alert or detection or have already been cleaned up/deleted.", + "hasMissingObjects": "Adjust your configuration if you want Frigate to save tracked objects for the following labels: {{objects}}" + }, + "toast": { + "success": { + "regenerate": "A new description has been requested from {{provider}}. Depending on the speed of your provider, the new description may take some time to regenerate.", + "updatedSublabel": "Successfully updated sub label.", + "updatedLPR": "Successfully updated license plate." + }, + "error": { + "regenerate": "Failed to call {{provider}} for a new description: {{errorMessage}}", + "updatedSublabelFailed": "Failed to update sub label: {{errorMessage}}", + "updatedLPRFailed": "Failed to update license plate: {{errorMessage}}" + } + } + }, + "label": "Label", + "editSubLabel": { + "title": "Edit sub label", + "desc": "Enter a new sub label for this {{label}}", + "descNoLabel": "Enter a new sub label for this tracked object" + }, + "editLPR": { + "title": "Edit license plate", + "desc": "Enter a new license plate value for this {{label}}", + "descNoLabel": "Enter a new license plate value for this tracked object" + }, + "snapshotScore": { + "label": "Snapshot Score" + }, + "topScore": { + "label": "Top Score", + "info": "The top score is the highest median score for the tracked object, so this may differ from the score shown on the search result thumbnail." + }, + "recognizedLicensePlate": "Recognized License Plate", + "estimatedSpeed": "Estimated Speed", + "objects": "Objects", + "camera": "Camera", + "zones": "Zones", + "timestamp": "Timestamp", + "button": { + "findSimilar": "Find Similar", + "regenerate": { + "title": "Regenerate", + "label": "Regenerate tracked object description" + } + }, + "description": { + "label": "Description", + "placeholder": "Description of the tracked object", + "aiTips": "Frigate will not request a description from your Generative AI provider until the tracked object's lifecycle has ended." + }, + "expandRegenerationMenu": "Expand regeneration menu", + "regenerateFromSnapshot": "Regenerate from Snapshot", + "regenerateFromThumbnails": "Regenerate from Thumbnails", + "tips": { + "descriptionSaved": "Successfully saved description", + "saveDescriptionFailed": "Failed to update the description: {{errorMessage}}" + } + }, + "itemMenu": { + "downloadVideo": { + "label": "Download video", + "aria": "Download video" + }, + "downloadSnapshot": { + "label": "Download snapshot", + "aria": "Download snapshot" + }, + "viewObjectLifecycle": { + "label": "View object lifecycle", + "aria": "Show the object lifecycle" + }, + "findSimilar": { + "label": "Find similar", + "aria": "Find similar tracked objects" + }, + "submitToPlus": { + "label": "Submit to Frigate+", + "aria": "Submit to Frigate Plus" + }, + "viewInHistory": { + "label": "View in History", + "aria": "View in History" + }, + "deleteTrackedObject": { + "label": "Delete this tracked object" + } + }, + "dialog": { + "confirmDelete": { + "title": "Confirm Delete", + "desc": "Deleting this tracked object removes the snapshot, any saved embeddings, and any associated object lifecycle entries. Recorded footage of this tracked object in History view will NOT be deleted.

    Are you sure you want to proceed?" + } + }, + "noTrackedObjects": "No Tracked Objects Found", + "fetchingTrackedObjectsFailed": "Error fetching tracked objects: {{errorMessage}}", + "trackedObjectsCount_one": "{{count}} tracked object ", + "trackedObjectsCount_other": "{{count}} tracked objects ", + "searchResult": { + "tooltip": "Matched {{type}} at {{confidence}}%", + "deleteTrackedObject": { + "toast": { + "success": "Tracked object deleted successfully.", + "error": "Failed to delete tracked object: {{errorMessage}}" + } + } + } +} diff --git a/web/public/locales/en/views/exports.json b/web/public/locales/en/views/exports.json new file mode 100644 index 000000000..729899443 --- /dev/null +++ b/web/public/locales/en/views/exports.json @@ -0,0 +1,17 @@ +{ + "documentTitle": "Export - Frigate", + "search": "Search", + "noExports": "No exports found", + "deleteExport": "Delete Export", + "deleteExport.desc": "Are you sure you want to delete {{exportName}}?", + "editExport": { + "title": "Rename Export", + "desc": "Enter a new name for this export.", + "saveExport": "Save Export" + }, + "toast": { + "error": { + "renameExportFailed": "Failed to rename export: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/en/views/faceLibrary.json b/web/public/locales/en/views/faceLibrary.json new file mode 100644 index 000000000..bb5f7e9e0 --- /dev/null +++ b/web/public/locales/en/views/faceLibrary.json @@ -0,0 +1,98 @@ +{ + "description": { + "addFace": "Walk through adding a new collection to the Face Library.", + "placeholder": "Enter a name for this collection" + }, + "details": { + "person": "Person", + "subLabelScore": "Sub Label Score", + "scoreInfo": "The sub label score is the weighted score for all of the recognized face confidences, so this may differ from the score shown on the snapshot.", + "face": "Face Details", + "faceDesc": "Details of the tracked object that generated this face", + "timestamp": "Timestamp", + "unknown": "Unknown" + }, + "documentTitle": "Face Library - Frigate", + "uploadFaceImage": { + "title": "Upload Face Image", + "desc": "Upload an image to scan for faces and include for {{pageToggle}}" + }, + "collections": "Collections", + "createFaceLibrary": { + "title": "Create Collection", + "desc": "Create a new collection", + "new": "Create New Face", + "nextSteps": "To build a strong foundation:
  • Use the Train tab to select and train on images for each detected person.
  • Focus on straight-on images for best results; avoid training images that capture faces at an angle.
  • " + }, + "steps": { + "faceName": "Enter Face Name", + "uploadFace": "Upload Face Image", + "nextSteps": "Next Steps", + "description": { + "uploadFace": "Upload an image of {{name}} that shows their face from a front-facing angle. The image does not need to be cropped to just their face." + } + }, + "train": { + "title": "Train", + "aria": "Select train", + "empty": "There are no recent face recognition attempts" + }, + "selectItem": "Select {{item}}", + "selectFace": "Select Face", + "deleteFaceLibrary": { + "title": "Delete Name", + "desc": "Are you sure you want to delete the collection {{name}}? This will permanently delete all associated faces." + }, + "deleteFaceAttempts": { + "title": "Delete Faces", + "desc_one": "Are you sure you want to delete {{count}} face? This action cannot be undone.", + "desc_other": "Are you sure you want to delete {{count}} faces? This action cannot be undone." + }, + "renameFace": { + "title": "Rename Face", + "desc": "Enter a new name for {{name}}" + }, + "button": { + "deleteFaceAttempts": "Delete Faces", + "addFace": "Add Face", + "renameFace": "Rename Face", + "deleteFace": "Delete Face", + "uploadImage": "Upload Image", + "reprocessFace": "Reprocess Face" + }, + "imageEntry": { + "validation": { + "selectImage": "Please select an image file." + }, + "dropActive": "Drop the image here…", + "dropInstructions": "Drag and drop an image here, or click to select", + "maxSize": "Max size: {{size}}MB" + }, + "nofaces": "No faces available", + "readTheDocs": "Read the documentation", + "trainFaceAs": "Train Face as:", + "trainFace": "Train Face", + "toast": { + "success": { + "uploadedImage": "Successfully uploaded image.", + "addFaceLibrary": "{{name}} has successfully been added to the Face Library!", + "deletedFace_one": "Successfully deleted {{count}} face.", + "deletedFace_other": "Successfully deleted {{count}} faces.", + "deletedName_zero": "Empty collection deleted successfully.", + "deletedName_one": "{{count}} face has been successfully deleted.", + "deletedName_other": "{{count}} faces have been successfully deleted.", + "renamedFace": "Successfully renamed face to {{name}}", + "trainedFace": "Successfully trained face.", + "updatedFaceScore": "Successfully updated face score." + }, + "error": { + "uploadingImageFailed": "Failed to upload image: {{errorMessage}}", + "addFaceLibraryFailed": "Failed to set face name: {{errorMessage}}", + "deleteFaceFailed": "Failed to delete: {{errorMessage}}", + "deleteNameFailed": "Failed to delete name: {{errorMessage}}", + "renameFaceFailed": "Failed to rename face: {{errorMessage}}", + "trainFailed": "Failed to train: {{errorMessage}}", + "updateFaceScoreFailed": "Failed to update face score: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/en/views/live.json b/web/public/locales/en/views/live.json new file mode 100644 index 000000000..1790467d2 --- /dev/null +++ b/web/public/locales/en/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "Live - Frigate", + "documentTitle.withCamera": "{{camera}} - Live - Frigate", + "lowBandwidthMode": "Low-bandwidth Mode", + "twoWayTalk": { + "enable": "Enable Two Way Talk", + "disable": "Disable Two Way Talk" + }, + "cameraAudio": { + "enable": "Enable Camera Audio", + "disable": "Disable Camera Audio" + }, + "ptz": { + "move": { + "clickMove": { + "label": "Click in the frame to center the camera", + "enable": "Enable click to move", + "disable": "Disable click to move" + }, + "left": { + "label": "Move PTZ camera to the left" + }, + "up": { + "label": "Move PTZ camera up" + }, + "down": { + "label": "Move PTZ camera down" + }, + "right": { + "label": "Move PTZ camera to the right" + } + }, + "zoom": { + "in": { + "label": "Zoom PTZ camera in" + }, + "out": { + "label": "Zoom PTZ camera out" + } + }, + "frame": { + "center": { + "label": "Click in the frame to center the PTZ camera" + } + }, + "presets": "PTZ camera presets" + }, + "camera": { + "enable": "Enable Camera", + "disable": "Disable Camera" + }, + "muteCameras": { + "enable": "Mute All Cameras", + "disable": "Unmute All Cameras" + }, + "detect": { + "enable": "Enable Detect", + "disable": "Disable Detect" + }, + "recording": { + "enable": "Enable Recording", + "disable": "Disable Recording" + }, + "snapshots": { + "enable": "Enable Snapshots", + "disable": "Disable Snapshots" + }, + "audioDetect": { + "enable": "Enable Audio Detect", + "disable": "Disable Audio Detect" + }, + "autotracking": { + "enable": "Enable Autotracking", + "disable": "Disable Autotracking" + }, + "streamStats": { + "enable": "Show Stream Stats", + "disable": "Hide Stream Stats" + }, + "manualRecording": { + "title": "On-Demand Recording", + "tips": "Start a manual event based on this camera's recording retention settings.", + "playInBackground": { + "label": "Play in background", + "desc": "Enable this option to continue streaming when the player is hidden." + }, + "showStats": { + "label": "Show Stats", + "desc": "Enable this option to show stream statistics as an overlay on the camera feed." + }, + "debugView": "Debug View", + "start": "Start on-demand recording", + "started": "Started manual on-demand recording.", + "failedToStart": "Failed to start manual on-demand recording.", + "recordDisabledTips": "Since recording is disabled or restricted in the config for this camera, only a snapshot will be saved.", + "end": "End on-demand recording", + "ended": "Ended manual on-demand recording.", + "failedToEnd": "Failed to end manual on-demand recording." + }, + "streamingSettings": "Streaming Settings", + "notifications": "Notifications", + "audio": "Audio", + "suspend": { + "forTime": "Suspend for: " + }, + "stream": { + "title": "Stream", + "audio": { + "tips": { + "title": "Audio must be output from your camera and configured in go2rtc for this stream.", + "documentation": "Read the documentation " + }, + "available": "Audio is available for this stream", + "unavailable": "Audio is not available for this stream" + }, + "twoWayTalk": { + "tips": "Your device must support the feature and WebRTC must be configured for two-way talk.", + "tips.documentation": "Read the documentation ", + "available": "Two-way talk is available for this stream", + "unavailable": "Two-way talk is unavailable for this stream" + }, + "lowBandwidth": { + "tips": "Live view is in low-bandwidth mode due to buffering or stream errors.", + "resetStream": "Reset stream" + }, + "playInBackground": { + "label": "Play in background", + "tips": "Enable this option to continue streaming when the player is hidden." + } + }, + "cameraSettings": { + "title": "{{camera}} Settings", + "cameraEnabled": "Camera Enabled", + "objectDetection": "Object Detection", + "recording": "Recording", + "snapshots": "Snapshots", + "audioDetection": "Audio Detection", + "autotracking": "Autotracking" + }, + "history": { + "label": "Show historical footage" + }, + "effectiveRetainMode": { + "modes": { + "all": "All", + "motion": "Motion", + "active_objects": "Active Objects" + }, + "notAllTips": "Your {{source}} recording retention configuration is set to mode: {{effectiveRetainMode}}, so this on-demand recording will only keep segments with {{effectiveRetainModeName}}." + }, + "editLayout": { + "label": "Edit Layout", + "group": { + "label": "Edit Camera Group" + }, + "exitEdit": "Exit Editing" + } +} diff --git a/web/public/locales/en/views/recording.json b/web/public/locales/en/views/recording.json new file mode 100644 index 000000000..9ca7c43e8 --- /dev/null +++ b/web/public/locales/en/views/recording.json @@ -0,0 +1,12 @@ +{ + "export": "Export", + "calendar": "Calendar", + "filter": "Filter", + "filters": "Filters", + "toast": { + "error": { + "noValidTimeSelected": "No valid time range selected", + "endTimeMustAfterStartTime": "End time must be after start time" + } + } +} diff --git a/web/public/locales/en/views/search.json b/web/public/locales/en/views/search.json new file mode 100644 index 000000000..22da7721f --- /dev/null +++ b/web/public/locales/en/views/search.json @@ -0,0 +1,72 @@ +{ + "search": "Search", + "savedSearches": "Saved Searches", + "searchFor": "Search for {{inputValue}}", + "button": { + "clear": "Clear search", + "save": "Save search", + "delete": "Delete saved search", + "filterInformation": "Filter information", + "filterActive": "Filters active" + }, + "trackedObjectId": "Tracked Object ID", + "filter": { + "label": { + "cameras": "Cameras", + "labels": "Labels", + "zones": "Zones", + "sub_labels": "Sub Labels", + "search_type": "Search Type", + "time_range": "Time Range", + "before": "Before", + "after": "After", + "min_score": "Min Score", + "max_score": "Max Score", + "min_speed": "Min Speed", + "max_speed": "Max Speed", + "recognized_license_plate": "Recognized License Plate", + "has_clip": "Has Clip", + "has_snapshot": "Has Snapshot" + }, + "searchType": { + "thumbnail": "Thumbnail", + "description": "Description" + }, + "toast": { + "error": { + "beforeDateBeLaterAfter": "The 'before' date must be later than the 'after' date.", + "afterDatebeEarlierBefore": "The 'after' date must be earlier than the 'before' date.", + "minScoreMustBeLessOrEqualMaxScore": "The 'min_score' must be less than or equal to the 'max_score'.", + "maxScoreMustBeGreaterOrEqualMinScore": "The 'max_score' must be greater than or equal to the 'min_score'.", + "minSpeedMustBeLessOrEqualMaxSpeed": "The 'min_speed' must be less than or equal to the 'max_speed'.", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "The 'max_speed' must be greater than or equal to the 'min_speed'." + } + }, + "tips": { + "title": "How to use text filters", + "desc": { + "text": "Filters help you narrow down your search results. Here's how to use them in the input field:", + "step1": "Type a filter key name followed by a colon (e.g., \"cameras:\").", + "step2": "Select a value from the suggestions or type your own.", + "step3": "Use multiple filters by adding them one after another with a space in between.", + "step4": "Date filters (before: and after:) use {{DateFormat}} format.", + "step5": "Time range filter uses {{exampleTime}} format.", + "step6": "Remove filters by clicking the 'x' next to them.", + "exampleLabel": "Example:" + } + }, + "header": { + "currentFilterType": "Filter Values", + "noFilters": "Filters", + "activeFilters": "Active Filters" + } + }, + "similaritySearch": { + "title": "Similarity Search", + "active": "Similarity search active", + "clear": "Clear similarity search" + }, + "placeholder": { + "search": "Search…" + } +} diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json new file mode 100644 index 000000000..d5f9e140d --- /dev/null +++ b/web/public/locales/en/views/settings.json @@ -0,0 +1,603 @@ +{ + "documentTitle": { + "default": "Settings - Frigate", + "authentication": "Authentication Settings - Frigate", + "camera": "Camera Settings - Frigate", + "classification": "Classification Settings - Frigate", + "masksAndZones": "Mask and Zone Editor - Frigate", + "motionTuner": "Motion Tuner - Frigate", + "object": "Debug - Frigate", + "general": "General Settings - Frigate", + "frigatePlus": "Frigate+ Settings - Frigate", + "notifications": "Notification Settings - Frigate" + }, + "menu": { + "ui": "UI", + "classification": "Classification", + "cameras": "Camera Settings", + "masksAndZones": "Masks / Zones", + "motionTuner": "Motion Tuner", + "debug": "Debug", + "users": "Users", + "notifications": "Notifications", + "frigateplus": "Frigate+" + }, + "dialog": { + "unsavedChanges": { + "title": "You have unsaved changes.", + "desc": "Do you want to save your changes before continuing?" + } + }, + "cameraSetting": { + "camera": "Camera", + "noCamera": "No Camera" + }, + "general": { + "title": "General Settings", + "liveDashboard": { + "title": "Live Dashboard", + "automaticLiveView": { + "label": "Automatic Live View", + "desc": "Automatically switch to a camera's live view when activity is detected. Disabling this option causes static camera images on the Live dashboard to only update once per minute." + }, + "playAlertVideos": { + "label": "Play Alert Videos", + "desc": "By default, recent alerts on the Live dashboard play as small looping videos. Disable this option to only show a static image of recent alerts on this device/browser." + } + }, + "storedLayouts": { + "title": "Stored Layouts", + "desc": "The layout of cameras in a camera group can be dragged/resized. The positions are stored in your browser's local storage.", + "clearAll": "Clear All Layouts" + }, + "cameraGroupStreaming": { + "title": "Camera Group Streaming Settings", + "desc": "Streaming settings for each camera group are stored in your browser's local storage.", + "clearAll": "Clear All Streaming Settings" + }, + "recordingsViewer": { + "title": "Recordings Viewer", + "defaultPlaybackRate": { + "label": "Default Playback Rate", + "desc": "Default playback rate for recordings playback." + } + }, + "calendar": { + "title": "Calendar", + "firstWeekday": { + "label": "First Weekday", + "desc": "The day that the weeks of the review calendar begin on.", + "sunday": "Sunday", + "monday": "Monday" + } + }, + "toast": { + "success": { + "clearStoredLayout": "Cleared stored layout for {{cameraName}}", + "clearStreamingSettings": "Cleared streaming settings for all camera groups." + }, + "error": { + "clearStoredLayoutFailed": "Failed to clear stored layout: {{errorMessage}}", + "clearStreamingSettingsFailed": "Failed to clear streaming settings: {{errorMessage}}" + } + } + }, + "classification": { + "title": "Classification Settings", + "unsavedChanges": "Unsaved Classification settings changes", + "birdClassification": { + "title": "Bird Classification", + "desc": "Bird classification identifies known birds using a quantized Tensorflow model. When a known bird is recognized, its common name will be added as a sub_label. This information is included in the UI, filters, as well as in notifications." + }, + "semanticSearch": { + "title": "Semantic Search", + "desc": "Semantic Search in Frigate allows you to find tracked objects within your review items using either the image itself, a user-defined text description, or an automatically generated one.", + "readTheDocumentation": "Read the Documentation", + "reindexNow": { + "label": "Reindex Now", + "desc": "Reindexing will regenerate embeddings for all tracked object. This process runs in the background and may max out your CPU and take a fair amount of time depending on the number of tracked objects you have.", + "confirmTitle": "Confirm Reindexing", + "confirmDesc": "Are you sure you want to reindex all tracked object embeddings? This process will run in the background but it may max out your CPU and take a fair amount of time. You can watch the progress on the Explore page.", + "confirmButton": "Reindex", + "success": "Reindexing started successfully.", + "alreadyInProgress": "Reindexing is already in progress.", + "error": "Failed to start reindexing: {{errorMessage}}" + }, + "modelSize": { + "label": "Model Size", + "desc": "The size of the model used for semantic search embeddings.", + "small": { + "title": "small", + "desc": "Using small employs a quantized version of the model that uses less RAM and runs faster on CPU with a very negligible difference in embedding quality." + }, + "large": { + "title": "large", + "desc": "Using large employs the full Jina model and will automatically run on the GPU if applicable." + } + } + }, + "faceRecognition": { + "title": "Face Recognition", + "desc": "Face recognition allows people to be assigned names and when their face is recognized Frigate will assign the person's name as a sub label. This information is included in the UI, filters, as well as in notifications.", + "readTheDocumentation": "Read the Documentation", + "modelSize": { + "label": "Model Size", + "desc": "The size of the model used for face recognition.", + "small": { + "title": "small", + "desc": "Using small employs a FaceNet face embedding model that runs efficiently on most CPUs." + }, + "large": { + "title": "large", + "desc": "Using large employs an ArcFace face embedding model and will automatically run on the GPU if applicable." + } + } + }, + "licensePlateRecognition": { + "title": "License Plate Recognition", + "desc": "Frigate can recognize license plates on vehicles and automatically add the detected characters to the recognized_license_plate field or a known name as a sub_label to objects that are of type car. A common use case may be to read the license plates of cars pulling into a driveway or cars passing by on a street.", + "readTheDocumentation": "Read the Documentation" + }, + "restart_required": "Restart required (Classification settings changed)", + "toast": { + "success": "Classification settings have been saved. Restart Frigate to apply your changes.", + "error": "Failed to save config changes: {{errorMessage}}" + } + }, + "camera": { + "title": "Camera Settings", + "streams": { + "title": "Streams", + "desc": "Disabling a camera completely stops Frigate's processing of this camera's streams. Detection, recording, and debugging will be unavailable.
    Note: This does not disable go2rtc restreams." + }, + "review": { + "title": "Review", + "desc": "Enable/disable alerts and detections for this camera. When disabled, no new review items will be generated.", + "alerts": "Alerts ", + "detections": "Detections " + }, + "reviewClassification": { + "title": "Review Classification", + "desc": "Frigate categorizes review items as Alerts and Detections. By default, all person and car objects are considered Alerts. You can refine categorization of your review items by configuring required zones for them.", + "readTheDocumentation": "Read the Documentation", + "noDefinedZones": "No zones are defined for this camera.", + "objectAlertsTips": "All {{alertsLabels}} objects on {{cameraName}} will be shown as Alerts.", + "zoneObjectAlertsTips": "All {{alertsLabels}} objects detected in {{zone}} on {{cameraName}} will be shown as Alerts.", + "objectDetectionsTips": "All {{detectionsLabels}} objects not categorized on {{cameraName}} will be shown as Detections regardless of which zone they are in.", + "zoneObjectDetectionsTips": { + "text": "All {{detectionsLabels}} objects not categorized in {{zone}} on {{cameraName}} will be shown as Detections.", + "notSelectDetections": "All {{detectionsLabels}} objects detected in {{zone}} on {{cameraName}} not categorized as Alerts will be shown as Detections regardless of which zone they are in.", + "regardlessOfZoneObjectDetectionsTips": "All {{detectionsLabels}} objects not categorized on {{cameraName}} will be shown as Detections regardless of which zone they are in." + }, + "unsavedChanges": "Unsaved Review Classification settings for {{camera}}", + "selectAlertsZones": "Select zones for Alerts", + "selectDetectionsZones": "Select zones for Detections", + "limitDetections": "Limit detections to specific zones", + "toast": { + "success": "Review Classification configuration has been saved. Restart Frigate to apply changes." + } + } + }, + "masksAndZones": { + "filter": { + "all": "All Masks and Zones" + }, + "restart_required": "Restart required (masks/zones changed)", + "toast": { + "success": { + "copyCoordinates": "Copied coordinates for {{polyName}} to clipboard." + }, + "error": { + "copyCoordinatesFailed": "Could not copy coordinates to clipboard." + } + }, + "form": { + "zoneName": { + "error": { + "mustBeAtLeastTwoCharacters": "Zone name must be at least 2 characters.", + "mustNotBeSameWithCamera": "Zone name must not be the same as camera name.", + "alreadyExists": "A zone with this name already exists for this camera.", + "mustNotContainPeriod": "Zone name must not contain periods.", + "hasIllegalCharacter": "Zone name contains illegal characters." + } + }, + "distance": { + "error": { + "text": "Distance must be greater than or equal to 0.1.", + "mustBeFilled": "All distance fields must be filled to use speed estimation." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "Inertia must be above 0." + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "Loitering time must be greater than or equal to 0." + } + }, + "polygonDrawing": { + "removeLastPoint": "Remove last point", + "reset": { + "label": "Clear all points" + }, + "snapPoints": { + "true": "Snap points", + "false": "Don't Snap points" + }, + "delete": { + "title": "Confirm Delete", + "desc": "Are you sure you want to delete the {{type}} {{name}}?", + "success": "{{name}} has been deleted." + }, + "error": { + "mustBeFinished": "Polygon drawing must be finished before saving." + } + } + }, + "zones": { + "label": "Zones", + "documentTitle": "Edit Zone - Frigate", + "desc": { + "title": "Zones allow you to define a specific area of the frame so you can determine whether or not an object is within a particular area.", + "documentation": "Documentation" + }, + "add": "Add Zone", + "edit": "Edit Zone", + "point_one": "{{count}} point", + "point_other": "{{count}} points", + "clickDrawPolygon": "Click to draw a polygon on the image.", + "name": { + "title": "Name", + "inputPlaceHolder": "Enter a name…", + "tips": "Name must be at least 2 characters and must not be the name of a camera or another zone." + }, + "inertia": { + "title": "Inertia", + "desc": "Specifies how many frames that an object must be in a zone before they are considered in the zone. Default: 3" + }, + "loiteringTime": { + "title": "Loitering Time", + "desc": "Sets a minimum amount of time in seconds that the object must be in the zone for it to activate. Default: 0" + }, + "objects": { + "title": "Objects", + "desc": "List of objects that apply to this zone." + }, + "allObjects": "All Objects", + "speedEstimation": { + "title": "Speed Estimation", + "desc": "Enable speed estimation for objects in this zone. The zone must have exactly 4 points.", + "docs": "Read the documentation" + }, + "speedThreshold": { + "title": "Speed Threshold ({{unit}})", + "desc": "Specifies a minimum speed for objects to be considered in this zone.", + "toast": { + "error": { + "pointLengthError": "Speed estimation has been disabled for this zone. Zones with speed estimation must have exactly 4 points.", + "loiteringTimeError": "Zones with loitering times greater than 0 should not be used with speed estimation." + } + } + }, + "toast": { + "success": "Zone ({{zoneName}}) has been saved. Restart Frigate to apply changes." + } + }, + "motionMasks": { + "label": "Motion Mask", + "documentTitle": "Edit Motion Mask - Frigate", + "desc": { + "title": "Motion masks are used to prevent unwanted types of motion from triggering detection. Over masking will make it more difficult for objects to be tracked.", + "documentation": "Documentation" + }, + "add": "New Motion Mask", + "edit": "Edit Motion Mask", + "context": { + "title": "Motion masks are used to prevent unwanted types of motion from triggering detection (example: tree branches, camera timestamps). Motion masks should be used very sparingly, over-masking will make it more difficult for objects to be tracked.", + "documentation": "Read the documentation" + }, + "point_one": "{{count}} point", + "point_other": "{{count}} points", + "clickDrawPolygon": "Click to draw a polygon on the image.", + "polygonAreaTooLarge": { + "title": "The motion mask is covering {{polygonArea}}% of the camera frame. Large motion masks are not recommended.", + "tips": "Motion masks do not prevent objects from being detected. You should use a required zone instead.", + "documentation": "Read the documentation" + }, + "toast": { + "success": { + "title": "{{polygonName}} has been saved. Restart Frigate to apply changes.", + "noName": "Motion Mask has been saved. Restart Frigate to apply changes." + } + } + }, + "objectMasks": { + "label": "Object Masks", + "documentTitle": "Edit Object Mask - Frigate", + "desc": { + "title": "Object filter masks are used to filter out false positives for a given object type based on location.", + "documentation": "Documentation" + }, + "add": "Add Object Mask", + "edit": "Edit Object Mask", + "context": "Object filter masks are used to filter out false positives for a given object type based on location.", + "point_one": "{{count}} point", + "point_other": "{{count}} points", + "clickDrawPolygon": "Click to draw a polygon on the image.", + "objects": { + "title": "Objects", + "desc": "The object type that that applies to this object mask.", + "allObjectTypes": "All object types" + }, + "toast": { + "success": { + "title": "{{polygonName}} has been saved. Restart Frigate to apply changes.", + "noName": "Object Mask has been saved. Restart Frigate to apply changes." + } + } + } + }, + "motionDetectionTuner": { + "title": "Motion Detection Tuner", + "unsavedChanges": "Unsaved Motion Tuner changes ({{camera}})", + "desc": { + "title": "Frigate uses motion detection as a first line check to see if there is anything happening in the frame worth checking with object detection.", + "documentation": "Read the Motion Tuning Guide" + }, + "Threshold": { + "title": "Threshold", + "desc": "The threshold value dictates how much of a change in a pixel's luminance is required to be considered motion. Default: 30" + }, + "contourArea": { + "title": "Contour Area", + "desc": "The contour area value is used to decide which groups of changed pixels qualify as motion. Default: 10" + }, + "improveContrast": { + "title": "Improve Contrast", + "desc": "Improve contrast for darker scenes. Default: ON" + }, + "toast": { + "success": "Motion settings have been saved." + } + }, + "debug": { + "title": "Debug", + "detectorDesc": "Frigate uses your detectors ({{detectors}}) to detect objects in your camera's video stream.", + "desc": "Debugging view shows a real-time view of tracked objects and their statistics. The object list shows a time-delayed summary of detected objects.", + "debugging": "Debugging", + "objectList": "Object List", + "noObjects": "No objects", + "boundingBoxes": { + "title": "Bounding boxes", + "desc": "Show bounding boxes around tracked objects", + "colors": { + "label": "Object Bounding Box Colors", + "info": "
  • At startup, different colors will be assigned to each object label
  • A dark blue thin line indicates that object is not detected at this current point in time
  • A gray thin line indicates that object is detected as being stationary
  • A thick line indicates that object is the subject of autotracking (when enabled)
  • " + } + }, + "timestamp": { + "title": "Timestamp", + "desc": "Overlay a timestamp on the image" + }, + "zones": { + "title": "Zones", + "desc": "Show an outline of any defined zones" + }, + "mask": { + "title": "Motion masks", + "desc": "Show motion mask polygons" + }, + "motion": { + "title": "Motion boxes", + "desc": "Show boxes around areas where motion is detected", + "tips": "

    Motion Boxes


    Red boxes will be overlaid on areas of the frame where motion is currently being detected

    " + }, + "regions": { + "title": "Regions", + "desc": "Show a box of the region of interest sent to the object detector", + "tips": "

    Region Boxes


    Bright green boxes will be overlaid on areas of interest in the frame that are being sent to the object detector.

    " + }, + "objectShapeFilterDrawing": { + "title": "Object Shape Filter Drawing", + "desc": "Draw a rectangle on the image to view area and ratio details", + "tips": "Enable this option to draw a rectangle on the camera image to show its area and ratio. These values can then be used to set object shape filter parameters in your config.", + "document": "Read the documentation ", + "score": "Score", + "ratio": "Ratio", + "area": "Area" + } + }, + "users": { + "title": "Users", + "management": { + "title": "User Management", + "desc": "Manage this Frigate instance's user accounts." + }, + "addUser": "Add User", + "updatePassword": "Update Password", + "toast": { + "success": { + "createUser": "User {{user}} created successfully", + "deleteUser": "User {{user}} deleted successfully", + "updatePassword": "Password updated successfully.", + "roleUpdated": "Role updated for {{user}}" + }, + "error": { + "setPasswordFailed": "Failed to save password: {{errorMessage}}", + "createUserFailed": "Failed to create user: {{errorMessage}}", + "deleteUserFailed": "Failed to delete user: {{errorMessage}}", + "roleUpdateFailed": "Failed to update role: {{errorMessage}}" + } + }, + "table": { + "username": "Username", + "actions": "Actions", + "role": "Role", + "noUsers": "No users found.", + "changeRole": "Change user role", + "password": "Password", + "deleteUser": "Delete user" + }, + "dialog": { + "form": { + "user": { + "title": "Username", + "desc": "Only letters, numbers, periods and underscores allowed.", + "placeholder": "Enter username" + }, + "password": { + "title": "Password", + "placeholder": "Enter password", + "confirm": { + "title": "Confirm Password", + "placeholder": "Confirm Password" + }, + "strength": { + "title": "Password strength: ", + "weak": "Weak", + "medium": "Medium", + "strong": "Strong", + "veryStrong": "Very Strong" + }, + "match": "Passwords match", + "notMatch": "Passwords don't match" + }, + "newPassword": { + "title": "New Password", + "placeholder": "Enter new password", + "confirm": { + "placeholder": "Re-enter new password" + } + }, + "usernameIsRequired": "Username is required" + }, + "createUser": { + "title": "Create New User", + "desc": "Add a new user account and specify an role for access to areas of the Frigate UI.", + "usernameOnlyInclude": "Username may only include letters, numbers, . or _" + }, + "deleteUser": { + "title": "Delete User", + "desc": "This action cannot be undone. This will permanently delete the user account and remove all associated data.", + "warn": "Are you sure you want to delete {{username}}?" + }, + "passwordSetting": { + "updatePassword": "Update Password for {{username}}", + "setPassword": "Set Password", + "desc": "Create a strong password to secure this account." + }, + "changeRole": { + "title": "Change User Role", + "desc": "Update permissions for {{username}}", + "roleInfo": { + "intro": "Select the appropriate role for this user:", + "admin": "Admin", + "adminDesc": "Full access to all features.", + "viewer": "Viewer", + "viewerDesc": "Limited to Live dashboards, Review, Explore, and Exports only." + } + } + } + }, + "notification": { + "title": "Notifications", + "notificationSettings": { + "title": "Notification Settings", + "desc": "Frigate can natively send push notifications to your device when it is running in the browser or installed as a PWA.", + "documentation": "Read the Documentation" + }, + "notificationUnavailable": { + "title": "Notifications Unavailable", + "desc": "Web push notifications require a secure context (https://…). This is a browser limitation. Access Frigate securely to use notifications.", + "documentation": "Read the Documentation" + }, + "globalSettings": { + "title": "Global Settings", + "desc": "Temporarily suspend notifications for specific cameras on all registered devices." + }, + "email": { + "title": "Email", + "placeholder": "e.g. example@email.com", + "desc": "A valid email is required and will be used to notify you if there are any issues with the push service." + }, + "cameras": { + "title": "Cameras", + "noCameras": "No cameras available", + "desc": "Select which cameras to enable notifications for." + }, + "deviceSpecific": "Device Specific Settings", + "registerDevice": "Register This Device", + "unregisterDevice": "Unregister This Device", + "sendTestNotification": "Send a test notification", + "unsavedRegistrations": "Unsaved Notification registrations", + "unsavedChanges": "Unsaved Notification changes", + "active": "Notifications Active", + "suspended": "Notifications suspended {{time}}", + "suspendTime": { + "suspend": "Suspend", + "5minutes": "Suspend for 5 minutes", + "10minutes": "Suspend for 10 minutes", + "30minutes": "Suspend for 30 minutes", + "1hour": "Suspend for 1 hour", + "12hours": "Suspend for 12 hours", + "24hours": "Suspend for 24 hours", + "untilRestart": "Suspend until restart" + }, + "cancelSuspension": "Cancel Suspension", + "toast": { + "success": { + "registered": "Successfully registered for notifications. Restarting Frigate is required before any notifications (including a test notification) can be sent.", + "settingSaved": "Notification settings have been saved." + }, + "error": { + "registerFailed": "Failed to save notification registration." + } + } + }, + "frigatePlus": { + "title": "Frigate+ Settings", + "apiKey": { + "title": "Frigate+ API Key", + "validated": "Frigate+ API key is detected and validated", + "notValidated": "Frigate+ API key is not detected or not validated", + "desc": "The Frigate+ API key enables integration with the Frigate+ service.", + "plusLink": "Read more about Frigate+" + }, + "snapshotConfig": { + "title": "Snapshot Configuration", + "desc": "Submitting to Frigate+ requires both snapshots and clean_copy snapshots to be enabled in your config.", + "documentation": "Read the documentation", + "cleanCopyWarning": "Some cameras have snapshots enabled but have the clean copy disabled. You need to enable clean_copy in your snapshot config to be able to submit images from these cameras to Frigate+.", + "table": { + "camera": "Camera", + "snapshots": "Snapshots", + "cleanCopySnapshots": "clean_copy Snapshots" + } + }, + "modelInfo": { + "title": "Model Information", + "modelType": "Model Type", + "trainDate": "Train Date", + "baseModel": "Base Model", + "plusModelType": { + "baseModel": "Base Model", + "userModel": "Fine-Tuned" + }, + "supportedDetectors": "Supported Detectors", + "cameras": "Cameras", + "loading": "Loading model information…", + "error": "Failed to load model information", + "availableModels": "Available Models", + "loadingAvailableModels": "Loading available models…", + "modelSelect": "Your available models on Frigate+ can be selected here. Note that only models compatible with your current detector configuration can be selected." + }, + "unsavedChanges": "Unsaved Frigate+ settings changes", + "restart_required": "Restart required (Frigate+ model changed)", + "toast": { + "success": "Frigate+ settings have been saved. Restart Frigate to apply changes.", + "error": "Failed to save config changes: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/en/views/system.json b/web/public/locales/en/views/system.json new file mode 100644 index 000000000..2750d14a9 --- /dev/null +++ b/web/public/locales/en/views/system.json @@ -0,0 +1,179 @@ +{ + "documentTitle": { + "cameras": "Cameras Stats - Frigate", + "storage": "Storage Stats - Frigate", + "general": "General Stats - Frigate", + "enrichments": "Enrichments Stats - Frigate", + "logs": { + "frigate": "Frigate Logs - Frigate", + "go2rtc": "Go2RTC Logs - Frigate", + "nginx": "Nginx Logs - Frigate" + } + }, + "title": "System", + "metrics": "System metrics", + "logs": { + "download": { + "label": "Download Logs" + }, + "copy": { + "label": "Copy to Clipboard", + "success": "Copied logs to clipboard", + "error": "Could not copy logs to clipboard" + }, + "type": { + "label": "Type", + "timestamp": "Timestamp", + "tag": "Tag", + "message": "Message" + }, + "tips": "Logs are streaming from the server", + "toast": { + "error": { + "fetchingLogsFailed": "Error fetching logs: {{errorMessage}}", + "whileStreamingLogs": "Error while streaming logs: {{errorMessage}}" + } + } + }, + "general": { + "title": "General", + "detector": { + "title": "Detectors", + "inferenceSpeed": "Detector Inference Speed", + "temperature": "Detector Temperature", + "cpuUsage": "Detector CPU Usage", + "memoryUsage": "Detector Memory Usage" + }, + "hardwareInfo": { + "title": "Hardware Info", + "gpuUsage": "GPU Usage", + "gpuMemory": "GPU Memory", + "gpuEncoder": "GPU Encoder", + "gpuDecoder": "GPU Decoder", + "gpuInfo": { + "vainfoOutput": { + "title": "Vainfo Output", + "returnCode": "Return Code: {{code}}", + "processOutput": "Process Output:", + "processError": "Process Error:" + }, + "nvidiaSMIOutput": { + "title": "Nvidia SMI Output", + "name": "Name: {{name}}", + "driver": "Driver: {{driver}}", + "cudaComputerCapability": "CUDA Compute Capability: {{cuda_compute}}", + "vbios": "VBios Info: {{vbios}}" + }, + "closeInfo": { + "label": "Close GPU info" + }, + "copyInfo": { + "label": "Copy GPU info" + }, + "toast": { + "success": "Copied GPU info to clipboard" + } + }, + "npuUsage": "NPU Usage", + "npuMemory": "NPU Memory" + }, + "otherProcesses": { + "title": "Other Processes", + "processCpuUsage": "Process CPU Usage", + "processMemoryUsage": "Process Memory Usage" + } + }, + "storage": { + "title": "Storage", + "overview": "Overview", + "recordings": { + "title": "Recordings", + "tips": "This value represents the total storage used by the recordings in Frigate's database. Frigate does not track storage usage for all files on your disk.", + "earliestRecording": "Earliest recording available:" + }, + "cameraStorage": { + "title": "Camera Storage", + "camera": "Camera", + "unusedStorageInformation": "Unused Storage Information", + "storageUsed": "Storage", + "percentageOfTotalUsed": "Percentage of Total", + "bandwidth": "Bandwidth", + "unused": { + "title": "Unused", + "tips": "This value may not accurately represent the free space available to Frigate if you have other files stored on your drive beyond Frigate's recordings. Frigate does not track storage usage outside of its recordings." + } + } + }, + "cameras": { + "title": "Cameras", + "overview": "Overview", + "info": { + "cameraProbeInfo": "{{camera}} Camera Probe Info", + "streamDataFromFFPROBE": "Stream data is obtained with ffprobe.", + "fetching": "Fetching Camera Data", + "stream": "Stream {{idx}}", + "video": "Video:", + "codec": "Codec:", + "resolution": "Resolution:", + "fps": "FPS:", + "unknown": "Unknown", + "audio": "Audio:", + "error": "Error: {{error}}", + "tips": { + "title": "Camera Probe Info" + } + }, + "framesAndDetections": "Frames / Detections", + "label": { + "camera": "camera", + "detect": "detect", + "skipped": "skipped", + "ffmpeg": "FFmpeg", + "capture": "capture", + "overallFramesPerSecond": "overall frames per second", + "overallDetectionsPerSecond": "overall detections per second", + "overallSkippedDetectionsPerSecond": "overall skipped detections per second", + "cameraFfmpeg": "{{camName}} FFmpeg", + "cameraCapture": "{{camName}} capture", + "cameraDetect": "{{camName}} detect", + "cameraFramesPerSecond": "{{camName}} frames per second", + "cameraDetectionsPerSecond": "{{camName}} detections per second", + "cameraSkippedDetectionsPerSecond": "{{camName}} skipped detections per second" + }, + "toast": { + "success": { + "copyToClipboard": "Copied probe data to clipboard." + }, + "error": { + "unableToProbeCamera": "Unable to probe camera: {{errorMessage}}" + } + } + }, + "lastRefreshed": "Last refreshed: ", + "stats": { + "ffmpegHighCpuUsage": "{{camera}} has high FFmpeg CPU usage ({{ffmpegAvg}}%)", + "detectHighCpuUsage": "{{camera}} has high detect CPU usage ({{detectAvg}}%)", + "healthy": "System is healthy", + "reindexingEmbeddings": "Reindexing embeddings ({{processed}}% complete)", + "cameraIsOffline": "{{camera}} is offline", + "detectIsSlow": "{{detect}} is slow ({{speed}} ms)", + "detectIsVerySlow": "{{detect}} is very slow ({{speed}} ms)" + }, + "enrichments": { + "title": "Enrichments", + "infPerSecond": "Inferences Per Second", + "embeddings": { + "image_embedding": "Image Embedding", + "text_embedding": "Text Embedding", + "face_recognition": "Face Recognition", + "plate_recognition": "Plate Recognition", + "image_embedding_speed": "Image Embedding Speed", + "face_embedding_speed": "Face Embedding Speed", + "face_recognition_speed": "Face Recognition Speed", + "plate_recognition_speed": "Plate Recognition Speed", + "text_embedding_speed": "Text Embedding Speed", + "yolov9_plate_detection_speed": "YOLOv9 Plate Detection Speed", + "yolov9_plate_detection": "YOLOv9 Plate Detection" + } + } +} diff --git a/web/public/locales/es/audio.json b/web/public/locales/es/audio.json new file mode 100644 index 000000000..16288b261 --- /dev/null +++ b/web/public/locales/es/audio.json @@ -0,0 +1,429 @@ +{ + "bark": "Ladrido", + "sheep": "Oveja", + "goat": "Cabra", + "car": "Coche", + "boat": "Barco", + "bus": "Autobus", + "motorcycle": "Motocicleta", + "train": "Tren", + "skateboard": "Monopatín", + "sink": "Fregadero", + "blender": "Batidora", + "hair_dryer": "Secador de pelo", + "scissors": "Tijeras", + "clock": "Reloj", + "camera": "Cámara", + "door": "Puerta", + "dog": "Perro", + "horse": "Caballo", + "toothbrush": "Cepillo de dientes", + "bird": "Pájaro", + "vehicle": "Vehículo", + "mouse": "Ratón", + "bicycle": "Bicicleta", + "cat": "Gato", + "keyboard": "Teclado", + "animal": "Animal", + "yell": "Grito", + "bellow": "Voz de trueno", + "whoop": "Aullido", + "crying": "Llanto", + "synthetic_singing": "Canto sintético", + "rapping": "Rap", + "humming": "Tarareo", + "groan": "Gemido", + "grunt": "Gruñido", + "whistling": "Silbido", + "breathing": "Respiración", + "wheeze": "Sibilancia", + "snoring": "Ronquido", + "gasp": "Jadeo", + "snort": "Resoplido", + "cough": "Tos", + "sneeze": "Estornudo", + "sniff": "Oler", + "run": "Correr", + "shuffle": "Arrastrar los pies", + "footsteps": "Pasos", + "chewing": "Masticar", + "biting": "Morder", + "gargling": "Hacer gárgaras", + "stomach_rumble": "Rugido de estómago", + "burping": "Eructo", + "finger_snapping": "Chasquido de dedos", + "clapping": "Aplausos", + "heartbeat": "Latido del corazón", + "heart_murmur": "Soplo cardíaco", + "cheering": "Aclamación", + "applause": "Aplausos", + "whispering": "Susurro", + "speech": "Habla", + "mantra": "Mantra", + "fart": "Pedos", + "snicker": "Risa maliciosa", + "yodeling": "Yodeling", + "laughter": "Risa", + "child_singing": "Canto infantil", + "pant": "Jadeo", + "throat_clearing": "Despejar la garganta", + "sigh": "Suspiro", + "choir": "Coro", + "babbling": "Balbuceo", + "singing": "Canto", + "hands": "Manos", + "hiccup": "Hipido", + "chant": "Cántico", + "chatter": "Charla", + "crowd": "Multitud", + "children_playing": "Niños jugando", + "pets": "Mascotas", + "yip": "Ladrido corto", + "howl": "Aullido", + "bow_wow": "Guau", + "growling": "Gruñido", + "whimper_dog": "Gemido de perro", + "purr": "Ronroneo", + "hiss": "Siseo", + "caterwaul": "Aullido de gato", + "livestock": "Ganado", + "clip_clop": "Trote de caballo", + "neigh": "Relincho", + "cattle": "Ganado", + "moo": "Muu", + "cowbell": "Campanilla de vaca", + "pig": "Cerdo", + "oink": "Oink", + "bleat": "Balido", + "fowl": "Aves", + "cluck": "Cacareo", + "cock_a_doodle_doo": "Quiquiriquí", + "turkey": "Pavo", + "gobble": "Gluglú", + "duck": "Pato", + "goose": "Ganso", + "honk": "Bocina", + "wild_animals": "Animales salvajes", + "roar": "Rugido", + "chirp": "Canto (de insecto o pájaro)", + "pigeon": "Paloma", + "coo": "Arrullo", + "caw": "Grito de cuervo", + "owl": "Búho", + "dogs": "Perros", + "insect": "Insecto", + "cricket": "Grillo", + "mosquito": "Mosquito", + "buzz": "Zumbido", + "frog": "Rana", + "croak": "Croar", + "snake": "Serpiente", + "rattle": "Sonajero", + "whale_vocalization": "Vocalización de ballena", + "plucked_string_instrument": "Instrumento de cuerda punteada", + "guitar": "Guitarra", + "steel_guitar": "Guitarra de acero", + "tapping": "Tapping (técnica de guitarra)", + "strum": "Rasgueo", + "banjo": "Banjo", + "sitar": "Sitar", + "mandolin": "Mandolina", + "zither": "Cítara", + "ukulele": "Ukulele", + "piano": "Piano", + "organ": "Órgano", + "electronic_organ": "Órgano electrónico", + "hammond_organ": "Órgano Hammond", + "sampler": "Sampler", + "harpsichord": "Clavicémbalo", + "percussion": "Percusión", + "drum_kit": "Batería", + "drum_machine": "Caja de ritmos", + "drum": "Tambor", + "snare_drum": "Caja (o redoblante)", + "rimshot": "Golpe en el borde del tambor", + "tabla": "Tabla", + "cymbal": "Platillo", + "hi_hat": "Hi-Hat", + "wood_block": "Bloque de madera", + "tambourine": "Pandereta", + "maraca": "Maraca", + "gong": "Gong", + "tubular_bells": "Campanas tubulares", + "mallet_percussion": "Percusión con mazas", + "marimba": "Marimba", + "glockenspiel": "Glockenspiel", + "steelpan": "Steelpan", + "orchestra": "Orquesta", + "trumpet": "Trompeta", + "string_section": "Sección de cuerdas", + "violin": "Violín", + "double_bass": "Contrabajo", + "wind_instrument": "Instrumento de viento", + "flute": "Flauta", + "saxophone": "Saxofón", + "harp": "Arpa", + "jingle_bell": "Campanilla", + "bicycle_bell": "Campana de bicicleta", + "tuning_fork": "Diapasón", + "chime": "Campanilla", + "wind_chime": "Campanario de viento", + "harmonica": "Armónica", + "accordion": "Acordeón", + "didgeridoo": "Didgeridoo", + "theremin": "Theremín", + "singing_bowl": "Cuenco tibetano", + "scratching": "Rasguñado", + "hip_hop_music": "Música hip-hop", + "rock_music": "Música rock", + "heavy_metal": "Heavy metal", + "punk_rock": "Punk rock", + "progressive_rock": "Progressive rock", + "rock_and_roll": "Rock and roll", + "psychedelic_rock": "Rock psicodélico", + "rhythm_and_blues": "Rhythm and blues", + "soul_music": "Música soul", + "country": "Country", + "swing_music": "Música swing", + "disco": "Disco", + "house_music": "Música House", + "dubstep": "Dubstep", + "drum_and_bass": "Drum and Bass", + "electronica": "Electronica", + "electronic_dance_music": "Música Dance Electronica", + "music_of_latin_america": "Música de América Latina", + "salsa_music": "Música Salsa", + "flamenco": "Flamenco", + "blues": "Blues", + "music_for_children": "Música para niños", + "new-age_music": "Música New Age", + "vocal_music": "Música Vocal", + "a_capella": "A capella", + "afrobeat": "Afrobeat", + "music_of_asia": "Música de Asia", + "carnatic_music": "Música Carnatic", + "music_of_bollywood": "Música de Bollywood", + "ska": "Ska", + "song": "Canción", + "background_music": "Música Background", + "soundtrack_music": "Música de Pelicula", + "lullaby": "Lullaby", + "video_game_music": "Música de Videojuego", + "christmas_music": "Música Navideña", + "sad_music": "Música triste", + "tender_music": "Música suave", + "exciting_music": "Música emocionante", + "angry_music": "Música enojada", + "scary_music": "Música aterradora", + "wind": "Viento", + "rustling_leaves": "Hojas susurrantes", + "wind_noise": "Ruido del viento", + "thunderstorm": "Tormenta eléctrica", + "thunder": "Trueno", + "raindrop": "Gota de lluvia", + "stream": "Arroyo", + "waterfall": "Cascada", + "ocean": "Oceano", + "steam": "Vapor", + "gurgling": "Gorgoteo", + "sailboat": "Vela", + "rowboat": "Bote de remos", + "motorboat": "Lancha motora", + "motor_vehicle": "Vehículo a motor", + "toot": "Pitido", + "tire_squeal": "Chillido de neumáticos", + "car_passing_by": "Coche pasando", + "ambulance": "Ambulancia", + "fire_engine": "Camión de bomberos", + "traffic_noise": "Ruido de tráfico", + "rail_transport": "Transporte ferroviario", + "aircraft_engine": "Aeronave motor", + "engine": "Motor", + "chainsaw": "Motosierra", + "medium_engine": "Motor de tamaño medio", + "heavy_engine": "Motor pesado", + "engine_knocking": "Golpeteo del motor", + "engine_starting": "Arranque del motor", + "idling": "Ralentí", + "accelerating": "Acelerando", + "doorbell": "Timbre", + "ding-dong": "Ding Dong", + "sliding_door": "Puerta corredera", + "slam": "Portazo", + "knock": "Golpe", + "tap": "Golpe suave", + "cupboard_open_or_close": "Apertura o cierre del armario", + "drawer_open_or_close": "Apertura o cierre del cajón", + "dishes": "Platos", + "cutlery": "Cubertería", + "chopping": "Cortando", + "frying": "Freír", + "microwave_oven": "Horno Microondas", + "water_tap": "Grifo de Agua", + "toilet_flush": "Descarga del Inodoro", + "electric_toothbrush": "Cepillo de Dientes Eléctrico", + "vacuum_cleaner": "Aspiradora", + "zipper": "Cremallera", + "keys_jangling": "Llaves Tintineando", + "coin": "Moneda", + "electric_shaver": "Afeitadora Eléctrica", + "shuffling_cards": "Barajar Cartas", + "typing": "Teclear", + "typewriter": "Máquina de Escribir", + "computer_keyboard": "Teclado de Computadora", + "writing": "Escribir", + "alarm": "Alarma", + "telephone": "Teléfono", + "telephone_bell_ringing": "Timbre de Teléfono Sonando", + "ringtone": "Tono de Llamada", + "telephone_dialing": "Marcación de Teléfono", + "dial_tone": "Tono de Marcación", + "busy_signal": "Señal de Ocupado", + "alarm_clock": "Reloj Despertador", + "siren": "Sirena", + "civil_defense_siren": "Sirena de Defensa Civil", + "buzzer": "Zumbador", + "fire_alarm": "Alarma de Incendio", + "foghorn": "Bocina de Niebla", + "whistle": "Silbato", + "steam_whistle": "Silbato de Vapor", + "mechanisms": "Mecanismos", + "ratchet": "Trinquete", + "tick": "Tictac", + "tick-tock": "Tictoc", + "gears": "Engranajes", + "pulleys": "Poleas", + "sewing_machine": "Máquina de Coser", + "mechanical_fan": "Ventilador Mecánico", + "air_conditioning": "Aire Acondicionado", + "cash_register": "Caja Registradora", + "printer": "Impresora", + "fly": "Mosca", + "patter": "Golpeteo", + "bell": "Campana", + "meow": "Miau", + "squawk": "Chillido", + "classical_music": "Música Clásica", + "cello": "Violoncello", + "quack": "Cuac", + "hoot": "Ulular", + "synthesizer": "Sintetizador", + "happy_music": "Música Alegre", + "timpani": "Tímpano", + "bowed_string_instrument": "Instrumento de cuerda frotada", + "jazz": "Jazz", + "train_whistle": "Silbido de tren", + "car_alarm": "Alarma de coche", + "truck": "Camion", + "ice_cream_truck": "Camión de helados", + "railroad_car": "Vagón de tren", + "aircraft": "Aeronave", + "helicopter": "Helicóptero", + "light_engine": "Motor ligero", + "dental_drill's_drill": "Talonador dental", + "crow": "Cuervo", + "flapping_wings": "Aleteo de alas", + "opera": "Opera", + "funk": "Funk", + "roaring_cats": "Gatos rugiendo", + "chicken": "Pollo", + "bagpipes": "Gaita", + "rats": "Ratas", + "music": "Música", + "musical_instrument": "Música instrumental", + "electric_guitar": "Guitarra eléctrica", + "bass_drum": "Bombo", + "acoustic_guitar": "Guitarra acústica", + "pizzicato": "Pizzicato", + "beatboxing": "Beatboxing", + "bass_guitar": "Bajo eléctrico", + "bluegrass": "Bluegrass", + "folk_music": "Música Folk", + "electronic_music": "Música electrónica", + "techno": "Techno", + "french_horn": "Trompa francesa", + "ship": "Barco", + "lawn_mower": "Cortacésped", + "electric_piano": "Piano eléctrico", + "train_wheels_squealing": "Chillido de ruedas de tren", + "drum_roll": "Redoble de tambor", + "vibraphone": "Vibrafón", + "trombone": "Trombón", + "brass_instrument": "Instrumento de metal", + "church_bell": "Campana de iglesia", + "clarinet": "Clarinete", + "grunge": "Grunge", + "pop_music": "Música pop", + "jingle": "Single", + "rain_on_surface": "Lluvia sobre superficie", + "emergency_vehicle": "Vehículo de emergencias", + "ambient_music": "Música Ambiente", + "trance_music": "Música Trance", + "music_of_africa": "Música de Africa", + "christian_music": "Música Cristiana", + "gospel_music": "Música Gospel", + "traditional_music": "Música Tradicional", + "wedding_music": "Música de Boda", + "rain": "Lluvia", + "waves": "Ondas", + "fire": "Fuego", + "police_car": "Coche de policia", + "squeak": "Chirrido", + "crackle": "Crepitar", + "reggae": "Reggae", + "middle_eastern_music": "Música del Medio Oriente", + "smoke_detector": "Detector de Humo", + "race_car": "Coche de carreras", + "air_horn": "Bocina de aire", + "independent_music": "Música Independiente", + "theme_music": "Música de Película", + "dance_music": "Música Dance", + "fixed-wing_aircraft": "Aeronave de ala fija", + "water": "Agua", + "propeller": "Hélice", + "air_brake": "Freno de aire", + "jet_engine": "Motor a reacción", + "power_windows": "Ventanas eléctricas", + "skidding": "Deslizamiento", + "reversing_beeps": "Bips de marcha atras", + "bathtub": "Bañera", + "train_horn": "Bocina de tren", + "subway": "Metro", + "single-lens_reflex_camera": "Cámara Réflex de un Solo Objetivo", + "tools": "Herramientas", + "hammer": "Martillo", + "filing": "Limar", + "jackhammer": "Martillo Neumático", + "sawing": "Serrar", + "sanding": "Lijar", + "power_tool": "Herramienta Eléctrica", + "burst": "Estallido", + "eruption": "Erupción", + "boom": "Estallido (Boom)", + "firecracker": "Petardo", + "artillery_fire": "Fuego de Artillería", + "cap_gun": "Pistola de Fulminantes", + "fireworks": "Fuegos Artificiales", + "wood": "Madera", + "chop": "Cortar (Madera)", + "splinter": "Astilla", + "crack": "Crujido", + "chink": "Tintineo (de Vidrio)", + "glass": "Vidrio", + "environmental_noise": "Ruido Ambiental", + "sound_effect": "Efecto de sonido", + "shatter": "Romperse", + "static": "Estatico", + "silence": "Silencio", + "scream": "Grito", + "white_noise": "Ruido Blanco", + "drill": "Taladro", + "field_recording": "Grabación de Campo", + "explosion": "Explosión", + "machine_gun": "Ametralladora", + "television": "Televisión", + "radio": "Radio", + "gunshot": "Disparo", + "fusillade": "Descarga de Fusilería", + "pink_noise": "Ruido Rosa" +} diff --git a/web/public/locales/es/common.json b/web/public/locales/es/common.json new file mode 100644 index 000000000..d8b69ed58 --- /dev/null +++ b/web/public/locales/es/common.json @@ -0,0 +1,265 @@ +{ + "time": { + "yesterday": "Ayer", + "thisMonth": "Este mes", + "yr": "{{time}}año", + "formattedTimestampWithYear": { + "12hour": "%b %-d %Y, %I:%M %p", + "24hour": "%b %-d %Y, %H:%M" + }, + "second_one": "{{time}} segundo", + "second_many": "{{time}} segundos", + "second_other": "{{time}} segundos", + "formattedTimestampOnlyMonthAndDay": "%b %-d", + "formattedTimestampExcludeSeconds": { + "24hour": "%b %-d, %H:%M", + "12hour": "%b %-d, %I:%M %p" + }, + "formattedTimestamp": { + "24hour": "MMM d, HH:mm:ss", + "12hour": "MMM d, h:mm:ss aaa" + }, + "day_one": "{{time}} día", + "day_many": "{{time}} días", + "day_other": "{{time}} días", + "untilForTime": "Hasta {{time}}", + "untilForRestart": "Hasta que Frigate se reinicie.", + "untilRestart": "Hasta que se reinicie", + "ago": "Hace {{timeAgo}}", + "justNow": "Ahora mismo", + "today": "Hoy", + "last7": "Últimos 7 días", + "last14": "Últimos 14 días", + "last30": "Últimos 30 días", + "thisWeek": "Esta semana", + "lastWeek": "Semana pasada", + "lastMonth": "Mes pasado", + "10minutes": "10 minutos", + "30minutes": "30 minutos", + "1hour": "1 hora", + "12hours": "12 horas", + "24hours": "24 horas", + "pm": "pm", + "year_one": "{{time}} año", + "year_many": "{{time}} años", + "year_other": "{{time}} años", + "mo": "{{time}}mes", + "month_one": "{{time}} mes", + "month_many": "{{time}} meses", + "month_other": "{{time}} meses", + "h": "{{time}}h", + "m": "{{time}}m", + "minute_one": "{{time}} minuto", + "minute_many": "{{time}} minutos", + "minute_other": "{{time}} minutos", + "s": "{{time}}s", + "formattedTimestamp2": { + "12hour": "MM/dd h:mm:ssa", + "24hour": "d MMM HH:mm:ss" + }, + "5minutes": "5 minutos", + "am": "am", + "d": "{{time}}d", + "hour_one": "{{time}} hora", + "hour_many": "{{time}} horas", + "hour_other": "{{time}} horas", + "formattedTimestampHourMinute": { + "12hour": "h:mm aaa", + "24hour": "HH:mm" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "MMM d, h:mm aaa", + "24hour": "MMM d, HH:mm" + }, + "formattedTimestampMonthDay": "MMM d", + "formattedTimestampFilename": { + "12hour": "MM-dd-yy-h-mm-ss-a", + "24hour": "MM-dd-yy-HH-mm-ss" + }, + "formattedTimestampHourMinuteSecond": { + "12hour": "h:mm:ss aaa", + "24hour": "HH:mm:ss" + }, + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "MMM d yyyy, h:mm aaa", + "24hour": "MMM d yyyy, HH:mm" + } + }, + "menu": { + "settings": "Ajustes", + "export": "Exportar", + "user": { + "title": "Usuario", + "account": "Cuenta", + "anonymous": "Anónimo", + "logout": "Cerrar sesión", + "setPassword": "Establecer contraseña", + "current": "Usuario actual: {{user}}" + }, + "systemMetrics": "Métricas del sistema", + "help": "Ayuda", + "system": "Sistema", + "configuration": "Configuración", + "systemLogs": "Registros del sistema", + "configurationEditor": "Editor de configuración", + "languages": "Idiomas", + "language": { + "en": "English (Inglés)", + "zhCN": "简体中文 (Chino simplificado)", + "withSystem": { + "label": "Usar los ajustes del sistema para el idioma" + }, + "ru": "Русский (Ruso)", + "de": "Deutsch (Alemán)", + "ja": "日本語 (Japonés)", + "tr": "Türkçe (Turco)", + "sv": "Svenska (Sueco)", + "nb": "Norsk Bokmål (Noruego Bokmål)", + "ko": "한국어 (Coreano)", + "vi": "Tiếng Việt (Vietnamita)", + "fa": "فارسی (Persa)", + "pl": "Polski (Polaco)", + "uk": "Українська (Ucraniano)", + "he": "עברית (Hebreo)", + "el": "Ελληνικά (Griego)", + "ro": "Română (Rumano)", + "hu": "Magyar (Húngaro)", + "fi": "Suomi (Finlandés)", + "it": "Italian (Italiano)", + "da": "Dansk (Danés)", + "sk": "Slovenčina (Eslovaco)", + "hi": "हिन्दी (Hindi)", + "es": "Español", + "ar": "العربية (Árabe)", + "pt": "Português (Portugues)", + "cs": "Čeština (Checo)", + "nl": "Nederlands (Neerlandés)", + "fr": "Français (Frances)", + "yue": "粵語 (Cantonés)" + }, + "appearance": "Apariencia", + "darkMode": { + "label": "Modo oscuro", + "light": "Claro", + "dark": "Oscuro", + "withSystem": { + "label": "Usar los ajustes del sistema para el modo claro u oscuro" + } + }, + "withSystem": "Sistema", + "theme": { + "label": "Tema", + "blue": "Azul", + "green": "Verde", + "nord": "Nord", + "red": "Rojo", + "contrast": "Alto contraste", + "default": "Predeterminado", + "highcontrast": "Alto Contraste" + }, + "documentation": { + "title": "Documentación", + "label": "Documentación de Frigate" + }, + "restart": "Reiniciar Frigate", + "live": { + "title": "Directo", + "cameras": { + "title": "Cámaras", + "count_one": "{{count}} Cámara", + "count_many": "{{count}} Cámaras", + "count_other": "{{count}} Cámaras" + }, + "allCameras": "Todas las cámaras" + }, + "review": "Revisar", + "explore": "Explorar", + "uiPlayground": "Zona de pruebas de la interfaz de usuario", + "faceLibrary": "Biblioteca de rostros" + }, + "unit": { + "speed": { + "mph": "mph", + "kph": "kph" + } + }, + "button": { + "off": "APAGADO", + "copyCoordinates": "Copiar coordenadas", + "fullscreen": "Pantalla completa", + "apply": "Aplicar", + "reset": "Restablecer", + "done": "Hecho", + "enable": "Habilitar", + "disabled": "Deshabilitado", + "disable": "Deshabilitar", + "save": "Guardar", + "cancel": "Cancelar", + "close": "Cerrar", + "copy": "Copiar", + "back": "Atrás", + "history": "Historial", + "pictureInPicture": "Imagen en imagen", + "twoWayTalk": "Conversación bidireccional", + "cameraAudio": "Audio de la cámara", + "delete": "Eliminar", + "yes": "Sí", + "no": "No", + "download": "Descargar", + "info": "Información", + "suspended": "Suspendido", + "unsuspended": "Reactivar", + "play": "Reproducir", + "unselect": "Deseleccionar", + "export": "Exportar", + "deleteNow": "Eliminar ahora", + "next": "Siguiente", + "edit": "Editar", + "enabled": "Habilitado", + "saving": "Guardando…", + "exitFullscreen": "Salir de pantalla completa", + "on": "ENCENDIDO" + }, + "toast": { + "save": { + "error": { + "noMessage": "No se pudieron guardar los cambios de configuración", + "title": "No se pudieron guardar los cambios de configuración: {{errorMessage}}" + }, + "title": "Guardar" + }, + "copyUrlToClipboard": "URL copiada al portapapeles." + }, + "label": { + "back": "Volver atrás" + }, + "role": { + "title": "Rol", + "admin": "Administrador", + "viewer": "Espectador", + "desc": "Los administradores tienen acceso completo a todas las funciones en la interfaz de usuario de Frigate. Los espectadores están limitados a ver cámaras, elementos de revisión y grabaciones históricas en la interfaz de usuario." + }, + "pagination": { + "label": "paginación", + "previous": { + "title": "Anterior", + "label": "Ir a la página anterior" + }, + "next": { + "title": "Siguiente", + "label": "Ir a la página siguiente" + }, + "more": "Más páginas" + }, + "accessDenied": { + "documentTitle": "Acceso denegado - Frigate", + "desc": "No tienes permiso para ver esta página.", + "title": "Acceso denegado" + }, + "notFound": { + "documentTitle": "No se ha encontrado - Frigate", + "title": "404", + "desc": "Página no encontrada" + }, + "selectItem": "Seleccionar {{item}}" +} diff --git a/web/public/locales/es/components/auth.json b/web/public/locales/es/components/auth.json new file mode 100644 index 000000000..fde9c5a9f --- /dev/null +++ b/web/public/locales/es/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "user": "Nombre de usuario", + "errors": { + "passwordRequired": "Se requiere contraseña", + "rateLimit": "Se ha superado el límite de solicitudes. Intenta de nuevo más tarde.", + "webUnknownError": "Error desconocido. Revisa los registros de la consola.", + "usernameRequired": "Se requiere nombre de usuario", + "unknownError": "Error desconocido. Revisa los registros.", + "loginFailed": "Error de inicio de sesión" + }, + "password": "Contraseña", + "login": "Iniciar sesión" + } +} diff --git a/web/public/locales/es/components/camera.json b/web/public/locales/es/components/camera.json new file mode 100644 index 000000000..672d07317 --- /dev/null +++ b/web/public/locales/es/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "label": "Grupos de cámaras", + "add": "Agregar grupo de cámaras", + "edit": "Editar grupo de cámaras", + "delete": { + "label": "Eliminar grupo de cámaras", + "confirm": { + "title": "Confirmar eliminación", + "desc": "¿Estás seguro de que quieres eliminar el grupo de cámaras {{name}}?" + } + }, + "name": { + "label": "Nombre", + "placeholder": "Introduce un nombre…", + "errorMessage": { + "mustLeastCharacters": "El nombre del grupo de cámaras debe tener al menos 2 caracteres.", + "nameMustNotPeriod": "El nombre del grupo de cámaras no debe contener un punto.", + "invalid": "Nombre de grupo de cámaras no válido.", + "exists": "El nombre del grupo de cámaras ya existe." + } + }, + "cameras": { + "desc": "Selecciona cámaras para este grupo.", + "label": "Cámaras" + }, + "icon": "Icono", + "success": "El grupo de cámaras ({{name}}) ha sido guardado.", + "camera": { + "setting": { + "title": "Ajustes de transmisión de {{cameraName}}", + "audioIsAvailable": "El audio está disponible para esta transmisión", + "audioIsUnavailable": "El audio no está disponible para esta transmisión", + "audio": { + "tips": { + "title": "El audio debe provenir de tu cámara y estar configurado en go2rtc para esta transmisión.", + "document": "Leer la documentación " + } + }, + "streamMethod": { + "method": { + "noStreaming": { + "desc": "Las imágenes de la cámara solo se actualizarán una vez por minuto y no habrá transmisión en vivo.", + "label": "Sin transmisión" + }, + "smartStreaming": { + "label": "Transmisión inteligente (recomendada)", + "desc": "La transmisión inteligente actualizará la imagen de tu cámara una vez por minuto cuando no se detecte actividad para conservar ancho de banda y recursos. Cuando se detecte actividad, la imagen cambiará sin problemas a una transmisión en vivo." + }, + "continuousStreaming": { + "label": "Transmisión continua", + "desc": { + "title": "La imagen de la cámara siempre será una transmisión en vivo cuando esté visible en el panel de control, incluso si no se detecta ninguna actividad.", + "warning": "La transmisión continua puede causar un alto uso de ancho de banda y problemas de rendimiento. Usa con precaución." + } + } + }, + "label": "Método de transmisión" + }, + "compatibilityMode": { + "label": "Modo de compatibilidad", + "desc": "Habilita esta opción solo si la transmisión en vivo de tu cámara muestra artefactos de color y tiene una línea diagonal en el lado derecho de la imagen." + }, + "label": "Ajustes de transmisión de la cámara", + "desc": "Cambia las opciones de transmisión en vivo para el panel de control de este grupo de cámaras. Estos ajustes son específicos del dispositivo/navegador." + } + } + }, + "debug": { + "options": { + "label": "Ajustes", + "title": "Opciones", + "showOptions": "Mostrar opciones", + "hideOptions": "Ocultar opciones" + }, + "timestamp": "Marca de tiempo", + "zones": "Zonas", + "motion": "Movimiento", + "regions": "Regiones", + "boundingBox": "Caja delimitadora", + "mask": "Máscara" + } +} diff --git a/web/public/locales/es/components/dialog.json b/web/public/locales/es/components/dialog.json new file mode 100644 index 000000000..35997635f --- /dev/null +++ b/web/public/locales/es/components/dialog.json @@ -0,0 +1,122 @@ +{ + "restart": { + "restarting": { + "title": "Frigate se está reiniciando", + "button": "Forzar recarga ahora", + "content": "Esta página se recargará en {{countdown}} segundos." + }, + "title": "¿Estás seguro de que quieres reiniciar Frigate?", + "button": "Reiniciar" + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "Enviar a Frigate+", + "desc": "Los objetos en ubicaciones que deseas evitar no son falsos positivos. Enviarlos como falsos positivos confundirá al modelo." + }, + "review": { + "false": { + "label": "No confirmar esta etiqueta para Frigate Plus", + "false_one": "Esto no es un {{label}}", + "false_many": "Esto no es un {{label}}", + "false_other": "Esto no es un {{label}}" + }, + "true": { + "true_one": "Esto es un {{label}}", + "true_many": "Esto es un {{label}}", + "true_other": "Esto es un {{label}}", + "label": "Confirmar esta etiqueta para Frigate+" + }, + "state": { + "submitted": "Enviado" + }, + "question": { + "label": "Confirmar esta etiqueta para Frigate Plus", + "ask_a": "¿Es este objeto un {{label}}?", + "ask_an": "¿Es este objeto un {{label}}?", + "ask_full": "¿Es este objeto un {{untranslatedLabel}} ({{translatedLabel}})?" + } + } + }, + "video": { + "viewInHistory": "Ver en el historial" + } + }, + "export": { + "time": { + "fromTimeline": "Seleccionar desde la línea de tiempo", + "lastHour_one": "Última hora", + "lastHour_many": "Últimas {{count}} horas", + "lastHour_other": "Últimas {{count}} horas", + "custom": "Personalizado", + "start": { + "title": "Hora de inicio", + "label": "Seleccionar hora de inicio" + }, + "end": { + "title": "Hora de finalización", + "label": "Seleccionar hora de finalización" + } + }, + "name": { + "placeholder": "Nombrar la exportación" + }, + "select": "Seleccionar", + "export": "Exportar", + "toast": { + "error": { + "failed": "No se pudo iniciar la exportación: {{error}}", + "noVaildTimeSelected": "No se seleccionó un rango de tiempo válido.", + "endTimeMustAfterStartTime": "La hora de finalización debe ser posterior a la hora de inicio." + }, + "success": "Exportación iniciada con éxito. Ver el archivo en la carpeta /exports." + }, + "fromTimeline": { + "saveExport": "Guardar exportación", + "previewExport": "Vista previa de la exportación" + }, + "selectOrExport": "Seleccionar o exportar" + }, + "streaming": { + "restreaming": { + "disabled": "La retransmisión no está habilitada para esta cámara.", + "desc": { + "title": "Configura go2rtc para opciones adicionales de vista en vivo y audio para esta cámara.", + "readTheDocumentation": "Leer la documentación" + } + }, + "debugView": "Vista de depuración", + "label": "Transmisión", + "showStats": { + "label": "Mostrar estadísticas de transmisión", + "desc": "Habilita esta opción para mostrar estadísticas de transmisión como una superposición en la alimentación de la cámara." + } + }, + "search": { + "saveSearch": { + "label": "Guardar búsqueda", + "desc": "Proporciona un nombre para esta búsqueda guardada.", + "overwrite": "{{searchName}} ya existe. Guardar sobrescribirá el valor existente.", + "success": "La búsqueda ({{searchName}}) ha sido guardada.", + "button": { + "save": { + "label": "Guardar esta búsqueda" + } + }, + "placeholder": "Introduce un nombre para tu búsqueda" + } + }, + "recording": { + "confirmDelete": { + "title": "Confirmar eliminación", + "desc": { + "selected": "¿Estás seguro de que quieres eliminar todo el video grabado asociado con este elemento de revisión?

    Mantén presionada la tecla Shift para omitir este diálogo en el futuro." + } + }, + "button": { + "export": "Exportar", + "markAsReviewed": "Marcar como revisado", + "deleteNow": "Eliminar ahora" + } + } +} diff --git a/web/public/locales/es/components/filter.json b/web/public/locales/es/components/filter.json new file mode 100644 index 000000000..1086d132a --- /dev/null +++ b/web/public/locales/es/components/filter.json @@ -0,0 +1,126 @@ +{ + "filter": "Filtro", + "labels": { + "all": { + "short": "Etiquetas", + "title": "Todas las etiquetas" + }, + "count": "{{count}} Etiquetas", + "label": "Etiquetas", + "count_one": "{{count}} Etiqueta", + "count_other": "{{count}} Etiquetas" + }, + "zones": { + "all": { + "title": "Todas las zonas", + "short": "Zonas" + }, + "label": "Zonas" + }, + "dates": { + "all": { + "title": "Todas las fechas", + "short": "Fechas" + } + }, + "timeRange": "Rango de tiempo", + "subLabels": { + "all": "Todas las subetiquetas", + "label": "Subetiquetas" + }, + "score": "Puntuación", + "estimatedSpeed": "Velocidad estimada ({{unit}})", + "features": { + "label": "Características", + "submittedToFrigatePlus": { + "label": "Enviado a Frigate+", + "tips": "Primero debes filtrar por objetos rastreados que tengan una captura de pantalla.

    Los objetos rastreados sin una captura de pantalla no pueden enviarse a Frigate+." + }, + "hasSnapshot": "Tiene una captura instantánea", + "hasVideoClip": "Tiene un clip de vídeo" + }, + "sort": { + "label": "Ordenar", + "dateAsc": "Fecha (Ascendente)", + "dateDesc": "Fecha (Descendente)", + "scoreAsc": "Puntuación del objeto (Ascendente)", + "scoreDesc": "Puntuación del objeto (Descendente)", + "speedAsc": "Velocidad estimada (Ascendente)", + "speedDesc": "Velocidad estimada (Descendente)", + "relevance": "Relevancia" + }, + "cameras": { + "label": "Filtro de cámaras", + "all": { + "title": "Todas las cámaras", + "short": "Cámaras" + } + }, + "review": { + "showReviewed": "Mostrar revisados" + }, + "motion": { + "showMotionOnly": "Mostrar solo movimiento" + }, + "explore": { + "settings": { + "title": "Configuración", + "defaultView": { + "title": "Vista predeterminada", + "summary": "Resumen", + "desc": "Cuando no se seleccionen filtros, muestra un resumen de los objetos rastreados más recientes por etiqueta, o muestra una cuadrícula sin filtrar.", + "unfilteredGrid": "Cuadrícula sin filtrar" + }, + "searchSource": { + "label": "Fuente de búsqueda", + "options": { + "thumbnailImage": "Miniatura Imagen", + "description": "Descripción" + }, + "desc": "Elige si deseas buscar en las miniaturas o en las descripciones de tus objetos rastreados." + }, + "gridColumns": { + "title": "Columnas de la cuadrícula", + "desc": "Selecciona el número de columnas en la vista de cuadrícula." + } + }, + "date": { + "selectDateBy": { + "label": "Selecciona una fecha para filtrar" + } + } + }, + "reset": { + "label": "Restablecer filtros a los valores predeterminados" + }, + "more": "Más filtros", + "logSettings": { + "label": "Filtrar nivel de registro", + "loading": { + "title": "Cargando", + "desc": "Cuando el panel de registros está desplazado hasta el final, los nuevos registros se transmiten automáticamente a medida que se añaden." + }, + "disableLogStreaming": "Deshabilitar transmisión de registros", + "filterBySeverity": "Filtrar registros por gravedad", + "allLogs": "Todos los registros" + }, + "trackedObjectDelete": { + "title": "Confirmar eliminación", + "desc": "Eliminar estos {{objectLength}} objetos rastreados elimina la captura de pantalla, cualquier incrustación guardada y cualquier entrada asociada al ciclo de vida del objeto. Las grabaciones de estos objetos rastreados en la vista de Historial NO se eliminarán.

    ¿Estás seguro de que quieres proceder?

    Mantén presionada la tecla Shift para omitir este diálogo en el futuro.", + "toast": { + "success": "Objetos rastreados eliminados con éxito.", + "error": "No se pudo eliminar los objetos rastreados: {{errorMessage}}" + } + }, + "recognizedLicensePlates": { + "title": "Matrículas reconocidas", + "loadFailed": "No se pudieron cargar las matrículas reconocidas.", + "loading": "Cargando matrículas reconocidas…", + "placeholder": "Escribe para buscar matrículas…", + "noLicensePlatesFound": "No se encontraron matrículas.", + "selectPlatesFromList": "Selecciona una o más matrículas de la lista." + }, + "zoneMask": { + "filterBy": "Filtrar por máscara de zona" + } +} diff --git a/web/public/locales/es/components/icons.json b/web/public/locales/es/components/icons.json new file mode 100644 index 000000000..d4112aecb --- /dev/null +++ b/web/public/locales/es/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "Selecciona un icono", + "search": { + "placeholder": "Buscar un icono…" + } + } +} diff --git a/web/public/locales/es/components/input.json b/web/public/locales/es/components/input.json new file mode 100644 index 000000000..986f0c4b3 --- /dev/null +++ b/web/public/locales/es/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Descargar vídeo", + "toast": { + "success": "El vídeo de tu elemento de revisión ha comenzado a descargarse." + } + } + } +} diff --git a/web/public/locales/es/components/player.json b/web/public/locales/es/components/player.json new file mode 100644 index 000000000..2a3e4deb1 --- /dev/null +++ b/web/public/locales/es/components/player.json @@ -0,0 +1,51 @@ +{ + "noPreviewFound": "No se encontró vista previa", + "noPreviewFoundFor": "No se encontró vista previa para {{cameraName}}", + "submitFrigatePlus": { + "submit": "Enviar", + "title": "¿Enviar este fotograma a Frigate+?" + }, + "streamOffline": { + "desc": "No se han recibido fotogramas en la transmisión detect de {{cameraName}}, revisa los registros de errores", + "title": "Transmisión desconectada" + }, + "cameraDisabled": "La cámara está deshabilitada", + "stats": { + "streamType": { + "title": "Tipo de transmisión:", + "short": "Tipo" + }, + "bandwidth": { + "title": "Ancho de banda:", + "short": "Ancho de banda" + }, + "latency": { + "title": "Latencia:", + "short": { + "title": "Latencia", + "value": "{{seconds}} seg" + }, + "value": "{{seconds}} segundos" + }, + "totalFrames": "Fotogramas totales:", + "droppedFrames": { + "title": "Fotogramas perdidos:", + "short": { + "title": "Perdidos", + "value": "{{droppedFrames}} fotogramas" + } + }, + "decodedFrames": "Fotogramas decodificados:", + "droppedFrameRate": "Tasa de fotogramas perdidos:" + }, + "toast": { + "success": { + "submittedFrigatePlus": "Fotograma enviado correctamente a Frigate+" + }, + "error": { + "submitFrigatePlusFailed": "Error al enviar el fotograma a Frigate+" + } + }, + "livePlayerRequiredIOSVersion": "Se requiere iOS 17.1 o superior para este tipo de transmisión en vivo.", + "noRecordingsFoundForThisTime": "No se encontraron grabaciones para este momento" +} diff --git a/web/public/locales/es/objects.json b/web/public/locales/es/objects.json new file mode 100644 index 000000000..0e972102c --- /dev/null +++ b/web/public/locales/es/objects.json @@ -0,0 +1,120 @@ +{ + "person": "Persona", + "bicycle": "Bicicleta", + "car": "Coche", + "motorcycle": "Motocicleta", + "airplane": "Avión", + "bus": "Autobus", + "train": "Tren", + "boat": "Barco", + "traffic_light": "Semáforo", + "fire_hydrant": "Boca de incendios", + "street_sign": "Señal de tráfico", + "stop_sign": "Señal de stop", + "parking_meter": "Parquímetro", + "bench": "Banco", + "dog": "Perro", + "cow": "Vaca", + "elephant": "Elefante", + "bear": "Oso", + "zebra": "Cebra", + "giraffe": "Jirafa", + "hat": "Sombrero", + "backpack": "Mochila", + "shoe": "Zapato", + "eye_glasses": "Gafas", + "handbag": "Bolso de mano", + "tie": "Corbata", + "suitcase": "Maleta", + "frisbee": "Disco Volador", + "skis": "Esquís", + "sports_ball": "Pelota deportiva", + "kite": "Cometa", + "baseball_glove": "Guante de béisbol", + "skateboard": "Monopatín", + "surfboard": "Tabla de surf", + "tennis_racket": "Raqueta de tenis", + "bottle": "Botella", + "plate": "Plato", + "wine_glass": "Copa de vino", + "cup": "Taza", + "fork": "Tenedor", + "spoon": "Cuchara", + "bowl": "Cuenco", + "apple": "Manzana", + "orange": "Naranja", + "broccoli": "Brócoli", + "carrot": "Zanahoria", + "hot_dog": "Perrito caliente", + "pizza": "Pizza", + "donut": "Donut", + "chair": "Silla", + "couch": "Sofá", + "potted_plant": "Planta en maceta", + "bed": "Cama", + "mirror": "Espejo", + "dining_table": "Mesa de comedor", + "window": "Ventana", + "desk": "Escritorio", + "toilet": "Inodoro", + "door": "Puerta", + "laptop": "Portátil", + "mouse": "Ratón", + "remote": "Mando a distancia", + "keyboard": "Teclado", + "cell_phone": "Teléfono móvil", + "microwave": "Microondas", + "toaster": "Tostadora", + "sink": "Fregadero", + "refrigerator": "Frigorífico", + "blender": "Batidora", + "clock": "Reloj", + "vase": "Jarrón", + "scissors": "Tijeras", + "teddy_bear": "Osito de peluche", + "hair_dryer": "Secador de pelo", + "vehicle": "Vehículo", + "squirrel": "Ardilla", + "deer": "Ciervo", + "bark": "Ladrido", + "rabbit": "Conejo", + "face": "Rostro", + "license_plate": "Matrícula", + "package": "Paquete", + "bbq_grill": "Parrilla de barbacoa", + "ups": "UPS", + "fedex": "FedEx", + "dhl": "DHL", + "an_post": "An Post", + "purolator": "Purolator", + "postnl": "PostNL", + "umbrella": "Paraguas", + "horse": "Caballo", + "tv": "Televisión", + "on_demand": "Bajo demanda", + "toothbrush": "Cepillo de dientes", + "hair_brush": "Cepillo de pelo", + "amazon": "Amazon", + "sheep": "Oveja", + "bird": "Pájaro", + "knife": "Cuchillo", + "cake": "Tarta", + "baseball_bat": "Bate de béisbol", + "oven": "Horno", + "waste_bin": "Papelera", + "snowboard": "Snowboard", + "sandwich": "Sandwich", + "fox": "Zorro", + "nzpost": "NZPost", + "cat": "Gato", + "banana": "Plátano", + "book": "Libro", + "raccoon": "Mapache", + "dpd": "DPD", + "goat": "Cabra", + "robot_lawnmower": "Cortacésped robotizado", + "animal": "Animal", + "postnord": "PostNord", + "usps": "USPS", + "gls": "GLS" +} diff --git a/web/public/locales/es/views/configEditor.json b/web/public/locales/es/views/configEditor.json new file mode 100644 index 000000000..70bd04439 --- /dev/null +++ b/web/public/locales/es/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "configEditor": "Editor de Configuración", + "copyConfig": "Copiar configuración", + "saveAndRestart": "Guardar y reiniciar", + "saveOnly": "Guardar solo", + "toast": { + "success": { + "copyToClipboard": "Configuración copiada al portapapeles." + }, + "error": { + "savingError": "Error al guardar la configuración" + } + }, + "documentTitle": "Editor de Configuración - Frigate" +} diff --git a/web/public/locales/es/views/events.json b/web/public/locales/es/views/events.json new file mode 100644 index 000000000..79ffa15da --- /dev/null +++ b/web/public/locales/es/views/events.json @@ -0,0 +1,38 @@ +{ + "alerts": "Alertas", + "detections": "Detecciones", + "motion": { + "label": "Movimiento", + "only": "Solo movimiento" + }, + "allCameras": "Todas las cámaras", + "empty": { + "alert": "No hay alertas para revisar", + "detection": "No hay detecciones para revisar", + "motion": "No se encontraron datos de movimiento" + }, + "timeline": "Línea de tiempo", + "timeline.aria": "Seleccionar línea de tiempo", + "events": { + "label": "Eventos", + "aria": "Seleccionar eventos", + "noFoundForTimePeriod": "No se encontraron eventos para este período de tiempo." + }, + "documentTitle": "Revisión - Frigate", + "markAsReviewed": "Marcar como revisado", + "newReviewItems": { + "label": "Ver nuevos elementos de revisión", + "button": "Nuevos elementos para revisar" + }, + "camera": "Cámara", + "recordings": { + "documentTitle": "Grabaciones - Frigate" + }, + "calendarFilter": { + "last24Hours": "Últimas 24 horas" + }, + "markTheseItemsAsReviewed": "Marcar estos elementos como revisados", + "selected": "{{count}} seleccionados", + "selected_one": "{{count}} seleccionados", + "selected_other": "{{count}} seleccionados" +} diff --git a/web/public/locales/es/views/explore.json b/web/public/locales/es/views/explore.json new file mode 100644 index 000000000..bdeb99d39 --- /dev/null +++ b/web/public/locales/es/views/explore.json @@ -0,0 +1,202 @@ +{ + "generativeAI": "Inteligencia Artificial Generativa", + "exploreIsUnavailable": { + "title": "Explorar no está disponible", + "embeddingsReindexing": { + "startingUp": "Iniciando…", + "estimatedTime": "Tiempo estimado restante:", + "finishingShortly": "Finalizando en breve", + "step": { + "thumbnailsEmbedded": "Miniaturas incrustadas: ", + "descriptionsEmbedded": "Descripciones incrustadas: ", + "trackedObjectsProcessed": "Objetos rastreados procesados: " + }, + "context": "Explorar puede usarse después de que las incrustaciones de objetos rastreados hayan terminado de reindexarse." + }, + "downloadingModels": { + "context": "Frigate está descargando los modelos de incrustaciones necesarios para soportar la función de Búsqueda Semántica. Esto puede tomar varios minutos dependiendo de la velocidad de tu conexión de red.", + "error": "Ha ocurrido un error. Revisa los registros de Frigate.", + "setup": { + "visionModelFeatureExtractor": "Extractor de características del modelo de visión", + "visionModel": "Modelo de visión", + "textModel": "Modelo de texto", + "textTokenizer": "Tokenizador de texto" + }, + "tips": { + "context": "Es posible que desees reindexar las incrustaciones de tus objetos rastreados una vez que se hayan descargado los modelos.", + "documentation": "Leer la documentación" + } + } + }, + "details": { + "timestamp": "Marca de tiempo", + "item": { + "title": "Detalles del elemento de revisión", + "desc": "Detalles del elemento de revisión", + "button": { + "share": "Compartir este elemento de revisión", + "viewInExplore": "Ver en Explorar" + }, + "toast": { + "success": { + "updatedSublabel": "Subetiqueta actualizada con éxito.", + "regenerate": "Se ha solicitado una nueva descripción a {{provider}}. Dependiendo de la velocidad de tu proveedor, la nueva descripción puede tardar algún tiempo en regenerarse.", + "updatedLPR": "Matrícula actualizada con éxito." + }, + "error": { + "regenerate": "No se pudo llamar a {{provider}} para una nueva descripción: {{errorMessage}}", + "updatedSublabelFailed": "No se pudo actualizar la subetiqueta: {{errorMessage}}", + "updatedLPRFailed": "No se pudo actualizar la matrícula: {{errorMessage}}" + } + }, + "tips": { + "mismatch_one": "Se detectó y se incluyó en este elemento de revisión un objeto {{count}} no disponible. Esos objetos no calificaron como alerta o detección o ya han sido limpiados/eliminados.", + "mismatch_many": "Se detectaron y se incluyeron en este elemento de revisión {{count}} objetos no disponibles. Esos objetos no calificaron como alerta o detección o ya han sido limpiados/eliminados.", + "mismatch_other": "Se detectaron y se incluyeron en este elemento de revisión {{count}} objetos no disponibles. Esos objetos no calificaron como alerta o detección o ya han sido limpiados/eliminados.", + "hasMissingObjects": "Ajusta tu configuración si quieres que Frigate guarde los objetos rastreados para las siguientes etiquetas: {{objects}}" + } + }, + "topScore": { + "label": "Puntuación máxima", + "info": "La puntuación máxima es la mediana más alta para el objeto rastreado, por lo que puede diferir de la puntuación mostrada en la miniatura del resultado de búsqueda." + }, + "description": { + "aiTips": "Frigate no solicitará una descripción a tu proveedor de Inteligencia Artificial Generativa hasta que el ciclo de vida del objeto rastreado haya terminado.", + "placeholder": "Descripción del objeto rastreado", + "label": "Descripción" + }, + "expandRegenerationMenu": "Expandir menú de regeneración", + "regenerateFromSnapshot": "Regenerar desde captura de pantalla", + "regenerateFromThumbnails": "Regenerar desde miniaturas", + "tips": { + "descriptionSaved": "Descripción guardada con éxito", + "saveDescriptionFailed": "No se pudo actualizar la descripción: {{errorMessage}}" + }, + "zones": "Zonas", + "label": "Etiqueta", + "editSubLabel": { + "title": "Editar subetiqueta", + "descNoLabel": "Introduce una nueva subetiqueta para este objeto rastreado", + "desc": "Introduce una nueva subetiqueta para este {{label}}" + }, + "button": { + "regenerate": { + "label": "Regenerar descripción del objeto rastreado", + "title": "Regenerar" + }, + "findSimilar": "Buscar similares" + }, + "objects": "Objetos", + "estimatedSpeed": "Velocidad estimada", + "camera": "Cámara", + "editLPR": { + "title": "Editar matrícula", + "desc": "Introduce un nuevo valor de matrícula para este {{label}}", + "descNoLabel": "Introduce un nuevo valor de matrícula para este objeto rastreado" + }, + "recognizedLicensePlate": "Matrícula Reconocida", + "snapshotScore": { + "label": "Puntuación de Instantánea" + } + }, + "documentTitle": "Explorar - Frigate", + "trackedObjectDetails": "Detalles del objeto rastreado", + "type": { + "snapshot": "captura instantánea", + "video": "vídeo", + "object_lifecycle": "ciclo de vida del objeto", + "details": "detalles" + }, + "objectLifecycle": { + "title": "Ciclo de vida del objeto", + "noImageFound": "No se encontró ninguna imagen para esta marca de tiempo.", + "createObjectMask": "Crear máscara de objeto", + "adjustAnnotationSettings": "Ajustar configuración de anotaciones", + "scrollViewTips": "Desplázate para ver los momentos significativos del ciclo de vida de este objeto.", + "lifecycleItemDesc": { + "visible": "{{label}} detectado", + "entered_zone": "{{label}} entró en {{zones}}", + "attribute": { + "other": "{{label}} reconocido como {{attribute}}", + "faceOrLicense_plate": "{{attribute}} detectado para {{label}}" + }, + "gone": "{{label}} salió", + "heard": "{{label}} escuchado", + "external": "{{label}} detectado", + "active": "{{label}} se activó", + "stationary": "{{label}} se volvió estacionario", + "header": { + "zones": "Zonas", + "ratio": "Proporción", + "area": "Área" + } + }, + "annotationSettings": { + "offset": { + "label": "Desplazamiento de anotación", + "millisecondsToOffset": "Milisegundos para desplazar las anotaciones de detección. Valor por defecto: 0", + "desc": "Estos datos provienen de la transmisión de detección de tu cámara, pero se superponen en imágenes de la transmisión de grabación. Es poco probable que ambas transmisiones estén perfectamente sincronizadas. Como resultado, la caja delimitadora y la grabación no estarán perfectamente alineadas. Sin embargo, el campo annotation_offset se puede usar para ajustar esto.", + "documentation": "Leer la documentación ", + "tips": "CONSEJO: Imagina que hay un clip de evento con una persona caminando de izquierda a derecha. Si la caja delimitadora de la línea de tiempo del evento está constantemente a la izquierda de la persona, entonces se debe disminuir el valor. Del mismo modo, si una persona camina de izquierda a derecha y la caja delimitadora está constantemente por delante de la persona, entonces se debe aumentar el valor." + }, + "showAllZones": { + "title": "Mostrar todas las zonas", + "desc": "Mostrar siempre las zonas en los fotogramas donde los objetos hayan entrado en una zona." + }, + "title": "Configuración de anotaciones" + }, + "carousel": { + "previous": "Diapositiva anterior", + "next": "Siguiente diapositiva" + }, + "autoTrackingTips": "Las posiciones de las cajas delimitadoras serán inexactas para cámaras con seguimiento automático." + }, + "itemMenu": { + "downloadVideo": { + "label": "Descargar video", + "aria": "Descargar video" + }, + "downloadSnapshot": { + "label": "Descargar captura de pantalla", + "aria": "Descargar captura de pantalla" + }, + "viewObjectLifecycle": { + "label": "Ver ciclo de vida del objeto", + "aria": "Mostrar el ciclo de vida del objeto" + }, + "findSimilar": { + "label": "Buscar similares", + "aria": "Buscar objetos rastreados similares" + }, + "submitToPlus": { + "label": "Enviar a Frigate+", + "aria": "Enviar a Frigate Plus" + }, + "viewInHistory": { + "aria": "Ver en Historial", + "label": "Ver en Historial" + }, + "deleteTrackedObject": { + "label": "Eliminar este objeto rastreado" + } + }, + "dialog": { + "confirmDelete": { + "title": "Confirmar eliminación", + "desc": "Eliminar este objeto rastreado elimina la captura de pantalla, cualquier incrustación guardada y cualquier entrada asociada al ciclo de vida del objeto. Las grabaciones de este objeto rastreado en la vista de Historial NO se eliminarán.

    ¿Estás seguro de que quieres proceder?" + } + }, + "noTrackedObjects": "No se encontraron objetos rastreados", + "fetchingTrackedObjectsFailed": "Error al obtener objetos rastreados: {{errorMessage}}", + "searchResult": { + "deleteTrackedObject": { + "toast": { + "success": "Objeto rastreado eliminado con éxito.", + "error": "No se pudo eliminar el objeto rastreado: {{errorMessage}}" + } + } + }, + "trackedObjectsCount_one": "{{count}} objeto rastreado ", + "trackedObjectsCount_many": "{{count}} objetos rastreados ", + "trackedObjectsCount_other": "{{count}} objetos rastreados " +} diff --git a/web/public/locales/es/views/exports.json b/web/public/locales/es/views/exports.json new file mode 100644 index 000000000..b3b686cae --- /dev/null +++ b/web/public/locales/es/views/exports.json @@ -0,0 +1,17 @@ +{ + "search": "Búsqueda", + "documentTitle": "Exportar - Frigate", + "noExports": "No se encontraron exportaciones", + "deleteExport": "Eliminar exportación", + "editExport": { + "desc": "Introduce un nuevo nombre para esta exportación.", + "saveExport": "Guardar exportación", + "title": "Renombrar exportación" + }, + "toast": { + "error": { + "renameExportFailed": "No se pudo renombrar la exportación: {{errorMessage}}" + } + }, + "deleteExport.desc": "¿Estás seguro de que quieres eliminar {{exportName}}?" +} diff --git a/web/public/locales/es/views/faceLibrary.json b/web/public/locales/es/views/faceLibrary.json new file mode 100644 index 000000000..e64cdcaee --- /dev/null +++ b/web/public/locales/es/views/faceLibrary.json @@ -0,0 +1,86 @@ +{ + "description": { + "addFace": "Guía para agregar una nueva colección a la Biblioteca de Rostros.", + "placeholder": "Introduce un nombre para esta colección" + }, + "details": { + "person": "Persona", + "confidence": "Confianza", + "face": "Detalles del rostro", + "faceDesc": "Detalles del rostro y del objeto asociado", + "timestamp": "Marca de tiempo" + }, + "documentTitle": "Biblioteca de Rostros - Frigate", + "uploadFaceImage": { + "title": "Subir imagen del rostro", + "desc": "Sube una imagen para escanear rostros e incluirla en {{pageToggle}}" + }, + "createFaceLibrary": { + "title": "Crear colección", + "desc": "Crear una nueva colección", + "new": "Crear nuevo rostro", + "nextSteps": "Para construir una base sólida:
  • Usa la pestaña Entrenar para seleccionar y entrenar con imágenes de cada persona detectada.
  • Enfócate en imágenes frontales para obtener los mejores resultados; evita entrenar con imágenes que capturen rostros en ángulo.
  • " + }, + "train": { + "title": "Entrenar", + "aria": "Seleccionar entrenamiento" + }, + "selectItem": "Seleccionar {{item}}", + "selectFace": "Seleccionar rostro", + "deleteFaceLibrary": { + "title": "Eliminar nombre", + "desc": "¿Estás seguro de que quieres eliminar la colección {{name}}? Esto eliminará permanentemente todos los rostros asociados." + }, + "button": { + "deleteFaceAttempts": "Eliminar intentos de rostro", + "addFace": "Agregar rostro", + "uploadImage": "Subir imagen", + "reprocessFace": "Reprocesar rostro", + "renameFace": "Renombrar Rostro", + "deleteFace": "Eliminar Rostro" + }, + "imageEntry": { + "validation": { + "selectImage": "Por favor, selecciona un archivo de imagen." + }, + "dropActive": "Suelta la imagen aquí…", + "dropInstructions": "Arrastra y suelta una imagen aquí, o haz clic para seleccionar", + "maxSize": "Tamaño máximo: {{size}}MB" + }, + "toast": { + "success": { + "addFaceLibrary": "¡{{name}} ha sido añadido con éxito a la Biblioteca de Rostros!", + "trainedFace": "Rostro entrenado con éxito.", + "deletedName_one": "{{count}} rostro ha sido eliminado con éxito.", + "deletedName_many": "{{count}} rostros han sido eliminados con éxito.", + "deletedName_other": "{{count}} rostros han sido eliminados con éxito.", + "updatedFaceScore": "Puntuación del rostro actualizada con éxito.", + "deletedFace_one": "{{count}} rostro eliminado con éxito", + "deletedFace_many": "{{count}} rostros eliminados con éxito", + "deletedFace_other": "{{count}} rostros eliminados con éxito", + "uploadedImage": "Imagen subida con éxito.", + "renamedFace": "Rostro renombrado con éxito a {{name}}" + }, + "error": { + "uploadingImageFailed": "No se pudo subir la imagen: {{errorMessage}}", + "addFaceLibraryFailed": "No se pudo establecer el nombre del rostro: {{errorMessage}}", + "deleteFaceFailed": "No se pudo eliminar: {{errorMessage}}", + "deleteNameFailed": "No se pudo eliminar el nombre: {{errorMessage}}", + "trainFailed": "No se pudo entrenar: {{errorMessage}}", + "updateFaceScoreFailed": "No se pudo actualizar la puntuación del rostro: {{errorMessage}}", + "renameFaceFailed": "No se pudo renombrar el rostro: {{errorMessage}}" + } + }, + "readTheDocs": "Leer la documentación", + "trainFaceAs": "Entrenar rostro como:", + "trainFace": "Entrenar rostro", + "steps": { + "faceName": "Introducir Nombre de Rostro", + "uploadFace": "Subir Imagen de Rostro", + "nextSteps": "Próximos Pasos" + }, + "renameFace": { + "title": "Renombrar Rostro", + "desc": "Introduce un nuevo nombre para {{name}}" + } +} diff --git a/web/public/locales/es/views/live.json b/web/public/locales/es/views/live.json new file mode 100644 index 000000000..8191aebb8 --- /dev/null +++ b/web/public/locales/es/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "Directo - Frigate", + "documentTitle.withCamera": "{{camera}} - Directo - Frigate", + "twoWayTalk": { + "enable": "Habilitar conversación bidireccional", + "disable": "Deshabilitar conversación bidireccional" + }, + "cameraAudio": { + "enable": "Habilitar audio de la cámara", + "disable": "Deshabilitar audio de la cámara" + }, + "ptz": { + "move": { + "clickMove": { + "label": "Haz clic en el marco para centrar la cámara", + "enable": "Habilitar clic para mover", + "disable": "Deshabilitar clic para mover" + }, + "up": { + "label": "Mover la cámara PTZ hacia arriba" + }, + "down": { + "label": "Mover la cámara PTZ hacia abajo" + }, + "right": { + "label": "Mover la cámara PTZ hacia la derecha" + }, + "left": { + "label": "Mover la cámara PTZ hacia la izquierda" + } + }, + "zoom": { + "in": { + "label": "Acercar la cámara PTZ" + }, + "out": { + "label": "Alejar la cámara PTZ" + } + }, + "frame": { + "center": { + "label": "Haz clic en el marco para centrar la cámara PTZ" + } + }, + "presets": "Preajustes de cámara PTZ" + }, + "camera": { + "enable": "Habilitar cámara", + "disable": "Deshabilitar cámara" + }, + "muteCameras": { + "enable": "Silenciar todas las cámaras", + "disable": "Activar sonido de todas las cámaras" + }, + "detect": { + "enable": "Habilitar detección", + "disable": "Deshabilitar detección" + }, + "recording": { + "enable": "Habilitar grabación", + "disable": "Deshabilitar grabación" + }, + "snapshots": { + "enable": "Habilitar capturas de pantalla", + "disable": "Desactivar instantáneas" + }, + "audioDetect": { + "enable": "Activar detección de audio", + "disable": "Desactivar detección de audio" + }, + "autotracking": { + "enable": "Activar seguimiento automático", + "disable": "Desactivar seguimiento automático" + }, + "streamStats": { + "enable": "Mostrar estadísticas de transmisión", + "disable": "Ocultar estadísticas de transmisión" + }, + "manualRecording": { + "title": "Grabación bajo demanda", + "tips": "Iniciar un evento manual basado en la configuración de retención de grabaciones de esta cámara.", + "playInBackground": { + "label": "Reproducir en segundo plano", + "desc": "Habilitar esta opción para continuar transmitiendo cuando el reproductor esté oculto." + }, + "showStats": { + "label": "Mostrar estadísticas", + "desc": "Habilitar esta opción para mostrar estadísticas de transmisión como una superposición en la transmisión de la cámara." + }, + "debugView": "Vista de depuración", + "started": "Grabación manual bajo demanda iniciada.", + "failedToStart": "No se pudo iniciar la grabación manual bajo demanda.", + "start": "Iniciar grabación bajo demanda", + "recordDisabledTips": "Dado que la grabación está deshabilitada o restringida en la configuración de esta cámara, solo se guardará una captura de pantalla.", + "end": "Finalizar grabación bajo demanda", + "ended": "Finalizó la grabación manual bajo demanda.", + "failedToEnd": "No se pudo finalizar la grabación manual bajo demanda." + }, + "lowBandwidthMode": "Modo de bajo ancho de banda", + "streamingSettings": "Ajustes de transmisión", + "notifications": "Notificaciones", + "audio": "Audio", + "suspend": { + "forTime": "Suspender por: " + }, + "stream": { + "title": "Transmisión", + "audio": { + "tips": { + "documentation": "Leer la documentación ", + "title": "El audio debe provenir de tu cámara y estar configurado en go2rtc para esta transmisión." + }, + "available": "El audio está disponible para esta transmisión", + "unavailable": "El audio no está disponible para esta transmisión" + }, + "twoWayTalk": { + "tips.documentation": "Leer la documentación ", + "available": "La conversación bidireccional está disponible para esta transmisión", + "unavailable": "La conversación bidireccional está disponible para esta transmisión", + "tips": "Tu dispositivo debe soportar la función y WebRTC debe estar configurado para la conversación bidireccional." + }, + "lowBandwidth": { + "tips": "La vista en vivo está en modo de bajo ancho de banda debido a problemas de almacenamiento en búfer o errores de transmisión.", + "resetStream": "Restablecer transmisión" + }, + "playInBackground": { + "label": "Reproducir en segundo plano", + "tips": "Habilita esta opción para continuar la transmisión cuando el reproductor esté oculto." + } + }, + "cameraSettings": { + "title": "Ajustes de {{camera}}", + "objectDetection": "Detección de objetos", + "audioDetection": "Detección de audio", + "recording": "Grabación", + "snapshots": "Capturas de pantalla", + "autotracking": "Seguimiento automático", + "cameraEnabled": "Cámara habilitada" + }, + "history": { + "label": "Mostrar grabaciones históricas" + }, + "effectiveRetainMode": { + "modes": { + "motion": "Movimiento", + "active_objects": "Objetos activos", + "all": "Todo" + }, + "notAllTips": "Tu configuración de retención de grabación de {{source}} está establecida en modo: {{effectiveRetainMode}}, por lo que esta grabación bajo demanda solo mantendrá segmentos con {{effectiveRetainModeName}}." + }, + "editLayout": { + "label": "Editar diseño", + "group": { + "label": "Editar grupo de cámaras" + }, + "exitEdit": "Salir de la edición" + } +} diff --git a/web/public/locales/es/views/recording.json b/web/public/locales/es/views/recording.json new file mode 100644 index 000000000..ad362aab0 --- /dev/null +++ b/web/public/locales/es/views/recording.json @@ -0,0 +1,12 @@ +{ + "export": "Exportar", + "calendar": "Calendario", + "filter": "Filtro", + "filters": "Filtros", + "toast": { + "error": { + "noValidTimeSelected": "No se ha seleccionado un rango de tiempo válido", + "endTimeMustAfterStartTime": "La hora de finalización debe ser posterior a la hora de inicio" + } + } +} diff --git a/web/public/locales/es/views/search.json b/web/public/locales/es/views/search.json new file mode 100644 index 000000000..7458c491d --- /dev/null +++ b/web/public/locales/es/views/search.json @@ -0,0 +1,74 @@ +{ + "search": "Búsqueda", + "savedSearches": "Búsquedas Guardadas", + "searchFor": "Búsqueda de {{inputValue}}", + "button": { + "save": "Guardar búsqueda", + "delete": "Eliminar búsqueda guardada", + "clear": "Borrar búsqueda", + "filterInformation": "Información de filtro", + "filterActive": "Filtros activos" + }, + "trackedObjectId": "ID de Objeto Rastreado", + "filter": { + "label": { + "cameras": "Cámaras", + "labels": "Etiquetas", + "zones": "Zonas", + "sub_labels": "Subetiquetas", + "search_type": "Tipo de Búsqueda", + "time_range": "Rango de Tiempo", + "before": "Antes", + "after": "Después", + "min_score": "Puntuación Mínima", + "max_score": "Puntuación Máxima", + "min_speed": "Velocidad Mínima", + "max_speed": "Velocidad Máxima", + "recognized_license_plate": "Matrícula Reconocida", + "has_clip": "Tiene Clip", + "has_snapshot": "Tiene Instantánea" + }, + "searchType": { + "thumbnail": "Miniatura", + "description": "Descripción" + }, + "toast": { + "error": { + "maxSpeedMustBeGreaterOrEqualMinSpeed": "La 'velocidad máxima' debe ser mayor o igual que la 'velocidad mínima'.", + "maxScoreMustBeGreaterOrEqualMinScore": "La 'puntuación máxima' debe ser mayor o igual que la 'puntuación mínima'.", + "beforeDateBeLaterAfter": "La fecha 'antes' debe ser posterior a la fecha 'después'.", + "minScoreMustBeLessOrEqualMaxScore": "La 'puntuación mínima' debe ser menor o igual que la 'puntuación máxima'.", + "minSpeedMustBeLessOrEqualMaxSpeed": "La 'velocidad mínima' debe ser menor o igual que la 'velocidad máxima'.", + "afterDatebeEarlierBefore": "La fecha 'después' debe ser anterior a la fecha 'antes'." + } + }, + "tips": { + "title": "Cómo usar filtros de texto", + "desc": { + "text": "Los filtros te ayudan a reducir los resultados de tu búsqueda. Aquí te explicamos cómo usarlos en el campo de entrada:", + "example": "Ejemplo: cameras:front_door label:person before:01012024 time_range:3:00PM-4:00PM ", + "step": "
    • Escribe un nombre de filtro seguido de dos puntos (por ejemplo, \"cameras:\").
    • Selecciona un valor de las sugerencias o escribe el tuyo propio.
    • Usa múltiples filtros añadiéndolos uno tras otro con un espacio entre ellos.
    • Los filtros de fecha (before: y after:) usan el formato {{DateFormat}}.
    • El filtro de rango de tiempo usa el formato {{exampleTime}}.
    • Elimina filtros haciendo clic en la 'x' junto a ellos.
    ", + "step4": "Los filtros de fecha (antes: y después:) usan el formato {{DateFormat}}.", + "step6": "Elimina filtros haciendo clic en la 'x' junto a ellos.", + "exampleLabel": "Ejemplo:", + "step1": "Escribe un nombre de clave de filtro seguido de dos puntos (por ejemplo, \"cámaras:\").", + "step2": "Selecciona un valor de las sugerencias o escribe el tuyo propio.", + "step3": "Usa múltiples filtros añadiéndolos uno tras otro con un espacio entre ellos.", + "step5": "El filtro de rango de tiempo usa el formato {{exampleTime}}." + } + }, + "header": { + "currentFilterType": "Valores de Filtro", + "noFilters": "Filtros", + "activeFilters": "Filtros Activos" + } + }, + "similaritySearch": { + "title": "Búsqueda por Similitud", + "active": "Búsqueda por similitud activa", + "clear": "Borrar búsqueda por similitud" + }, + "placeholder": { + "search": "Buscar…" + } +} diff --git a/web/public/locales/es/views/settings.json b/web/public/locales/es/views/settings.json new file mode 100644 index 000000000..9ffa7d283 --- /dev/null +++ b/web/public/locales/es/views/settings.json @@ -0,0 +1,600 @@ +{ + "documentTitle": { + "masksAndZones": "Editor de máscaras y zonas - Frigate", + "object": "Depurar - Frigate", + "default": "Configuración - Frigate", + "authentication": "Configuración de autenticación - Frigate", + "camera": "Configuración de cámara - Frigate", + "motionTuner": "Ajuste de movimiento - Frigate", + "classification": "Configuración de clasificación - Frigate", + "general": "Configuración general - Frigate", + "frigatePlus": "Configuración de Frigate+ - Frigate", + "notifications": "Configuración de Notificaciones - Frigate" + }, + "menu": { + "cameras": "Configuración de cámara", + "debug": "Depuración", + "ui": "Interfaz de usuario", + "classification": "Clasificación", + "motionTuner": "Ajuste de movimiento", + "masksAndZones": "Máscaras / Zonas", + "frigateplus": "Frigate+", + "users": "Usuarios", + "notifications": "Notificaciones" + }, + "dialog": { + "unsavedChanges": { + "title": "Tienes cambios sin guardar.", + "desc": "¿Quieres guardar los cambios antes de continuar?" + } + }, + "cameraSetting": { + "camera": "Cámara", + "noCamera": "Sin cámara" + }, + "general": { + "liveDashboard": { + "automaticLiveView": { + "label": "Vista en directo automática", + "desc": "Cambiar automáticamente a la vista en directo de una cámara cuando se detecta actividad. Si se desactiva esta opción, las imágenes de las cámaras en el panel en directo solo se actualizarán una vez por minuto." + }, + "playAlertVideos": { + "label": "Reproducir vídeos de alertas", + "desc": "De forma predeterminada, las alertas recientes en el panel en directo se reproducen como pequeños vídeos en bucle. Desactiva esta opción para mostrar solo una imagen estática de las alertas recientes en este dispositivo/navegador." + }, + "title": "Panel en directo" + }, + "cameraGroupStreaming": { + "desc": "La configuración de transmisión de cada grupo de cámaras se guarda en el almacenamiento local de tu navegador.", + "title": "Configuración de transmisión de grupo de cámaras", + "clearAll": "Borrar toda la configuración de transmisión" + }, + "recordingsViewer": { + "defaultPlaybackRate": { + "label": "Velocidad de reproducción predeterminada", + "desc": "Velocidad de reproducción predeterminada para la reproducción de grabaciones." + }, + "title": "Visor de grabaciones" + }, + "calendar": { + "firstWeekday": { + "label": "Primer día de la semana", + "sunday": "Domingo", + "desc": "El día con el que comienzan las semanas en el calendario de revisión.", + "monday": "Lunes" + }, + "title": "Calendario" + }, + "storedLayouts": { + "desc": "El diseño de las cámaras en un grupo de cámaras se puede arrastrar y redimensionar. Las posiciones se guardan en el almacenamiento local de tu navegador.", + "title": "Diseños guardados", + "clearAll": "Borrar todos los diseños" + }, + "title": "Configuración general", + "toast": { + "success": { + "clearStoredLayout": "Diseño almacenado eliminado para {{cameraName}}", + "clearStreamingSettings": "Se ha borrado la configuración de transmisión de todos los grupos de cámaras." + }, + "error": { + "clearStreamingSettingsFailed": "Error al borrar la configuración de transmisión: {{errorMessage}}", + "clearStoredLayoutFailed": "Error al borrar el diseño guardado: {{errorMessage}}" + } + } + }, + "classification": { + "semanticSearch": { + "title": "Búsqueda semántica", + "desc": "La búsqueda semántica en Frigate te permite encontrar objetos rastreados dentro de tus elementos de revisión utilizando la propia imagen, una descripción escrita por el usuario o una generada automáticamente.", + "readTheDocumentation": "Leer la documentación", + "reindexNow": { + "confirmTitle": "Confirmar reindexación", + "confirmButton": "Reindexar", + "success": "La reindexación comenzó con éxito.", + "label": "Reindexar ahora", + "desc": "La reindexación regenerará las incrustaciones para todos los objetos rastreados. Este proceso se ejecuta en segundo plano y puede maximizar el uso de tu CPU y tomar una cantidad considerable de tiempo dependiendo del número de objetos rastreados que tengas.", + "confirmDesc": "¿Estás seguro de que quieres reindexar todas las incrustaciones de objetos rastreados? Este proceso se ejecutará en segundo plano, pero puede maximizar el uso de tu CPU y tomar una cantidad considerable de tiempo. Puedes ver el progreso en la página de Explorar.", + "alreadyInProgress": "La reindexación ya está en curso.", + "error": "No se pudo iniciar la reindexación: {{errorMessage}}" + }, + "modelSize": { + "small": { + "desc": "Usar pequeño emplea una versión cuantizada del modelo que utiliza menos RAM y se ejecuta más rápido en la CPU con una diferencia muy insignificante en la calidad de las incrustaciones.", + "title": "pequeño" + }, + "large": { + "title": "grande", + "desc": "Usar grande emplea el modelo completo de Jina y se ejecutará automáticamente en la GPU si es aplicable." + }, + "label": "Tamaño del modelo", + "desc": "El tamaño del modelo utilizado para las incrustaciones de búsqueda semántica." + } + }, + "title": "Configuración de clasificación", + "faceRecognition": { + "title": "Reconocimiento facial", + "modelSize": { + "large": { + "title": "grande", + "desc": "Usar grande emplea un modelo de incrustación facial ArcFace y se ejecutará automáticamente en la GPU si es aplicable." + }, + "small": { + "desc": "Usar pequeño emplea un modelo de incrustación facial FaceNet que se ejecuta de manera eficiente en la mayoría de las CPUs.", + "title": "pequeño" + }, + "label": "Tamaño del modelo", + "desc": "El tamaño del modelo utilizado para el reconocimiento facial." + }, + "readTheDocumentation": "Leer la documentación", + "desc": "El reconocimiento facial permite asignar nombres a las personas y, cuando se reconoce su rostro, Frigate asignará el nombre de la persona como una subetiqueta. Esta información se incluye en la interfaz de usuario, los filtros y también en las notificaciones." + }, + "licensePlateRecognition": { + "title": "Reconocimiento de matrículas", + "desc": "Frigate puede reconocer matrículas en vehículos y agregar automáticamente los caracteres detectados al campo recognized_license_plate o un nombre conocido como subetiqueta a objetos que sean del tipo coche. Un caso de uso común puede ser leer las matrículas de los coches que entran en un camino de entrada o de los coches que pasan por una calle.", + "readTheDocumentation": "Leer la documentación" + }, + "toast": { + "success": "Los ajustes de clasificación han sido guardados. Reinicia Frigate para aplicar tus cambios.", + "error": "No se pudieron guardar los cambios de configuración: {{errorMessage}}" + }, + "birdClassification": { + "title": "Clasificación de Aves", + "desc": "La clasificación de aves identifica aves conocidas utilizando un modelo de TensorFlow cuantizado. Cuando se reconoce una ave conocida, su nombre común se añadirá como una subetiqueta. Esta información se incluye en la interfaz de usuario, en los filtros y en las notificaciones." + }, + "restart_required": "Es necesario reiniciar (se han cambiado las configuraciones de clasificación)" + }, + "camera": { + "review": { + "alerts": "Alertas ", + "desc": "Habilitar/deshabilitar alertas y detecciones para esta cámara. Cuando está deshabilitado, no se generarán nuevos elementos de revisión.", + "detections": "Detecciones ", + "title": "Revisar" + }, + "reviewClassification": { + "readTheDocumentation": "Leer la documentación", + "noDefinedZones": "No se han definido zonas para esta cámara.", + "selectAlertsZones": "Seleccionar zonas para Alertas", + "zoneObjectDetectionsTips": { + "regardlessOfZoneObjectDetectionsTips": "Todos los objetos {{detectionsLabels}} no categorizados en {{cameraName}} se mostrarán como Detecciones, independientemente de en qué zona se encuentren.", + "text": "Todos los objetos {{detectionsLabels}} no categorizados en {{zone}} en {{cameraName}} se mostrarán como Detecciones.", + "notSelectDetections": "Todos los objetos {{detectionsLabels}} detectados en {{zone}} en {{cameraName}} que no estén categorizados como Alertas se mostrarán como Detecciones, independientemente de en qué zona se encuentren." + }, + "desc": "Frigate clasifica los elementos de revisión como Alertas y Detecciones. Por defecto, todos los objetos persona y coche se consideran Alertas. Puedes refinar la categorización de tus elementos de revisión configurando zonas requeridas para ellos.", + "objectDetectionsTips": "Todos los objetos {{detectionsLabels}} no categorizados en {{cameraName}} se mostrarán como Detecciones, independientemente de en qué zona se encuentren.", + "zoneObjectAlertsTips": "Todos los objetos {{alertsLabels}} detectados en {{zone}} en {{cameraName}} se mostrarán como Alertas.", + "title": "Clasificación de revisión", + "objectAlertsTips": "Todos los objetos {{alertsLabels}} en {{cameraName}} se mostrarán como Alertas.", + "selectDetectionsZones": "Seleccionar zonas para Detecciones", + "limitDetections": "Limitar detecciones a zonas específicas", + "toast": { + "success": "La configuración de clasificación de revisión ha sido guardada. Reinicia Frigate para aplicar los cambios." + } + }, + "title": "Ajustes de la cámara", + "streams": { + "title": "Transmisiones", + "desc": "Deshabilitar una cámara detiene completamente el procesamiento de las transmisiones de esta cámara por parte de Frigate. La detección, la grabación y la depuración no estarán disponibles.
    Nota: Esto no deshabilita las retransmisiones de go2rtc." + } + }, + "masksAndZones": { + "form": { + "zoneName": { + "error": { + "alreadyExists": "Ya existe una zona con este nombre para esta cámara.", + "mustNotBeSameWithCamera": "El nombre de la zona no debe ser el mismo que el nombre de la cámara.", + "hasIllegalCharacter": "El nombre de la zona contiene caracteres no permitidos.", + "mustBeAtLeastTwoCharacters": "El nombre de la zona debe tener al menos 2 caracteres.", + "mustNotContainPeriod": "El nombre de la zona no debe contener puntos." + } + }, + "distance": { + "error": { + "mustBeFilled": "Todos los campos de distancia deben estar completados para usar la estimación de velocidad.", + "text": "La distancia debe ser mayor o igual a 0.1." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "La inercia debe ser mayor a 0." + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "El tiempo de merodeo debe ser mayor o igual a 0." + } + }, + "polygonDrawing": { + "snapPoints": { + "true": "Ajustar puntos", + "false": "No ajustar puntos" + }, + "delete": { + "desc": "¿Estás seguro de que quieres eliminar el {{type}} {{name}}?", + "success": "{{name}} ha sido eliminado.", + "title": "Confirmar eliminación" + }, + "error": { + "mustBeFinished": "El dibujo del polígono debe estar terminado antes de guardar." + }, + "reset": { + "label": "Borrar todos los puntos" + }, + "removeLastPoint": "Eliminar el último punto" + } + }, + "zones": { + "label": "Zonas", + "desc": { + "title": "Las zonas te permiten definir un área específica del cuadro para que puedas determinar si un objeto está o no dentro de un área particular.", + "documentation": "Documentación" + }, + "add": "Agregar zona", + "edit": "Editar zona", + "loiteringTime": { + "title": "Tiempo de merodeo", + "desc": "Establece una cantidad mínima de tiempo en segundos que el objeto debe estar en la zona para que se active. Predeterminado: 0" + }, + "objects": { + "title": "Objetos", + "desc": "Lista de objetos que aplican a esta zona." + }, + "inertia": { + "desc": "Especifica cuántos fotogramas debe estar un objeto en una zona antes de que se considere que está en la zona. Predeterminado: 3", + "title": "Inercia" + }, + "name": { + "title": "Nombre", + "inputPlaceHolder": "Introduce un nombre…", + "tips": "El nombre debe tener al menos 2 caracteres y no debe ser el nombre de una cámara ni de otra zona." + }, + "documentTitle": "Editar Zona - Frigate", + "clickDrawPolygon": "Haz clic para dibujar un polígono en la imagen.", + "speedEstimation": { + "desc": "Habilitar la estimación de velocidad para objetos en esta zona. La zona debe tener exactamente 4 puntos.", + "title": "Estimación de velocidad" + }, + "speedThreshold": { + "toast": { + "error": { + "pointLengthError": "La estimación de velocidad ha sido deshabilitada para esta zona. Las zonas con estimación de velocidad deben tener exactamente 4 puntos.", + "loiteringTimeError": "Las zonas con tiempos de merodeo mayores a 0 no deberían usarse con la estimación de velocidad." + } + }, + "title": "Umbral de velocidad ({{unit}})", + "desc": "Especifica una velocidad mínima para que los objetos sean considerados en esta zona." + }, + "point_one": "{{count}} punto", + "point_many": "{{count}} puntos", + "point_other": "{{count}} puntos", + "allObjects": "Todos los objetos", + "toast": { + "success": "La zona ({{zoneName}}) ha sido guardada. Reinicia Frigate para aplicar los cambios." + } + }, + "toast": { + "error": { + "copyCoordinatesFailed": "No se pudieron copiar las coordenadas al portapapeles." + }, + "success": { + "copyCoordinates": "Coordenadas copiadas para {{polyName}} al portapapeles." + } + }, + "filter": { + "all": "Todas las máscaras y zonas" + }, + "motionMasks": { + "label": "Máscara de movimiento", + "desc": { + "documentation": "Documentación", + "title": "Las máscaras de movimiento se utilizan para evitar que tipos de movimiento no deseados activen la detección. Un exceso de enmascaramiento puede dificultar el seguimiento de objetos." + }, + "add": "Nueva Máscara de Movimiento", + "edit": "Editar Máscara de Movimiento", + "context": { + "documentation": "Leer la documentación", + "title": "Las máscaras de movimiento se utilizan para evitar que tipos de movimiento no deseados activen la detección (por ejemplo: ramas de árboles, marcas de tiempo de la cámara). Las máscaras de movimiento deben usarse con moderación, un exceso de enmascaramiento dificultará el seguimiento de objetos." + }, + "clickDrawPolygon": "Haz clic para dibujar un polígono en la imagen.", + "polygonAreaTooLarge": { + "documentation": "Leer la documentación", + "title": "La máscara de movimiento está cubriendo el {{polygonArea}}% del marco de la cámara. No se recomiendan máscaras de movimiento grandes.", + "tips": "Las máscaras de movimiento no impiden que se detecten objetos. Deberías usar una zona requerida en su lugar." + }, + "toast": { + "success": { + "noName": "La máscara de movimiento ha sido guardada. Reinicia Frigate para aplicar los cambios.", + "title": "{{polygonName}} ha sido guardado. Reinicia Frigate para aplicar los cambios." + } + }, + "documentTitle": "Editar Máscara de Movimiento - Frigate", + "point_one": "{{count}} punto", + "point_many": "{{count}} puntos", + "point_other": "{{count}} puntos" + }, + "objectMasks": { + "label": "Máscaras de Objetos", + "documentTitle": "Editar Máscara de Objetos - Frigate", + "desc": { + "documentation": "Documentación", + "title": "Las máscaras de filtro de objetos se utilizan para descartar falsos positivos de un tipo de objeto específico según su ubicación." + }, + "add": "Añadir Máscara de Objetos", + "edit": "Editar Máscara de Objetos", + "context": "Las máscaras de filtro de objetos se utilizan para descartar falsos positivos de un tipo de objeto específico según su ubicación.", + "objects": { + "title": "Objetos", + "desc": "El tipo de objeto al que se aplica esta máscara de objetos.", + "allObjectTypes": "Todos los tipos de objetos" + }, + "toast": { + "success": { + "noName": "La máscara de objetos ha sido guardada. Reinicia Frigate para aplicar los cambios.", + "title": "{{polygonName}} ha sido guardado. Reinicia Frigate para aplicar los cambios." + } + }, + "point_one": "{{count}} punto", + "point_many": "{{count}} puntos", + "point_other": "{{count}} puntos", + "clickDrawPolygon": "Haz clic para dibujar un polígono en la imagen." + }, + "restart_required": "Es necesario reiniciar (se han cambiado las máscaras/zonas)" + }, + "motionDetectionTuner": { + "title": "Sintonizador de Detección de Movimiento", + "desc": { + "documentation": "Lee la Guía de Ajuste de Movimiento", + "title": "Frigate utiliza la detección de movimiento como una primera verificación para determinar si hay algo ocurriendo en el marco que merezca ser analizado con la detección de objetos." + }, + "Threshold": { + "title": "Umbral", + "desc": "El valor del umbral determina cuánto cambio en la luminancia de un píxel es necesario para que se considere movimiento. Predeterminado: 30" + }, + "contourArea": { + "title": "Área de Contorno", + "desc": "El valor del área de contorno se utiliza para decidir qué grupos de píxeles cambiados califican como movimiento. Predeterminado: 10" + }, + "improveContrast": { + "title": "Mejorar Contraste", + "desc": "Mejora el contraste para escenas más oscuras. Predeterminado: ACTIVADO" + }, + "toast": { + "success": "Los ajustes de movimiento han sido guardados." + } + }, + "debug": { + "title": "Depuración", + "debugging": "Depuración", + "objectList": "Lista de Objetos", + "noObjects": "Sin objetos", + "boundingBoxes": { + "title": "Cajas delimitadoras", + "desc": "Mostrar cajas delimitadoras alrededor de los objetos rastreados", + "colors": { + "label": "Colores de las Cajas Delimitadoras de Objetos", + "info": "
  • Al iniciar, se asignarán diferentes colores a cada etiqueta de objeto
  • Una línea fina azul oscura indica que el objeto no está detectado en este momento actual
  • Una línea fina gris indica que el objeto se detecta como estacionario
  • Una línea gruesa indica que el objeto es el sujeto de seguimiento automático (cuando está habilitado)
  • " + } + }, + "timestamp": { + "title": "Marca de tiempo", + "desc": "Superponer una marca de tiempo en la imagen" + }, + "zones": { + "title": "Zonas", + "desc": "Mostrar un contorno de las zonas definidas" + }, + "detectorDesc": "Frigate utiliza tus detectores ({{detectors}}) para detectar objetos en el flujo de video de tu cámara.", + "desc": "La vista de depuración muestra una vista en tiempo real de los objetos rastreados y sus estadísticas. La lista de objetos muestra un resumen con retraso temporal de los objetos detectados.", + "mask": { + "title": "Máscaras de movimiento", + "desc": "Mostrar polígonos de máscaras de movimiento" + }, + "motion": { + "title": "Cajas de movimiento", + "desc": "Mostrar cajas alrededor de las áreas donde se detecta movimiento", + "tips": "

    Cajas de Movimiento


    Se superpondrán cajas rojas en las áreas del fotograma donde se está detectando movimiento actualmente

    " + }, + "regions": { + "title": "Regiones", + "desc": "Mostrar una caja de la región de interés enviada al detector de objetos", + "tips": "

    Cajas de Región


    Se superpondrán cajas verdes brillantes en las áreas de interés del fotograma que se envían al detector de objetos.

    " + }, + "objectShapeFilterDrawing": { + "title": "Dibujo de Filtro de Forma de Objetos", + "desc": "Dibuja un rectángulo en la imagen para ver los detalles de área y proporción", + "tips": "Habilita esta opción para dibujar un rectángulo en la imagen de la cámara y mostrar su área y proporción. Estos valores pueden usarse luego para establecer parámetros de filtro de forma de objetos en tu configuración.", + "document": "Lee la documentación ", + "score": "Puntuación", + "ratio": "Proporción", + "area": "Área" + } + }, + "users": { + "title": "Usuarios", + "management": { + "title": "Gestión de Usuarios", + "desc": "Gestiona las cuentas de usuario de esta instancia de Frigate." + }, + "addUser": "Añadir usuario", + "toast": { + "success": { + "createUser": "Usuario {{user}} creado correctamente", + "deleteUser": "Usuario {{user}} eliminado correctamente", + "updatePassword": "Contraseña actualizada correctamente.", + "roleUpdated": "Rol actualizado para {{user}}" + }, + "error": { + "createUserFailed": "Error al crear el usuario: {{errorMessage}}", + "deleteUserFailed": "Error al eliminar el usuario: {{errorMessage}}", + "roleUpdateFailed": "Error al actualizar el rol: {{errorMessage}}", + "setPasswordFailed": "Error al guardar la contraseña: {{errorMessage}}" + } + }, + "table": { + "username": "Nombre de usuario", + "actions": "Acciones", + "role": "Rol", + "noUsers": "No se encontraron usuarios.", + "changeRole": "Cambiar el rol del usuario", + "password": "Contraseña", + "deleteUser": "Eliminar usuario" + }, + "dialog": { + "form": { + "user": { + "title": "Nombre de usuario", + "placeholder": "Introduce el nombre de usuario", + "desc": "Solo se permiten letras, números, puntos y guiones bajos." + }, + "password": { + "title": "Contraseña", + "placeholder": "Introduce la contraseña", + "confirm": { + "title": "Confirma la contraseña", + "placeholder": "Confirma la contraseña" + }, + "strength": { + "title": "Fortaleza de la contraseña: ", + "weak": "Débil", + "medium": "Media", + "strong": "Fuerte", + "veryStrong": "Muy fuerte" + }, + "match": "Las contraseñas coinciden", + "notMatch": "Las contraseñas no coinciden" + }, + "newPassword": { + "title": "Nueva contraseña", + "placeholder": "Introduce la nueva contraseña", + "confirm": { + "placeholder": "Vuelve a introducir la nueva contraseña" + } + }, + "usernameIsRequired": "Se requiere el nombre de usuario" + }, + "passwordSetting": { + "updatePassword": "Actualizar contraseña para {{username}}", + "setPassword": "Establecer contraseña", + "desc": "Crear una contraseña fuerte para asegurar esta cuenta." + }, + "createUser": { + "desc": "Añadir una nueva cuenta de usuario y especificar un rol para el acceso a áreas de la interfaz de usuario de Frigate.", + "title": "Crear nuevo usuario", + "usernameOnlyInclude": "El nombre de usuario solo puede incluir letras, números, . o _" + }, + "changeRole": { + "title": "Cambiar rol de usuario", + "desc": "Actualizar permisos para {{username}}", + "roleInfo": { + "intro": "Selecciona el rol adecuado para este usuario:", + "adminDesc": "Acceso completo a todas las funciones.", + "viewerDesc": "Limitado a paneles en vivo, revisión, exploración y exportaciones únicamente.", + "viewer": "Espectador", + "admin": "Administrador" + } + }, + "deleteUser": { + "warn": "¿Estás seguro de que quieres eliminar {{username}}?", + "title": "Eliminar usuario", + "desc": "Esta acción no se puede deshacer. Esto eliminará permanentemente la cuenta de usuario y eliminará todos los datos asociados." + } + }, + "updatePassword": "Actualizar contraseña" + }, + "notification": { + "title": "Notificaciones", + "notificationSettings": { + "title": "Configuración de notificaciones", + "desc": "Frigate puede enviar notificaciones push a tu dispositivo de forma nativa cuando se ejecuta en el navegador o está instalado como una PWA.", + "documentation": "Leer la documentación" + }, + "notificationUnavailable": { + "title": "Notificaciones no disponibles", + "documentation": "Leer la documentación", + "desc": "Las notificaciones push web requieren un contexto seguro (https://…). Esto es una limitación del navegador. Accede a Frigate de forma segura para usar las notificaciones." + }, + "globalSettings": { + "title": "Configuración global", + "desc": "Suspender temporalmente las notificaciones de cámaras específicas en todos los dispositivos registrados." + }, + "email": { + "title": "Correo electrónico", + "placeholder": "p.ej. ejemplo@correo.com", + "desc": "Se requiere un correo electrónico válido y se utilizará para notificarte si hay algún problema con el servicio de notificaciones push." + }, + "cameras": { + "title": "Cámaras", + "noCameras": "No hay cámaras disponibles", + "desc": "Selecciona qué cámaras habilitar para las notificaciones." + }, + "deviceSpecific": "Configuración específica del dispositivo", + "registerDevice": "Registrar este dispositivo", + "sendTestNotification": "Enviar una notificación de prueba", + "active": "Notificaciones activas", + "suspended": "Notificaciones suspendidas {{time}}", + "suspendTime": { + "5minutes": "Suspender por 5 minutos", + "1hour": "Suspender por 1 hora", + "12hours": "Suspender por 12 horas", + "untilRestart": "Suspender hasta reiniciar", + "30minutes": "Suspender por 30 minutos", + "24hours": "Suspender por 24 horas", + "10minutes": "Suspender por 10 minutos", + "suspend": "Suspender" + }, + "cancelSuspension": "Cancelar suspensión", + "toast": { + "success": { + "settingSaved": "La configuración de notificaciones se ha guardado.", + "registered": "Registrado correctamente para las notificaciones. Es necesario reiniciar Frigate antes de que se puedan enviar notificaciones (incluida una notificación de prueba)." + }, + "error": { + "registerFailed": "Error al guardar el registro de notificaciones." + } + }, + "unregisterDevice": "Cancelar el registro de este dispositivo" + }, + "frigatePlus": { + "title": "Configuración de Frigate+", + "apiKey": { + "title": "Clave API de Frigate+", + "notValidated": "La clave API de Frigate+ no ha sido detectada o no ha sido validada", + "plusLink": "Lee más sobre Frigate+", + "desc": "La clave API de Frigate+ permite la integración con el servicio Frigate+.", + "validated": "La clave API de Frigate+ ha sido detectada y validada" + }, + "snapshotConfig": { + "title": "Configuración de instantáneas", + "documentation": "Leer la documentación", + "table": { + "camera": "Cámara", + "snapshots": "Instantáneas", + "cleanCopySnapshots": "clean_copy Instantáneas" + }, + "desc": "Enviar a Frigate+ requiere que tanto las capturas instantáneas como las capturas clean_copy estén habilitadas en tu configuración.", + "cleanCopyWarning": "Algunas cámaras tienen las instantáneas habilitadas pero tienen la copia limpia desactivada. Necesitas habilitar clean_copy en tu configuración de instantáneas para poder enviar imágenes de estas cámaras a Frigate+." + }, + "modelInfo": { + "title": "Información del modelo", + "modelType": "Tipo de modelo", + "baseModel": "Modelo base", + "supportedDetectors": "Detectores compatibles", + "dimensions": "Dimensiones", + "cameras": "Cámaras", + "loading": "Cargando información del modelo…", + "error": "No se pudo cargar la información del modelo", + "availableModels": "Modelos disponibles", + "loadingAvailableModels": "Cargando modelos disponibles…", + "modelSelect": "Tus modelos disponibles en Frigate+ se pueden seleccionar aquí. Ten en cuenta que solo se pueden seleccionar modelos compatibles con tu configuración actual de detectores.", + "trainDate": "Fecha de entrenamiento", + "plusModelType": { + "baseModel": "Modelo Base", + "userModel": "Ajustado Finamente" + } + }, + "toast": { + "success": "La configuración de Frigate+ se ha guardado. Reinicia Frigate para aplicar los cambios.", + "error": "No se pudieron guardar los cambios en la configuración: {{errorMessage}}" + }, + "restart_required": "Es necesario reiniciar (se ha cambiado el modelo Frigate+)" + } +} diff --git a/web/public/locales/es/views/system.json b/web/public/locales/es/views/system.json new file mode 100644 index 000000000..6a9f7ad47 --- /dev/null +++ b/web/public/locales/es/views/system.json @@ -0,0 +1,179 @@ +{ + "documentTitle": { + "storage": "Estadísticas de almacenamiento - Frigate", + "general": "Estadísticas generales - Frigate", + "logs": { + "frigate": "Registros de Frigate - Frigate", + "go2rtc": "Registros de Go2RTC - Frigate", + "nginx": "Registros de Nginx - Frigate" + }, + "cameras": "Estadísticas de cámaras - Frigate", + "enrichments": "Estadísticas de Enriquecimientos - Frigate" + }, + "logs": { + "copy": { + "label": "Copiar al portapapeles", + "success": "Registros copiados al portapapeles", + "error": "No se pudieron copiar los registros al portapapeles" + }, + "type": { + "label": "Tipo", + "timestamp": "Marca de tiempo", + "tag": "Etiqueta", + "message": "Mensaje" + }, + "tips": "Los registros se están transmitiendo desde el servidor", + "toast": { + "error": { + "fetchingLogsFailed": "Error al obtener los registros: {{errorMessage}}", + "whileStreamingLogs": "Error mientras se transmitían los registros: {{errorMessage}}" + } + }, + "download": { + "label": "Descargar registros" + } + }, + "title": "Sistema", + "metrics": "Métricas del sistema", + "general": { + "title": "General", + "detector": { + "title": "Detectores", + "inferenceSpeed": "Velocidad de inferencia del detector", + "cpuUsage": "Uso de CPU del Detector", + "memoryUsage": "Uso de Memoria del Detector", + "temperature": "Detector de Temperatura" + }, + "hardwareInfo": { + "title": "Información de Hardware", + "gpuUsage": "Uso de GPU", + "gpuEncoder": "Codificador de GPU", + "gpuDecoder": "Decodificador de GPU", + "gpuInfo": { + "vainfoOutput": { + "title": "Salida de Vainfo", + "returnCode": "Código de Retorno: {{code}}", + "processOutput": "Salida del Proceso:", + "processError": "Error del Proceso:" + }, + "nvidiaSMIOutput": { + "cudaComputerCapability": "Capacidad de Cómputo CUDA: {{cuda_compute}}", + "title": "Salida de Nvidia SMI", + "driver": "Controlador: {{driver}}", + "name": "Nombre: {{name}}", + "vbios": "Información de VBios: {{vbios}}" + }, + "toast": { + "success": "Información de GPU copiada al portapapeles" + }, + "copyInfo": { + "label": "Copiar información de GPU" + }, + "closeInfo": { + "label": "Cerrar información de GPU" + } + }, + "gpuMemory": "Memoria de GPU", + "npuMemory": "Memoria de NPU", + "npuUsage": "Uso de NPU" + }, + "otherProcesses": { + "title": "Otros Procesos", + "processCpuUsage": "Uso de CPU del Proceso", + "processMemoryUsage": "Uso de Memoria del Proceso" + } + }, + "storage": { + "recordings": { + "title": "Grabaciones", + "tips": "Este valor representa el almacenamiento total utilizado por las grabaciones en la base de datos de Frigate. Frigate no realiza un seguimiento del uso de almacenamiento de todos los archivos en tu disco.", + "earliestRecording": "Grabación más antigua disponible:" + }, + "overview": "Resumen", + "title": "Almacenamiento", + "cameraStorage": { + "percentageOfTotalUsed": "Porcentaje del Total", + "bandwidth": "Ancho de Banda", + "camera": "Cámara", + "unused": { + "title": "No Utilizado", + "tips": "Este valor puede no representar con precisión el espacio libre disponible para Frigate si tienes otros archivos almacenados en tu disco además de las grabaciones de Frigate. Frigate no realiza un seguimiento del uso de almacenamiento fuera de sus grabaciones." + }, + "title": "Almacenamiento de la Cámara", + "storageUsed": "Almacenamiento", + "unusedStorageInformation": "Información de Almacenamiento No Utilizado" + } + }, + "cameras": { + "title": "Cámaras", + "overview": "Resumen", + "info": { + "cameraProbeInfo": "Información de Sondeo de la Cámara {{camera}}", + "streamDataFromFFPROBE": "Los datos del flujo se obtienen con ffprobe.", + "codec": "Codec:", + "fetching": "Obteniendo Datos de la Cámara", + "stream": "Flujo {{idx}}", + "video": "Video:", + "fps": "FPS:", + "resolution": "Resolución:", + "error": "Error: {{error}}", + "unknown": "Desconocido", + "audio": "Audio:", + "tips": { + "title": "Información de Sondeo de la Cámara" + } + }, + "framesAndDetections": "Fotogramas / Detecciones", + "label": { + "camera": "cámara", + "skipped": "omitido", + "detect": "detectar", + "ffmpeg": "FFmpeg", + "capture": "captura", + "overallFramesPerSecond": "cuadros por segundo totales", + "overallDetectionsPerSecond": "detecciones por segundo totales", + "cameraSkippedDetectionsPerSecond": "{{camName}} detecciones omitidas por segundo", + "cameraFfmpeg": "{{camName}} FFmpeg", + "cameraCapture": "{{camName}} captura", + "cameraDetect": "{{camName}} detectar", + "cameraFramesPerSecond": "{{camName}} cuadros por segundo", + "cameraDetectionsPerSecond": "{{camName}} detecciones por segundo", + "overallSkippedDetectionsPerSecond": "detecciones omitidas por segundo totales" + }, + "toast": { + "success": { + "copyToClipboard": "Datos de sondeo copiados al portapapeles." + }, + "error": { + "unableToProbeCamera": "No se pudo sondear la cámara: {{errorMessage}}" + } + } + }, + "lastRefreshed": "Última actualización: ", + "enrichments": { + "infPerSecond": "Inferencias Por Segundo", + "embeddings": { + "plate_recognition_speed": "Velocidad de Reconocimiento de Matrículas", + "face_embedding_speed": "Velocidad de Incrustación de Rostros", + "image_embedding_speed": "Velocidad de Incrustación de Imágenes", + "text_embedding_speed": "Velocidad de Incrustación de Texto", + "face_recognition_speed": "Velocidad de Reconocimiento Facial", + "text_embedding": "Incrustación de Texto", + "face_recognition": "Reconocimiento Facial", + "plate_recognition": "Reconocimiento de Matrículas", + "yolov9_plate_detection": "Detección de Matrículas YOLOv9", + "image_embedding": "Incrustación de Imágenes", + "yolov9_plate_detection_speed": "Velocidad de Detección de Matrículas YOLOv9" + }, + "title": "Enriquecimientos" + }, + "stats": { + "ffmpegHighCpuUsage": "{{camera}} tiene un uso elevado de CPU por FFmpeg ({{ffmpegAvg}}%)", + "detectHighCpuUsage": "{{camera}} tiene un uso elevado de CPU por detección ({{detectAvg}}%)", + "healthy": "El sistema está saludable", + "reindexingEmbeddings": "Reindexando incrustaciones ({{processed}}% completado)", + "detectIsSlow": "{{detect}} es lento ({{speed}} ms)", + "cameraIsOffline": "{{camera}} está desconectada", + "detectIsVerySlow": "{{detect}} es muy lento ({{speed}} ms)" + } +} diff --git a/web/public/locales/fi/audio.json b/web/public/locales/fi/audio.json new file mode 100644 index 000000000..aa288ae14 --- /dev/null +++ b/web/public/locales/fi/audio.json @@ -0,0 +1,17 @@ +{ + "speech": "Puhe", + "yell": "Huutaa", + "babbling": "Pulina", + "boat": "Vene", + "cat": "Kissa", + "dog": "Koira", + "horse": "Hevonen", + "sheep": "Lammas", + "bird": "Lintu", + "car": "Auto", + "motorcycle": "Moottoripyörä", + "bus": "Bussi", + "train": "Juna", + "bicycle": "Pyörä", + "skateboard": "Rullalauta" +} diff --git a/web/public/locales/fi/common.json b/web/public/locales/fi/common.json new file mode 100644 index 000000000..c45340fee --- /dev/null +++ b/web/public/locales/fi/common.json @@ -0,0 +1,44 @@ +{ + "time": { + "untilRestart": "Kunnes uudelleenkäynnistyy", + "ago": "{{timeAgo}} sitten", + "justNow": "Juuri nyt", + "today": "Tänään", + "yesterday": "Eilen", + "last14": "Viimeiset 14 päivää", + "untilForTime": "Kunnes {{time}}", + "untilForRestart": "Kunnes Frigate uudelleenkäynnistyy.", + "thisWeek": "Tämä viikko", + "lastWeek": "Viime viikko", + "last7": "Viimeiset 7 päivää", + "thisMonth": "Tämä kuu", + "lastMonth": "Viime kuu", + "last30": "Viimeiset 30 päivää", + "5minutes": "5 minuuttia", + "10minutes": "10 minuuttia", + "30minutes": "30 minuuttia", + "1hour": "1 tunti", + "12hours": "12 tuntia", + "24hours": "24 tuntia", + "pm": "ip", + "am": "ap", + "yr": "{{time}}v", + "year_one": "{{time}} vuosi", + "year_other": "{{time}} vuotta", + "mo": "{{time}}kk", + "month_one": "{{time}} kuukausi", + "month_other": "{{time}} kuukaudet", + "d": "{{time}}pv", + "day_one": "{{time}} päivä", + "day_other": "{{time}} päivät", + "h": "{{time}}t", + "hour_one": "{{time}} tunti", + "hour_other": "{{time}} tuntia", + "m": "{{time}}m", + "s": "{{time}}s", + "minute_one": "{{time}}minuutti", + "minute_other": "{{time}}minuuttia", + "second_one": "{{time}}sekuntti", + "second_other": "{{time}}sekunttia" + } +} diff --git a/web/public/locales/fi/components/auth.json b/web/public/locales/fi/components/auth.json new file mode 100644 index 000000000..5ce3ffa02 --- /dev/null +++ b/web/public/locales/fi/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "password": "Salasana", + "user": "Käyttäjä", + "login": "Kirjaudu", + "errors": { + "usernameRequired": "Käyttäjänimi vaaditaan", + "passwordRequired": "Salasana vaaditaan", + "rateLimit": "Käyttöraja ylitetty. Yritä myöhemmin uudelleen.", + "loginFailed": "Kirjautuminen epäonnistui", + "unknownError": "Tuntematon virhe. Tarkista logit.", + "webUnknownError": "Tuntematon virhe. Tarkista konsolilogi." + } + } +} diff --git a/web/public/locales/fi/components/camera.json b/web/public/locales/fi/components/camera.json new file mode 100644 index 000000000..14ebd87fb --- /dev/null +++ b/web/public/locales/fi/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "label": "Kameraryhmä", + "add": "Lisää kameraryhmä", + "edit": "Muokkaa kameraryhmää", + "delete": { + "label": "Poista kameraryhmä", + "confirm": { + "title": "Varmista poisto", + "desc": "Oletko varma että haluat poistaa kameraryhmän {{name}}?" + } + }, + "name": { + "label": "Nimi", + "placeholder": "Anna nimi…", + "errorMessage": { + "mustLeastCharacters": "Kameraryhmän nimi täytyy olla vähintään 2 kirjainta.", + "exists": "Kameraryhmän nimi on jo olemassa.", + "nameMustNotPeriod": "Kameraryhmän nimi ei voi sisältää pistettä.", + "invalid": "Virheellinen kameraryhmän nimi." + } + }, + "cameras": { + "label": "Kamerat", + "desc": "Valitse ryhmän kamera." + }, + "icon": "Ikoni", + "success": "Kameraryhmä ({{name}}) on tallennettu.", + "camera": { + "setting": { + "label": "Kameran suoratoistoasetukset", + "title": "{{cameraName}} suoratoistoasetukset", + "desc": "Muuta tämän kameraryhmän kojelaudan live-suoratoistoasetuksia.Nämä asetukset ovat laite/selainkohtaisia.", + "audioIsAvailable": "Ääni on saatavilla tähän suoratoistoon", + "audioIsUnavailable": "Ääni ei ole saatavilla tähän suoratoistoon", + "audio": { + "tips": { + "title": "Äänen on oltava kytkettynä kameraan ja määritettynä go2rtc:ssä tätä suoratoistoa varten.", + "document": "Lue dokumentaatio " + } + }, + "streamMethod": { + "label": "Suoratoistomenetelmä", + "method": { + "noStreaming": { + "label": "Ei suoratoistoa", + "desc": "Kamerakuvat päivittyvät vain kerran minuutissa, eikä suoratoistoa tapahdu." + }, + "smartStreaming": { + "label": "Älykäs suoratoisto (suositus)", + "desc": "Älykäs suoratoisto päivittää kamerakuvan kerran minuutissa kun havaittavaa toimintaa ei tapahdu, säästääkseen kaistanleveyttä ja resursseja. Kun toimintaa havaitaan, kuva vaihtuu saumattomasti reaaliaikaiseksi suoratoistoksi." + }, + "continuousStreaming": { + "label": "Jatkuva suoratoisto", + "desc": { + "title": "Kamerakuva näkyy aina reaaliaikaisena suoratoistona kojelaudassa, vaikka mitään liikettä ei havaitaisi.", + "warning": "Jatkuva suoratoisto voi lisätä kaistanleveyden käyttöä ja suorituskykyongelmia. Käytä varoen." + } + } + } + }, + "compatibilityMode": { + "label": "Yhteensopivuustila", + "desc": "Ota tämä vaihtoehto käyttöön vain, jos kamerasi live-suoratoistossa näkyy väriartefakteja ja kuvan oikealla puolella on vinoviiva." + } + } + } + }, + "debug": { + "options": { + "label": "Asetukset", + "title": "Vaihtoehdot", + "showOptions": "Näytä vaihtoehdot", + "hideOptions": "Piilota vaihtoehdot" + }, + "boundingBox": "Rajauslaatikko", + "timestamp": "Aikaleima", + "zones": "Vyöhykkeet", + "mask": "Peite", + "motion": "Liike", + "regions": "Alueet" + } +} diff --git a/web/public/locales/fi/components/dialog.json b/web/public/locales/fi/components/dialog.json new file mode 100644 index 000000000..c248f48b1 --- /dev/null +++ b/web/public/locales/fi/components/dialog.json @@ -0,0 +1,19 @@ +{ + "restart": { + "title": "Haluatko varmasti käynnistää Frigaten uudelleen?", + "button": "Uudelleenkäynnistys", + "restarting": { + "title": "Fregatti käynnistyy uudelleen", + "content": "Tämä sivu latautuu uudelleen {{countdown}} sekunnin kuluttua.", + "button": "Pakota uudelleenlataus nyt" + } + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "Lähetä Frigate+:lle", + "desc": "Välttämissäsi paikoissa olevat kohteet eivät ole vääriä positiivisia. Niiden lähettäminen väärinä positiivisina sekoittaa mallia." + } + } + } +} diff --git a/web/public/locales/fi/components/filter.json b/web/public/locales/fi/components/filter.json new file mode 100644 index 000000000..b254e27e1 --- /dev/null +++ b/web/public/locales/fi/components/filter.json @@ -0,0 +1,3 @@ +{ + "filter": "Suodatin" +} diff --git a/web/public/locales/fi/components/icons.json b/web/public/locales/fi/components/icons.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/fi/components/icons.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/fi/components/input.json b/web/public/locales/fi/components/input.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/fi/components/input.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/fi/components/player.json b/web/public/locales/fi/components/player.json new file mode 100644 index 000000000..43e7e7153 --- /dev/null +++ b/web/public/locales/fi/components/player.json @@ -0,0 +1,4 @@ +{ + "noPreviewFound": "Esikatselua ei löytynyt", + "noPreviewFoundFor": "Ei esikatselua {{cameraName}}lle" +} diff --git a/web/public/locales/fi/objects.json b/web/public/locales/fi/objects.json new file mode 100644 index 000000000..10ca41476 --- /dev/null +++ b/web/public/locales/fi/objects.json @@ -0,0 +1,55 @@ +{ + "frisbee": "Frisbee", + "knife": "Veitsi", + "umbrella": "Sateenvarjo", + "tie": "Kravatti", + "suitcase": "Matkalaukku", + "baseball_glove": "Pesäpallohanska", + "spoon": "Lusikka", + "person": "Henkilö", + "bicycle": "Pyörä", + "car": "Auto", + "motorcycle": "Moottoripyörä", + "airplane": "Lentokone", + "bus": "Bussi", + "train": "Juna", + "boat": "Vene", + "traffic_light": "Liikennevalo", + "fire_hydrant": "Paloposti", + "street_sign": "Tieviitta", + "stop_sign": "Stop merkki", + "parking_meter": "Pysäköintimittari", + "bench": "Penkki", + "bird": "Lintu", + "cat": "Kissa", + "dog": "Koira", + "horse": "Hevonen", + "sheep": "Lammas", + "cow": "Lehmä", + "elephant": "Elefantti", + "bear": "Karhu", + "zebra": "Seepra", + "giraffe": "Kirahvi", + "hat": "Hattu", + "backpack": "Reppu", + "shoe": "Kenkä", + "eye_glasses": "Silmälasit", + "handbag": "Käsilaukku", + "skis": "Sukset", + "snowboard": "Lumilauta", + "sports_ball": "Pallo", + "kite": "Leija", + "baseball_bat": "Pesäpallomaila", + "skateboard": "Rullalauta", + "surfboard": "Surffilauta", + "tennis_racket": "Tennismaila", + "bottle": "Pullo", + "plate": "Lautanen", + "wine_glass": "Viinilasi", + "cup": "Kuppi", + "fork": "Haarukka", + "bowl": "Malja", + "banana": "Banaani", + "apple": "Omena", + "couch": "Sohva" +} diff --git a/web/public/locales/fi/views/configEditor.json b/web/public/locales/fi/views/configEditor.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/fi/views/configEditor.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/fi/views/events.json b/web/public/locales/fi/views/events.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/fi/views/events.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/fi/views/explore.json b/web/public/locales/fi/views/explore.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/fi/views/explore.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/fi/views/exports.json b/web/public/locales/fi/views/exports.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/fi/views/exports.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/fi/views/faceLibrary.json b/web/public/locales/fi/views/faceLibrary.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/fi/views/faceLibrary.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/fi/views/live.json b/web/public/locales/fi/views/live.json new file mode 100644 index 000000000..69c0d23bf --- /dev/null +++ b/web/public/locales/fi/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "Suora - Frigate", + "documentTitle.withCamera": "{{camera}} - Suora - Frigate", + "lowBandwidthMode": "Pienen kaistanleveyden tila", + "twoWayTalk": { + "enable": "Ota käyttöön kaksisuuntainen puhe", + "disable": "Poista kaksisuuntainen puhe käytöstä" + }, + "cameraAudio": { + "enable": "Ota kameran ääni käyttöön", + "disable": "Poista kameran ääni käytöstä" + }, + "ptz": { + "move": { + "clickMove": { + "label": "Napsauta ruutua keskittääksesi kameran", + "enable": "Ota käyttöön napsauttamalla siirtäminen", + "disable": "Poista napsauttamalla siirtäminen" + }, + "left": { + "label": "Siirrä PTZ-kameraa vasemmalle" + }, + "up": { + "label": "Siirrä PTZ-kameraa ylös" + }, + "down": { + "label": "Siirrä PTZ-kameraa alas" + }, + "right": { + "label": "Siirrä PTZ-kameraa oikealle" + } + }, + "zoom": { + "out": { + "label": "Zoomaa PTZ-kamera ulos" + }, + "in": { + "label": "Zoomaa PTZ-kamera sisään" + } + }, + "frame": { + "center": { + "label": "Napsauta kehystä keskittääksesi PTZ-kamera" + } + }, + "presets": "PTZ-kameroiden esiasetukset" + }, + "camera": { + "enable": "Ota kamera käyttöön", + "disable": "Poista kamera käytöstä" + }, + "muteCameras": { + "enable": "Mykistä kaikki kamerat", + "disable": "Poista kaikkien kameroiden mykistys" + }, + "detect": { + "enable": "Ota tunnistus käyttöön", + "disable": "Poista tunnistus käytöstä" + }, + "recording": { + "enable": "Ota tallennus käyttöön", + "disable": "Poista tallennus käytöstä" + }, + "snapshots": { + "enable": "Ota tilannekuva käyttöön", + "disable": "Poista tilannekuva käytöstä" + }, + "audioDetect": { + "enable": "Ota käyttöön äänen tunnistus", + "disable": "Poista äänen tunnistus käytöstä" + }, + "autotracking": { + "enable": "Ota automaattinen seuranta käyttöön", + "disable": "Poista automaattinen seuranta käytöstä" + }, + "streamStats": { + "enable": "Näytä suoratoiston tilastot", + "disable": "Piilota suoratoiston tilastot" + }, + "manualRecording": { + "title": "Tallennus pyynnöstä", + "tips": "Aloita manuaalinen tapahtuma tämän kameran tallenteen tallennusasetusten perusteella.", + "playInBackground": { + "label": "Toista taustalla", + "desc": "Ota tämä asetus käyttöön, jos haluat jatkaa suoratoistoa kun soitin on piilotettu." + }, + "showStats": { + "label": "Näytä tilastot", + "desc": "Ota tämä asetus käyttöön, jos haluat näyttää suoratoistotilastot kamerasyötteen päällä." + }, + "debugView": "Virheenkorjausnäkymä", + "start": "Aloita tallennus pyynnöstä", + "started": "Manuaalinen pyynnöstätallennus aloitettu.", + "failedToStart": "Manuaalisen pyynnöstätallennuksen aloittaminen epäonnistui.", + "recordDisabledTips": "Koska tallennus on poistettu käytöstä tai rajoitettu tämän kameran asetuksissa, vain tilannekuva tallennetaan.", + "end": "Lopeta pyynnöstätallennus", + "ended": "Manuaalinen on-demand-tallennus lopetettu.", + "failedToEnd": "Manuaalisen pyynnöstätallennuksen lopettaminen epäonnistui." + }, + "streamingSettings": "Suoratoistoasetukset", + "notifications": "Ilmoitukset", + "audio": "Ääni", + "suspend": { + "forTime": "Keskeytys: " + }, + "stream": { + "title": "Suoratoisto", + "audio": { + "tips": { + "title": "Äänen on oltava kytkettynä kameraan ja määritettynä go2rtc:ssä tätä suoratoistoa varten.", + "documentation": "Lue dokumentaatio " + }, + "available": "Ääni on saatavilla tälle suoratoistolle", + "unavailable": "Ääni ei ole saatavilla tälle suoratoistolle" + }, + "twoWayTalk": { + "tips": "Laitteesi on tuettava ominaisuutta ja WebRTC:n on oltava määritetty kaksisuuntaista ääntä varten.", + "tips.documentation": "Lue dokumentaatio ", + "available": "Kaksisuuntainen ääni on saatavilla tässä suoratoistossa", + "unavailable": "Kaksisuuntainen ääni ei ole käytettävissä tässä suoratoistossa" + }, + "lowBandwidth": { + "tips": "Live-näkymä on matalan kaistanleveyden tilassa puskuroinnin tai suoratoistovirheiden vuoksi.", + "resetStream": "Nollaa suoratoisto" + }, + "playInBackground": { + "label": "Toista taustalla", + "tips": "Ota tämä asetus käyttöön, jos haluat jatkaa suoratoistoa, kun soitin on piilotettu." + } + }, + "cameraSettings": { + "title": "{{camera}} Asetukset", + "cameraEnabled": "Kamera käytössä", + "objectDetection": "Kohteen tunnistus", + "recording": "Nauhoitus", + "snapshots": "Tilannekuvat", + "audioDetection": "Äänen tunnistus", + "autotracking": "Automaattinen seuranta" + }, + "history": { + "label": "Näytä historiallista materiaalia" + }, + "effectiveRetainMode": { + "modes": { + "all": "Kaikki", + "motion": "Liike", + "active_objects": "Aktiiviset kohteet" + }, + "notAllTips": "{{source}}-tallenteiden säilytysmäärityksesi on asetettu tila: {{effectiveRetainMode}}, joten tämä tilattu tallenne säilyttää vain ne osat joiden tyyppi on {{effectiveRetainModeName}}." + }, + "editLayout": { + "label": "Muokkaa asettelua", + "group": { + "label": "Muokkaa kameraryhmää" + }, + "exitEdit": "Poistu muokkauksesta" + } +} diff --git a/web/public/locales/fi/views/recording.json b/web/public/locales/fi/views/recording.json new file mode 100644 index 000000000..84daba26f --- /dev/null +++ b/web/public/locales/fi/views/recording.json @@ -0,0 +1,12 @@ +{ + "calendar": "Kalenteri", + "filter": "Suodatin", + "filters": "Suodattimet", + "toast": { + "error": { + "noValidTimeSelected": "Sopimaton aikaväli valittu", + "endTimeMustAfterStartTime": "Loppuaika täytyy olla aloituksen jälkeen" + } + }, + "export": "Vie" +} diff --git a/web/public/locales/fi/views/search.json b/web/public/locales/fi/views/search.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/fi/views/search.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/fi/views/settings.json b/web/public/locales/fi/views/settings.json new file mode 100644 index 000000000..cc982214d --- /dev/null +++ b/web/public/locales/fi/views/settings.json @@ -0,0 +1,428 @@ +{ + "documentTitle": { + "camera": "Kamera-asetukset - Frigate", + "classification": "Klassifiointiasetukset - Frigate", + "masksAndZones": "Peite ja vyöhykemuokkain - Frigate", + "motionTuner": "Liikesäädin - Frigate", + "default": "Asetukset - Frigate", + "general": "Yleiset asetukset - Frigate", + "frigatePlus": "Frigate+ asetukset - Frigate", + "object": "Objektiasetukset - Frigate", + "authentication": "Autentikointiuasetukset - Frigate" + }, + "menu": { + "ui": "Käyttöliittymä", + "cameras": "Kameroiden asetukset", + "users": "Käyttäjät", + "classification": "Klassifiointi", + "frigateplus": "Frigate+", + "masksAndZones": "Maskit / alueet", + "debug": "Debuggaus", + "motionTuner": "Liikesäädin", + "notifications": "Ilmoitukset" + }, + "dialog": { + "unsavedChanges": { + "desc": "Haluatko tallentaa muutokset ennen jatkamista?", + "title": "Et ole tallentanut muutoksia." + } + }, + "cameraSetting": { + "camera": "Kamera", + "noCamera": "Ei kameraa" + }, + "general": { + "title": "Yleiset asetukset", + "liveDashboard": { + "automaticLiveView": { + "label": "Automaattinen reaaliaika-näkymä", + "desc": "Vaihda automaattisesti reaaliaikaiseen kameranäkymään kun liikettä on huomattu. Mikäli asetus on kytketty pois päivittyy reaaliaikaisen kojelaudan kuva vain kerran minuutissa." + }, + "title": "Reaaliaikainen kojelauta", + "playAlertVideos": { + "label": "Näytä hälyytysvideot", + "desc": "Vakiona viimeaikaiset hälytykset pyörivät pieninä luuppaavina videoina reaaliaikaisella kojelaudalla. Ota tämä asetus pois päältä näyttääksesi vain staattisen kuvan viimeaikaisista hälytyksistä tässä laitteessa/selaimessa." + } + }, + "storedLayouts": { + "title": "Tallennetut sijoittelut", + "desc": "Kameroiden sijoittelua kameraryhmissä voidaan raahata tai niiden kokoa muuttaa. Sijainnit tallennetaan selaimen paikalliseen muistiin.", + "clearAll": "Tyhjennä kaikki sijoittelut" + }, + "cameraGroupStreaming": { + "title": "Kameraryhmän striimauksen asetukset", + "desc": "Striimauksen asetukset jokaiselle kameraryhmälle tallennetaan selaimesi paikalliseen muistiin.", + "clearAll": "Tyhjennä kaikkai striimauksen asetukset" + }, + "recordingsViewer": { + "title": "Tallennusten näyttäjä", + "defaultPlaybackRate": { + "label": "Toiston vakionopeus", + "desc": "Toiston vakionopeus tallennusten näytölle." + } + }, + "calendar": { + "title": "Kalenteri", + "firstWeekday": { + "label": "Viikon ensimmäinen päivä", + "desc": "Päivä josta kertauskalenterin viikot alkaa.", + "sunday": "sunnuntai", + "monday": "maanantai" + } + }, + "toast": { + "success": { + "clearStoredLayout": "Tyhjennä tallennetut sijoittelut kameralle nimeltä {{cameraName}}", + "clearStreamingSettings": "Tyhjennä striimausasetukset kaikista kameraryhmistä." + }, + "error": { + "clearStoredLayoutFailed": "Sijoittelujen tyhjentäminen ei onnistunut: {{errorMessage}}", + "clearStreamingSettingsFailed": "Striimausasetusten tyhjentäminen ei onnistunut: {{errorMessage}}" + } + } + }, + "classification": { + "title": "Klassifiointiasetukset", + "semanticSearch": { + "reindexNow": { + "label": "Uudelleen indeksoi nyt", + "confirmDesc": "Oletko varma että haluat indeksoida uudelleen kaikki seurattujen kohteiden upotukset? Tämä prosessi toimii taustalla ja saattaa maksimoida prosessorin käytön sekä viedä runsaasti aikaa. Voit seurata prosessin etenemistä tarkastelu -sivulta.", + "desc": "Indeksoinnin luominen uudelleen jälleenrakentaa upotukset kaikkiin seurattuihin kohteisiin. Tämä prosessi toimii taustalla ja saattaa maksimoida prosessorin käytön sekä viedä reilusti aikaa riippuen paljonko seurattavia kohteita sinulla on.", + "confirmButton": "Indeksoi uudelleen", + "success": "Uudelleen indeksointi aloitettiin onnistuneesti.", + "alreadyInProgress": "Uudelleen indeksointi on jo käynnissä.", + "error": "Uudelleen indeksointia ei voitu aloittaa: {{errorMessage}}", + "confirmTitle": "Vahvista uudelleen indeksointi" + }, + "modelSize": { + "label": "Mallin koko", + "small": { + "desc": "Valitessa pieni käytetään kvantisoitunutta versiota mallista joka käyttää vähemmän muistia sekä prosesoria upotuksen laatueron ollessa lähes olematon.", + "title": "pieni" + }, + "large": { + "desc": "Valittaessa suuri käytettään täyttä Jina-mallia joka ajetaan automaattisesti grafiikkaytimellä mikäli mahdollista.", + "title": "suuri" + }, + "desc": "Semanttisen haun upotuksiin käytetyn mallin koko." + }, + "title": "Semanttinen haku", + "readTheDocumentation": "Lue dokumentaatio", + "desc": "Frigaten semanttisen haun kanssa voit hakea seurattuja kohteita esikatseluista joko kuvasta itsestään, käyttäjän määrittelemän teksti-kuvauksen perusteella tai automaattisesti generoidun kuvauksen kanssa." + }, + "faceRecognition": { + "title": "Kasvojentunnistus", + "readTheDocumentation": "Lue dokumentaatio", + "modelSize": { + "label": "Mallin koko", + "desc": "Kasvojentunnistukseen käytetyn mallin koko.", + "small": { + "title": "pieni", + "desc": "Valitessa pieni FaceNet käyttää kasvojen upotukseen mallia joka toimii tehokkaasti suurimmalla osalla prosessoreista." + }, + "large": { + "title": "suuri", + "desc": "Valitessa suuri käytetään ArcFace mallia kasvojen upotukseen joka ajetaan automaattisesti grafiikkaprosessorilla mikäli mahdollista." + } + }, + "desc": "Kasvojentunnistus sallii nimien antamisen ihmisille ja kun heidän kasvonsa tunnistetaan Frigate antaa henkilölle nimen ala-viittenä. Tämä tieto sisällytetään käyttöliittymään, filttereihin sekä ilmoituksiin." + }, + "licensePlateRecognition": { + "title": "Rekisterikilven tunnistus", + "desc": "Frigate voi tunnistaa ajoneuvojen rekisterikilpiä ja lisätä tunnistetut kirjaimet automaattisesti recognized_license_plate -kenttään tai tunnettu nimi sub_label kohteisiin joiden tyyppi on ajoneuvo. Yleinen käyttökohde on lukea pihatielle ajavien tai kadulla ohiajavien ajoneuvojen rekisterikilvet.", + "readTheDocumentation": "Lue dokumentaatio" + }, + "toast": { + "success": "Klassifiointiasetukset on tallennettu. Käynnistä Frigate uudelleen saadaksesi ne käyttöön.", + "error": "Konfiguraatio muutoksia ei voitu tallentaa: {{errorMessage}}" + }, + "restart_required": "Tarvitaan uudelleenkäynnistys (luokitusasetuksia muutettu)", + "birdClassification": { + "title": "Lintujen luokittelu", + "desc": "Lintujen luokittelu tunnistaa tunnetut linnut kvantisoidun Tensorflow-mallin avulla. Kun tunnettu lintu tunnistetaan, sen yleinen nimi lisätään alitunnisteena. Tämä tieto sisältyy käyttöliittymään, suodattimiin ja ilmoituksiin." + } + }, + "camera": { + "title": "Kamera-asetukset", + "streams": { + "title": "Striimit", + "desc": "Kameran poiskytkeminen lopettaa kameran videostriimien käsittelyn. Havainnot, tallennus ja debuggaus ovat pois käytöstä.
    Huom: tämä ei poista käytöstä go2rtc uusinta striimejä." + }, + "review": { + "title": "Katselu", + "desc": "Kytke päälle/pois hälytykset ja tunnistus tälle kameralle. Kun ne ovat pois päältä, uusia katseltavia tapahtumia ei luoda.", + "alerts": "Hälytykset ", + "detections": "Tunnistukset " + }, + "reviewClassification": { + "title": "Katseluiden klassifiointi", + "readTheDocumentation": "Lue dokumentaatio", + "noDefinedZones": "Tälle kameralle ei ole määritelty vyöhykkeitä.", + "objectAlertsTips": "Kaikki {{alertsLabels}} objektit lähteelle {{cameraName}} näytetään hälytyksinä.", + "zoneObjectAlertsTips": "Kaikki {{alertsLabels}} objektit jotka tunnistetaan alueella {{zone}} lähteessä {{cameraName}} näytetään Hälytyksinä.", + "objectDetectionsTips": "Kaikki {{detectionsLabels}} objektit joita ei ole kategorisoitu lähteessä {{cameraName}} näytetään Tunnistuksina niiden vyöhykkeestä huolimatta.", + "zoneObjectDetectionsTips": { + "text": "Kaikki {{detectionsLabels}} objektit joita ei ole kategorisoitu vyöhykkeellä {{zone}} lähteessä {{cameraName}} näytetään Tunnistuksina.", + "notSelectDetections": "Kaikki {{detectionsLabels}} objektit jotka tunnistetaan vyöhykkeellä {{zone}} lähteessä {{cameraName}}, joita ei ole kategorisoitu Hälytyksiksi näytetään Tunnistuksina niiden vyöhykkeestä huolimatta.", + "regardlessOfZoneObjectDetectionsTips": "Kaikki {{detectionsLabels}} objektit joita ei ole kategorisoitu lähteessä {{cameraName}} näytetään Tunnistuksina niiden vyöhykkeestä huolimatta." + }, + "selectAlertsZones": "Valitse vyöhykkeet Hälytystä varten", + "desc": "Frigate kategorisoi tahtumia Hälytyksiksi ja Tunnistuksiksi. Vakiona kaikki henkilö sekä ajoneuvo objektit käsitellään Hälytyksinä. Voit kategorisoida uudelleen katseltavat tapahtumat antamalla niille vaaditut alueet.", + "limitDetections": "Rajoita tunnistukset tiettyihin vyöhykkeisiin", + "selectDetectionsZones": "Valitse vyöhykkeet tunnistusta varten", + "toast": { + "success": "Luokittelumäärityksen tarkistus on tallennettu. Käynnistä Frigate uudelleen muutosten käyttöönottamiseksi." + } + } + }, + "masksAndZones": { + "filter": { + "all": "Kaikki peitteet ja vyöhykkeet" + }, + "form": { + "polygonDrawing": { + "delete": { + "desc": "Oletko varma että haluat poistaa {{type}}{{name}}?", + "success": "{{name}} on poistettu.", + "title": "Varmista poistaminen" + }, + "error": { + "mustBeFinished": "Polygonien piirron pitää olla valmis ennen tallennusta." + }, + "removeLastPoint": "Poista edellinen piste", + "snapPoints": { + "true": "Napsauta pisteet", + "false": "Älä napsauta pisteitä" + }, + "reset": { + "label": "Poista kaikki pisteet" + } + }, + "zoneName": { + "error": { + "mustBeAtLeastTwoCharacters": "Alueen nimen tulee olla vähintään 2 merkin pituinen.", + "alreadyExists": "Tämän niminen alue on jo olemassa.", + "mustNotContainPeriod": "Alueen nimessä ei saa olla pisteitä.", + "hasIllegalCharacter": "Vyöhykkeen nimessä on kiellettyjä merkkejä.", + "mustNotBeSameWithCamera": "Alueen nimi ei saa olla sama kuin kameran nimi." + } + }, + "distance": { + "error": { + "text": "Välimatkan tulee olla suurempi tai yhtä suuri kuin 0.1.", + "mustBeFilled": "Kaikki välimatka -kentät tulee olla täytetty jotta nopeusarviota voidaan käyttää." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "Inertian tulee olla yli 0." + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "Oleiluaika tulee olla suurempi tai yhtä suuri kuin 0." + } + } + }, + "zones": { + "label": "Vyöhykkeet", + "documentTitle": "Muokkaa vyöhykkeitä - Frigate", + "edit": "Myokkaa vyöhykettä", + "inertia": { + "title": "Inertia", + "desc": "Määrittää, kuinka monta kehystä objektin on oltava vyöhykkeellä, ennen kuin se lasketaan vyöhykkeeksi. Oletus: 3" + }, + "loiteringTime": { + "title": "Oleskeluaika", + "desc": "Asettaa vähimmäisajan sekunteina, jonka objektin on oltava vyöhykkeellä, jotta se aktivoituu. Oletus: 0" + }, + "objects": { + "title": "Kohteet", + "desc": "Luettelo tähän vyöhykkeeseen liittyvistä kohteista." + }, + "desc": { + "title": "Vyöhykkeiden avulla voit määrittää tietyn alueen kuvassa, jotta voit selvittää, onko kohde kyseisellä alueella.", + "documentation": "Dokumentaatio" + }, + "add": "Lisää vyöhyke", + "clickDrawPolygon": "Napsauta piirtääksesi monikulmion kuvaan.", + "name": { + "title": "Nimi", + "inputPlaceHolder": "Anna nimi…", + "tips": "Nimen on oltava vähintään kaksi merkkiä pitkä, eikä se saa olla kameran tai toisen vyöhykkeen nimi." + }, + "point_one": "{{count}} piste", + "point_other": "{{count}} pisteet", + "allObjects": "Kaikki kohteet", + "speedEstimation": { + "title": "Nopeuden arviointi", + "desc": "Ota käyttöön nopeuden arviointi tällä vyöhykkeellä oleville kohteille. Sillä on oltava täsmälleen 4 pistettä." + }, + "speedThreshold": { + "title": "Nopeuskynnys ({{unit}})", + "desc": "Määrittää kohteiden vähimmäisnopeuden, joka otetaan huomioon tässä vyöhykkeessä.", + "toast": { + "error": { + "pointLengthError": "Nopeuden arviointi on poistettu käytöstä tällä vyöhykkeellä. Vyöhykkeillä joilla on nopeuden arviointi, on oltava täsmälleen 4 pistettä.", + "loiteringTimeError": "Vyöhykkeitä, joiden oleskeluajat ovat yli 0, ei tule käyttää nopeuden arvioinnissa." + } + } + }, + "toast": { + "success": "Vyöhyke ({{zoneName}}) on tallennettu. Käynnistä Frigatti uudelleen muutosten käyttöönottamiseksi." + } + }, + "toast": { + "error": { + "copyCoordinatesFailed": "Koordinaattien kopioiminen leikepöydälle epäonnistui." + }, + "success": { + "copyCoordinates": "{{polyName}} - koordinaatit kopioitu leikepöydälle." + } + }, + "restart_required": "Uudelleenkäynnistys vaaditaan (peitteitä/vyöhykeitä muutettu)", + "motionMasks": { + "point_one": "{{count}} piste", + "point_other": "{{count}} pisteet", + "clickDrawPolygon": "Napsauta piirtääksesi monikulmion kuvaan.", + "label": "Liikepeitto", + "context": { + "documentation": "Lue dokumentaatio", + "title": "Liikepeittoja käytetään estämään ei-toivottujen liiketyyppien (esimerkiksi puiden oksat, kameroiden aikaleimat) aiheuttamat tunnistukset. Liikepeittoja tulisi käyttää hyvin säästeliäästi, sillä liiallinen maskaus vaikeuttaa kohteiden seurantaa." + }, + "documentTitle": "Muokkaa liikepeittoa - Frigate", + "desc": { + "title": "Liikepeittoa käytetään estämään ei-toivottujen liiketyyppien aiheuttamat tunnistukset. Liiallinen peittäminen vaikeuttaa kohteiden seurantaa.", + "documentation": "Dokumentaatio" + }, + "add": "Uusi liikepeitto", + "edit": "Muokkaa liikepeittoa", + "polygonAreaTooLarge": { + "title": "Liikepeitto peittää {{polygonArea}}% kameran kuvasta. Suuria liikemaskeja ei suositella.", + "tips": "Liikepeitto eivät estä kohteiden havaitsemista. Sinun tulisi sen sijaan käyttää vaadittua vyöhykettä.", + "documentation": "Lue dokumentaatio" + }, + "toast": { + "success": { + "title": "{{polygonName}} on tallennettu. Käynnistä Frigatti uudelleen muutosten käyttöönottamiseksi.", + "noName": "Liikepeitto on tallennettu. Käynnistä Frigatti uudelleen muutosten käyttöönottamiseksi." + } + } + }, + "objectMasks": { + "point_one": "{{count}} piste", + "point_other": "{{count}} pisteet", + "label": "Kohdepeitot", + "context": "Objektisuodatinpeittoja käytetään suodattamaan pois väärät positiiviset tulokset tietylle kohdetyypille sijainnin perusteella.", + "objects": { + "title": "Kohteet", + "desc": "Kohdetyyppi, jota käytetään tähän kohdepeittoon.", + "allObjectTypes": "Kaikki kohdetyypit" + }, + "toast": { + "success": { + "title": "{{polygonName}} on tallennettu. Käynnistä Frigatti uudelleen muutosten käyttöönottamiseksi.", + "noName": "Kohdepeitto on tallennettu. Käynnistä Frigatti uudelleen muutosten käyttöönottamiseksi." + } + }, + "documentTitle": "Muokkaa kohdepeittoa - Frigate", + "desc": { + "title": "Objektisuodatinpeittoja käytetään suodattamaan pois väärät positiiviset tulokset tietylle kohdetyypille sijainnin perusteella.", + "documentation": "Dokumentaatio" + }, + "add": "Lisää kohdepeitto", + "edit": "Muokkaa kohdepeittoa", + "clickDrawPolygon": "Napsauta piirtääksesi monikulmion kuvaan." + } + }, + "debug": { + "regions": { + "title": "Alueet", + "desc": "Näytä kohdeilmaisimelle lähetetyn kiinnostuksen kohteena olevan alueen laatikko", + "tips": "

    Aluelaatikot


    Kirkkaanvihreät laatikot peittävät kuvassa olevat kiinnostavat alueet, jotka lähetetään objektinilmaisimelle.

    " + }, + "objectShapeFilterDrawing": { + "title": "Objektin muodon suodattimen piirtäminen", + "desc": "Piirrä kuvaan suorakulmio nähdäksesi pinta-alan ja kuvasuhteen tiedot", + "document": "Lue dokumentaatio ", + "score": "Pisteet", + "ratio": "Suhde", + "area": "Alue", + "tips": "Ota tämä asetus käyttöön piirtääksesi kamerakuvaan suorakulmion, joka näyttää sen pinta-alan ja suhteen. Näitä arvoja voidaan sitten käyttää objektin muodon suodatusparametrien asettamiseen asetuksissasi." + }, + "timestamp": { + "title": "Aikaleima", + "desc": "Lisää aikaleima kuvan päälle" + }, + "noObjects": "Ei kohteita", + "zones": { + "title": "Vyöhykkeet", + "desc": "Näytä määriteltyjen vyöhykkeiden ääriviivat" + }, + "boundingBoxes": { + "colors": { + "info": "
  • Käynnistettäessä kullekin kohteen merkinnälle määritetään eri värit
  • Tummansininen ohut viiva osoittaa, että kohdetta ei ole havaittu tällä hetkellä
  • Harmaa ohut viiva osoittaa, että kohde on havaittu paikallaan olevaksi
  • Paksu viiva osoittaa, että kohde on automaattisen seurannan kohteena (kun se on käytössä)
  • " + } + }, + "mask": { + "title": "Liikepeitot", + "desc": "Näytä liikepeiton monikulmiot" + }, + "motion": { + "title": "Liikelaatikot", + "desc": "Näytä laatikot alueiden ympärillä, joilla liikettä havaitaan", + "tips": "

    Liikelaatikot


    Punaiset laatikot peittävät ruudun alueet, joilla liikettä havaitaan parhaillaan.

    " + } + }, + "users": { + "title": "Käyttäjät", + "management": { + "title": "Käyttäjien hallinta", + "desc": "Hallinnoi tämän Frigate-instanssin käyttäjätilejä." + }, + "addUser": "Lisää käyttäjä", + "updatePassword": "Päivitä salasana", + "toast": { + "success": { + "roleUpdated": "Rooli päivitetty käyttäjälle {{user}}", + "createUser": "Käyttäjä {{user}} luotu onnistuneesti", + "deleteUser": "Käyttäjä {{user}} poistettu onnistuneesti", + "updatePassword": "Salasana päivitetty onnistuneesti." + }, + "error": { + "setPasswordFailed": "Salasanan tallentaminen epäonnistui: {{errorMessage}}", + "createUserFailed": "Käyttäjän luonti epäonnistui: {{errorMessage}}", + "roleUpdateFailed": "Roolin päivittäminen epäonnistui: {{errorMessage}}", + "deleteUserFailed": "Käyttäjän poisto epäonistui: {{errorMessage}}" + } + }, + "table": { + "username": "Käyttäjänimi", + "actions": "Toiminnot", + "noUsers": "Käyttäjiä ei löytynyt.", + "changeRole": "Vaihda käyttäjäroolia", + "password": "Salasana", + "deleteUser": "Poista tili", + "role": "Rooli" + }, + "dialog": { + "form": { + "user": { + "desc": "Vain kirjaimet, numerot, pisteet ja alaviivat sallitaan.", + "placeholder": "Syötä käyttäjätunnus", + "title": "Käyttäjätunnus" + } + } + } + }, + "motionDetectionTuner": { + "title": "Liiketunnistuksen säätäminen", + "desc": { + "title": "Frigate käyttää liiketunnistusta ensimmäisenä tarkistuksena nähdäkseen, tapahtuuko kuvassa jotain, mikä kannattaisi tarkistaa objektitunnistuksella.", + "documentation": "Lue liikkeensäädön opas" + }, + "Threshold": { + "title": "Kynnys" + } + } +} diff --git a/web/public/locales/fi/views/system.json b/web/public/locales/fi/views/system.json new file mode 100644 index 000000000..78138fc41 --- /dev/null +++ b/web/public/locales/fi/views/system.json @@ -0,0 +1,9 @@ +{ + "logs": { + "type": { + "timestamp": "Aikaleima", + "tag": "Tagi", + "message": "Viesti" + } + } +} diff --git a/web/public/locales/fr/audio.json b/web/public/locales/fr/audio.json new file mode 100644 index 000000000..9388b1307 --- /dev/null +++ b/web/public/locales/fr/audio.json @@ -0,0 +1,429 @@ +{ + "speech": "Conversation", + "babbling": "Babillage", + "yell": "Crier", + "bicycle": "Vélo", + "car": "Voiture", + "bellow": "Ci-dessous", + "whispering": "Chuchotement", + "laughter": "Rires", + "snicker": "Ricanement", + "crying": "Pleurs", + "boat": "Bateau", + "bus": "Bus", + "train": "Train", + "motorcycle": "Moto", + "whoop": "Cri", + "sigh": "Soupir", + "singing": "Chant", + "choir": "Chorale", + "yodeling": "Yodel", + "chant": "Chant", + "mantra": "Mantra", + "child_singing": "Chant d'enfant", + "bird": "Oiseau", + "cat": "Chat", + "synthetic_singing": "Chant synthétique", + "rapping": "Rap", + "horse": "Cheval", + "dog": "Chien", + "sheep": "Mouton", + "whistling": "Sifflement", + "breathing": "Respiration", + "snoring": "Ronflement", + "gasp": "Souffle", + "pant": "halètement", + "snort": "Reniflement", + "camera": "Caméra", + "cough": "Toussotement", + "groan": "Gémissement", + "grunt": "Grognement", + "throat_clearing": "Éclaircissement de la gorge", + "wheeze": "Respiration bruyante", + "sneeze": "Éternuement", + "sniff": "Reniflement", + "chewing": "Mastication", + "gargling": "Gargarisme", + "ambulance": "Ambulance", + "police_car": "Voiture de police", + "emergency_vehicle": "Véhicule d'urgence", + "subway": "Métro", + "fire_alarm": "Alarme Incendie", + "smoke_detector": "Détecteur de Fumée", + "siren": "Sirène", + "pulleys": "Poulies", + "gears": "Engrenages", + "clock": "Horloge", + "ratchet": "Cliquet", + "mechanisms": "Mécanismes", + "steam_whistle": "Sifflet à vapeur", + "whistle": "Sifflet", + "foghorn": "Corne de brume", + "tools": "Outils", + "printer": "Imprimante", + "air_conditioning": "Climatisation", + "mechanical_fan": "Ventilateur mécanique", + "sewing_machine": "Machine à coudre", + "wood": "Bois", + "fireworks": "Feux d'artifice", + "glass": "Verre", + "television": "Télévision", + "sound_effect": "Effet sonore", + "burping": "Rots", + "fart": "Pet", + "crowd": "Foule", + "children_playing": "Enfants en train de jouer", + "animal": "Animal", + "bark": "Aboiement", + "pig": "Cochon", + "goat": "Chèvre", + "chicken": "Poulet", + "turkey": "Dinde", + "duck": "Canard", + "goose": "Dindon", + "wild_animals": "Animaux Sauvages", + "crow": "Corbeau", + "dogs": "Chiens", + "mouse": "Souris", + "insect": "Insecte", + "cricket": "Grillon", + "mosquito": "Moustique", + "fly": "Mouche", + "frog": "Grenouille", + "snake": "Serpent", + "music": "Musique", + "guitar": "Guitare", + "electric_guitar": "Guitare électrique", + "keyboard": "Clavier", + "piano": "Piano", + "vehicle": "Véhicule", + "skateboard": "Skateboard", + "door": "Porte", + "blender": "Mixer", + "hair_dryer": "Sèche cheveux", + "toothbrush": "Brosse à dents", + "sink": "Lavabo", + "scissors": "Paire de ciseaux", + "humming": "Bourdonnement", + "shuffle": "Mélanger", + "footsteps": "Pas", + "hiccup": "Hoquet", + "finger_snapping": "Claquement de doigts", + "clapping": "Claquements", + "applause": "Applaudissements", + "heartbeat": "Battements de coeur", + "cheering": "Applaudissement", + "electric_shaver": "Rasoir électrique", + "truck": "Camion", + "run": "Démarrer", + "biting": "Mordre", + "stomach_rumble": "Gargouillements d'estomac", + "hands": "Mains", + "heart_murmur": "Souffle au cœur", + "chatter": "Bavarder", + "pets": "Animaux de compagnie", + "yip": "Ouais", + "howl": "Hurler", + "growling": "Grondement", + "whimper_dog": "Gémissements de chien", + "purr": "Ronronnements", + "caterwaul": "Miaulement", + "meow": "Miaou", + "livestock": "Bétail", + "neigh": "Hennissement", + "quack": "Coin-coin", + "honk": "Klaxon", + "roaring_cats": "Feulements", + "roar": "Rugissements", + "chirp": "Gazouillis", + "squawk": "Braillement", + "pigeon": "Pigeon", + "coo": "Roucoulement", + "caw": "Croassement", + "owl": "Chouette", + "hoot": "Hululement", + "flapping_wings": "Battement d'ailes", + "rats": "Rats", + "patter": "Crépitements", + "buzz": "Bourdonnement", + "croak": "Coassement", + "rattle": "Cliquetis", + "whale_vocalization": "Chant des baleines", + "musical_instrument": "Instrument de musique", + "plucked_string_instrument": "Instrument à cordes pincées", + "bass_guitar": "Guitare basse", + "acoustic_guitar": "Guitare acoustique", + "tapping": "Tapotement", + "strum": "Grattement", + "banjo": "Banjo", + "sitar": "Sitar", + "mandolin": "Mandoline", + "steel_guitar": "Steel Guitar", + "zither": "Cithare", + "ukulele": "Ukulélé", + "electric_piano": "Piano électrique", + "organ": "Orgue", + "electronic_organ": "Orgue électrique", + "hammond_organ": "Orgue Hammond", + "synthesizer": "Synthétiseur", + "sampler": "Échantillonneur", + "harpsichord": "Clavecin", + "percussion": "Percussions", + "drum_kit": "Batterie", + "drum_machine": "Boîte à rythmes", + "drum": "Tambour", + "snare_drum": "Caisse claire", + "rimshot": "Rimshot", + "drum_roll": "Roulement de tambour", + "bass_drum": "Grosse caisse", + "timpani": "Timbales", + "tabla": "Tabla", + "cymbal": "Cymbale", + "hi_hat": "Charleston", + "wood_block": "Wood Block", + "maraca": "Maraca", + "gong": "Gong", + "tubular_bells": "Carillon tubulaire", + "marimba": "Marimba", + "mallet_percussion": "Maillet de percussion", + "glockenspiel": "Glockenspiel", + "vibraphone": "Vibraphone", + "steelpan": "Pan", + "orchestra": "Orchestre", + "brass_instrument": "Cuivres", + "french_horn": "Cor français", + "trumpet": "Trompette", + "bowed_string_instrument": "Instrument à cordes frottées", + "string_section": "Section des cordes", + "violin": "Violon", + "pizzicato": "Pizzicato", + "cello": "Violoncelle", + "double_bass": "Contrebasse", + "wind_instrument": "Instrument à vent", + "flute": "Flûte", + "saxophone": "Saxophone", + "clarinet": "Clarinette", + "harp": "Harpe", + "church_bell": "Cloche d'église", + "bell": "Cloche", + "jingle_bell": "Grelot", + "bicycle_bell": "Sonnette de vélo", + "tuning_fork": "Diapason", + "chime": "Carillon", + "wind_chime": "Carillon à vent", + "harmonica": "Harmonica", + "accordion": "Accordéon", + "bagpipes": "Cornemuse", + "didgeridoo": "Didgeridoo", + "theremin": "Thérémine", + "singing_bowl": "Bol chantant", + "scratching": "Scratch", + "pop_music": "Musique pop", + "hip_hop_music": "Musique hip-hop", + "beatboxing": "Beatboxing", + "rock_music": "Musique rock", + "punk_rock": "Punk Rock", + "soul_music": "Musique Soul", + "reggae": "Reggae", + "country": "Country", + "funk": "Funk", + "folk_music": "Musique Folk", + "jazz": "Jazz", + "techno": "Techno", + "dubstep": "Dubstep", + "drum_and_bass": "Drum and Bass", + "traditional_music": "Musique traditionnelle", + "independent_music": "Musique indépendante", + "song": "Chanson", + "background_music": "Musique de fond", + "theme_music": "Thème musical", + "jingle": "Tintement", + "soundtrack_music": "Musique de bande originale", + "lullaby": "Berceuse", + "video_game_music": "Musique de jeux vidéo", + "dance_music": "Musique Dance", + "wedding_music": "Musique de mariage", + "happy_music": "Musique joyeuse", + "sad_music": "Musique triste", + "tender_music": "Musique tendre", + "exciting_music": "Musique stimulante", + "angry_music": "Musique énervée", + "scary_music": "Musique effrayante", + "wind": "Vent", + "rustling_leaves": "Bruissements de feuilles", + "wind_noise": "Bruit de vent", + "thunderstorm": "Orage", + "thunder": "Tonnerre", + "water": "Eau", + "rain": "Pluie", + "raindrop": "Goutte de pluie", + "rain_on_surface": "Pluie sur une surface", + "stream": "Flux", + "waterfall": "Cascade", + "ocean": "Océan", + "waves": "Vagues", + "steam": "Vapeur", + "gurgling": "Gargouillis", + "fire": "Feu", + "crackle": "Crépitement", + "sailboat": "Voilier", + "rowboat": "Chaloupe", + "motorboat": "Bateau à moteur", + "ship": "Bateau", + "motor_vehicle": "Véhicule à moteur", + "toot": "Sifflotement", + "car_alarm": "Alarme de voiture", + "power_windows": "Vitres électriques", + "skidding": "Dérapage", + "tire_squeal": "Crissements de pneu", + "car_passing_by": "Passage de voiture", + "race_car": "Course de voitures", + "air_brake": "Frein pneumatique", + "air_horn": "Klaxon à air", + "reversing_beeps": "Bips de marche arrière", + "ice_cream_truck": "Camion de glaces", + "fire_engine": "Camion de pompiers", + "traffic_noise": "Bruit de circulation", + "rail_transport": "Transport ferroviaire", + "train_whistle": "Sifflet de train", + "train_horn": "Klaxon de train", + "railroad_car": "Wagon de chemin de fer", + "train_wheels_squealing": "Crissements de roues de train", + "aircraft": "Aéronef", + "aircraft_engine": "Moteur d'avion", + "jet_engine": "Moteur à réaction", + "propeller": "Hélice", + "helicopter": "Hélicoptère", + "fixed-wing_aircraft": "Avion à voilure fixe", + "engine": "Moteur", + "light_engine": "Moteur léger", + "dental_drill's_drill": "Fraise dentaire", + "lawn_mower": "Tondeuse à gazon", + "chainsaw": "Tronçonneuse", + "heavy_engine": "Moteur lourd", + "engine_knocking": "Détonations de moteur", + "engine_starting": "Démarrage de moteur", + "accelerating": "Accélération", + "doorbell": "Sonnette", + "ding-dong": "Ding-Dong", + "knock": "Coup", + "tap": "Tapotement", + "squeak": "Grincement", + "cupboard_open_or_close": "Ouverture ou fermeture de placard", + "drawer_open_or_close": "Ouverture ou fermeture de tiroir", + "dishes": "Plats", + "cutlery": "Couverts", + "chopping": "Hacher", + "frying": "Friture", + "microwave_oven": "Four à micro-ondes", + "water_tap": "Robinet d'eau", + "bathtub": "Baignoire", + "toilet_flush": "Chasse d'eau", + "electric_toothbrush": "Brosse à dents électrique", + "vacuum_cleaner": "Aspirateur", + "zipper": "Fermeture éclair", + "keys_jangling": "Tintements de clés", + "coin": "Pièce de monnaie", + "shuffling_cards": "Mélange de cartes", + "typing": "Frappe au clavier", + "typewriter": "Machine à écrire", + "writing": "Écriture", + "alarm": "Alarme", + "telephone_bell_ringing": "Sonnerie de téléphone", + "ringtone": "Sonnerie", + "telephone_dialing": "Numérotation téléphonique", + "dial_tone": "Tonalité", + "busy_signal": "Tonalité occupée", + "alarm_clock": "Réveille-matin", + "civil_defense_siren": "Sirène d'alerte aux populations", + "buzzer": "Buzzer", + "tick": "Tic-tac", + "tick-tock": "Tic-Tac", + "cash_register": "Caisse enregistreuse", + "single-lens_reflex_camera": "Appareil photo reflex mono-objectif", + "hammer": "Marteau", + "jackhammer": "Marteau-piqueur", + "sawing": "Sciage", + "filing": "Limage", + "sanding": "Ponçage", + "power_tool": "Outil électrique", + "drill": "Perceuse", + "explosion": "Explosion", + "gunshot": "Coup de feu", + "machine_gun": "Mitrailleuse", + "fusillade": "Fusillade", + "artillery_fire": "Tir d'artillerie", + "cap_gun": "Pistolet à amorces", + "firecracker": "Pétard", + "eruption": "Éruption", + "boom": "Boom", + "chop": "Coup de hache", + "splinter": "Éclat", + "crack": "Fissure", + "chink": "Fente", + "shatter": "Brisure", + "silence": "Silence", + "environmental_noise": "Bruit ambiant", + "static": "Statique", + "white_noise": "Bruit blanc", + "pink_noise": "Bruit rose", + "field_recording": "Enregistrement sur le terrain", + "scream": "Cri", + "tambourine": "Tambourin", + "electronic_music": "Musique électronique", + "rock_and_roll": "Rock and Roll", + "vocal_music": "Musique vocale", + "trombone": "Trombone", + "flamenco": "Flamenco", + "carnatic_music": "Musique carnatique", + "a_capella": "A Capella", + "christmas_music": "Musique de Noël", + "afrobeat": "Afrobeat", + "sliding_door": "Porte coulissante", + "opera": "Opéra", + "music_of_africa": "Musique d'Afrique", + "music_of_latin_america": "Musique d'Amérique Latine", + "blues": "Blues", + "music_for_children": "Musique pour enfants", + "electronica": "Electronica", + "ska": "Ska", + "salsa_music": "Salsa", + "medium_engine": "Moteur moyen", + "heavy_metal": "Heavy Metal", + "disco": "Disco", + "grunge": "Grunge", + "music_of_asia": "Musique d'Asie", + "progressive_rock": "Rock progressif", + "psychedelic_rock": "Rock psychédélique", + "rhythm_and_blues": "Rhythm and Blues", + "electronic_dance_music": "Electronic Dance Music", + "trance_music": "Musique Trance", + "new-age_music": "Musique New Age", + "bluegrass": "Bluegrass", + "swing_music": "Musique Swing", + "ambient_music": "Musique d'ambiance", + "middle_eastern_music": "Musique orientale", + "house_music": "Musique House", + "christian_music": "Musique chrétienne", + "classical_music": "Musique classique", + "gospel_music": "Musique Gospel", + "slam": "Claquement", + "computer_keyboard": "Clavier d'ordinateur", + "burst": "Éclatement", + "music_of_bollywood": "Musique de Bollywood", + "idling": "Ralenti", + "radio": "Radio", + "telephone": "Téléphone", + "bow_wow": "Ouaf ouaf", + "hiss": "Sifflement", + "clip_clop": "Clic-clac", + "cattle": "Bétail", + "moo": "Meuglement", + "cowbell": "Clochette", + "oink": "Grouin-grouin", + "bleat": "Bêler", + "fowl": "Volaille", + "cluck": "Gloussement", + "cock_a_doodle_doo": "Cocorico", + "gobble": "Glouglou" +} diff --git a/web/public/locales/fr/common.json b/web/public/locales/fr/common.json new file mode 100644 index 000000000..32cb68df5 --- /dev/null +++ b/web/public/locales/fr/common.json @@ -0,0 +1,265 @@ +{ + "time": { + "untilForRestart": "Jusqu'au redémarrage de Frigate.", + "untilRestart": "Jusqu'au redémarrage", + "untilForTime": "Jusqu'à {{time}}", + "justNow": "À l'instant", + "today": "Aujourd'hui", + "last7": "7 derniers jours", + "last14": "14 derniers jours", + "ago": "{{timeAgo}} avant", + "yesterday": "Hier", + "last30": "30 derniers jours", + "thisWeek": "Cette semaine", + "lastWeek": "Semaine dernière", + "thisMonth": "Ce mois-ci", + "lastMonth": "Mois dernier", + "10minutes": "10 minutes", + "5minutes": "5 minutes", + "30minutes": "30 minutes", + "12hours": "12 heures", + "h": "{{time}}h", + "pm": "PM", + "am": "AM", + "yr": "{{time}}a", + "year_one": "{{time}} année", + "year_many": "{{time}} années", + "year_other": "{{time}} années", + "mo": "{{time}}m", + "month_one": "{{time}} mois", + "month_many": "{{time}} mois", + "month_other": "{{time}} mois", + "s": "{{time}}s", + "second_one": "{{time}} seconde", + "second_many": "{{time}} secondes", + "second_other": "{{time}} secondes", + "m": "{{time}}m", + "hour_one": "{{time}} heure", + "hour_many": "{{time}} heures", + "hour_other": "{{time}} heures", + "24hours": "24 heures", + "minute_one": "{{time}} minute", + "minute_many": "{{time}} minutes", + "minute_other": "{{time}} minutes", + "d": "{{time}}j", + "day_one": "{{time}} jour", + "day_many": "{{time}} jours", + "day_other": "{{time}} jours", + "1hour": "1 heure", + "formattedTimestamp": { + "12hour": "d MMM HH:mm:ss", + "24hour": "d MMM HH:mm:ss" + }, + "formattedTimestampWithYear": { + "24hour": "%b %-d %Y, %H:%M", + "12hour": "%b %-d %Y, %I:%M %p" + }, + "formattedTimestampOnlyMonthAndDay": "%b %-d", + "formattedTimestampExcludeSeconds": { + "12hour": "%b %-d, %I:%M %p", + "24hour": "%b %-d, %H:%M" + }, + "formattedTimestamp2": { + "12hour": "dd/MM HH:mm:ss", + "24hour": "d MMM HH:mm:ss" + }, + "formattedTimestampHourMinute": { + "24hour": "HH:mm", + "12hour": "HH:mm" + }, + "formattedTimestampMonthDay": "d MMM", + "formattedTimestampFilename": { + "12hour": "dd-MM-yy-HH-mm-ss", + "24hour": "dd-MM-yy-HH-mm-ss" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "d MMM HH:mm", + "24hour": "d MMM HH:mm" + }, + "formattedTimestampHourMinuteSecond": { + "24hour": "HH:mm:ss", + "12hour": "HH:mm:ss" + }, + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "d MMM yyyy, HH:mm", + "24hour": "d MMM yyyy HH:mm" + } + }, + "button": { + "apply": "Appliquer", + "reset": "Réinitialiser", + "disabled": "Désactivé", + "save": "Enregistrer", + "saving": "Enregistrement…", + "close": "Fermer", + "copy": "Copier", + "back": "Retour", + "history": "Historique", + "pictureInPicture": "Image en incrustation", + "twoWayTalk": "Conversation bidirectionnelle", + "off": "Inactif", + "edit": "Editer", + "copyCoordinates": "Copier les coordonnées", + "delete": "Supprimer", + "yes": "Oui", + "no": "Non", + "unsuspended": "Reprendre", + "play": "Lire", + "unselect": "Désélectionner", + "suspended": "Suspendu", + "enable": "Activer", + "enabled": "Activé", + "info": "Info", + "disable": "Désactiver", + "cancel": "Annuler", + "fullscreen": "Plein écran", + "next": "Suivant", + "exitFullscreen": "Sortir du mode plein écran", + "cameraAudio": "Son de la caméra", + "on": "Actif", + "export": "Exporter", + "deleteNow": "Supprimer maintenant", + "download": "Télécharger", + "done": "Terminé" + }, + "menu": { + "configuration": "Configuration", + "language": { + "en": "Anglais (Anglais)", + "withSystem": { + "label": "Utiliser les paramètres système pour la langue" + }, + "zhCN": "简体中文 (Chinois simplifié)", + "hi": "हिन्दी (Hindi)", + "fr": "Français (Français)", + "ja": "日本語 (Japonais)", + "tr": "Türkçe (Turc)", + "it": "Italiano (Italien)", + "nl": "Nederlands (Néerlandais)", + "sv": "Svenska (Suédois)", + "cs": "Čeština (Tchèque)", + "nb": "Norsk Bokmål (Bokmål Norvégien)", + "ko": "한국어 (Coréen)", + "fa": "فارسی (Perse)", + "pl": "Polski (Polonais)", + "el": "Ελληνικά (Grec)", + "ro": "Română (Roumain)", + "hu": "Magyar (Hongrois)", + "he": "עברית (Hebreu)", + "ru": "Русский (Russe)", + "de": "Deutsch (Allemand)", + "es": "Español (Espagnol)", + "ar": "العربية (Arabe)", + "da": "Dansk (Danois)", + "fi": "Suomi (Finlandais)", + "pt": "Português (Portugais)", + "sk": "Slovenčina (Slovaque)", + "uk": "Українська (Ukrainien)", + "vi": "Tiếng Việt (Vietnamien)", + "yue": "粵語 (Cantonais)" + }, + "appearance": "Apparence", + "darkMode": { + "light": "Clair", + "dark": "Sombre", + "withSystem": { + "label": "Utiliser les paramètres système pour le mode clair ou sombre" + }, + "label": "Mode sombre" + }, + "review": "Visionner", + "explore": "Explorer", + "export": "Exporter", + "user": { + "account": "Compte", + "logout": "Se déconnecter", + "setPassword": "Configurer un mot de passe", + "current": "Utilisateur actuel : {{user}}", + "title": "Utilisateur", + "anonymous": "anonyme" + }, + "systemLogs": "Journaux système", + "documentation": { + "title": "Documentation", + "label": "Documentation de Frigate" + }, + "system": "Système", + "help": "Aide", + "configurationEditor": "Editeur de configuration", + "theme": { + "contrast": "Contraste élevé", + "blue": "Bleu", + "green": "Vert", + "nord": "Nord", + "red": "Rouge", + "default": "Défaut", + "label": "Thème", + "highcontrast": "Contraste élevé" + }, + "systemMetrics": "Indicateurs systèmes", + "settings": "Paramètres", + "withSystem": "Système", + "restart": "Redémarrer Frigate", + "live": { + "cameras": { + "count_one": "{{count}} Caméra", + "count_many": "{{count}} Caméras", + "count_other": "{{count}} Caméras", + "title": "Caméras" + }, + "allCameras": "Toutes les caméras", + "title": "Direct" + }, + "uiPlayground": "Gestion de l'interface", + "faceLibrary": "Librairie des visages", + "languages": "Langues" + }, + "toast": { + "save": { + "title": "Enregistrer", + "error": { + "noMessage": "Echec lors de l'enregistrement des changements de configuration", + "title": "Echec lors de l'enregistrement des changements de configuration : {{errorMessage}}" + } + }, + "copyUrlToClipboard": "Lien copié dans le presse-papier." + }, + "role": { + "title": "Rôle", + "viewer": "Observateur", + "admin": "Administrateur", + "desc": "Les administrateurs accèdent à l'ensemble des fonctionnalités de l'interface Frigate. Les observateurs sont limités à la consultation des caméras, au contrôle des évènements, et à l'historique des enregistrements." + }, + "pagination": { + "next": { + "title": "Suivant", + "label": "Aller à la page suivante" + }, + "more": "Plus de pages", + "previous": { + "label": "Aller à la page précédente", + "title": "Précédent" + }, + "label": "pagination" + }, + "notFound": { + "title": "404", + "documentTitle": "Non trouvé - Frigate", + "desc": "Page non trouvée" + }, + "selectItem": "Sélectionner {{item}}", + "accessDenied": { + "title": "Accès refusé", + "documentTitle": "Accès refusé - Frigate", + "desc": "Vous n'avez pas l'autorisation de voir cette page." + }, + "label": { + "back": "Retour" + }, + "unit": { + "speed": { + "kph": "km/h", + "mph": "mph" + } + } +} diff --git a/web/public/locales/fr/components/auth.json b/web/public/locales/fr/components/auth.json new file mode 100644 index 000000000..c6ff47c87 --- /dev/null +++ b/web/public/locales/fr/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "password": "Mot de passe", + "login": "Identifiant", + "user": "Nom d'utilisateur", + "errors": { + "unknownError": "Erreur inconnue. Vérifiez les journaux.", + "webUnknownError": "Erreur inconnue. Vérifiez les journaux de la console.", + "passwordRequired": "Un mot de passe est requis", + "loginFailed": "Échec de l'authentification", + "usernameRequired": "Un nom d'utilisateur est requis", + "rateLimit": "Limite de débit dépassée. Réessayez plus tard." + } + } +} diff --git a/web/public/locales/fr/components/camera.json b/web/public/locales/fr/components/camera.json new file mode 100644 index 000000000..0c959889b --- /dev/null +++ b/web/public/locales/fr/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "edit": "Éditer le groupe de caméras", + "label": "Groupe de caméras", + "add": "Ajouter un groupe de caméras", + "delete": { + "label": "Supprimer le groupe de caméras", + "confirm": { + "title": "Confirmer la suppression", + "desc": "Êtes-vous sûr de vouloir supprimer le groupe de caméras {{name}}?" + } + }, + "name": { + "placeholder": "Saisissez un nom…", + "label": "Nom", + "errorMessage": { + "mustLeastCharacters": "Le nom du groupe de caméras doit comporter au moins 2 caractères.", + "exists": "Le nom du groupe de caméras existe déjà.", + "nameMustNotPeriod": "Le nom de groupe de caméras ne doit pas contenir de période.", + "invalid": "Nom de groupe de caméras invalide." + } + }, + "cameras": { + "label": "Caméras", + "desc": "Sélectionner les caméras pour ce groupe." + }, + "success": "Le groupe de caméras ({{name}}) a été enregistré.", + "icon": "Icône", + "camera": { + "setting": { + "label": "Paramètres de flux de caméra", + "title": "{{cameraName}} Paramètres de flux", + "audioIsUnavailable": "L'audio n'est pas disponible pour ce flux", + "audioIsAvailable": "L'audio est disponible pour ce flux", + "desc": "Modifie les options du flux temps réel pour le tableau de bord de ce groupe de caméras. Ces paramètres sont spécifiques à un périphérique et/ou navigateur.", + "audio": { + "tips": { + "document": "Lire la documentation ", + "title": "L'audio doit provenir de la caméra et être configuré dans go2rtc pour ce flux." + } + }, + "streamMethod": { + "label": "Méthode de streaming", + "method": { + "noStreaming": { + "label": "Pas de streaming", + "desc": "Les images provenant de la caméra ne seront mises à jour qu'une fois par minute et il n'y aura pas de diffusion en direct." + }, + "smartStreaming": { + "label": "Streaming intelligent (recommandé)", + "desc": "Le streaming intelligent mettra à jour les images de la caméra une fois par minute lorsqu'aucune activité n'est détectée afin de conserver la bande-passante et les ressources. Quand une activité est détectée, le flux bascule automatiquement en diffusion temps réel." + }, + "continuousStreaming": { + "label": "Streaming continu", + "desc": { + "title": "L'image de la caméra sera toujours un flux temps réel lorsqu'elle est visible dans le tableau de bord, même si aucune activité n'est détectée.", + "warning": "Le streaming continu peut engendrer une bande-passante élevée et des problèmes de performance. A utiliser avec précaution." + } + } + } + }, + "compatibilityMode": { + "label": "Mode de compatibilité", + "desc": "Activer cette option uniquement si votre flux temps réel affiche des erreurs chromatiques et a une ligne diagonale sur le côté droit de l'image." + } + } + } + }, + "debug": { + "timestamp": "Horodatage", + "motion": "Mouvement", + "mask": "Masque", + "options": { + "showOptions": "Afficher les options", + "title": "Options", + "label": "Paramètres", + "hideOptions": "Masquer les options" + }, + "boundingBox": "Boîte de délimitation", + "zones": "Zones", + "regions": "Régions" + } +} diff --git a/web/public/locales/fr/components/dialog.json b/web/public/locales/fr/components/dialog.json new file mode 100644 index 000000000..e88b206a9 --- /dev/null +++ b/web/public/locales/fr/components/dialog.json @@ -0,0 +1,122 @@ +{ + "restart": { + "title": "Êtes-vous sûr de vouloir redémarrer Frigate ?", + "restarting": { + "title": "Frigate redémarre", + "content": "Cette page sera rechargée dans {{countdown}} secondes.", + "button": "Forcer le rechargement maintenant" + }, + "button": "Redémarrer" + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "Soumettre à Frigate+", + "desc": "Les objets situés dans des endroits que vous souhaitez éviter ne sont pas des faux positifs. Les soumettre comme faux positifs perturberait le modèle." + }, + "review": { + "true": { + "label": "Confirmez cette étiquette pour Frigate Plus", + "true_one": "C'est un {{label}}", + "true_many": "Ce sont des {{label}}", + "true_other": "Ce sont des {{label}}" + }, + "false": { + "false_one": "Ceci n'est pas un {{label}}", + "false_many": "Ceux-ci ne sont pas des {{label}}", + "false_other": "Ceux-ci ne sont pas des {{label}}", + "label": "Ne pas confirmer cette étiquette pour Frigate Plus" + }, + "state": { + "submitted": "Soumis" + }, + "question": { + "label": "Confirmez cette étiquette pour Frigate Plus", + "ask_an": "Est-ce que cet objet est un {{label}} ?", + "ask_a": "Est-ce un objet pour un {{label}} ?", + "ask_full": "Est-ce-que cet objet est un(e) {{untranslatedLabel}} ({{translatedLabel}}) ?" + } + } + }, + "video": { + "viewInHistory": "Afficher dans l'historique" + } + }, + "export": { + "time": { + "custom": "Personnalisé", + "fromTimeline": "Sélectionner depuis la chronologie", + "lastHour_one": "Dernière heure", + "lastHour_many": "{{count}} dernières heures", + "lastHour_other": "{{count}} dernières heures", + "end": { + "label": "Sélectionner l'heure de fin", + "title": "Heure de fin" + }, + "start": { + "label": "Sélectionner une heure de début", + "title": "Heure de début" + } + }, + "selectOrExport": "Sélectionner ou Exporter", + "toast": { + "error": { + "failed": "Échec du démarrage de l'export : {{error}}", + "endTimeMustAfterStartTime": "L'heure de fin doit être après l'heure de début", + "noVaildTimeSelected": "La plage horaire sélectionnée n'est pas valide" + }, + "success": "Exportation démarrée. Consulter le fichier dans le dossier /exports." + }, + "select": "Sélectionner", + "name": { + "placeholder": "Nommer l'export" + }, + "export": "Exporter", + "fromTimeline": { + "saveExport": "Enregistrer l'export", + "previewExport": "Prévisualiser l'export" + } + }, + "search": { + "saveSearch": { + "desc": "Fournissez un nom pour cette recherche enregistrée.", + "label": "Enregistrer la recherche", + "success": "La recherche ({{searchName}}) a été enregistrée.", + "button": { + "save": { + "label": "Enregistrer cette recherche" + } + }, + "overwrite": "{{searchName}} existe déjà. L'enregistrement écrasera la recherche existante.", + "placeholder": "Renseignez un nom pour votre recherche" + } + }, + "streaming": { + "label": "Flux", + "restreaming": { + "disabled": "Le renvoi du flux n'est pas activé pour cette caméra.", + "desc": { + "readTheDocumentation": "Lire la documentation", + "title": "Installer go2rtc pour accéder à des options supplémentaires de visionnage en direct et l'audio pour cette caméra." + } + }, + "showStats": { + "label": "Afficher les statistiques de flux", + "desc": "Activer cette option pour afficher les statistiques des flux en surimpression sur le flux de la caméra." + }, + "debugView": "Vue de débogage" + }, + "recording": { + "confirmDelete": { + "desc": { + "selected": "Êtes-vous certain de vouloir supprimer toutes les vidéos enregistrées associées à cet élément Review ?

    Pressez la touche Maj pour éviter cette boîte de dialogue dans le futur." + }, + "title": "Confirmer la suppression" + }, + "button": { + "export": "Exporter", + "markAsReviewed": "Marquer comme vérifié", + "deleteNow": "Supprimer maintenant" + } + } +} diff --git a/web/public/locales/fr/components/filter.json b/web/public/locales/fr/components/filter.json new file mode 100644 index 000000000..06b629963 --- /dev/null +++ b/web/public/locales/fr/components/filter.json @@ -0,0 +1,126 @@ +{ + "labels": { + "label": "Étiquettes", + "all": { + "title": "Toutes les étiquettes", + "short": "Étiquettes" + }, + "count": "{{count}} Étiquettes", + "count_one": "{{count}} Étiquette", + "count_other": "{{count}} Étiquettes" + }, + "filter": "Filtre", + "zones": { + "label": "Zones", + "all": { + "title": "Toutes les zones", + "short": "Zones" + } + }, + "dates": { + "all": { + "title": "Toutes les dates", + "short": "Dates" + } + }, + "more": "Plus de filtres", + "reset": { + "label": "Réinitialiser les filtres aux valeurs par défaut" + }, + "timeRange": "Plage de temps", + "subLabels": { + "label": "Sous-étiquettes", + "all": "Toutes les sous-étiquettes" + }, + "score": "Score", + "estimatedSpeed": "Vitesse estimée ({{unit}})", + "sort": { + "label": "Tri", + "dateDesc": "Date (ordre chronologique inverse)", + "dateAsc": "Date (ordre chronologique)", + "scoreDesc": "Score d'objet (Descendant)", + "scoreAsc": "Score d'objet (Ascendant)", + "speedAsc": "Vitesse estimée (Ascendant)", + "speedDesc": "Vitesse estimée (Descendant)", + "relevance": "Pertinence" + }, + "features": { + "submittedToFrigatePlus": { + "tips": "Vous devez d'abord filtrer les objets suivis qui ont un instantané.

    Les objets suivis sans instantané ne peuvent pas être soumis à Frigate+.", + "label": "Soumis à Frigate+" + }, + "hasVideoClip": "A un clip vidéo", + "hasSnapshot": "A un instantané", + "label": "Caractéristiques" + }, + "explore": { + "settings": { + "title": "Paramètres", + "defaultView": { + "title": "Vue par défaut", + "summary": "Résumé", + "unfilteredGrid": "Grille non filtrée", + "desc": "Lorsqu'aucun filtre n'est sélectionné, affiche un résumé des objets suivis les plus récents par étiquette, ou affiche une grille non filtrée." + }, + "gridColumns": { + "desc": "Sélectionner le nombre de colonnes dans la vue grille.", + "title": "Colonnes de la grille" + }, + "searchSource": { + "label": "Source de recherche", + "options": { + "thumbnailImage": "Image de la vignette", + "description": "Description" + }, + "desc": "Choisissez si vous souhaitez rechercher les vignettes ou les descriptions de vos objets suivis." + } + }, + "date": { + "selectDateBy": { + "label": "Sélectionner une date pour filtrer par" + } + } + }, + "review": { + "showReviewed": "Montrer les éléments évalués" + }, + "cameras": { + "label": "Filtre des caméras", + "all": { + "short": "Caméras", + "title": "Toutes les Caméras" + } + }, + "motion": { + "showMotionOnly": "Afficher uniquement le mouvement" + }, + "logSettings": { + "filterBySeverity": "Filtrer les journaux par sévérité", + "loading": { + "title": "Chargement", + "desc": "Lorsque le volet des journaux est défilé jusqu'en bas, les nouveaux enregistrements sont automatiquement diffusées au fur et à mesure de leur ajout." + }, + "label": "Niveau de journal du filtre", + "disableLogStreaming": "Désactiver la diffusion des journaux", + "allLogs": "Tous les journaux" + }, + "recognizedLicensePlates": { + "placeholder": "Tapez pour rechercher des plaques d'immatriculation…", + "noLicensePlatesFound": "Aucune plaque d'immatriculation trouvée.", + "loading": "Chargement des plaques d'immatriculation reconnues…", + "title": "Plaques d'immatriculation reconnues", + "loadFailed": "Échec du chargement des plaques d'immatriculation reconnues.", + "selectPlatesFromList": "Sélectionner une ou plusieurs plaques d'immatriculation dans la liste." + }, + "trackedObjectDelete": { + "title": "Confirmer la suppression", + "toast": { + "success": "Les objets suivis ont été supprimés avec succès.", + "error": "Échec de la suppression des objets suivis : {{errorMessage}}" + }, + "desc": "La suppression de ces objets suivis {{objectLength}} supprime l'instantané, les incorporations enregistrées et les entrées du cycle de vie de l'objet associées. Les séquences enregistrées de ces objets suivis dans la vue Historique NE seront PAS supprimées.

    Voulez-vous vraiment continuer ?

    Maintenez la touche Maj enfoncée pour ignorer cette boîte de dialogue à l'avenir." + }, + "zoneMask": { + "filterBy": "Filtrer par masque de zone" + } +} diff --git a/web/public/locales/fr/components/icons.json b/web/public/locales/fr/components/icons.json new file mode 100644 index 000000000..90ce0bb1f --- /dev/null +++ b/web/public/locales/fr/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "search": { + "placeholder": "Chercher une icône…" + }, + "selectIcon": "Sélectionnez une icône" + } +} diff --git a/web/public/locales/fr/components/input.json b/web/public/locales/fr/components/input.json new file mode 100644 index 000000000..6a79afa25 --- /dev/null +++ b/web/public/locales/fr/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Télécharger la vidéo", + "toast": { + "success": "Le téléchargement de votre vidéo de revue a commencé." + } + } + } +} diff --git a/web/public/locales/fr/components/player.json b/web/public/locales/fr/components/player.json new file mode 100644 index 000000000..90c1a4551 --- /dev/null +++ b/web/public/locales/fr/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "Aucun enregistrement trouvé pour cette période", + "noPreviewFoundFor": "Aucun aperçu trouvé pour {{cameraName}}", + "noPreviewFound": "Aucun aperçu trouvé", + "submitFrigatePlus": { + "title": "Soumettre cette image à Frigate+?", + "submit": "Soumettre" + }, + "streamOffline": { + "title": "Flux hors ligne", + "desc": "Aucune image n'a été reçue sur le flux de détection de la caméra {{cameraName}}, vérifiez le journal d'erreurs" + }, + "livePlayerRequiredIOSVersion": "iOS 17.1 ou une version ultérieure est requis pour ce type de flux en direct.", + "cameraDisabled": "La caméra est désactivée", + "stats": { + "streamType": { + "title": "Type de flux :", + "short": "Type" + }, + "bandwidth": { + "title": "Bande passante :", + "short": "Bande passante" + }, + "latency": { + "title": "Latence :", + "value": "{{seconds}} secondes", + "short": { + "title": "Latence", + "value": "{{seconds}} sec" + } + }, + "droppedFrames": { + "short": { + "value": "{{droppedFrames}} images", + "title": "Perdues" + }, + "title": "Images perdues :" + }, + "decodedFrames": "Images décodées :", + "droppedFrameRate": "Proportion d'images perdues :", + "totalFrames": "Total images :" + }, + "toast": { + "error": { + "submitFrigatePlusFailed": "Échec de la soumission de l'image à Frigate+" + }, + "success": { + "submittedFrigatePlus": "Image soumise avec succès à Frigate+" + } + } +} diff --git a/web/public/locales/fr/objects.json b/web/public/locales/fr/objects.json new file mode 100644 index 000000000..db7b3458b --- /dev/null +++ b/web/public/locales/fr/objects.json @@ -0,0 +1,120 @@ +{ + "bicycle": "Vélo", + "car": "Voiture", + "person": "Personne", + "motorcycle": "Moto", + "airplane": "Avion", + "bus": "Bus", + "train": "Train", + "boat": "Bateau", + "traffic_light": "Feu de circulation", + "fire_hydrant": "Bouche d'incendie", + "street_sign": "Plaque de rue", + "parking_meter": "Parcmètre", + "bench": "Banc", + "bird": "Oiseau", + "cat": "Chat", + "stop_sign": "Panneau de stop", + "dog": "Chien", + "horse": "Cheval", + "sheep": "Mouton", + "cow": "Vache", + "elephant": "Eléphant", + "bear": "Ours", + "zebra": "Zèbre", + "hat": "Chapeau", + "tie": "Cravate", + "suitcase": "Valise", + "frisbee": "Frisbee", + "skis": "Skis", + "snowboard": "Surf des neiges", + "sports_ball": "Ballon des sports", + "kite": "Cerf-volant", + "baseball_bat": "Batte de base-ball", + "umbrella": "Parapluie", + "giraffe": "Girafe", + "eye_glasses": "Lunettes", + "backpack": "Sac à dos", + "handbag": "Sac à main", + "shoe": "Chaussure", + "clock": "Horloge", + "bottle": "Bouteille", + "baseball_glove": "Gant de baseball", + "skateboard": "Skateboard", + "surfboard": "Planche de surf", + "tennis_racket": "Raquette de Tennis", + "plate": "Assiette", + "cup": "Tasse", + "banana": "Banane", + "apple": "Pomme", + "wine_glass": "Verre à vin", + "pizza": "Pizza", + "couch": "Canapé", + "potted_plant": "Plante en pot", + "mirror": "Miroir", + "window": "Fenêtre", + "desk": "Bureau", + "door": "Porte", + "remote": "Télécommande", + "keyboard": "Clavier", + "mouse": "Souris", + "tv": "TV", + "laptop": "Ordinateur portable", + "toaster": "Grille-pain", + "book": "Livre", + "teddy_bear": "Ours en peluche", + "blender": "Mixer", + "toothbrush": "Brosse à dents", + "hair_brush": "Brosse à cheveux", + "vehicle": "Véhicule", + "fox": "Renard", + "deer": "Cerf", + "animal": "Animal", + "goat": "Chèvre", + "rabbit": "Lapin", + "raccoon": "Raton laveur", + "waste_bin": "Poubelle", + "robot_lawnmower": "Robot tondeuse", + "on_demand": "Sur demande", + "face": "Visage", + "license_plate": "Plaque d'immatriculation", + "bbq_grill": "Barbecue", + "ups": "UPS", + "fedex": "FedEx", + "dhl": "DHL", + "package": "Colis", + "an_post": "An Post", + "gls": "GLS", + "dpd": "DPD", + "postnl": "PostNL", + "amazon": "Amazon", + "hot_dog": "Hot Dog", + "refrigerator": "Réfrigérateur", + "bark": "Aboiement", + "oven": "Four", + "scissors": "Paire de ciseaux", + "toilet": "Toilettes", + "carrot": "Carotte", + "bed": "Lit", + "cell_phone": "Téléphone portable", + "fork": "Fourchette", + "squirrel": "Écureuil", + "microwave": "Micro-ondes", + "hair_dryer": "Sèche cheveux", + "bowl": "Bol", + "spoon": "Cuillère", + "sandwich": "Sandwich", + "sink": "Lavabo", + "broccoli": "Brocoli", + "knife": "Couteau", + "nzpost": "NZPost", + "orange": "Orange", + "chair": "Chaise", + "donut": "Donut", + "usps": "USPS", + "cake": "Gâteau", + "dining_table": "Table à manger", + "vase": "Vase", + "purolator": "Purolator", + "postnord": "PostNord" +} diff --git a/web/public/locales/fr/views/configEditor.json b/web/public/locales/fr/views/configEditor.json new file mode 100644 index 000000000..0e67abc73 --- /dev/null +++ b/web/public/locales/fr/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "configEditor": "Éditeur de configuration", + "documentTitle": "Éditeur de configuration - Frigate", + "copyConfig": "Copier la configuration", + "saveOnly": "Enregistrer seulement", + "saveAndRestart": "Enregistrer & redémarrer", + "toast": { + "success": { + "copyToClipboard": "Configuration copiée dans le presse-papiers." + }, + "error": { + "savingError": "Erreur lors de l'enregistrement de la configuration" + } + } +} diff --git a/web/public/locales/fr/views/events.json b/web/public/locales/fr/views/events.json new file mode 100644 index 000000000..3d1675192 --- /dev/null +++ b/web/public/locales/fr/views/events.json @@ -0,0 +1,38 @@ +{ + "detections": "Détections", + "motion": { + "label": "Mouvement", + "only": "Mouvement seulement" + }, + "alerts": "Alertes", + "allCameras": "Toutes les caméras", + "empty": { + "alert": "Il n'y a aucune alerte à passer en revue", + "detection": "Il n'y a aucune détection à passer en revue", + "motion": "Aucune donnée de mouvement trouvée" + }, + "timeline": "Chronologie", + "events": { + "label": "Événements", + "aria": "Sélectionner les événements", + "noFoundForTimePeriod": "Aucun événement trouvé pour cette plage de temps." + }, + "documentTitle": "Évaluations - Frigate", + "recordings": { + "documentTitle": "Enregistrements - Frigate" + }, + "calendarFilter": { + "last24Hours": "Dernières 24 heures" + }, + "timeline.aria": "Sélectionner une chronologie", + "markAsReviewed": "Marqué comme évalué", + "newReviewItems": { + "button": "Nouveaux éléments à évaluer", + "label": "Afficher les nouveaux éléments à évaluer" + }, + "camera": "Caméra", + "markTheseItemsAsReviewed": "Marquer ces éléments comme évalués", + "selected": "{{count}} sélectionné(s)", + "selected_other": "{{count}} sélectionné(s)", + "selected_one": "{{count}} sélectionné(s)" +} diff --git a/web/public/locales/fr/views/explore.json b/web/public/locales/fr/views/explore.json new file mode 100644 index 000000000..28ba131fa --- /dev/null +++ b/web/public/locales/fr/views/explore.json @@ -0,0 +1,202 @@ +{ + "generativeAI": "IA générative", + "documentTitle": "Explorer - Frigate", + "exploreIsUnavailable": { + "title": "L'exploration est indisponible", + "embeddingsReindexing": { + "estimatedTime": "Temps restant estimé :", + "finishingShortly": "Termine bientôt", + "context": "L'exploration peut être utilisée une fois la réindexation des objets suivis terminée.", + "startingUp": "Démarrage…", + "step": { + "thumbnailsEmbedded": "Vignettes intégrées : ", + "descriptionsEmbedded": "Descriptions intégrées : ", + "trackedObjectsProcessed": "Objets suivis traités : " + } + }, + "downloadingModels": { + "context": "Frigate télécharge les modèles d'incorporation nécessaires pour prendre en charge la fonctionnalité de recherche sémantique. Cette opération peut prendre plusieurs minutes selon la vitesse de votre connexion réseau.", + "setup": { + "visionModelFeatureExtractor": "Extracteur de caractéristiques de modèle de vision", + "textTokenizer": "Tokeniseur de texte", + "visionModel": "Modèle de vision", + "textModel": "Modèle de texte" + }, + "tips": { + "documentation": "Lire la documentation", + "context": "Vous souhaiterez peut-être réindexer les incorporations de vos objets suivis une fois les modèles téléchargés." + }, + "error": "Une erreur est survenue. Vérifier les journaux Frigate." + } + }, + "details": { + "timestamp": "Horodatage", + "item": { + "title": "Évaluer les détails de l'élément", + "button": { + "share": "Partager cet élément d'évaluation", + "viewInExplore": "Afficher dans Explorer" + }, + "toast": { + "success": { + "regenerate": "Une nouvelle description a été demandée à {{provider}}. Selon la vitesse de votre fournisseur, la régénération de la nouvelle description peut prendre un certain temps.", + "updatedSublabel": "Sous-étiquette mise à jour avec succès.", + "updatedLPR": "Plaque d'immatriculation mise à jour avec succès." + }, + "error": { + "regenerate": "Échec de l'appel de {{provider}} pour une nouvelle description : {{errorMessage}}", + "updatedSublabelFailed": "Échec de la mise à jour de la sous-étiquette : {{errorMessage}}", + "updatedLPRFailed": "Échec à la mise à jour de la plaque d'immatriculation : {{errorMessage}}" + } + }, + "tips": { + "mismatch_one": "{{count}} objet indisponible a été détecté et inclus dans cet élément d'évaluation. Cet objet n'a pas été considéré comme une alerte ou une détection, ou a déjà été nettoyé/supprimé.", + "mismatch_many": "{{count}} objets indisponibles ont été détectés et inclus dans cet élément d'évaluation. Ces objets n'ont pas été considérés comme une alerte ou une détection, ou ont déjà été nettoyés/supprimés.", + "mismatch_other": "{{count}} objets indisponibles ont été détectés et inclus dans cet élément d'évaluation. Ces objets n'ont pas été considérés comme une alerte ou une détection, ou ont déjà été nettoyés/supprimés.", + "hasMissingObjects": "Ajustez votre configuration si vous souhaitez que Frigate enregistre les objets suivis pour les étiquettes suivantes : {{objects}}" + }, + "desc": "Vérifier les détails de l'élément" + }, + "label": "Étiquette", + "editSubLabel": { + "title": "Modifier la sous-étiquette", + "desc": "Saisissez une nouvelle sous-étiquette pour ce {{label}}", + "descNoLabel": "Entrer une nouvelle sous-étiquette pour cet objet suivi" + }, + "topScore": { + "label": "Meilleur score", + "info": "Le meilleur score est le score médian le plus élevé pour l'objet suivi, il peut donc différer du score affiché sur la vignette des résultats de recherche." + }, + "objects": "Objets", + "button": { + "regenerate": { + "label": "Régénérer la description de l'objet suivi", + "title": "Regénérer" + }, + "findSimilar": "Trouver similaire" + }, + "description": { + "label": "Description", + "placeholder": "Description de l'objet suivi", + "aiTips": "Frigate ne demandera pas de description à votre fournisseur d'IA générative tant que le cycle de vie de l'objet suivi ne sera pas terminé." + }, + "regenerateFromSnapshot": "Régénérer à partir d'un instantané", + "regenerateFromThumbnails": "Régénérer à partir des vignettes", + "editLPR": { + "title": "Modifier la plaque d'immatriculation", + "desc": "Saisissez une nouvelle valeur de plaque d'immatriculation pour ce {{label}}", + "descNoLabel": "Saisir une nouvelle valeur de plaque d'immatriculation pour cet objet suivi" + }, + "recognizedLicensePlate": "Plaque d'immatriculation reconnue", + "estimatedSpeed": "Vitesse estimée", + "zones": "Zones", + "expandRegenerationMenu": "Développer le menu de régénération", + "camera": "Caméra", + "tips": { + "descriptionSaved": "Description enregistrée avec succès", + "saveDescriptionFailed": "Échec de la mise à jour de la description : {{errorMessage}}" + }, + "snapshotScore": { + "label": "Score du cliché" + } + }, + "type": { + "details": "détails", + "video": "vidéo", + "object_lifecycle": "cycle de vie de l'objet", + "snapshot": "instantané" + }, + "objectLifecycle": { + "title": "Cycle de vie de l'objet", + "noImageFound": "Aucune image trouvée pour cet horodatage.", + "createObjectMask": "Créer un masque d'objet", + "scrollViewTips": "Faites défiler pour voir les moments importants du cycle de vie de cet objet.", + "adjustAnnotationSettings": "Ajuster les paramètres d'annotation", + "autoTrackingTips": "Les positions de la zone de délimitation seront inexactes pour les caméras de suivi automatique.", + "lifecycleItemDesc": { + "visible": "{{label}} détecté", + "entered_zone": "{{label}} est entré dans {{zones}}", + "stationary": "{{label}} est devenu stationnaire", + "attribute": { + "other": "{{label}} reconnu comme {{attribute}}", + "faceOrLicense_plate": "{{attribute}} détecté pour {{label}}" + }, + "gone": "{{label}} parti", + "heard": "{{label}} entendu", + "external": "{{label}} détecté", + "active": "{{label}} est devenu actif", + "header": { + "zones": "Zones", + "area": "Aire", + "ratio": "Ratio" + } + }, + "annotationSettings": { + "title": "Paramètres d'annotation", + "showAllZones": { + "title": "Montrer toutes les zones", + "desc": "Afficher toujours les zones sur les images où les objets sont entrés dans une zone." + }, + "offset": { + "label": "Décalage de l'annotation", + "documentation": "Lire la documentation ", + "desc": "Ces données proviennent du flux de détection de votre caméra, mais sont superposées aux images du flux d'enregistrement. Il est peu probable que les deux flux soient parfaitement synchronisés. Par conséquent, le cadre de délimitation et la séquence ne seront pas parfaitement alignés. Cependant, le champ annotation_offset peut être utilisé pour ajuster ce décalage.", + "millisecondsToOffset": "Millisecondes pour décaler les annotations détectées. Par défaut : 0", + "tips": "ASTUCE : Imaginez un clip d'événement avec une personne marchant de gauche à droite. Si le cadre de la chronologie de l'événement est constamment à gauche de la personne, la valeur doit être diminuée. De même, si une personne marche de gauche à droite et que le cadre de la chronologie est constamment devant elle, la valeur doit être augmentée." + } + }, + "carousel": { + "next": "Diapositive suivante", + "previous": "Diapositive précédente" + } + }, + "trackedObjectDetails": "Détails de l'objet suivi", + "itemMenu": { + "downloadSnapshot": { + "label": "Télécharger l'instantané", + "aria": "Télécharger l'instantané" + }, + "findSimilar": { + "label": "Trouver similaire", + "aria": "Trouver des objets suivis similaires" + }, + "viewObjectLifecycle": { + "aria": "Afficher le cycle de vie de l'objet", + "label": "Visualiser le cycle de vie de l'objet" + }, + "viewInHistory": { + "label": "Afficher dans l'historique", + "aria": "Afficher dans l'historique" + }, + "downloadVideo": { + "label": "Télécharger la vidéo", + "aria": "Télécharger la vidéo" + }, + "submitToPlus": { + "label": "Soumettre à Frigate+", + "aria": "Soumettre à Frigate Plus" + }, + "deleteTrackedObject": { + "label": "Supprimer cet objet suivi" + } + }, + "dialog": { + "confirmDelete": { + "title": "Confirmer la suppression", + "desc": "La suppression de cet objet suivi supprime l'instantané, les incorporations enregistrées et les entrées du cycle de vie de l'objet associé. Les images enregistrées de cet objet suivi dans la vue Historique NE seront PAS supprimées.

    Êtes-vous sûr de vouloir continuer ?" + } + }, + "noTrackedObjects": "Aucun objet suivi trouvé", + "fetchingTrackedObjectsFailed": "Erreur lors de la récupération des objets suivis : {{errorMessage}}", + "trackedObjectsCount_one": "{{count}} objet suivi ", + "trackedObjectsCount_many": "{{count}} objets suivis ", + "trackedObjectsCount_other": "{{count}} objets suivis ", + "searchResult": { + "deleteTrackedObject": { + "toast": { + "success": "L'objet suivi a été supprimé avec succès.", + "error": "Échec de la suppression de l'objet suivi : {{errorMessage}}" + } + } + } +} diff --git a/web/public/locales/fr/views/exports.json b/web/public/locales/fr/views/exports.json new file mode 100644 index 000000000..7eab408b9 --- /dev/null +++ b/web/public/locales/fr/views/exports.json @@ -0,0 +1,17 @@ +{ + "documentTitle": "Exporter - Frigate", + "search": "Chercher", + "noExports": "Aucun export trouvé", + "deleteExport": "Supprimer l'export", + "deleteExport.desc": "Êtes-vous sûr de vouloir supprimer {{exportName}}?", + "editExport": { + "title": "Renommer l'export", + "desc": "Saisissez un nouveau nom pour cet export.", + "saveExport": "Enregistrer l'export" + }, + "toast": { + "error": { + "renameExportFailed": "Échec du renommage de l'export : {{errorMessage}}" + } + } +} diff --git a/web/public/locales/fr/views/faceLibrary.json b/web/public/locales/fr/views/faceLibrary.json new file mode 100644 index 000000000..439a06ec0 --- /dev/null +++ b/web/public/locales/fr/views/faceLibrary.json @@ -0,0 +1,86 @@ +{ + "description": { + "addFace": "Parcourez la procédure d’ajout d’une nouvelle collection à la bibliothèque de visages.", + "placeholder": "Saisissez un nom pour cette collection" + }, + "details": { + "person": "Personne", + "confidence": "Confiance", + "face": "Détails du visage", + "timestamp": "Horodatage", + "faceDesc": "Détails du visage et de l'objet associé" + }, + "documentTitle": "Bibliothèque de visages - Frigate", + "uploadFaceImage": { + "title": "Téléverser l'image du visage", + "desc": "Téléversez une image pour rechercher des visages et l'inclure dans {{pageToggle}}" + }, + "createFaceLibrary": { + "title": "Créer une collection", + "desc": "Créer une nouvelle collection", + "new": "Créer un nouveau visage", + "nextSteps": "Pour construire une base solide :
  • Utilisez l’onglet Entraîner pour sélectionner et entraîner le modèle sur des images pour chaque personne détectée.
  • Concentrez-vous sur des images de face pour de meilleurs résultats ; évitez d’entraîner le modèle des images qui capturent des visages de biais.
  • " + }, + "train": { + "title": "Entraîner", + "aria": "Sélectionner entraîner" + }, + "selectFace": "Sélectionner un visage", + "button": { + "addFace": "Ajouter un visage", + "uploadImage": "Téléverser une image", + "deleteFaceAttempts": "Supprimer les tentatives de reconnaissance faciale", + "reprocessFace": "Réanalyser le visage", + "renameFace": "Renommer le visage", + "deleteFace": "Supprimer le visage" + }, + "selectItem": "Sélectionner {{item}}", + "deleteFaceLibrary": { + "title": "Supprimer un nom", + "desc": "Etes-vous certain de vouloir supprimer la collection {{name}} ? Cette action supprimera définitivement tous les visages associés." + }, + "imageEntry": { + "dropActive": "Déposez l'image ici…", + "dropInstructions": "Glissez et déposez une image ici, ou cliquez pour sélectionner", + "maxSize": "Taille max : {{size}}MB", + "validation": { + "selectImage": "Veuillez sélectionner un fichier image." + } + }, + "readTheDocs": "Lire la documentation", + "toast": { + "success": { + "deletedName_one": "{{count}} visage a été supprimé avec succès.", + "deletedName_many": "{{count}} visages ont été supprimés avec succès.", + "deletedName_other": "{{count}} visages ont été supprimés avec succès.", + "uploadedImage": "Image téléversée avec succès.", + "addFaceLibrary": "{{name}} a été ajouté avec succès à la bibliothèque de visages !", + "updatedFaceScore": "Score du visage mis à jour avec succès.", + "deletedFace_one": "{{count}} visage a été supprimé avec succès.", + "deletedFace_many": "{{count}} visages ont été supprimés avec succès.", + "deletedFace_other": "{{count}} visages ont été supprimés avec succès.", + "trainedFace": "Visage entraîné avec succès.", + "renamedFace": "Visage renommé avec succés en {{name}}" + }, + "error": { + "uploadingImageFailed": "Échec du téléversement de l'image : {{errorMessage}}", + "deleteFaceFailed": "Échec de la suppression : {{errorMessage}}", + "trainFailed": "Échec de l'entrainement : {{errorMessage}}", + "updateFaceScoreFailed": "Échec de la mise à jour du score du visage : {{errorMessage}}", + "addFaceLibraryFailed": "Échec du nommage du visage : {{errorMessage}}", + "deleteNameFailed": "Échec de la suppression du nom : {{errorMessage}}", + "renameFaceFailed": "Échec du renommage du visage : {{errorMessage}}" + } + }, + "trainFaceAs": "Entraîner un visage comme :", + "trainFace": "Entraîner visage", + "steps": { + "uploadFace": "Téléverser l'image de visage", + "faceName": "Entrer un nom pour le visage", + "nextSteps": "Prochaines étapes" + }, + "renameFace": { + "title": "Renommer le visage", + "desc": "Saisissez un nouveau nom pour {{name}}" + } +} diff --git a/web/public/locales/fr/views/live.json b/web/public/locales/fr/views/live.json new file mode 100644 index 000000000..8c8603972 --- /dev/null +++ b/web/public/locales/fr/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "Direct - Frigate", + "lowBandwidthMode": "Mode faible bande-passante", + "documentTitle.withCamera": "{{camera}} - Direct - Frigate", + "twoWayTalk": { + "disable": "Désactiver la conversation bidirectionnelle", + "enable": "Activer la conversation bidirectionnelle" + }, + "cameraAudio": { + "disable": "Désactiver le son de la caméra", + "enable": "Activer le son de la caméra" + }, + "ptz": { + "move": { + "clickMove": { + "label": "Cliquez dans le cadre pour centrer la caméra", + "enable": "Activer le click pour déplacer", + "disable": "Désactiver le click pour déplacer" + }, + "left": { + "label": "Déplacer la caméra PTZ sur la gauche" + }, + "up": { + "label": "Déplacer la caméra PTZ vers le haut" + }, + "right": { + "label": "Déplacer la caméra PTZ sur la droite" + }, + "down": { + "label": "Déplacer la caméra PTZ vers le bas" + } + }, + "zoom": { + "in": { + "label": "Zoomer avant de la caméra PTZ" + }, + "out": { + "label": "Zoom arrière de la caméra PTZ" + } + }, + "frame": { + "center": { + "label": "Cliquez dans le cadre pour centrer la caméra PTZ" + } + }, + "presets": "Paramètres prédéfinis pour les caméras PTZ" + }, + "camera": { + "enable": "Activer la caméra", + "disable": "Désactiver la caméra" + }, + "detect": { + "enable": "Activer la détection", + "disable": "Désactiver la détection" + }, + "recording": { + "enable": "Activer l'enregistrement", + "disable": "Désactiver l'enregistrement" + }, + "snapshots": { + "enable": "Activer les instantanés", + "disable": "Désactiver les instantanés" + }, + "muteCameras": { + "enable": "Couper le son de toutes les caméras", + "disable": "Activer le son de toutes les caméras" + }, + "audioDetect": { + "enable": "Activer la détection audio", + "disable": "Désactiver la détection audio" + }, + "manualRecording": { + "playInBackground": { + "label": "Jouer en arrière plan", + "desc": "Activer cette option pour continuer à streamer lorsque le lecteur est masqué." + }, + "showStats": { + "label": "Afficher les statistiques", + "desc": "Activer cette option pour afficher les statistiques de flux en surimpression sur le flux de la caméra." + }, + "debugView": "Vue de débogage", + "start": "Démarrer l'enregistrement à la demande", + "failedToStart": "Echec du démarrage de l'enregistrement à la demande manuel.", + "end": "Terminer l'enregistrement à la demande", + "ended": "Enregistrement à la demande terminé.", + "failedToEnd": "Impossible de terminer l'enregistrement manuel à la demande.", + "started": "Enregistrement à la demande démarré.", + "recordDisabledTips": "Puisque l'enregistrement est désactivé ou restreint dans la configuration de cette caméra, seul un instantané sera enregistré.", + "title": "Enregistrement à la demande", + "tips": "Démarrez un événement manuel en fonction des paramètres de conservation d'enregistrement de cette caméra." + }, + "streamingSettings": "Paramètres de streaming", + "notifications": "Notifications", + "suspend": { + "forTime": "Mettre en pause pour : " + }, + "stream": { + "audio": { + "available": "Audio disponible pour ce flux", + "tips": { + "documentation": "Lire la documentation ", + "title": "L'audio doit être capté par votre caméra et configuré dans go2rtc pour ce flux." + }, + "unavailable": "Audio non disponible pour ce flux" + }, + "twoWayTalk": { + "tips": "Votre périphérique doit supporter la fonctionnalité et WebRTC doit être configuré pour supporter la conversation bidirectionnelle.", + "tips.documentation": "Lire la documention ", + "available": "Conversation bidirectionnelle disponible pour ce flux", + "unavailable": "Conversation bidirectionnelle non disponible pour ce flux" + }, + "lowBandwidth": { + "tips": "La vue temps réel est en mode faible bande passante à cause d'erreurs de cache ou de flux.", + "resetStream": "Réinitialiser le flux" + }, + "playInBackground": { + "tips": "Activer cette option pour continuer le streaming lorsque le lecteur est masqué.", + "label": "Jouer en arrière plan" + }, + "title": "Flux" + }, + "cameraSettings": { + "objectDetection": "Détection d'objets", + "recording": "Enregistrement", + "snapshots": "Instantanés", + "audioDetection": "Détection audio", + "autotracking": "Suivi automatique", + "cameraEnabled": "Caméra activée", + "title": "Paramètres de {{camera}}" + }, + "history": { + "label": "Afficher l'historique de capture" + }, + "effectiveRetainMode": { + "modes": { + "all": "Tous", + "motion": "Mouvement", + "active_objects": "Objets actifs" + }, + "notAllTips": "Votre configuration de conservation d'enregistrement {{source}} est définie sur mode : {{effectiveRetainMode}}, donc cet enregistrement à la demande ne conservera que les segments avec {{effectiveRetainModeName}}." + }, + "audio": "Audio", + "autotracking": { + "enable": "Activer le suivi automatique", + "disable": "Désactiver le suivi automatique" + }, + "streamStats": { + "enable": "Afficher les statistiques du flux", + "disable": "Masquer les statistiques du flux" + }, + "editLayout": { + "label": "Modifier la mise en page", + "group": { + "label": "Modifier le groupe de caméras" + }, + "exitEdit": "Quitter l'édition" + } +} diff --git a/web/public/locales/fr/views/recording.json b/web/public/locales/fr/views/recording.json new file mode 100644 index 000000000..f04812f4c --- /dev/null +++ b/web/public/locales/fr/views/recording.json @@ -0,0 +1,12 @@ +{ + "export": "Exporter", + "calendar": "Calendrier", + "filter": "Filtre", + "filters": "Filtres", + "toast": { + "error": { + "noValidTimeSelected": "Pas de période valide sélectionnée", + "endTimeMustAfterStartTime": "L'heure de fin doit être après l'heure de début" + } + } +} diff --git a/web/public/locales/fr/views/search.json b/web/public/locales/fr/views/search.json new file mode 100644 index 000000000..cfb650cd4 --- /dev/null +++ b/web/public/locales/fr/views/search.json @@ -0,0 +1,74 @@ +{ + "savedSearches": "Recherches enregistrées", + "search": "Chercher", + "searchFor": "Chercher {{inputValue}}", + "button": { + "clear": "Effacer la recherche", + "filterInformation": "Filtrer les informations", + "filterActive": "Filtres actifs", + "save": "Enregistrer la recherche", + "delete": "Supprimer la recherche enregistrée" + }, + "trackedObjectId": "ID d'objet suivi", + "filter": { + "label": { + "zones": "Zones", + "sub_labels": "Sous-étiquettes", + "search_type": "Type de recherche", + "time_range": "Plage de temps", + "labels": "Étiquettes", + "cameras": "Caméras", + "after": "Après", + "before": "Avant", + "min_speed": "Vitesse minimum", + "max_speed": "Vitesse maximum", + "min_score": "Score minimum", + "recognized_license_plate": "Plaques d'immatriculation reconnues", + "has_clip": "Contient un clip", + "has_snapshot": "Contient un instantané", + "max_score": "Score maximum" + }, + "searchType": { + "thumbnail": "Vignette", + "description": "Description" + }, + "toast": { + "error": { + "beforeDateBeLaterAfter": "La date de début « avant » doit être postérieure à la date « après ».", + "afterDatebeEarlierBefore": "La date « après » doit être antérieure à la date « avant ».", + "minScoreMustBeLessOrEqualMaxScore": "Le « min_score » doit être inférieur ou égal au « max_score ».", + "maxScoreMustBeGreaterOrEqualMinScore": "Le « max_score » doit être supérieur ou égal au « min_score ».", + "minSpeedMustBeLessOrEqualMaxSpeed": "La « vitesse_min » doit être inférieure ou égale à la « vitesse_max ».", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "La « vitesse maximale » doit être supérieure ou égale à la « vitesse minimale »." + } + }, + "header": { + "currentFilterType": "Valeurs du filtre", + "activeFilters": "Filtres actifs", + "noFilters": "Filtres" + }, + "tips": { + "title": "Comment utiliser les filtres de texte", + "desc": { + "text": "Les filtres vous aident à affiner vos résultats de recherche. Voici comment les utiliser dans le champ de saisie :", + "example": "Exemple: cameras:front_door label:person before:01012024 time_range:3:00PM-4:00PM ", + "step": "
    • Saisissez un nom de filtre suivi de deux points (par exemple, «cameras:»).
    • Sélectionnez une valeur parmi les suggestions ou saisissez la vôtre.
    • Utilisez plusieurs filtres en les ajoutant les uns après les autres, en laissant un espace entre eux.
    • Les filtres de date (avant: et après:) utilisent le format {{DateFormat}}.
    • Le filtre de plage horaire utilise le format {{exampleTime}}.
    • Supprimez les filtres en cliquant sur le «x» à côté d'eux.
    ", + "step1": "Saisissez un nom de clé de filtre suivi de deux points (par exemple, \"cameras:\").", + "step2": "Sélectionnez une valeur pour la suggestion ou saisissez la vôtre.", + "step3": "Utilisez plusieurs filtres en les ajoutant les uns après les autres avec un espace entre.", + "step5": "Le filtre de plage de temps utilise le format {{exampleTime}}.", + "step6": "Supprimer les filtres en cliquant sur le 'x' à côté d'eux.", + "step4": "Filtres de dates (avant : et après :) utilisez le format {{DateFormat}}.", + "exampleLabel": "Exemple :" + } + } + }, + "similaritySearch": { + "title": "Recherche par similarité", + "active": "Recherche par similarité activée", + "clear": "Effacer la recherche par similarité" + }, + "placeholder": { + "search": "Rechercher…" + } +} diff --git a/web/public/locales/fr/views/settings.json b/web/public/locales/fr/views/settings.json new file mode 100644 index 000000000..23995bdef --- /dev/null +++ b/web/public/locales/fr/views/settings.json @@ -0,0 +1,600 @@ +{ + "documentTitle": { + "default": "Paramètres - Frigate", + "authentication": "Paramètres d'authentification - Frigate", + "camera": "Paramètres des caméras - Frigate", + "classification": "Paramètres de classification - Frigate", + "motionTuner": "Réglages du mouvement - Frigate", + "general": "Paramètres généraux - Frigate", + "masksAndZones": "Éditeur de masques et de zones - Frigate", + "object": "Débogage - Frigate", + "frigatePlus": "Paramètres Frigate+ - Frigate", + "notifications": "Paramètres de notification - Frigate" + }, + "menu": { + "ui": "Interface utilisateur", + "classification": "Classification", + "masksAndZones": "Masques / Zones", + "motionTuner": "Réglages du mouvement", + "debug": "Débogage", + "cameras": "Paramètres des caméras", + "users": "Utilisateurs", + "notifications": "Notifications", + "frigateplus": "Frigate+" + }, + "dialog": { + "unsavedChanges": { + "title": "Vous avez des modifications non enregistrées.", + "desc": "Voulez-vous enregistrer vos modifications avant de continuer ?" + } + }, + "cameraSetting": { + "camera": "Caméra", + "noCamera": "Aucune caméra" + }, + "general": { + "title": "Paramètres généraux", + "liveDashboard": { + "title": "Tableau de bord en direct", + "automaticLiveView": { + "label": "Vue en direct automatique", + "desc": "Basculez automatiquement vers la vue en direct d'une caméra lorsqu'une activité est détectée. La désactivation de cette option limite la mise à jour des images statiques de la caméra sur le tableau de bord en direct à une fois par minute seulement." + }, + "playAlertVideos": { + "label": "Lire les vidéos d'alertes", + "desc": "Par défaut, les alertes récentes du tableau de bord en direct sont diffusées sous forme de petites vidéos en boucle. Désactivez cette option pour afficher uniquement une image statique des alertes récentes sur cet appareil/navigateur." + } + }, + "storedLayouts": { + "title": "Mises en page stockées", + "desc": "La disposition des caméras d'un groupe peut être déplacée/redimensionnée. Les positions sont enregistrées dans le stockage local de votre navigateur.", + "clearAll": "Effacer toutes les mises en page" + }, + "cameraGroupStreaming": { + "title": "Paramètres de diffusion du groupe de caméras", + "desc": "Les paramètres de diffusion en continu pour chaque groupe de caméras sont stockés dans le stockage local de votre navigateur.", + "clearAll": "Effacer tous les paramètres de streaming" + }, + "recordingsViewer": { + "title": "Visionneuse d'enregistrements", + "defaultPlaybackRate": { + "label": "Vitesse de lecture par défaut", + "desc": "Vitesse de lecture par défaut pour la lecture des enregistrements." + } + }, + "calendar": { + "firstWeekday": { + "label": "Premier jour de la semaine", + "desc": "Le jour du début de semaine du calendrier de révision.", + "sunday": "Dimanche", + "monday": "Lundi" + }, + "title": "Calendrier" + }, + "toast": { + "error": { + "clearStoredLayoutFailed": "Échec à l'effacement de la mise en page enregistrée : {{errorMessage}}", + "clearStreamingSettingsFailed": "Échec de l'effacement des paramètres de diffusion : {{errorMessage}}" + }, + "success": { + "clearStreamingSettings": "Paramètres de diffusion effacés pour tous les groupes de caméras.", + "clearStoredLayout": "Mise en page enregistrée effacée pour {{cameraName}}" + } + } + }, + "notification": { + "suspendTime": { + "untilRestart": "Suspendre jusqu'au redémarrage", + "24hours": "Suspendre pendant 24 heures", + "10minutes": "Suspendre pendant 10 minutes", + "12hours": "Suspendre pendant 12 heures", + "5minutes": "Suspendre pendant 5 minutes", + "1hour": "Suspendre pendant 1 heure", + "30minutes": "Suspendre pendant 30 minutes", + "suspend": "Suspendre" + }, + "toast": { + "success": { + "registered": "Inscription réussie aux notifications. Le redémarrage de Frigate est nécessaire avant l'envoi de toute notification (y compris une notification de test).", + "settingSaved": "Les paramètres de notification ont été enregistrés." + }, + "error": { + "registerFailed": "Impossible de sauvegarder l'enregistrement de la notification." + } + }, + "cancelSuspension": "Annuler la suspension", + "notificationSettings": { + "title": "Paramètres de notification", + "documentation": "Lire la Documentation", + "desc": "Frigate peut envoyer nativement des notifications push à votre appareil lorsqu'il est exécuté dans le navigateur ou installé en tant que PWA." + }, + "notificationUnavailable": { + "title": "Notifications indisponibles", + "documentation": "Lire la Documentation", + "desc": "Les notifications push Web nécessitent un contexte sécurisé (https://…). Il s'agit d'une limitation du navigateur. Accédez à Frigate en toute sécurité pour utiliser les notifications." + }, + "globalSettings": { + "title": "Paramètres globaux", + "desc": "Suspendre temporairement les notifications pour des caméras spécifiques sur tous les appareils enregistrés." + }, + "email": { + "title": "Email", + "desc": "Une adresse e-mail valide est requise et sera utilisée pour vous avertir en cas de problème avec le service push.", + "placeholder": "e.g. example@email.com" + }, + "cameras": { + "title": "Caméras", + "noCameras": "Aucune caméra disponible", + "desc": "Sélectionnez les caméras pour lesquelles activer les notifications." + }, + "deviceSpecific": "Paramètres spécifiques de l'appareil", + "suspended": "Notifications suspendues {{time}}", + "title": "Notifications", + "active": "Notifications actives", + "registerDevice": "Enregistrer cet appareil", + "unregisterDevice": "Désenregistrer cet appareil", + "sendTestNotification": "Envoyer une notification de test" + }, + "frigatePlus": { + "apiKey": { + "notValidated": "La clé API Frigate+ n'est pas détectée ou non validée", + "title": "Clé API Frigate+", + "validated": "La clé API Frigate+ est détectée et validée", + "desc": "La clé API Frigate+ permet l'intégration avec le service Frigate+.", + "plusLink": "En savoir plus sur Frigate+" + }, + "title": "Paramètres Frégate+", + "snapshotConfig": { + "documentation": "Lire la documentation", + "desc": "La soumission à Frigate+ nécessite que les instantanés et les instantanés clean_copy soient activés dans votre configuration.", + "title": "Configuration de l'instantané", + "table": { + "snapshots": "Instantanés", + "camera": "Caméra", + "cleanCopySnapshots": "clean_copy Instantanés" + }, + "cleanCopyWarning": "Certaines caméras ont des instantanés activés, mais la copie propre est désactivée. Vous devez activer clean_copy dans votre configuration d'instantanés pour pouvoir envoyer les images de ces caméras à Frigate+." + }, + "modelInfo": { + "baseModel": "Modèle de base", + "modelType": "Type de Modèle", + "cameras": "Caméras", + "supportedDetectors": "Détecteurs pris en charge", + "loading": "Chargement des informations sur le modèle…", + "title": "Informations sur le modèle", + "trainDate": "Date d'entrainement", + "error": "Échec au chargement des informations du modèle", + "availableModels": "Modèles disponibles", + "dimensions": "Dimensions", + "loadingAvailableModels": "Chargement des modèles disponibles…", + "modelSelect": "Vous pouvez sélectionner ici vos modèles disponibles sur Frigate+. Notez que seuls les modèles compatibles avec votre configuration de détecteur actuelle peuvent être sélectionnés.", + "plusModelType": { + "baseModel": "Modèle de base", + "userModel": "Optimisé" + } + }, + "toast": { + "success": "Les paramètres de Frigate+ ont été enregistrés. Redémarrez Frigate pour appliquer les modifications.", + "error": "Échec de l'enregistrement des modifications de configuration : {{errorMessage}}" + }, + "restart_required": "Redémarrage requis (modèle Frigate+ changé)" + }, + "classification": { + "title": "Paramètres de classification", + "semanticSearch": { + "title": "Recherche sémantique", + "reindexNow": { + "label": "Réindexé maintenant", + "confirmTitle": "Confirmer la réindexation", + "error": "Échec du démarrage de la réindexation : {{errorMessage}}", + "desc": "La réindexation régénère les intégrations pour tous les objets suivis. Ce processus s'exécute en arrière-plan et peut saturer votre processeur et prendre un certain temps, selon le nombre d'objets suivis.", + "confirmDesc": "Êtes-vous sûr de vouloir réindexer toutes les incorporations d'objets suivis ? Ce processus s'exécutera en arrière-plan, mais il risque de saturer votre processeur et de prendre un certain temps. Vous pouvez suivre la progression sur la page Explorateur.", + "success": "La réindexation a démarré avec succès.", + "alreadyInProgress": "La réindexation est déjà en cours.", + "confirmButton": "Réindexer" + }, + "desc": "La recherche sémantique dans Frigate vous permet de trouver des objets suivis dans vos éléments d'évaluation en utilisant soit l'image elle-même, soit une description textuelle définie par l'utilisateur, soit une description générée automatiquement.", + "modelSize": { + "small": { + "desc": "L'utilisation de petit utilise une version quantifiée du modèle qui utilise moins de RAM et s'exécute plus rapidement sur le processeur avec une différence très négligeable dans la qualité d'intégration.", + "title": "petit" + }, + "large": { + "desc": "L'utilisation de grand utilise le modèle Jina complet et s'exécutera automatiquement sur le GPU si applicable.", + "title": "grand" + }, + "desc": "La taille du modèle utilisé pour les intégrations de recherche sémantique.", + "label": "Taille du modèle" + }, + "readTheDocumentation": "Lire la documentation" + }, + "faceRecognition": { + "readTheDocumentation": "Lire la documentation", + "modelSize": { + "large": { + "title": "grand", + "desc": "L'utilisation de grand utilise un modèle d'intégration de visage ArcFace et s'exécutera automatiquement sur le GPU si applicable." + }, + "small": { + "desc": "L'utilisation de petit utilise un modèle d'intégration de visage FaceNet qui fonctionne efficacement sur la plupart des processeurs.", + "title": "petit" + }, + "label": "Taille du modèle", + "desc": "La taille du modèle utilisé pour la reconnaissance faciale." + }, + "desc": "La reconnaissance faciale permet d'attribuer un nom aux personnes. Une fois leur visage reconnu, Frigate attribuera le nom de la personne comme sous-étiquette. Ces informations sont incluses dans l'interface utilisateur, les filtres et les notifications.", + "title": "Reconnaissance faciale" + }, + "licensePlateRecognition": { + "desc": "Frigate peut reconnaître les plaques d'immatriculation des véhicules et ajouter automatiquement les caractères détectés au champ recognized_license_plate, ou un nom connu comme sous-étiquette aux objets de type voiture. Un cas d'utilisation courant est la lecture des plaques d'immatriculation des voitures entrant dans une allée ou circulant dans la rue.", + "readTheDocumentation": "Lire la documentation", + "title": "Reconnaissance de plaque d'immatriculation" + }, + "toast": { + "success": "Les paramètres de classification ont été enregistrés. Redémarrez Frigate pour appliquer vos modifications.", + "error": "Échec de l'enregistrement des modifications de configuration : {{errorMessage}}" + }, + "birdClassification": { + "title": "Classification des oiseaux", + "desc": "La classification des oiseaux identifie les oiseaux connus à l'aide d'un modèle Tensorflow quantifié. Lorsqu'un oiseau connu est reconnu, son nom commun sera ajouté en tant que sous-étiquette. Cette information est incluse dans l'interface utilisateur, les filtres, ainsi que dans les notifications." + }, + "restart_required": "Redémarrage requis (paramètres de classification changés)" + }, + "camera": { + "title": "Paramètres de la caméra", + "review": { + "title": "Evaluation", + "detections": "Détections ", + "alerts": "Alertes ", + "desc": "Activer/désactiver les alertes et les détections pour cette caméra. Si cette option est désactivée, aucun nouvel élément d'évaluation ne sera généré." + }, + "reviewClassification": { + "title": "Evaluer la Classification", + "objectDetectionsTips": "Tous les objets {{detectionsLabels}} non classés sur {{cameraName}} seront affichés comme des Détections, quelle que soit la zone dans laquelle ils se trouvent.", + "zoneObjectDetectionsTips": { + "text": "Tous les objets {{detectionsLabels}} non classés dans {{zone}} sur {{cameraName}} seront affichés comme Détections.", + "regardlessOfZoneObjectDetectionsTips": "Tous les objets {{detectionsLabels}} non classés sur {{cameraName}} seront affichés comme des Détections, quelle que soit la zone dans laquelle ils se trouvent.", + "notSelectDetections": "Tous les objets {{detectionsLabels}} détectés dans {{zone}} sur {{cameraName}} non classés comme Alertes seront affichés comme Détections, quelle que soit la zone dans laquelle ils se trouvent." + }, + "selectDetectionsZones": "Sélectionner les zones pour les Détections", + "toast": { + "success": "La configuration de la classification des évaluations a été enregistrée. Redémarrez Frigate pour appliquer les modifications." + }, + "readTheDocumentation": "Lire la Documentation", + "objectAlertsTips": "Tous les objets {{alertsLabels}} sur {{cameraName}} seront affichés sous forme d'Alertes.", + "limitDetections": "Limiter les détections à des zones spécifiques", + "zoneObjectAlertsTips": "Tous les objets {{alertsLabels}} détectés dans {{zone}} sur {{cameraName}} seront affichés sous forme d'Alertes.", + "noDefinedZones": "Aucune zone n'est définie pour cette caméra.", + "selectAlertsZones": "Sélectionner les zones pour les Alertes", + "desc": "Frigate catégorise les éléments d'évaluation en Alertes et Détections. Par défaut, tous les objets personne et voiture sont considérés comme des Alertes. Vous pouvez affiner la catégorisation de vos éléments d'évaluation en configurant les zones requises pour ces éléments." + }, + "streams": { + "title": "Flux", + "desc": "La désactivation complète d'une caméra interrompt le traitement des flux de cette caméra par Frigate. La détection, l'enregistrement et le débogage seront indisponibles.
    Remarque : cela ne désactive pas les rediffusions go2rtc." + } + }, + "masksAndZones": { + "form": { + "zoneName": { + "error": { + "mustBeAtLeastTwoCharacters": "Le nom de la zone doit comporter au moins 2 caractères.", + "mustNotBeSameWithCamera": "Le nom de la zone ne doit pas être le même que le nom de la caméra.", + "mustNotContainPeriod": "Le nom de la zone ne doit pas contenir de points.", + "hasIllegalCharacter": "Le nom de la zone contient des caractères illégaux.", + "alreadyExists": "Une zone portant ce nom existe déjà pour cette caméra." + } + }, + "distance": { + "error": { + "text": "La distance doit être supérieure ou égale à 0,1.", + "mustBeFilled": "Tous les champs de distance doivent être remplis pour utiliser l'estimation de la vitesse." + } + }, + "polygonDrawing": { + "removeLastPoint": "Supprimer le dernier point", + "delete": { + "title": "Confirmer la suppression", + "desc": "Êtes-vous sûr de vouloir supprimer le {{type}} {{name}} ?", + "success": "{{name}} a été supprimé." + }, + "error": { + "mustBeFinished": "Le dessin du polygone doit être terminé avant d'enregistrer." + }, + "reset": { + "label": "Effacer tous les points" + }, + "snapPoints": { + "true": "Points d'accrochage", + "false": "Ne cassez pas les points" + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "Le temps de latence doit être supérieur ou égal à 0." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "L'inertie doit être supérieure à 0." + } + } + }, + "zones": { + "documentTitle": "Modifier la Zone - Frigate", + "desc": { + "title": "Les zones vous permettent de définir une zone spécifique de l'image afin de déterminer si un objet se trouve ou non dans une zone particulière.", + "documentation": "Documentation" + }, + "add": "Ajouter une Zone", + "edit": "Modifier une Zone", + "name": { + "title": "Nom", + "inputPlaceHolder": "Entrer un nom…", + "tips": "Le nom doit comporter au moins 2 caractères et ne doit pas être le nom d'une caméra ou d'une autre zone." + }, + "loiteringTime": { + "desc": "Définit une durée minimale en secondes pendant laquelle l'objet doit rester dans la zone pour qu'elle s'active. Par défaut : 0", + "title": "Temps de latence" + }, + "speedEstimation": { + "title": "Estimation de la Vitesse", + "desc": "Activer l'estimation de la vitesse des objets dans cette zone. La zone doit comporter exactement 4 points." + }, + "speedThreshold": { + "title": "Seuil de vitesse ({{unit}})", + "desc": "Spécifie une vitesse minimale pour que les objets soient pris en compte dans cette zone.", + "toast": { + "error": { + "loiteringTimeError": "Les zones avec des temps de latence supérieurs à 0 ne doivent pas être utilisées avec l'estimation de la vitesse.", + "pointLengthError": "L'estimation de vitesse a été désactivée pour cette zone. Les zones avec estimation de vitesse doivent comporter exactement 4 points." + } + } + }, + "point_one": "{{count}} point", + "point_many": "{{count}} points", + "point_other": "{{count}} points", + "label": "Zones", + "inertia": { + "desc": "Spécifie le nombre d'images qu'un objet doit avoir dans une zone avant d'être considéré comme faisant partie de la zone. Par défaut : 3", + "title": "Inertie" + }, + "toast": { + "success": "La zone ({{zoneName}}) a été enregistrée. Redémarrez Frigate pour appliquer les modifications." + }, + "objects": { + "title": "Objets", + "desc": "Liste des objets qui s'appliquent à cette zone." + }, + "clickDrawPolygon": "Cliquer pour dessiner un polygone sur l'image.", + "allObjects": "Tous les Objets" + }, + "motionMasks": { + "label": "Masque de mouvement", + "documentTitle": "Modifier Masque de Mouvement - Frigate", + "context": { + "documentation": "Lire la Documentation", + "title": "Les masques de mouvement servent à empêcher les mouvements indésirables de déclencher la détection (par exemple : branches d'arbres, horodatage des caméras). Ils doivent être utilisés avec parcimonie, car un surmasquage complique le suivi des objets." + }, + "polygonAreaTooLarge": { + "title": "Le masque de mouvement couvre {{polygonArea}} % du cadre de la caméra. Les grands masques de mouvement ne sont pas recommandés.", + "tips": "Les masques de mouvement n'empêchent pas la détection des objets. Il est préférable d'utiliser une zone obligatoire.", + "documentation": "Lire la documentation" + }, + "edit": "Modifier le masque de mouvement", + "point_one": "{{count}} point", + "point_many": "{{count}} points", + "point_other": "{{count}} points", + "clickDrawPolygon": "Cliquer pour dessiner un polygone sur l'image.", + "toast": { + "success": { + "title": "{{polygonName}} a été enregistré. Redémarrez Frigate pour appliquer les modifications.", + "noName": "Le masque de mouvement a été enregistré. Redémarrez Frigate pour appliquer les modifications." + } + }, + "desc": { + "title": "Les masques de mouvement servent à empêcher la détection de mouvements indésirables. Un masquage excessif complique le suivi des objets.", + "documentation": "Documentation" + }, + "add": "Nouveau masque de mouvement" + }, + "objectMasks": { + "label": "Masques de l'objet", + "desc": { + "documentation": "Documentation", + "title": "Les masques de filtrage d'objets sont utilisés pour filtrer les faux positifs pour un type d'objet donné en fonction de l'emplacement." + }, + "edit": "Modifier un masque d'objet", + "clickDrawPolygon": "Cliquez pour dessiner un polygone sur l'image.", + "objects": { + "title": "Objets", + "desc": "Le type d'objet qui s'applique à ce masque d'objet.", + "allObjectTypes": "Tous les types d'objet" + }, + "toast": { + "success": { + "noName": "Le masque d'objet a été enregistré. Redémarrez Frigate pour appliquer les modifications.", + "title": "{{polygonName}} a été enregistré. Redémarrez Frigate pour appliquer les modifications." + } + }, + "point_one": "{{count}} point", + "point_many": "{{count}} points", + "point_other": "{{count}} points", + "add": "Ajouter un masque d'objet", + "documentTitle": "Modifier le masque de l'objet - Frigate", + "context": "Les masques de filtrage d'objets sont utilisés pour filtrer les faux positifs pour un type d'objet donné en fonction de l'emplacement." + }, + "filter": { + "all": "Tous les masques et zones" + }, + "toast": { + "success": { + "copyCoordinates": "Coordonnées copiées pour {{polyName}} dans le presse-papiers." + }, + "error": { + "copyCoordinatesFailed": "Impossible de copier les coordonnées dans le presse-papiers." + } + }, + "restart_required": "Redémarrage requis (masques/zones changés)" + }, + "motionDetectionTuner": { + "title": "Réglage de la détection de mouvement", + "desc": { + "documentation": "Lisez le guide de réglage de mouvement", + "title": "Frigate utilise la détection de mouvement comme première ligne de contrôle pour voir s'il se passe quelque chose dans l'image qui mérite d'être vérifié avec la détection d'objet." + }, + "Threshold": { + "title": "Seuil", + "desc": "La valeur seuil détermine dans quelle mesure un changement dans la luminance d'un pixel est nécessaire pour être considéré comme un mouvement. Valeur par défaut : 30" + }, + "contourArea": { + "title": "Zone de contour", + "desc": "La valeur de la zone de contour est utilisée pour déterminer quels groupes de pixels modifiés sont qualifiés de mouvement. Par défaut : 10" + }, + "improveContrast": { + "title": "Améliorer le contraste", + "desc": "Améliorer le contraste pour les scènes plus sombres. Par défaut : ACTIVÉ" + }, + "toast": { + "success": "Les paramètres de mouvement ont été enregistrés." + } + }, + "debug": { + "debugging": "Débogage", + "objectList": "Liste d'objets", + "boundingBoxes": { + "title": "Cadres de délimitation", + "colors": { + "label": "Couleurs du cadre de délimitation d'un objet", + "info": "
  • Au démarrage, différentes couleurs seront attribuées à chaque étiquette d'objet
  • Une fine ligne bleu foncé indique que l'objet n'est pas détecté à ce moment précis
  • Une fine ligne grise indique que l'objet est détecté comme étant stationnaire
  • Une ligne épaisse indique que l'objet fait l'objet d'un suivi automatique (lorsqu'il est activé)
  • " + }, + "desc": "Afficher les cadres de délimitation autour des objets suivis" + }, + "timestamp": { + "title": "Horodatage", + "desc": "Superposer un horodatage sur l'image" + }, + "zones": { + "title": "Zones", + "desc": "Afficher un aperçu de toutes les zones définies" + }, + "mask": { + "title": "Masques de mouvement", + "desc": "Afficher les polygones du masque de mouvement" + }, + "motion": { + "desc": "Afficher des cadres autour des zones où un mouvement est détecté", + "title": "Cadres de mouvement", + "tips": "

    Cadres de mouvement


    Des cadres rouges seront superposées sur les zones de l'image où un mouvement est actuellement détecté

    " + }, + "regions": { + "title": "Régions", + "desc": "Afficher une boîte de la région d'intérêt envoyée au détecteur d'objet", + "tips": "

    Cadres de région


    Des cadres verts lumineux seront superposés sur les zones d'intérêt de l'image qui sont envoyées au détecteur d'objets.

    " + }, + "objectShapeFilterDrawing": { + "title": "Dessin de filtre de forme d'objet", + "area": "Zone", + "desc": "Dessinez un rectangle sur l'image pour afficher les détails de la zone et du rapport", + "score": "Score", + "tips": "Activez cette option pour dessiner un rectangle sur l'image de la caméra afin d'afficher sa surface et son ratio. Ces valeurs peuvent ensuite être utilisées pour définir les paramètres de filtre de forme d'objet dans votre configuration.", + "document": "Lire la documentation ", + "ratio": "Ratio" + }, + "noObjects": "Aucun objet", + "title": "Debug", + "detectorDesc": "Frigate utilise vos détecteurs ({{detectors}}) pour détecter les objets dans le flux vidéo de votre caméra.", + "desc": "La vue de débogage affiche en temps réel les objets suivis et leurs statistiques. La liste des objets affiche un résumé différé des objets détectés." + }, + "users": { + "title": "Utilisateurs", + "management": { + "title": "Gestion des utilisateurs", + "desc": "Gérez les comptes utilisateurs de cette instance Frigate." + }, + "addUser": "Ajouter un utilisateur", + "updatePassword": "Mettre à jour le mot de passe", + "toast": { + "success": { + "roleUpdated": "Rôle mis à jour pour {{user}}", + "deleteUser": "L'utilisateur {{user}} a été supprimé avec succès", + "createUser": "L'utilisateur {{user}} a été créé avec succès", + "updatePassword": "Mot de passe mis à jour avec succès." + }, + "error": { + "setPasswordFailed": "Échec à l'enregistrement du mot de passe : {{errorMessage}}", + "createUserFailed": "Échec à la création de l'utilisateur : {{errorMessage}}", + "deleteUserFailed": "Échec à de la suppression de l'utilisateur : {{errorMessage}}", + "roleUpdateFailed": "Échec à la mise à jour du rôle : {{errorMessage}}" + } + }, + "table": { + "username": "Nom d'utilisateur", + "actions": "Actions", + "noUsers": "Aucun utilisateur trouvé.", + "changeRole": "Changer le rôle d'utilisateur", + "password": "Mot de passe", + "deleteUser": "Supprimer un utilisateur", + "role": "Rôle" + }, + "dialog": { + "form": { + "user": { + "title": "Nom d'utilisateur", + "placeholder": "Entrez le nom d'utilisateur", + "desc": "Seules les lettres, les chiffres, les points et les traits de soulignement sont autorisés." + }, + "password": { + "strength": { + "weak": "Faible", + "title": "Sécurité du mot de passe : ", + "medium": "Moyen", + "strong": "Fort", + "veryStrong": "Très fort" + }, + "match": "Les mots de passe correspondent", + "notMatch": "Les mots de passe ne correspondent pas", + "placeholder": "Entrez le mot de passe", + "title": "Mot de passe", + "confirm": { + "title": "Confirmez le mot de passe", + "placeholder": "Confirmez le mot de passe" + } + }, + "newPassword": { + "title": "Nouveau mot de passe", + "placeholder": "Entrez le nouveau mot de passe", + "confirm": { + "placeholder": "Ré-entrez le nouveau mot de passe" + } + }, + "usernameIsRequired": "Le nom d'utilisateur est requis" + }, + "deleteUser": { + "title": "Supprimer un utilisateur", + "desc": "Cette action est irréversible. Elle supprimera définitivement le compte utilisateur et toutes les données associées.", + "warn": "Êtes-vous sûr de vouloir supprimer {{username}} ?" + }, + "passwordSetting": { + "updatePassword": "Mettre à jour le mot de passe pour {{username}}", + "setPassword": "Définir le mot de passe", + "desc": "Créez un mot de passe fort pour sécuriser ce compte." + }, + "changeRole": { + "title": "Changer le rôle de l'utilisateur", + "desc": "Mettre à jour les autorisations pour {{username}}", + "roleInfo": { + "intro": "Sélectionnez le rôle approprié pour cet utilisateur :", + "admin": "Administrateur", + "adminDesc": "Accès complet à l'ensemble des fonctionnalités.", + "viewer": "Observateur", + "viewerDesc": "Limité aux tableaux de bord Direct, Examiner, Explorer et Exports." + } + }, + "createUser": { + "title": "Créer un nouvel utilisateur", + "desc": "Ajoutez un nouveau compte utilisateur et spécifiez un rôle pour accéder aux zones de l'interface utilisateur Frigate.", + "usernameOnlyInclude": "Le nom d'utilisateur ne peut inclure que des lettres, des chiffres, . ou _" + } + } + } +} diff --git a/web/public/locales/fr/views/system.json b/web/public/locales/fr/views/system.json new file mode 100644 index 000000000..562ab047d --- /dev/null +++ b/web/public/locales/fr/views/system.json @@ -0,0 +1,179 @@ +{ + "documentTitle": { + "storage": "Statistiques de stockage - Frigate", + "cameras": "Statistiques des caméras - Frigate", + "general": "Statistiques générales - Frigate", + "enrichments": "Statistiques enrichies - Frigate", + "logs": { + "frigate": "Journaux de Frigate - Frigate", + "nginx": "Journaux Nginx - Frigate", + "go2rtc": "Journaux Go2RTC - Frigate" + } + }, + "title": "Système", + "metrics": "Métriques du système", + "logs": { + "download": { + "label": "Télécharger les journaux" + }, + "copy": { + "label": "Copier dans le presse-papiers", + "success": "Journaux copiés vers le presse-papiers", + "error": "Échec du copiage des journaux dans le presse-papiers" + }, + "type": { + "label": "Type", + "timestamp": "Horodatage", + "tag": "Étiqueter", + "message": "Message" + }, + "tips": "Les logs sont diffusés en continu depuis le serveur", + "toast": { + "error": { + "fetchingLogsFailed": "Erreur lors de la récupération des logs : {{errorMessage}}", + "whileStreamingLogs": "Erreur lors de la diffusion des logs : {{errorMessage}}" + } + } + }, + "general": { + "title": "Général", + "detector": { + "title": "Détecteurs", + "inferenceSpeed": "Vitesse d'inférence du détecteur", + "cpuUsage": "Utilisation CPU Détecteur", + "memoryUsage": "Utilisation Mémoire Détecteur", + "temperature": "Température du détecteur" + }, + "hardwareInfo": { + "title": "Info Matériel", + "gpuUsage": "Utilisation GPU", + "gpuMemory": "Mémoire GPU", + "gpuEncoder": "Encodeur GPU", + "gpuDecoder": "Décodeur GPU", + "gpuInfo": { + "vainfoOutput": { + "title": "Sortie Vainfo", + "returnCode": "Code de retour : {{code}}", + "processOutput": "Tâche de Sortie :", + "processError": "Erreur de tâche :" + }, + "nvidiaSMIOutput": { + "title": "Sortie Nvidia SMI", + "name": "Nom : {{name}}", + "cudaComputerCapability": "Capacité de calcul CUDA : {{cuda_compute}}", + "vbios": "Informations VBios : {{vbios}}", + "driver": "Pilote : {{driver}}" + }, + "copyInfo": { + "label": "Information de copie du GPU" + }, + "toast": { + "success": "Informations GPU copiées dans le presse-papier" + }, + "closeInfo": { + "label": "Information de fermeture du GPU" + } + }, + "npuUsage": "Utilisation NPU", + "npuMemory": "Mémoire NPU" + }, + "otherProcesses": { + "title": "Autres tâches", + "processCpuUsage": "Utilisation CPU des tâches", + "processMemoryUsage": "Utilisation mémoire des tâches" + } + }, + "storage": { + "title": "Stockage", + "recordings": { + "title": "Enregistrements", + "earliestRecording": "Enregistrement le plus ancien :", + "tips": "Cette valeur corresponds au total du stockage utilisé par les enregistrements dans la base de données Frigate. Frigate ne suit pas l'utilisation du stockage pour tous les fichiers sur votre disque." + }, + "cameraStorage": { + "title": "Stockage de la caméra", + "bandwidth": "Bande passante", + "unused": { + "title": "Inutilisé", + "tips": "Cette valeur ne représente peut-être pas précisément l'espace libre et utilisable par Frigate si vous avez d'autres fichiers stockés sur ce disque en plus des enregistrements Frigate. Frigate ne suit pas l'utilisation du stockage en dehors de ses propres enregistrements." + }, + "percentageOfTotalUsed": "Pourcentage du Total", + "storageUsed": "Stockage", + "camera": "Caméra", + "unusedStorageInformation": "Information sur le stockage non utilisé" + }, + "overview": "Prévisualisation" + }, + "cameras": { + "title": "Caméras", + "info": { + "cameraProbeInfo": "{{camera}} Information récupérée depuis la Caméra", + "fetching": "En cours de récupération des données de la Caméra", + "stream": "Flux {{idx}}", + "fps": "Images par seconde :", + "unknown": "Inconnu", + "audio": "Audio :", + "tips": { + "title": "Information récupérée depuis la Caméra" + }, + "streamDataFromFFPROBE": "Le flux de données est obtenu par ffprobe.", + "resolution": "Résolution :", + "error": "Erreur : {{error}}", + "codec": "Codec :", + "video": "Vidéo :" + }, + "framesAndDetections": "Images / Détections", + "label": { + "camera": "caméra", + "detect": "Détecter", + "skipped": "ignoré", + "ffmpeg": "FFmpeg", + "capture": "capture", + "cameraFfmpeg": "{{camName}} FFmpeg", + "cameraSkippedDetectionsPerSecond": "{{camName}} détections manquées par seconde", + "overallDetectionsPerSecond": "Moyenne de détections par seconde", + "overallFramesPerSecond": "Moyenne d'images par seconde", + "overallSkippedDetectionsPerSecond": "Moyenne de détections manquées par seconde", + "cameraCapture": "{{camName}} capture", + "cameraDetect": "{{camName}} détection", + "cameraFramesPerSecond": "{{camName}} images par seconde", + "cameraDetectionsPerSecond": "{{camName}} détections par seconde" + }, + "overview": "Prévisualisation", + "toast": { + "success": { + "copyToClipboard": "Données récupérées copiées dans le presse-papier." + }, + "error": { + "unableToProbeCamera": "Impossible de récupérer des infos depuis la caméra : {{errorMessage}}" + } + } + }, + "lastRefreshed": "Dernier rafraichissement : ", + "stats": { + "ffmpegHighCpuUsage": "{{camera}} a un taux élevé d'utilisation CPU par FFmpeg ({{ffmpegAvg}}%)", + "detectHighCpuUsage": "{{camera}} a un taux élevé d'utilisation CPU ({{detectAvg}}%)", + "healthy": "Le système est sain", + "reindexingEmbeddings": "Réindexation des données complémentaires ({{processed}}% complété)", + "cameraIsOffline": "{{camera}} est hors ligne", + "detectIsSlow": "{{detect}} est lent ({{speed}} ms)", + "detectIsVerySlow": "{{detect}} est très lent ({{speed}} ms)" + }, + "enrichments": { + "title": "Améliorations", + "infPerSecond": "Inférences par seconde", + "embeddings": { + "face_embedding_speed": "Vitesse de capture des données complémentaires de visage", + "text_embedding_speed": "Vitesse de capture des données complémentaire de texte", + "image_embedding_speed": "Vitesse de capture des données complémentaires à l'image", + "plate_recognition_speed": "Vitesse de reconnaissance des plaques d'immatriculation", + "face_recognition_speed": "Vitesse de reconnaissance faciale", + "plate_recognition": "Reconnaissance de plaques d'immatriculation", + "image_embedding": "Représentation vectorielle d'image", + "yolov9_plate_detection": "Détection de plaques d'immatriculation YOLOv9", + "face_recognition": "Reconnaissance faciale", + "text_embedding": "Représentation vectorielle de texte", + "yolov9_plate_detection_speed": "Vitesse de détection de plaques d'immatriculation YOLOv9" + } + } +} diff --git a/web/public/locales/hi/audio.json b/web/public/locales/hi/audio.json new file mode 100644 index 000000000..afffaf44a --- /dev/null +++ b/web/public/locales/hi/audio.json @@ -0,0 +1,143 @@ +{ + "babbling": "बड़बड़ाना", + "yell": "चिल्लाना", + "whispering": "फुसफुसाना", + "crying": "रोना", + "laughter": "हँसना", + "singing": "गाना", + "chant": "जपना", + "mantra": "मंत्र", + "run": "भागना", + "sniff": "सूँघना", + "sneeze": "छींंकना", + "whistling": "सीटी बजाना", + "speech": "बोलना", + "sigh": "आह भरना", + "humming": "गुनगुनाना", + "child_singing": "बच्चे का गाना", + "groan": "कराहना", + "breathing": "साँस लेना", + "snoring": "खर्राटे लेना", + "cough": "खाँसना", + "throat_clearing": "गला साफ़ करना", + "footsteps": "कदमों की आहट", + "chewing": "चबाना", + "biting": "काटना", + "gargling": "गरारे करना", + "stomach_rumble": "पेट की गुड़गुड़ाहट", + "burping": "डकारना", + "hiccup": "हिचकी", + "fart": "पादना", + "heartbeat": "धड़कन", + "cheering": "जयकार करना", + "pets": "पालतू जानवर", + "animal": "जानवर", + "children_playing": "बच्चों का खेलना", + "crowd": "भीड़", + "dog": "कुत्ता", + "hiss": "फुफकारना", + "neigh": "हिनहिनाना", + "cattle": "मवेशी", + "moo": "रंभाहट", + "goat": "बकरी", + "bleat": "मेमियाहट", + "hands": "हाथ", + "pig": "सुअर", + "clapping": "ताली बजाना", + "chatter": "गपशप", + "finger_snapping": "उँगलियाँ चटकाना", + "bark": "भौंकना", + "cowbell": "गाय की घंटी", + "sheep": "भेड़", + "yip": "कूँकना", + "livestock": "पशुधन", + "horse": "घोड़ा", + "cat": "बिल्ली", + "chicken": "मुर्गी", + "wild_animals": "जंगली जानवर", + "bird": "पक्षी", + "chirp": "चहचहाना", + "roar": "दहाड़ना", + "pigeon": "कबूतर", + "crow": "कौआ", + "flapping_wings": "पंख फड़फड़ाना", + "dogs": "कुत्ते", + "insect": "कीड़ा", + "patter": "पटपटाहट", + "cymbal": "झांझ", + "tambourine": "डफली", + "orchestra": "वाद्यवृंद", + "wind_instrument": "वायु वाद्ययंत्र", + "bowed_string_instrument": "धनुष तार वाद्ययंत्र", + "harp": "हार्प", + "bell": "घंटी", + "church_bell": "गिरजाघर का घंटा", + "accordion": "अकोर्डियन", + "opera": "ओपेरा", + "disco": "डिस्को", + "jazz": "जैज़", + "dubstep": "डबस्टेप", + "song": "गीत", + "lullaby": "लोरी", + "sad_music": "दुखभरा संगीत", + "tender_music": "कोमल संगीत", + "wind": "हवा", + "wind_noise": "हवा की आवाज़", + "thunderstorm": "आंधी-तूफ़ान", + "thunder": "गर्जना", + "water": "पानी", + "rain": "बारिश", + "rain_on_surface": "सतह पर गिरती बारिश", + "waterfall": "झरना", + "ocean": "सागर", + "waves": "लहरें", + "stream": "धारा", + "steam": "भाप", + "vehicle": "वाहन", + "car": "गाड़ी", + "boat": "नाव", + "ship": "जहाज़", + "truck": "ट्रक", + "bus": "बस", + "motor_vehicle": "मोटर वाहन", + "motorboat": "इंजन वाली नाव", + "sailboat": "पाल वाली नाव", + "police_car": "पुलिस की गाड़ी", + "saxophone": "सैक्सोफोन", + "sitar": "सितार", + "music": "संगीत", + "snake": "साँप", + "mouse": "चूहा", + "wedding_music": "शादी का संगीत", + "buzz": "भनभनाहट", + "fire": "आग", + "caw": "कांव कांव करना", + "owl": "उल्लू", + "mosquito": "मच्छर", + "scary_music": "डरावना संगीत", + "duck": "बतख", + "hoot": "उल्लू की आवाज़", + "rustling_leaves": "खड़खड़ाते पत्ते", + "rats": "चूहे", + "cricket": "झिंगुर", + "fly": "मक्खी", + "frog": "मेंढक", + "croak": "टर्राना", + "guitar": "गिटार", + "tabla": "तबला", + "trumpet": "तुरही", + "brass_instrument": "पीतल वाद्ययंत्र", + "flute": "बाँसुरी", + "clarinet": "क्लैरिनेट", + "bicycle_bell": "साइकिल की घंटी", + "harmonica": "हारमोनिका", + "bagpipes": "बैगपाइप", + "angry_music": "क्रोधित संगीत", + "music_of_bollywood": "बॉलीवुड संगीत", + "happy_music": "खुशहाल संगीत", + "exciting_music": "रोमांचक संगीत", + "raindrop": "बारिश की बूंद", + "rowboat": "चप्पू वाली नाव", + "aircraft": "विमान", + "bicycle": "साइकिल" +} diff --git a/web/public/locales/hi/common.json b/web/public/locales/hi/common.json new file mode 100644 index 000000000..392c9a844 --- /dev/null +++ b/web/public/locales/hi/common.json @@ -0,0 +1,7 @@ +{ + "time": { + "untilForTime": "{{time}} तक", + "untilForRestart": "जब तक फ्रिगेट पुनः रीस्टार्ट नहीं हो जाता।", + "untilRestart": "रीस्टार्ट होने में" + } +} diff --git a/web/public/locales/hi/components/auth.json b/web/public/locales/hi/components/auth.json new file mode 100644 index 000000000..c58f433de --- /dev/null +++ b/web/public/locales/hi/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "password": "पासवर्ड", + "login": "प्रवेश करें", + "errors": { + "passwordRequired": "पासवर्ड आवश्यक है", + "rateLimit": "दर सीमा पार हो गई है। बाद में पुनः प्रयास करें।", + "unknownError": "अज्ञात त्रुटि। प्रविष्टियाँ जांचें।", + "usernameRequired": "प्रयोक्ता नाम आवश्यक है", + "webUnknownError": "अज्ञात त्रुटि। कंसोल प्रविष्टियाँ जांचें।", + "loginFailed": "लॉगिन असफल हुआ" + }, + "user": "प्रयोक्ता नाम" + } +} diff --git a/web/public/locales/hi/components/camera.json b/web/public/locales/hi/components/camera.json new file mode 100644 index 000000000..37c5b27ed --- /dev/null +++ b/web/public/locales/hi/components/camera.json @@ -0,0 +1,7 @@ +{ + "group": { + "label": "कैमरा समूह", + "add": "कैमरा समूह जोड़ें", + "edit": "कैमरा समूह संपादित करें" + } +} diff --git a/web/public/locales/hi/components/dialog.json b/web/public/locales/hi/components/dialog.json new file mode 100644 index 000000000..dce6983b5 --- /dev/null +++ b/web/public/locales/hi/components/dialog.json @@ -0,0 +1,9 @@ +{ + "restart": { + "title": "क्या आप निश्चित हैं कि आप फ्रिगेट को रीस्टार्ट करना चाहते हैं?", + "button": "रीस्टार्ट", + "restarting": { + "title": "फ्रिगेट रीस्टार्ट हो रहा है" + } + } +} diff --git a/web/public/locales/hi/components/filter.json b/web/public/locales/hi/components/filter.json new file mode 100644 index 000000000..214179375 --- /dev/null +++ b/web/public/locales/hi/components/filter.json @@ -0,0 +1,9 @@ +{ + "filter": "फ़िल्टर", + "labels": { + "label": "लेबल", + "all": { + "title": "सभी लेबल" + } + } +} diff --git a/web/public/locales/hi/components/icons.json b/web/public/locales/hi/components/icons.json new file mode 100644 index 000000000..7f5236e6b --- /dev/null +++ b/web/public/locales/hi/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "चिह्न चुनें", + "search": { + "placeholder": "चिह्न खोजें..।" + } + } +} diff --git a/web/public/locales/hi/components/input.json b/web/public/locales/hi/components/input.json new file mode 100644 index 000000000..13b65c133 --- /dev/null +++ b/web/public/locales/hi/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "वीडियो डाउनलोड करें", + "toast": { + "success": "आपकी समीक्षा वीडियो डाउनलोड होना शुरू हो गई है।" + } + } + } +} diff --git a/web/public/locales/hi/components/player.json b/web/public/locales/hi/components/player.json new file mode 100644 index 000000000..9b4ed4389 --- /dev/null +++ b/web/public/locales/hi/components/player.json @@ -0,0 +1,5 @@ +{ + "noRecordingsFoundForThisTime": "इस समय का कोई रिकॉर्डिंग नहीं मिला", + "noPreviewFound": "कोई प्रीव्यू नहीं मिला", + "noPreviewFoundFor": "{{cameraName}} के लिए कोई पूर्वावलोकन नहीं मिला" +} diff --git a/web/public/locales/hi/objects.json b/web/public/locales/hi/objects.json new file mode 100644 index 000000000..436a57668 --- /dev/null +++ b/web/public/locales/hi/objects.json @@ -0,0 +1,17 @@ +{ + "horse": "घोड़ा", + "sheep": "भेड़", + "bark": "भौंकना", + "animal": "जानवर", + "dog": "कुत्ता", + "cat": "बिल्ली", + "goat": "बकरी", + "boat": "नाव", + "bus": "बस", + "bird": "पक्षी", + "mouse": "चूहा", + "vehicle": "वाहन", + "car": "गाड़ी", + "person": "व्यक्ति", + "bicycle": "साइकिल" +} diff --git a/web/public/locales/hi/views/configEditor.json b/web/public/locales/hi/views/configEditor.json new file mode 100644 index 000000000..784f8ec46 --- /dev/null +++ b/web/public/locales/hi/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "saveOnly": "केवल सहेजें", + "saveAndRestart": "सहेजें और पुनः प्रारंभ करें", + "configEditor": "विन्यास संपादक", + "copyConfig": "विन्यास कॉपी करें", + "toast": { + "error": { + "savingError": "विन्यास सहेजने में त्रुटि हुई" + }, + "success": { + "copyToClipboard": "विन्यास क्लिपबोर्ड पर कॉपी कर लिया गया है।" + } + }, + "documentTitle": "विन्यास संपादक - Frigate" +} diff --git a/web/public/locales/hi/views/events.json b/web/public/locales/hi/views/events.json new file mode 100644 index 000000000..b6fba2aa1 --- /dev/null +++ b/web/public/locales/hi/views/events.json @@ -0,0 +1,4 @@ +{ + "alerts": "अलर्टस", + "detections": "खोजें" +} diff --git a/web/public/locales/hi/views/explore.json b/web/public/locales/hi/views/explore.json new file mode 100644 index 000000000..bb214ba12 --- /dev/null +++ b/web/public/locales/hi/views/explore.json @@ -0,0 +1,4 @@ +{ + "documentTitle": "अन्वेषण करें - फ्रिगेट", + "generativeAI": "जनरेटिव ए आई" +} diff --git a/web/public/locales/hi/views/exports.json b/web/public/locales/hi/views/exports.json new file mode 100644 index 000000000..97a0f0e53 --- /dev/null +++ b/web/public/locales/hi/views/exports.json @@ -0,0 +1,4 @@ +{ + "documentTitle": "निर्यात - फ्रिगेट", + "search": "खोजें" +} diff --git a/web/public/locales/hi/views/faceLibrary.json b/web/public/locales/hi/views/faceLibrary.json new file mode 100644 index 000000000..5c8de952e --- /dev/null +++ b/web/public/locales/hi/views/faceLibrary.json @@ -0,0 +1,6 @@ +{ + "description": { + "addFace": "फेस लाइब्रेरी में नया संग्रह जोड़ने की प्रक्रिया को आगे बढ़ाएं।", + "placeholder": "इस संग्रह का नाम बताएं" + } +} diff --git a/web/public/locales/hi/views/live.json b/web/public/locales/hi/views/live.json new file mode 100644 index 000000000..86d2a9235 --- /dev/null +++ b/web/public/locales/hi/views/live.json @@ -0,0 +1,4 @@ +{ + "documentTitle": "लाइव - फ्रिगेट", + "documentTitle.withCamera": "{{camera}} - लाइव - फ्रिगेट" +} diff --git a/web/public/locales/hi/views/recording.json b/web/public/locales/hi/views/recording.json new file mode 100644 index 000000000..a9846e445 --- /dev/null +++ b/web/public/locales/hi/views/recording.json @@ -0,0 +1,11 @@ +{ + "calendar": "पंचांग", + "toast": { + "error": { + "noValidTimeSelected": "कोई मान्य समय सीमा चयनित नहीं है", + "endTimeMustAfterStartTime": "समाप्ति समय प्रारंभ समय के बाद होना चाहिए" + } + }, + "export": "निर्यात", + "filter": "फ़िल्टर" +} diff --git a/web/public/locales/hi/views/search.json b/web/public/locales/hi/views/search.json new file mode 100644 index 000000000..b38dd11af --- /dev/null +++ b/web/public/locales/hi/views/search.json @@ -0,0 +1,4 @@ +{ + "search": "खोजें", + "savedSearches": "सहेजी गई खोजें" +} diff --git a/web/public/locales/hi/views/settings.json b/web/public/locales/hi/views/settings.json new file mode 100644 index 000000000..5fe3a3233 --- /dev/null +++ b/web/public/locales/hi/views/settings.json @@ -0,0 +1,6 @@ +{ + "documentTitle": { + "default": "सेटिंग्स - फ्रिगेट", + "authentication": "प्रमाणीकरण सेटिंग्स - फ्रिगेट" + } +} diff --git a/web/public/locales/hi/views/system.json b/web/public/locales/hi/views/system.json new file mode 100644 index 000000000..b29ff9abb --- /dev/null +++ b/web/public/locales/hi/views/system.json @@ -0,0 +1,6 @@ +{ + "documentTitle": { + "cameras": "कैमरा आँकड़े - फ्रिगेट", + "storage": "भंडारण आँकड़े - फ्रिगेट" + } +} diff --git a/web/public/locales/hu/audio.json b/web/public/locales/hu/audio.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/audio.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/common.json b/web/public/locales/hu/common.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/common.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/components/auth.json b/web/public/locales/hu/components/auth.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/components/auth.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/components/camera.json b/web/public/locales/hu/components/camera.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/components/camera.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/components/dialog.json b/web/public/locales/hu/components/dialog.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/components/dialog.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/components/filter.json b/web/public/locales/hu/components/filter.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/components/filter.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/components/icons.json b/web/public/locales/hu/components/icons.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/components/icons.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/components/input.json b/web/public/locales/hu/components/input.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/components/input.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/components/player.json b/web/public/locales/hu/components/player.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/components/player.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/objects.json b/web/public/locales/hu/objects.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/objects.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/views/configEditor.json b/web/public/locales/hu/views/configEditor.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/views/configEditor.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/views/events.json b/web/public/locales/hu/views/events.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/views/events.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/views/explore.json b/web/public/locales/hu/views/explore.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/views/explore.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/views/exports.json b/web/public/locales/hu/views/exports.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/views/exports.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/views/faceLibrary.json b/web/public/locales/hu/views/faceLibrary.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/views/faceLibrary.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/views/live.json b/web/public/locales/hu/views/live.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/views/live.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/views/recording.json b/web/public/locales/hu/views/recording.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/views/recording.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/views/search.json b/web/public/locales/hu/views/search.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/views/search.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/views/settings.json b/web/public/locales/hu/views/settings.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/views/settings.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/hu/views/system.json b/web/public/locales/hu/views/system.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/hu/views/system.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/audio.json b/web/public/locales/id/audio.json new file mode 100644 index 000000000..829dac589 --- /dev/null +++ b/web/public/locales/id/audio.json @@ -0,0 +1,25 @@ +{ + "yell": "Teriakan", + "speech": "Bahasa", + "babbling": "Ocehan", + "bellow": "Di bawah", + "whoop": "Teriakan", + "whispering": "Bisikan", + "snicker": "Tertawa", + "crying": "Menangis", + "sigh": "Mendesah", + "choir": "Paduan Suara", + "yodeling": "Bernyanyi Yodel", + "chant": "Nyanyian", + "child_singing": "Anak bernyanyi", + "rapping": "Mengetuk", + "humming": "Bersenandung", + "groan": "Mengerang", + "grunt": "Mendengus", + "breathing": "Bernafas", + "laughter": "Tertawa", + "singing": "Nyanyian", + "mantra": "Mantra", + "synthetic_singing": "Nyanyian sintesis", + "whistling": "Siulan" +} diff --git a/web/public/locales/id/common.json b/web/public/locales/id/common.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/common.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/components/auth.json b/web/public/locales/id/components/auth.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/components/auth.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/components/camera.json b/web/public/locales/id/components/camera.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/components/camera.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/components/dialog.json b/web/public/locales/id/components/dialog.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/components/dialog.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/components/filter.json b/web/public/locales/id/components/filter.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/components/filter.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/components/icons.json b/web/public/locales/id/components/icons.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/components/icons.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/components/input.json b/web/public/locales/id/components/input.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/components/input.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/components/player.json b/web/public/locales/id/components/player.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/components/player.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/objects.json b/web/public/locales/id/objects.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/objects.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/views/configEditor.json b/web/public/locales/id/views/configEditor.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/views/configEditor.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/views/events.json b/web/public/locales/id/views/events.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/views/events.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/views/explore.json b/web/public/locales/id/views/explore.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/views/explore.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/views/exports.json b/web/public/locales/id/views/exports.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/views/exports.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/views/faceLibrary.json b/web/public/locales/id/views/faceLibrary.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/views/faceLibrary.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/views/live.json b/web/public/locales/id/views/live.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/views/live.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/views/recording.json b/web/public/locales/id/views/recording.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/views/recording.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/views/search.json b/web/public/locales/id/views/search.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/views/search.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/views/settings.json b/web/public/locales/id/views/settings.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/views/settings.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/id/views/system.json b/web/public/locales/id/views/system.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/id/views/system.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/it/audio.json b/web/public/locales/it/audio.json new file mode 100644 index 000000000..eb9b98a5b --- /dev/null +++ b/web/public/locales/it/audio.json @@ -0,0 +1,429 @@ +{ + "oink": "Grugnito", + "engine": "Motore", + "keyboard": "Tastiera", + "snake": "Serpente", + "mantra": "Mantra", + "radio": "Radio", + "goat": "Capra", + "bird": "Uccello", + "clock": "Orologio", + "gears": "Ingranaggi", + "fire": "Fuoco", + "hammer": "Martello", + "gunshot": "Sparo", + "bell": "Campana", + "explosion": "Esplosione", + "silence": "Silenzio", + "ambulance": "Ambulanza", + "thunder": "Tuono", + "purr": "Fusa", + "guitar": "Chitarra", + "bass_guitar": "Basso elettrico", + "eruption": "Eruzione", + "sound_effect": "Effetto sonoro", + "bicycle": "Bicicletta", + "vehicle": "Veicolo", + "flute": "Flauto", + "harp": "Arpa", + "steam": "Vapore", + "sailboat": "Barca a vela", + "helicopter": "Elicottero", + "coin": "Moneta", + "scissors": "Forbici", + "electric_shaver": "Rasoio elettrico", + "mechanisms": "Meccanismi", + "printer": "Stampante", + "television": "Televisione", + "environmental_noise": "Rumore ambientale", + "smoke_detector": "Rilevatore di fumo", + "clarinet": "Clarinetto", + "horse": "Cavallo", + "electric_guitar": "Chitarra elettrica", + "meow": "Miao", + "ringtone": "Suoneria", + "boat": "Barca", + "sampler": "Campionatore", + "song": "Canzone", + "clapping": "Applausi", + "cat": "Gatto", + "chicken": "Pollo", + "acoustic_guitar": "Chitarra acustica", + "speech": "Discorso", + "babbling": "Balbettio", + "motorcycle": "Motociclo", + "yell": "Urlo", + "whoop": "Ululato", + "car": "Automobile", + "bellow": "Ruggito", + "whispering": "Bisbiglio", + "snicker": "Risatina", + "crying": "Pianto", + "sigh": "Sospiro", + "singing": "Canto", + "choir": "Coro", + "yodeling": "Gorgheggio", + "chant": "Cantilena", + "child_singing": "Canto di bambino", + "laughter": "Risata", + "synthetic_singing": "Canto sintetico", + "rapping": "Rap", + "humming": "Mormorio", + "groan": "Gemito", + "grunt": "Grugnito", + "whistling": "Fischio", + "breathing": "Respiro", + "wheeze": "Respiro affannoso", + "snoring": "Russare", + "gasp": "Respiro profondo", + "cough": "Tosse", + "snort": "Sbuffare", + "pant": "Ansimare", + "throat_clearing": "Schiarimento della gola", + "sneeze": "Starnuto", + "sniff": "Sniffare", + "footsteps": "Passi", + "run": "Corsa", + "chewing": "Masticare", + "gargling": "Gargarismo", + "stomach_rumble": "Brontolio di stomaco", + "burping": "Rutto", + "fart": "Peto", + "hiccup": "Singhiozzo", + "finger_snapping": "Schiocco di dita", + "hands": "Mani", + "heartbeat": "Battito cardiaco", + "applause": "Applauso", + "heart_murmur": "Soffio cardiaco", + "cheering": "Tifo", + "animal": "Animale", + "pets": "Animali domestici", + "dog": "Cane", + "bark": "Abbaio", + "howl": "Ululato", + "yip": "Guaito", + "crowd": "Folla", + "livestock": "Bestiame", + "cowbell": "Campanaccio", + "turkey": "Tacchino", + "children_playing": "Bambini che giocano", + "chatter": "Chiacchiere", + "bow_wow": "Bau Bau", + "growling": "Ringhio", + "whimper_dog": "Lamento di cane", + "hiss": "Sibilo", + "caterwaul": "Miagolio", + "pig": "Maiale", + "sheep": "Pecora", + "fowl": "Pollame", + "bleat": "Belato", + "cock_a_doodle_doo": "Chicchirichì", + "gobble": "Glu Glu", + "cluck": "Chioccia", + "duck": "Anatra", + "quack": "Qua Qua", + "wild_animals": "Animali selvatici", + "goose": "Oca", + "honk": "Starnazzare", + "roar": "Ruggito", + "roaring_cats": "Ruggito felino", + "chirp": "Cinguettio", + "pigeon": "Piccione", + "crow": "Corvo", + "coo": "Tubare", + "owl": "Gufo", + "caw": "Gracchio", + "dogs": "Cani", + "hoot": "Bubbolio", + "flapping_wings": "Battito d'ali", + "mouse": "Mouse", + "rats": "Ratti", + "insect": "Insetto", + "cricket": "Grillo", + "mosquito": "Zanzara", + "buzz": "Ronzio", + "fly": "Mosca", + "frog": "Rana", + "croak": "Gracidio", + "rattle": "Sonaglio", + "music": "Musica", + "musical_instrument": "Strumento musicale", + "whale_vocalization": "Canto della balena", + "plucked_string_instrument": "Strumento a corda pizzicata", + "tapping": "Tapping (tecnica di chitarra)", + "steel_guitar": "Chitarra d'acciaio", + "strum": "Strimpellio", + "banjo": "Banjo", + "sitar": "Sitar", + "mandolin": "Mandolino", + "zither": "Cetra da tavolo", + "ukulele": "Ukulele", + "piano": "Pianoforte", + "electric_piano": "Pianoforte elettrico", + "organ": "Organo", + "electronic_organ": "Organo elettronico", + "synthesizer": "Sintetizzatore", + "hammond_organ": "Organo Hammond", + "drum_kit": "Batteria", + "drum": "Tamburo", + "drum_machine": "Drum Machine", + "tabla": "Tabla", + "cymbal": "Piatto", + "hi_hat": "Charleston", + "wood_block": "Blocco di legno", + "tambourine": "Tamburello", + "maraca": "Maracas", + "gong": "Gong", + "tubular_bells": "Campane tubolari", + "mallet_percussion": "Mazzuola", + "marimba": "Marimba", + "glockenspiel": "Glockenspiel", + "vibraphone": "Vibrafono", + "steelpan": "Tamburo d'acciaio", + "orchestra": "Orchestra", + "brass_instrument": "Ottoni", + "trumpet": "Tromba", + "french_horn": "Corno francese", + "trombone": "Trombone", + "bowed_string_instrument": "Strumento ad arco", + "violin": "Violino", + "string_section": "Sezione d'archi", + "cello": "Violoncello", + "double_bass": "Contrabbasso", + "pizzicato": "Pizzicato", + "wind_instrument": "Strumento a fiato", + "saxophone": "Sassofono", + "church_bell": "Campana della chiesa", + "jingle_bell": "Campanellino", + "bicycle_bell": "Campanello della bici", + "tuning_fork": "Diapason", + "chime": "Carillon", + "wind_chime": "Campane a vento", + "harmonica": "Armonica", + "accordion": "Fisarmonica", + "bagpipes": "Cornamusa", + "didgeridoo": "Didgeridoo", + "pop_music": "Musica pop", + "theremin": "Theremin", + "singing_bowl": "Campana tibetana", + "rock_music": "Musica rock", + "heavy_metal": "Heavy Metal", + "beatboxing": "Beatboxing", + "hip_hop_music": "Musica hip hop", + "punk_rock": "Punk Rock", + "grunge": "Grunge", + "rock_and_roll": "Rock and Roll", + "psychedelic_rock": "Rock psichedelico", + "bus": "Autobus", + "train": "Treno", + "percussion": "Percussioni", + "harpsichord": "Clavicembalo", + "snare_drum": "Rullante", + "rimshot": "Colpi nei bordi del tamburo", + "drum_roll": "Rullo di tamburi", + "bass_drum": "Grancassa", + "timpani": "Timpano", + "progressive_rock": "Rock progressivo", + "scratching": "Graffio", + "rhythm_and_blues": "Rhythm and Blues", + "soul_music": "Musica soul", + "reggae": "Reggae", + "country": "Country", + "bluegrass": "Bluegrass", + "funk": "Funk", + "folk_music": "Musica folk", + "middle_eastern_music": "Musica mediorientale", + "jazz": "Jazz", + "disco": "Disco", + "classical_music": "Musica classica", + "opera": "Opera", + "electronic_music": "Musica elettronica", + "house_music": "Musica house", + "techno": "Techno", + "dubstep": "Dubstep", + "drum_and_bass": "Drum and Bass", + "electronica": "Elettronica", + "camera": "Telecamera", + "shuffle": "Trascinare i piedi", + "biting": "Mordere", + "clip_clop": "Trotto di cavallo", + "neigh": "Nitrire", + "cattle": "Bestiame", + "moo": "Muggire", + "squawk": "Strillo", + "patter": "Ticchettio", + "swing_music": "Musica swing", + "electronic_dance_music": "Musica dance elettronica", + "ambient_music": "Musica ambientale", + "trance_music": "Musica trance", + "blues": "Blues", + "music_for_children": "Musica per bambini", + "new-age_music": "Musica new age", + "vocal_music": "Musica vocale", + "a_capella": "A capella", + "music_of_latin_america": "Musica latinoamericana", + "music_of_africa": "Musica africana", + "afrobeat": "Afrobeat", + "christian_music": "Musica cristiana", + "gospel_music": "Musica gospel", + "music_of_asia": "Musica asiatica", + "carnatic_music": "Musica carnatica", + "music_of_bollywood": "Musica di Bollywood", + "ska": "Ska", + "traditional_music": "Musica tradizionale", + "independent_music": "Musica indipendente", + "background_music": "Musica di sottofondo", + "theme_music": "Musica a tema", + "jingle": "Motivetto", + "soundtrack_music": "Colonna sonora musicale", + "lullaby": "Ninna nanna", + "video_game_music": "Musica per videogiochi", + "christmas_music": "Musica natalizia", + "dance_music": "Musica da ballo", + "wedding_music": "Musica per matrimoni", + "happy_music": "Musica allegra", + "sad_music": "Musica triste", + "tender_music": "Musica dolce", + "salsa_music": "Musica salsa", + "flamenco": "Flamenco", + "angry_music": "Musica arrabbiata", + "scary_music": "Musica spaventosa", + "wind": "Vento", + "rustling_leaves": "Fruscio di foglie", + "wind_noise": "Rumore del vento", + "thunderstorm": "Temporale", + "water": "Acqua", + "rain": "Pioggia", + "raindrop": "Goccia di pioggia", + "stream": "Ruscello", + "waterfall": "Cascata", + "ocean": "Oceano", + "waves": "Onde", + "rain_on_surface": "Pioggia in superficie", + "gurgling": "Gorgoglio", + "crackle": "Crepitio", + "rowboat": "Barca a remi", + "motorboat": "Motoscafo", + "ship": "Nave", + "toot": "Fischio", + "motor_vehicle": "Veicolo a motore", + "car_alarm": "Allarme auto", + "power_windows": "Alzacristalli elettrici", + "skidding": "Sbandare", + "tire_squeal": "Stridio di pneumatici", + "car_passing_by": "Auto che passa", + "race_car": "Auto da corsa", + "air_brake": "Freno ad aria compressa", + "air_horn": "Clacson ad aria", + "reversing_beeps": "Bip di retromarcia", + "ice_cream_truck": "Camioncino dei gelati", + "emergency_vehicle": "Veicolo di emergenza", + "police_car": "Auto della polizia", + "fire_engine": "Camion dei pompieri", + "traffic_noise": "Rumore del traffico", + "rail_transport": "Trasporto ferroviario", + "train_whistle": "Fischio del treno", + "train_horn": "Clacson del treno", + "railroad_car": "Vagone ferroviario", + "train_wheels_squealing": "Ruote del treno che stridono", + "subway": "Metropolitana", + "aircraft": "Aeromobile", + "aircraft_engine": "Motore aeronautico", + "jet_engine": "Motore a reazione", + "propeller": "Elica", + "fixed-wing_aircraft": "Aeromobile ad ala fissa", + "skateboard": "Skateboard", + "light_engine": "Motore leggero", + "dental_drill's_drill": "Trapano dentale", + "lawn_mower": "Taglia erba", + "exciting_music": "Musica emozionante", + "truck": "Camion", + "firecracker": "Petardo", + "chainsaw": "Motosega", + "medium_engine": "Motore medio", + "heavy_engine": "Motore pesante", + "engine_knocking": "Battito del motore", + "engine_starting": "Avviamento del motore", + "idling": "Al minimo", + "accelerating": "Accelerando", + "door": "Porta", + "doorbell": "Campanello", + "ding-dong": "Ding Dong", + "sliding_door": "Porta scorrevole", + "slam": "Sbattere", + "knock": "Bussare", + "tap": "Tocco", + "squeak": "Squittio", + "cupboard_open_or_close": "Apertura o chiusura armadio", + "drawer_open_or_close": "Apertura o chiusura cassetto", + "dishes": "Piatti", + "cutlery": "Posate", + "chopping": "Tritare", + "frying": "Frittura", + "microwave_oven": "Forno a microonde", + "blender": "Miscelatore", + "water_tap": "Rubinetto dell'acqua", + "sink": "Lavello", + "bathtub": "Vasca", + "hair_dryer": "Asciugacapelli", + "toilet_flush": "Scarico del water", + "toothbrush": "Spazzolino da denti", + "electric_toothbrush": "Spazzolino elettrico", + "vacuum_cleaner": "Aspirapolvere", + "zipper": "Cerniera", + "keys_jangling": "Chiavi che tintinnano", + "shuffling_cards": "Mescolare le carte", + "typing": "Digitazione", + "typewriter": "Macchina da scrivere", + "computer_keyboard": "Tastiera del computer", + "writing": "Scrivere", + "alarm": "Allarme", + "telephone": "Telefono", + "telephone_bell_ringing": "Telefono che squilla", + "telephone_dialing": "Composizione telefonica", + "dial_tone": "Tono di linea", + "busy_signal": "Segnale di occupato", + "alarm_clock": "Sveglia", + "siren": "Sirena", + "civil_defense_siren": "Sirena della Protezione Civile", + "buzzer": "Cicalino", + "fire_alarm": "Allarme antincendio", + "foghorn": "Corno da nebbia", + "whistle": "Fischio", + "steam_whistle": "Fischio a vapore", + "ratchet": "Cricchetto", + "tick": "Tic tac", + "tick-tock": "Tic-Tac", + "pulleys": "Pulegge", + "sewing_machine": "Macchina da cucire", + "mechanical_fan": "Ventilatore meccanico", + "air_conditioning": "Aria condizionata", + "cash_register": "Registratore di cassa", + "single-lens_reflex_camera": "Fotocamera reflex a obiettivo singolo", + "tools": "Utensili", + "jackhammer": "Martello pneumatico", + "sawing": "Segare", + "filing": "Limare", + "sanding": "Levigatura", + "power_tool": "Utensile elettrico", + "drill": "Trapano", + "fusillade": "Fucilazione", + "machine_gun": "Mitragliatrice", + "artillery_fire": "Fuoco di artiglieria", + "cap_gun": "Pistola a fumogeni", + "fireworks": "Fuochi d'artificio", + "burst": "Esplosione", + "boom": "Scoppio", + "wood": "Legno", + "chop": "Taglio", + "splinter": "Scheggia", + "crack": "Crepa", + "glass": "Vetro", + "chink": "Fessura", + "shatter": "Frantumare", + "static": "Statico", + "white_noise": "Rumore bianco", + "pink_noise": "Rumore rosa", + "field_recording": "Registrazione sul campo", + "scream": "Grido" +} diff --git a/web/public/locales/it/common.json b/web/public/locales/it/common.json new file mode 100644 index 000000000..b2f6ebe59 --- /dev/null +++ b/web/public/locales/it/common.json @@ -0,0 +1,265 @@ +{ + "time": { + "last14": "Ultimi 14 giorni", + "pm": "pm", + "last30": "Ultimi 30 giorni", + "untilRestart": "Fino al riavvio", + "yesterday": "Ieri", + "am": "am", + "untilForTime": "Fino alle {{time}}", + "minute_one": "{{time}} minuto", + "minute_many": "{{time}} minuti", + "minute_other": "{{time}} minuti", + "5minutes": "5 minuti", + "24hours": "24 ore", + "second_one": "{{time}} secondo", + "second_many": "{{time}} secondi", + "second_other": "{{time}} secondi", + "untilForRestart": "Fino al riavvio di Frigate.", + "ago": "{{timeAgo}} fa", + "justNow": "Adesso", + "today": "Oggi", + "last7": "Ultimi 7 giorni", + "thisWeek": "Questa settimana", + "lastWeek": "Settimana scorsa", + "thisMonth": "Questo mese", + "lastMonth": "Mese scorso", + "10minutes": "10 minuti", + "30minutes": "30 minuti", + "1hour": "1 ora", + "12hours": "12 ore", + "year_one": "{{time}} anno", + "year_many": "{{time}} anni", + "year_other": "{{time}} anni", + "month_one": "{{time}} mese", + "month_many": "{{time}} mesi", + "month_other": "{{time}} mesi", + "day_one": "{{time}} giorno", + "day_many": "{{time}} giorni", + "day_other": "{{time}} giorni", + "hour_one": "{{time}} ora", + "hour_many": "{{time}} ore", + "hour_other": "{{time}} ore", + "yr": "{{time}}anno", + "mo": "{{time}}mese", + "d": "{{time}}giorno", + "h": "{{time}}ora", + "m": "{{time}}min", + "s": "{{time}}sec", + "formattedTimestamp": { + "12hour": "MMM d, h:mm:ss aaa", + "24hour": "MMM d, HH:mm:ss" + }, + "formattedTimestamp2": { + "12hour": "MM/dd h:mm:ssa", + "24hour": "d MMM HH:mm:ss" + }, + "formattedTimestampExcludeSeconds": { + "12hour": "%b %-d, %I:%M %p", + "24hour": "%b %-d, %H:%M" + }, + "formattedTimestampWithYear": { + "12hour": "%b %-d %Y, %I:%M %p", + "24hour": "%b %-d %Y, %H:%M" + }, + "formattedTimestampOnlyMonthAndDay": "%b %-d", + "formattedTimestampHourMinute": { + "12hour": "h:mm aaa", + "24hour": "HH:mm" + }, + "formattedTimestampHourMinuteSecond": { + "12hour": "h:mm:ss aaa", + "24hour": "HH:mm:ss" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "MMM d, h:mm aaa", + "24hour": "MMM d, HH:mm" + }, + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "MMM d yyyy, h:mm aaa", + "24hour": "MMM d yyyy, HH:mm" + }, + "formattedTimestampMonthDay": "MMM d", + "formattedTimestampFilename": { + "24hour": "MM-dd-yy-HH-mm-ss", + "12hour": "MM-dd-yy-h-mm-ss-a" + } + }, + "button": { + "cancel": "Annulla", + "yes": "Sì", + "unselect": "Deseleziona", + "disabled": "Disabilitato", + "fullscreen": "A schermo intero", + "save": "Salva", + "no": "No", + "edit": "Modifica", + "export": "Esporta", + "disable": "Disabilita", + "apply": "Applica", + "reset": "Reimposta", + "done": "Fatto", + "enabled": "Abilitato", + "enable": "Abilita", + "saving": "Salvataggio…", + "copy": "Copia", + "history": "Storico", + "exitFullscreen": "Esci da schermo intero", + "on": "ACCESO", + "copyCoordinates": "Copia coordinate", + "download": "Scarica", + "info": "Informazioni", + "suspended": "Sospeso", + "unsuspended": "Riattiva", + "play": "Riproduci", + "deleteNow": "Elimina ora", + "next": "Successivo", + "off": "SPENTO", + "delete": "Elimina", + "close": "Chiudi", + "back": "Indietro", + "pictureInPicture": "Immagine nell'immagine", + "twoWayTalk": "Comunicazione bidirezionale", + "cameraAudio": "Audio della telecamera" + }, + "unit": { + "speed": { + "kph": "km/h", + "mph": "miglia/h" + } + }, + "label": { + "back": "Indietro" + }, + "menu": { + "configuration": "Configurazione", + "languages": "Lingue", + "appearance": "Aspetto", + "systemMetrics": "Metriche di sistema", + "systemLogs": "Registri di sistema", + "settings": "Impostazioni", + "configurationEditor": "Editor di configurazione", + "language": { + "en": "English (Inglese)", + "zhCN": "简体中文 (Cinese semplificato)", + "withSystem": { + "label": "Usa la lingua di sistema" + }, + "es": "Español (Spagnolo)", + "hi": "हिन्दी (Hindi)", + "fr": "Français (Francese)", + "ar": "العربية (Arabo)", + "pt": "Português (Portoghese)", + "ru": "Русский (Russo)", + "tr": "Türkçe (Turco)", + "nl": "Nederlands (Olandese)", + "sv": "Svenska (Svedese)", + "cs": "Čeština (Ceco)", + "nb": "Norsk Bokmål (Norvegese)", + "ko": "한국어 (Coreano)", + "vi": "Tiếng Việt (Vietnamita)", + "fa": "فارسی (Persiano)", + "ro": "Română (Rumeno)", + "hu": "Magyar (Ungherese)", + "fi": "Suomi (Finlandese)", + "da": "Dansk (Danese)", + "el": "Ελληνικά (Greco)", + "sk": "Slovenčina (Slovacco)", + "ja": "日本語 (Giapponese)", + "uk": "Українська (Ucraino)", + "pl": "Polski (Polacco)", + "de": "Deutsch (Tedesco)", + "he": "עברית (Ebraico)", + "it": "Italiano (Italiano)", + "yue": "粵語 (Cantonese)" + }, + "darkMode": { + "label": "Modalità scura", + "light": "Chiara", + "dark": "Scura", + "withSystem": { + "label": "Usa le impostazioni di sistema per le modalità chiara/scura" + } + }, + "system": "Sistema", + "theme": { + "label": "Tema", + "blue": "Blu", + "contrast": "Alto contrasto", + "green": "Verde", + "default": "Predefinito", + "red": "Rosso", + "nord": "Nord", + "highcontrast": "Contrasto elevato" + }, + "live": { + "cameras": { + "title": "Telecamere", + "count_one": "{{count}} Telecamera", + "count_many": "{{count}} Telecamere", + "count_other": "{{count}} Telecamere" + }, + "title": "Dal vivo", + "allCameras": "Tutte le telecamere" + }, + "help": "Aiuto", + "documentation": { + "title": "Documentazione", + "label": "Documentazione di Frigate" + }, + "restart": "Riavvia Frigate", + "review": "Rivedi", + "explore": "Esplora", + "export": "Esporta", + "uiPlayground": "Interfaccia area prove", + "user": { + "account": "Account", + "current": "Utente attuale: {{user}}", + "anonymous": "anonimo", + "logout": "Esci", + "title": "Utente", + "setPassword": "Imposta password" + }, + "withSystem": "Sistema", + "faceLibrary": "Raccolta volti" + }, + "pagination": { + "next": { + "title": "Successiva", + "label": "Vai alla pagina successiva" + }, + "previous": { + "label": "Vai alla pagina precedente", + "title": "Precedente" + }, + "label": "paginazione", + "more": "Altre pagine" + }, + "role": { + "title": "Ruolo", + "admin": "Amministratore", + "viewer": "Spettatore", + "desc": "Gli Amministratori hanno accesso completo a tutte le funzionalità dell'interfaccia di Frigate. Gli Spettatori sono limitati alla sola visualizzazione delle telecamere, rivedono gli oggetti e le registrazioni storiche nell'interfaccia utente." + }, + "accessDenied": { + "desc": "Non hai i permessi per visualizzare questa pagina.", + "documentTitle": "Accesso vietato - Frigate", + "title": "Accesso vietato" + }, + "notFound": { + "desc": "Pagina non trovata", + "documentTitle": "Non trovato - Frigate", + "title": "404" + }, + "toast": { + "copyUrlToClipboard": "URL copiata negli appunti.", + "save": { + "error": { + "title": "Impossibile salvare le modifiche alla configurazione: {{errorMessage}}", + "noMessage": "Impossibile salvare le modifiche alla configurazione" + }, + "title": "Salva" + } + }, + "selectItem": "Seleziona {{item}}" +} diff --git a/web/public/locales/it/components/auth.json b/web/public/locales/it/components/auth.json new file mode 100644 index 000000000..bb6e2200d --- /dev/null +++ b/web/public/locales/it/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "user": "Nome utente", + "password": "Password", + "login": "Accedi", + "errors": { + "usernameRequired": "Il nome utente è obbligatorio", + "passwordRequired": "La password è obbligatoria", + "rateLimit": "Superato il limite di tentativi. Riprova più tardi.", + "unknownError": "Errore sconosciuto. Controlla i registri.", + "webUnknownError": "Errore sconosciuto. Controlla i registri della console.", + "loginFailed": "Accesso non riuscito" + } + } +} diff --git a/web/public/locales/it/components/camera.json b/web/public/locales/it/components/camera.json new file mode 100644 index 000000000..f9a243cd2 --- /dev/null +++ b/web/public/locales/it/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "label": "Gruppo di telecamere", + "add": "Aggiungi gruppo di telecamere", + "delete": { + "label": "Elimina gruppo di telecamere", + "confirm": { + "title": "Conferma eliminazione", + "desc": "Sei sicuro di voler eliminare il gruppo di telecamere {{name}}?" + } + }, + "edit": "Modifica gruppo di telecamere", + "name": { + "label": "Nome", + "placeholder": "Inserisci un nome…", + "errorMessage": { + "exists": "Il nome scelto per il gruppo telecamere è già presente.", + "invalid": "Nome del gruppo di telecamere non valido.", + "mustLeastCharacters": "Il nome del gruppo di telecamere deve contenere almeno 2 caratteri.", + "nameMustNotPeriod": "Il nome del gruppo di telecamere non deve contenere punti." + } + }, + "camera": { + "setting": { + "label": "Impostazioni di trasmissione della telecamera", + "title": "Impostazioni di trasmissione di {{cameraName}}", + "audioIsAvailable": "L'audio è disponibile per questo flusso", + "streamMethod": { + "label": "Metodo di trasmissione", + "method": { + "smartStreaming": { + "label": "Trasmissione intelligente (consigliato)", + "desc": "La trasmissione intelligente aggiorna l'immagine della telecamera una volta al minuto quando non si verifica alcuna attività rilevabile, per risparmiare larghezza di banda e risorse. Quando viene rilevata un'attività, l'immagine passa automaticamente alla trasmissione dal vivo." + }, + "continuousStreaming": { + "label": "Trasmissione continua", + "desc": { + "warning": "La trasmissione continua può causare un elevato utilizzo di larghezza di banda e problemi di prestazioni. Da usare con cautela.", + "title": "L'immagine della telecamera sarà sempre trasmessa dal vivo quando è visibile sulla schermata, anche se non viene rilevata alcuna attività." + } + }, + "noStreaming": { + "label": "Nessuna trasmissione", + "desc": "Le immagini delle telecamere verranno aggiornate solo una volta al minuto e non verrà effettuata alcuna trasmissione dal vivo." + } + } + }, + "compatibilityMode": { + "label": "Modalità di compatibilità", + "desc": "Abilita questa opzione solo se la trasmissione dal vivo della tua telecamera mostra artefatti cromatici e presenta una linea diagonale sul lato destro dell'immagine." + }, + "audio": { + "tips": { + "document": "Leggi la documentazione ", + "title": "L'audio deve essere trasmesso dalla tua telecamera e configurato in go2rtc per questo flusso." + } + }, + "audioIsUnavailable": "L'audio non è disponibile per questo flusso", + "desc": "Modifica le opzioni di trasmissione dal vivo per la schermata di questo gruppo di telecamere. Queste impostazioni sono specifiche del dispositivo/browser." + } + }, + "cameras": { + "desc": "Seleziona le telecamere per questo gruppo.", + "label": "Telecamere" + }, + "icon": "Icona", + "success": "Il gruppo di telecamere ({{name}}) è stato salvato." + }, + "debug": { + "options": { + "label": "Impostazioni", + "title": "Opzioni", + "showOptions": "Mostra opzioni", + "hideOptions": "Nascondi opzioni" + }, + "boundingBox": "Riquadro di delimitazione", + "timestamp": "Orario", + "zones": "Zone", + "mask": "Maschera", + "motion": "Movimento", + "regions": "Regioni" + } +} diff --git a/web/public/locales/it/components/dialog.json b/web/public/locales/it/components/dialog.json new file mode 100644 index 000000000..4a44a877f --- /dev/null +++ b/web/public/locales/it/components/dialog.json @@ -0,0 +1,122 @@ +{ + "restart": { + "title": "Sei sicuro di voler riavviare Frigate?", + "button": "Riavvia", + "restarting": { + "title": "Frigate si sta riavviando", + "content": "Questa pagina si ricaricherà in {{countdown}} secondi.", + "button": "Forza ricarica ora" + } + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "Invia a Frigate+", + "desc": "Gli oggetti in posizioni che si desidera evitare non sono falsi positivi. Inviarli come falsi positivi confonderà il modello." + }, + "review": { + "false": { + "label": "Non confermare questa etichetta per Frigate Plus", + "false_one": "Questo non è un {{label}}", + "false_many": "Questi non sono un {{label}}", + "false_other": "Questi non sono un {{label}}" + }, + "true": { + "label": "Conferma questa etichetta per Frigate Plus", + "true_one": "Questo è un {{label}}", + "true_many": "Questi sono {{label}}", + "true_other": "Questi sono {{label}}" + }, + "state": { + "submitted": "Inviato" + }, + "question": { + "label": "Conferma questa etichetta per Frigate Plus", + "ask_a": "Questo oggetto è un {{label}}?", + "ask_an": "Questo oggetto è un {{label}}?", + "ask_full": "Questo oggetto è un {{untranslatedLabel}} ({{translatedLabel}})?" + } + } + }, + "video": { + "viewInHistory": "Visualizza in Storico" + } + }, + "export": { + "time": { + "fromTimeline": "Seleziona dalla cronologia", + "custom": "Personalizzato", + "start": { + "title": "Ora di inizio", + "label": "Seleziona l'ora di inizio" + }, + "end": { + "title": "Ora di fine", + "label": "Seleziona l'ora di fine" + }, + "lastHour_one": "Ultima ora", + "lastHour_many": "Ultime {{count}} ore", + "lastHour_other": "Ultime {{count}} ore" + }, + "export": "Esporta", + "selectOrExport": "Seleziona o esporta", + "toast": { + "success": "Esportazione avviata correttamente. Visualizza il file nella cartella /exports.", + "error": { + "failed": "Impossibile avviare l'esportazione: {{error}}", + "endTimeMustAfterStartTime": "L'ora di fine deve essere successiva all'ora di inizio", + "noVaildTimeSelected": "Nessun intervallo di tempo valido selezionato" + } + }, + "fromTimeline": { + "saveExport": "Salva esportazione", + "previewExport": "Anteprima esportazione" + }, + "select": "Seleziona", + "name": { + "placeholder": "Assegna un nome all'esportazione" + } + }, + "streaming": { + "label": "Trasmissione", + "showStats": { + "label": "Mostra statistiche di trasmissione", + "desc": "Abilita questa opzione per visualizzare le statistiche della trasmissione come sovrapposizione sul flusso della telecamera." + }, + "debugView": "Vista correzioni", + "restreaming": { + "disabled": "La ritrasmissione non è abilitata per questa telecamera.", + "desc": { + "title": "Imposta go2rtc per opzioni aggiuntive di visualizzazione dal vivo e audio per questa telecamera.", + "readTheDocumentation": "Leggi la documentazione" + } + } + }, + "search": { + "saveSearch": { + "label": "Salva ricerca", + "overwrite": "{{searchName}} esiste già. Il salvataggio sovrascriverà il valore esistente.", + "desc": "Specifica un nome per questa ricerca salvata.", + "button": { + "save": { + "label": "Salva questa ricerca" + } + }, + "placeholder": "Inserisci un nome per la tua ricerca", + "success": "La ricerca ({{searchName}}) è stata salvata." + } + }, + "recording": { + "button": { + "export": "Esporta", + "markAsReviewed": "Segna come visto", + "deleteNow": "Elimina ora" + }, + "confirmDelete": { + "desc": { + "selected": "Vuoi davvero eliminare tutti i video registrati associati a questo elemento di visto?

    Tieni premuto il tasto Maiusc per ignorare questa finestra di dialogo in futuro." + }, + "title": "Conferma eliminazione" + } + } +} diff --git a/web/public/locales/it/components/filter.json b/web/public/locales/it/components/filter.json new file mode 100644 index 000000000..a5503af46 --- /dev/null +++ b/web/public/locales/it/components/filter.json @@ -0,0 +1,125 @@ +{ + "filter": "Filtro", + "labels": { + "label": "Etichette", + "all": { + "title": "Tutte le etichette", + "short": "Etichette" + }, + "count_one": "{{count}} Etichetta", + "count_other": "{{count}} Etichette" + }, + "more": "Altri filtri", + "zones": { + "label": "Zone", + "all": { + "title": "Tutte le zone", + "short": "Zone" + } + }, + "dates": { + "all": { + "title": "Tutte le date", + "short": "Date" + } + }, + "reset": { + "label": "Ripristina i filtri ai valori predefiniti" + }, + "features": { + "submittedToFrigatePlus": { + "label": "Inviato a Frigate+", + "tips": "Devi prima filtrare gli oggetti tracciati che hanno un'istantanea.

    Gli oggetti tracciati senza istantanee non possono essere inviati a Frigate+." + }, + "hasSnapshot": "Contiene una istantanea", + "hasVideoClip": "Contiene un filmato video", + "label": "Caratteristiche" + }, + "sort": { + "dateAsc": "Data (crescente)", + "scoreAsc": "Punteggio dell'oggetto (crescente)", + "dateDesc": "Data (discendente)", + "speedAsc": "Velocità stimata (crescente)", + "speedDesc": "Velocità stimata (discendente)", + "relevance": "Rilevanza", + "label": "Ordina", + "scoreDesc": "Punteggio dell'oggetto (discrescente)" + }, + "explore": { + "settings": { + "title": "Impostazioni", + "gridColumns": { + "desc": "Seleziona il numero di colonne nella vista griglia.", + "title": "Colonne della griglia" + }, + "defaultView": { + "title": "Vista predefinita", + "desc": "Se non è selezionato alcun filtro, visualizza un riepilogo degli oggetti tracciati più di recente per etichetta oppure visualizza una griglia non filtrata.", + "summary": "Riepilogo", + "unfilteredGrid": "Griglia non filtrata" + }, + "searchSource": { + "label": "Cerca la fonte", + "desc": "Scegli se cercare nelle miniature o nelle descrizioni degli oggetti tracciati.", + "options": { + "thumbnailImage": "Immagine anteprima", + "description": "Descrizione" + } + } + }, + "date": { + "selectDateBy": { + "label": "Seleziona una data da filtrare" + } + } + }, + "logSettings": { + "label": "Filtra livello di registro", + "loading": { + "title": "Caricamento", + "desc": "Scorrendo il riquadro dei registri fino in fondo, i nuovi registri vengono automaticamente visualizzati non appena vengono aggiunti." + }, + "filterBySeverity": "Filtra i registri per gravità", + "disableLogStreaming": "Disabilita la trasmissione del registro", + "allLogs": "Tutti i registri" + }, + "trackedObjectDelete": { + "toast": { + "success": "Oggetti tracciati eliminati correttamente.", + "error": "Impossibile eliminare gli oggetti tracciati: {{errorMessage}}" + }, + "desc": "L'eliminazione di questi {{objectLength}} oggetti tracciati rimuove l'istantanea, eventuali incorporamenti salvati e tutte le voci associate al ciclo di vita dell'oggetto. Il filmato registrato di questi oggetti tracciati nella vista Storico NON verrà eliminato.

    Vuoi procedere?

    Tieni premuto il tasto Maiusc per ignorare questa finestra di dialogo in futuro.", + "title": "Conferma eliminazione" + }, + "recognizedLicensePlates": { + "title": "Targhe riconosciute", + "selectPlatesFromList": "Seleziona una o più targhe dall'elenco.", + "loadFailed": "Impossibile caricare le targhe riconosciute.", + "loading": "Caricamento targhe riconosciute…", + "placeholder": "Digita per cercare le targhe…", + "noLicensePlatesFound": "Nessuna targa trovata." + }, + "timeRange": "Intervallo di tempo", + "subLabels": { + "label": "Sottoetichette", + "all": "Tutte le sottoetichette" + }, + "score": "Punteggio", + "estimatedSpeed": "Velocità stimata ({{unit}})", + "cameras": { + "label": "Filtro telecamere", + "all": { + "title": "Tutte le telecamere", + "short": "Telecamere" + } + }, + "review": { + "showReviewed": "Mostra visti" + }, + "motion": { + "showMotionOnly": "Mostra solo movimento" + }, + "zoneMask": { + "filterBy": "Filtra per maschera di zona" + } +} diff --git a/web/public/locales/it/components/icons.json b/web/public/locales/it/components/icons.json new file mode 100644 index 000000000..18778862b --- /dev/null +++ b/web/public/locales/it/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "search": { + "placeholder": "Cerca un'icona…" + }, + "selectIcon": "Seleziona un'icona" + } +} diff --git a/web/public/locales/it/components/input.json b/web/public/locales/it/components/input.json new file mode 100644 index 000000000..fdd42a76b --- /dev/null +++ b/web/public/locales/it/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "toast": { + "success": "Il video dell'oggetto da te visto ha iniziato a scaricarsi." + }, + "label": "Scarica video" + } + } +} diff --git a/web/public/locales/it/components/player.json b/web/public/locales/it/components/player.json new file mode 100644 index 000000000..2aee1a781 --- /dev/null +++ b/web/public/locales/it/components/player.json @@ -0,0 +1,51 @@ +{ + "noPreviewFound": "Nessuna anteprima trovata", + "noRecordingsFoundForThisTime": "Nessuna registrazione trovata per questo intervallo", + "noPreviewFoundFor": "Nessuna anteprima trovata per {{cameraName}}", + "submitFrigatePlus": { + "title": "Vuoi inviare questo fotogramma a Frigate+?", + "submit": "Invia" + }, + "livePlayerRequiredIOSVersion": "Per questo tipo di trasmissione dal vivo è richiesto iOS 17.1 o versione successiva.", + "stats": { + "streamType": { + "short": "Tipo", + "title": "Tipo di trasmissione:" + }, + "bandwidth": { + "title": "Larghezza di banda:", + "short": "Larghezza di banda" + }, + "latency": { + "title": "Latenza:", + "value": "{{seconds}} secondi", + "short": { + "title": "Latenza", + "value": "{{seconds}} sec" + } + }, + "droppedFrames": { + "title": "Fotogrammi persi:", + "short": { + "title": "Persi", + "value": "{{droppedFrames}} fotogrammi" + } + }, + "decodedFrames": "Fotogrammi decodificati:", + "totalFrames": "Totale fotogrammi:", + "droppedFrameRate": "Percentuali fotogrammi persi:" + }, + "streamOffline": { + "desc": "Nessun fotogramma ricevuto sul flusso detect di {{cameraName}}, controlla i registri degli errori", + "title": "Trasmissione disconnessa" + }, + "toast": { + "success": { + "submittedFrigatePlus": "Fotogramma inviato correttamente a Frigate+" + }, + "error": { + "submitFrigatePlusFailed": "Impossibile inviare il fotogramma a Frigate+" + } + }, + "cameraDisabled": "La telecamera è disattivata" +} diff --git a/web/public/locales/it/objects.json b/web/public/locales/it/objects.json new file mode 100644 index 000000000..a512b0021 --- /dev/null +++ b/web/public/locales/it/objects.json @@ -0,0 +1,120 @@ +{ + "bird": "Uccello", + "clock": "Orologio", + "scissors": "Forbici", + "vehicle": "Veicolo", + "cat": "Gatto", + "boat": "Barca", + "horse": "Cavallo", + "bicycle": "Bicicletta", + "person": "Persona", + "car": "Automobile", + "motorcycle": "Motociclo", + "dog": "Cane", + "bark": "Abbaio", + "animal": "Animale", + "sheep": "Pecora", + "mouse": "Mouse", + "bear": "Orso", + "elephant": "Elefante", + "zebra": "Zebra", + "giraffe": "Giraffa", + "hat": "Cappello", + "umbrella": "Ombrello", + "train": "Treno", + "backpack": "Zaino", + "cow": "Mucca", + "airplane": "Aereo", + "bus": "Autobus", + "shoe": "Scarpa", + "skateboard": "Skateboard", + "kite": "Aquilone", + "oven": "Forno", + "sink": "Lavello", + "stop_sign": "Segnale di stop", + "raccoon": "Procione", + "postnl": "PostNL", + "nzpost": "NZPost", + "book": "Libro", + "frisbee": "Frisbee", + "laptop": "Portatile", + "knife": "Coltello", + "spoon": "Cucchiaio", + "bowl": "Ciotola", + "dhl": "DHL", + "banana": "Banana", + "carrot": "Carota", + "dining_table": "Tavolo da pranzo", + "hot_dog": "Hot Dog", + "mirror": "Specchio", + "microwave": "Microonde", + "toaster": "Tostapane", + "teddy_bear": "Orsacchiotto di peluche", + "hair_brush": "Spazzola per capelli", + "squirrel": "Scoiattolo", + "deer": "Cervo", + "robot_lawnmower": "Robot tagliaerba", + "waste_bin": "Cestino", + "on_demand": "Su richiesta", + "ups": "UPS", + "fedex": "FedEx", + "postnord": "PostNord", + "traffic_light": "Semaforo", + "fire_hydrant": "Idrante antincendio", + "street_sign": "Cartello stradale", + "parking_meter": "Parchimetro", + "bench": "Panca", + "eye_glasses": "Occhiali da vista", + "handbag": "Borsa a mano", + "tie": "Cravatta", + "suitcase": "Valigia", + "skis": "Sci", + "snowboard": "Snowboard", + "sports_ball": "Palla sportiva", + "baseball_bat": "Mazza da baseball", + "baseball_glove": "Guanto da baseball", + "surfboard": "Tavola da surf", + "tennis_racket": "Racchetta da tennis", + "bottle": "Bottiglia", + "plate": "Piatto", + "wine_glass": "Bicchiere da vino", + "cup": "Tazza", + "fork": "Forchetta", + "apple": "Mela", + "sandwich": "Panino", + "orange": "Arancia", + "broccoli": "Broccoli", + "pizza": "Pizza", + "donut": "Ciambella", + "cake": "Torta", + "chair": "Sedia", + "couch": "Divano", + "door": "Porta", + "keyboard": "Tastiera", + "potted_plant": "Pianta in vaso", + "bed": "Letto", + "window": "Finestra", + "desk": "Scrivania", + "toilet": "Toilette", + "tv": "Televisione", + "remote": "Telecomando", + "cell_phone": "Telefono cellulare", + "blender": "Miscelatore", + "refrigerator": "Frigorifero", + "hair_dryer": "Asciugacapelli", + "toothbrush": "Spazzolino da denti", + "vase": "Vaso", + "fox": "Volpe", + "goat": "Capra", + "rabbit": "Coniglio", + "face": "Viso", + "license_plate": "Targa", + "package": "Pacchetto", + "bbq_grill": "Griglia per barbecue", + "amazon": "Amazon", + "usps": "USPS", + "an_post": "An Post", + "purolator": "Purolator", + "gls": "GLS", + "dpd": "DPD" +} diff --git a/web/public/locales/it/views/configEditor.json b/web/public/locales/it/views/configEditor.json new file mode 100644 index 000000000..b932a157a --- /dev/null +++ b/web/public/locales/it/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "configEditor": "Editor di configurazione", + "documentTitle": "Editor di configurazione - Frigate", + "copyConfig": "Copia configurazione", + "saveAndRestart": "Salva e riavvia", + "saveOnly": "Salva soltanto", + "toast": { + "success": { + "copyToClipboard": "Configurazione copiata negli appunti." + }, + "error": { + "savingError": "Errore durante il salvataggio della configurazione" + } + } +} diff --git a/web/public/locales/it/views/events.json b/web/public/locales/it/views/events.json new file mode 100644 index 000000000..9f41519c5 --- /dev/null +++ b/web/public/locales/it/views/events.json @@ -0,0 +1,38 @@ +{ + "alerts": "Avvisi", + "detections": "Rilevamento", + "motion": { + "label": "Movimento", + "only": "Solo movimento" + }, + "empty": { + "alert": "Non ci sono avvisi da rivedere", + "detection": "Non ci sono rilevamenti da rivedere", + "motion": "Nessun dato di movimento trovato" + }, + "newReviewItems": { + "label": "Visualizza i nuovi elementi da rivedere", + "button": "Nuovi elementi da rivedere" + }, + "markTheseItemsAsReviewed": "Segna questi elementi come visti", + "markAsReviewed": "Segna come visto", + "documentTitle": "Rivedi - Frigate", + "allCameras": "Tutte le camere", + "timeline": "Cronologia", + "timeline.aria": "Seleziona la cronologia", + "events": { + "label": "Eventi", + "aria": "Seleziona eventi", + "noFoundForTimePeriod": "Nessun evento trovato per questo intervallo." + }, + "recordings": { + "documentTitle": "Registrazioni - Frigate" + }, + "calendarFilter": { + "last24Hours": "Ultime 24 ore" + }, + "camera": "Telecamera", + "selected": "{{count}} selezionati", + "selected_one": "{{count}} selezionati", + "selected_other": "{{count}} selezionati" +} diff --git a/web/public/locales/it/views/explore.json b/web/public/locales/it/views/explore.json new file mode 100644 index 000000000..f1a2c8d95 --- /dev/null +++ b/web/public/locales/it/views/explore.json @@ -0,0 +1,202 @@ +{ + "generativeAI": "IA Generativa", + "documentTitle": "Esplora - Frigate", + "exploreIsUnavailable": { + "title": "Esplora non è disponibile", + "embeddingsReindexing": { + "context": "Potrai usare Esplora dopo che l'incorporamento degli oggetti tracciati avrà terminato la ricostruzione dell'indice.", + "step": { + "descriptionsEmbedded": "Descrizioni incorporate: ", + "thumbnailsEmbedded": "Miniature incorporate: ", + "trackedObjectsProcessed": "Oggetti tracciati elaborati: " + }, + "startingUp": "Avvio…", + "estimatedTime": "Tempo rimanente stimato:", + "finishingShortly": "Completamento a breve" + }, + "downloadingModels": { + "setup": { + "textModel": "Modello di testo", + "visionModel": "Modello di visione", + "visionModelFeatureExtractor": "Estrattore di funzionalità del modello di visione", + "textTokenizer": "Tokenizzatore di testo" + }, + "tips": { + "documentation": "Leggi la documentazione", + "context": "Una volta scaricati i modelli, potrebbe essere necessario reindicizzare gli incorporamenti degli oggetti tracciati." + }, + "error": "Si è verificato un errore. Controlla i registri di Frigate.", + "context": "Frigate sta scaricando i modelli di incorporamento necessari per supportare la funzione di Ricerca Semantica. L'operazione potrebbe richiedere diversi minuti, a seconda della velocità della connessione di rete." + } + }, + "details": { + "timestamp": "Orario", + "snapshotScore": { + "label": "Punteggio istantanea" + }, + "regenerateFromSnapshot": "Rigenera da istantanea", + "item": { + "tips": { + "mismatch_one": "E' stato rilevato {{count}} oggetto non disponibile e incluse in questo elemento visto. Tale oggetto non è stato classificato come avviso o rilevamento oppure è già stato ripulito/eliminato.", + "mismatch_many": "Sono stati rilevati {{count}} oggetti non disponibili e inclusi in questo elemento visto. Tali oggetti non sono stati classificati come avvisi o rilevamenti oppure sono già stati ripuliti/eliminati.", + "mismatch_other": "Sono stati rilevati {{count}} oggetti non disponibili e inclusi in questo elemento visto. Tali oggetti non sono stati classificati come avvisi o rilevamenti oppure sono già stati ripuliti/eliminati.", + "hasMissingObjects": "Modifica la configurazione se vuoi che Frigate salvi gli oggetti tracciati per le seguenti etichette: {{objects}}" + }, + "title": "Dettagli dell'elemento visto", + "desc": "Dettagli dell'elemento visto", + "button": { + "share": "Condividi questo elemento visto", + "viewInExplore": "Visualizza in Esplora" + }, + "toast": { + "success": { + "regenerate": "È stata richiesta una nuova descrizione a {{provider}}. A seconda della velocità del tuo provider, la rigenerazione della nuova descrizione potrebbe richiedere del tempo.", + "updatedSublabel": "Sottoetichetta aggiornata correttamente.", + "updatedLPR": "Targa aggiornata con successo." + }, + "error": { + "regenerate": "Impossibile chiamare {{provider}} per una nuova descrizione: {{errorMessage}}", + "updatedSublabelFailed": "Impossibile aggiornare la sottoetichetta: {{errorMessage}}", + "updatedLPRFailed": "Impossibile aggiornare la targa: {{errorMessage}}" + } + } + }, + "zones": "Zone", + "description": { + "label": "Descrizione", + "placeholder": "Descrizione dell'oggetto tracciato", + "aiTips": "Frigate non richiederà una descrizione al tuo fornitore di Intelligenza Artificiale Generativa finché non sarà terminato il ciclo di vita dell'oggetto tracciato." + }, + "label": "Etichetta", + "editSubLabel": { + "title": "Modifica sottoetichetta", + "desc": "Inserisci una nuova sottoetichetta per questa {{label}}", + "descNoLabel": "Inserisci una nuova sottoetichetta per questo oggetto tracciato" + }, + "editLPR": { + "title": "Modifica targa", + "desc": "Inserisci un nuovo valore della targa per questa {{label}}", + "descNoLabel": "Inserisci un nuovo valore di targa per questo oggetto tracciato" + }, + "topScore": { + "label": "Punteggio massimo", + "info": "Il punteggio massimo è il punteggio mediano più alto per l'oggetto tracciato, quindi potrebbe differire dal punteggio mostrato nella miniatura del risultato della ricerca." + }, + "recognizedLicensePlate": "Targa riconosciuta", + "estimatedSpeed": "Velocità stimata", + "objects": "Oggetti", + "camera": "Telecamera", + "button": { + "findSimilar": "Trova simili", + "regenerate": { + "title": "Rigenera", + "label": "Rigenera la descrizione dell'oggetto tracciato" + } + }, + "expandRegenerationMenu": "Espandi il menu di rigenerazione", + "regenerateFromThumbnails": "Rigenera dalle miniature", + "tips": { + "descriptionSaved": "Descrizione salvata correttamente", + "saveDescriptionFailed": "Impossibile aggiornare la descrizione: {{errorMessage}}" + } + }, + "objectLifecycle": { + "annotationSettings": { + "offset": { + "tips": "SUGGERIMENTO: immagina un filmato evento con una persona che cammina da sinistra verso destra. Se il riquadro di delimitazione della cronologia dell'evento si trova costantemente a sinistra della persona, il valore dovrebbe essere diminuito. Analogamente, se una persona cammina da sinistra verso destra e il riquadro di delimitazione si trova costantemente davanti alla persona, il valore dovrebbe essere aumentato.", + "desc": "Questi dati provengono dal flusso di rilevamento della telecamera, ma vengono sovrapposti alle immagini del flusso di registrazione. È improbabile che i due flussi siano perfettamente sincronizzati. Di conseguenza, il riquadro di delimitazione e il filmato non saranno perfettamente allineati. Tuttavia, è possibile utilizzare il campo annotation_offset per correggere questo problema.", + "label": "Compensazione di annotazione", + "documentation": "Leggi la documentazione ", + "millisecondsToOffset": "Millisecondi per compensare il rilevamento delle annotazioni. Predefinito: 0" + }, + "showAllZones": { + "title": "Mostra tutte le zone", + "desc": "Mostra sempre le zone nei fotogrammi in cui gli oggetti sono entrati in una zona." + }, + "title": "Impostazioni di annotazione" + }, + "lifecycleItemDesc": { + "heard": "{{label}} sentito", + "attribute": { + "faceOrLicense_plate": "{{attribute}} rilevato per {{label}}", + "other": "{{label}} riconosciuto come {{attribute}}" + }, + "gone": "{{label}} lasciato", + "external": "{{label}} rilevato", + "visible": "{{label}} rilevato", + "entered_zone": "{{label}} è entrato in {{zones}}", + "active": "{{label}} è diventato attivo", + "stationary": "{{label}} è diventato stazionario", + "header": { + "ratio": "Rapporto", + "area": "Area", + "zones": "Zone" + } + }, + "title": "Ciclo di vita dell'oggetto", + "createObjectMask": "Crea maschera oggetto", + "noImageFound": "Nessuna immagine trovata per questo orario.", + "adjustAnnotationSettings": "Regola le impostazioni di annotazione", + "scrollViewTips": "Scorri per visualizzare i momenti più significativi del ciclo di vita di questo oggetto.", + "autoTrackingTips": "Le posizioni dei riquadri di delimitazione non saranno precise per le telecamere con tracciamento automatico.", + "carousel": { + "previous": "Diapositiva precedente", + "next": "Diapositiva successiva" + } + }, + "type": { + "snapshot": "istantanea", + "object_lifecycle": "ciclo di vita dell'oggetto", + "details": "dettagli", + "video": "video" + }, + "itemMenu": { + "downloadSnapshot": { + "label": "Scarica istantanea", + "aria": "Scarica istantanea" + }, + "viewInHistory": { + "label": "Visualizza in Storico", + "aria": "Visualizza in Storico" + }, + "deleteTrackedObject": { + "label": "Elimina questo oggetto tracciato" + }, + "downloadVideo": { + "label": "Scarica video", + "aria": "Scarica video" + }, + "viewObjectLifecycle": { + "label": "Visualizza il ciclo di vita dell'oggetto", + "aria": "Mostra il ciclo di vita dell'oggetto" + }, + "findSimilar": { + "label": "Trova simili", + "aria": "Trova oggetti tracciati simili" + }, + "submitToPlus": { + "label": "Invia a Frigate+", + "aria": "Invia a Frigate Plus" + } + }, + "dialog": { + "confirmDelete": { + "desc": "L'eliminazione di questo oggetto tracciato rimuove l'istantanea, eventuali incorporamenti salvati e tutte le voci associate al ciclo di vita dell'oggetto. Il filmato registrato di questo oggetto tracciato nella vista Storico NON verrà eliminato.

    Vuoi davvero procedere?", + "title": "Conferma eliminazione" + } + }, + "trackedObjectDetails": "Dettagli dell'oggetto tracciato", + "searchResult": { + "deleteTrackedObject": { + "toast": { + "error": "Impossibile eliminare l'oggetto tracciato: {{errorMessage}}", + "success": "Oggetto tracciato eliminato correttamente." + } + } + }, + "trackedObjectsCount_one": "{{count}} oggetto tracciato ", + "trackedObjectsCount_many": "{{count}} oggetti tracciati ", + "trackedObjectsCount_other": "{{count}} oggetti tracciati ", + "fetchingTrackedObjectsFailed": "Errore durante il recupero degli oggetti tracciati: {{errorMessage}}", + "noTrackedObjects": "Nessun oggetto tracciato trovato" +} diff --git a/web/public/locales/it/views/exports.json b/web/public/locales/it/views/exports.json new file mode 100644 index 000000000..0c42816ef --- /dev/null +++ b/web/public/locales/it/views/exports.json @@ -0,0 +1,17 @@ +{ + "documentTitle": "Esporta - Frigate", + "search": "Cerca", + "noExports": "Nessuna esportazione trovata", + "deleteExport": "Elimina esportazione", + "deleteExport.desc": "Sei sicuro di voler eliminare {{exportName}}?", + "editExport": { + "desc": "Inserisci un nuovo nome per questa esportazione.", + "title": "Rinomina esportazione", + "saveExport": "Salva esportazione" + }, + "toast": { + "error": { + "renameExportFailed": "Impossibile rinominare l'esportazione: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/it/views/faceLibrary.json b/web/public/locales/it/views/faceLibrary.json new file mode 100644 index 000000000..51cf4508b --- /dev/null +++ b/web/public/locales/it/views/faceLibrary.json @@ -0,0 +1,86 @@ +{ + "selectItem": "Seleziona {{item}}", + "description": { + "addFace": "Procedura per aggiungere una nuova raccolta alla Libreria dei Volti.", + "placeholder": "Inserisci un nome per questa raccolta" + }, + "details": { + "confidence": "Fiducia", + "person": "Persona", + "face": "Dettagli del volto", + "faceDesc": "Dettagli del volto e dell'oggetto associato", + "timestamp": "Orario" + }, + "train": { + "title": "Addestra", + "aria": "Seleziona addestramento" + }, + "button": { + "addFace": "Aggiungi volto", + "deleteFaceAttempts": "Elimina tentativi di riconoscimento facciale", + "uploadImage": "Carica immagine", + "reprocessFace": "Rielabora il volto", + "deleteFace": "Elimina volto", + "renameFace": "Rinomina volto" + }, + "trainFace": "Addestra il volto", + "toast": { + "success": { + "deletedName_one": "{{count}} volto è stato eliminato con successo.", + "deletedName_many": "{{count}} volti sono stati eliminati con successo.", + "deletedName_other": "{{count}} volti sono stati eliminati con successo.", + "trainedFace": "Volto addestrato con successo.", + "deletedFace_one": "Eliminato con successo {{count}} volto.", + "deletedFace_many": "Eliminati con successo {{count}} volti.", + "deletedFace_other": "Eliminati con successo {{count}} volti.", + "updatedFaceScore": "Punteggio del volto aggiornato con successo.", + "uploadedImage": "Immagine caricata correttamente.", + "addFaceLibrary": "{{name}} è stato aggiunto con successo alla Libreria dei Volti!", + "renamedFace": "Rinominato correttamente il volto in {{name}}" + }, + "error": { + "addFaceLibraryFailed": "Impossibile impostare il nome del volto: {{errorMessage}}", + "uploadingImageFailed": "Impossibile caricare l'immagine: {{errorMessage}}", + "deleteFaceFailed": "Impossibile eliminare: {{errorMessage}}", + "trainFailed": "Impossibile addestrare: {{errorMessage}}", + "updateFaceScoreFailed": "Impossibile aggiornare il punteggio del volto: {{errorMessage}}", + "deleteNameFailed": "Impossibile eliminare il nome: {{errorMessage}}", + "renameFaceFailed": "Impossibile rinominare il volto: {{errorMessage}}" + } + }, + "imageEntry": { + "dropActive": "Rilascia l'immagine qui…", + "dropInstructions": "Trascina e rilascia un'immagine qui oppure fai clic per selezionarla", + "maxSize": "Dimensione massima: {{size}} MB", + "validation": { + "selectImage": "Seleziona un file immagine." + } + }, + "createFaceLibrary": { + "title": "Crea raccolta", + "nextSteps": "Per costruire una base solida:
  • Usa la scheda Addestra per selezionare e addestrare le immagini per ogni persona rilevata.
  • Concentrati sulle immagini dritte per ottenere risultati migliori; evita di addestrare immagini che catturano i volti da un'angolazione.
  • ", + "desc": "Crea una nuova raccolta", + "new": "Crea nuovo volto" + }, + "readTheDocs": "Leggi la documentazione", + "selectFace": "Seleziona volto", + "documentTitle": "Libreria dei Volti - Frigate", + "uploadFaceImage": { + "desc": "Carica un'immagine per scansionare i volti e includerla in {{pageToggle}}", + "title": "Carica l'immagine del volto" + }, + "deleteFaceLibrary": { + "title": "Elimina nome", + "desc": "Vuoi davvero eliminare la raccolta {{name}}? Questa operazione eliminerà definitivamente tutti i volti associati." + }, + "trainFaceAs": "Addestra il volto come:", + "steps": { + "faceName": "Inserisci il nome del volto", + "nextSteps": "Prossimi passi", + "uploadFace": "Carica l'immagine del volto" + }, + "renameFace": { + "title": "Rinomina volto", + "desc": "Inserisci un nuovo nome per {{name}}" + } +} diff --git a/web/public/locales/it/views/live.json b/web/public/locales/it/views/live.json new file mode 100644 index 000000000..b8a44ae27 --- /dev/null +++ b/web/public/locales/it/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "Dal vivo - Frigate", + "documentTitle.withCamera": "{{camera}} - Dal vivo - Frigate", + "lowBandwidthMode": "Modalità a bassa larghezza di banda", + "twoWayTalk": { + "enable": "Abilita audio bidirezionale", + "disable": "Disabilita audio bidirezionale" + }, + "snapshots": { + "enable": "Abilita istantanee", + "disable": "Disabilita istantanee" + }, + "manualRecording": { + "recordDisabledTips": "Poiché la registrazione è disabilitata o limitata nella configurazione di questa telecamera, verrà salvata solo un'istantanea.", + "title": "Registrazione su richiesta", + "tips": "Avvia un evento manuale in base alle impostazioni di conservazione della registrazione di questa telecamera.", + "playInBackground": { + "label": "Riproduci in sottofondo", + "desc": "Abilita questa opzione per continuare la trasmissione quando il lettore è nascosto." + }, + "showStats": { + "label": "Mostra statistiche", + "desc": "Abilita questa opzione per visualizzare le statistiche della trasmissione come sovrapposizione sul flusso della telecamera." + }, + "debugView": "Vista correzioni", + "start": "Avvia la registrazione su richiesta", + "started": "Registrazione manuale su richiesta avviata.", + "failedToStart": "Impossibile avviare la registrazione manuale su richiesta.", + "end": "Termina la registrazione su richiesta", + "ended": "Registrazione manuale su richiesta terminata.", + "failedToEnd": "Impossibile terminare la registrazione manuale su richiesta." + }, + "cameraSettings": { + "snapshots": "Istantanee", + "autotracking": "Tracciamento automatico", + "title": "Impostazioni di {{camera}}", + "cameraEnabled": "Telecamera abilitata", + "objectDetection": "Rilevamento di oggetti", + "recording": "Registrazione", + "audioDetection": "Rilevamento audio" + }, + "history": { + "label": "Mostra filmati storici" + }, + "notifications": "Notifiche", + "streamingSettings": "Impostazioni di trasmissione", + "audio": "Audio", + "cameraAudio": { + "enable": "Abilita audio della telecamera", + "disable": "Disabilita audio della telecamera" + }, + "ptz": { + "move": { + "clickMove": { + "enable": "Abilita clic per spostare", + "disable": "Disabilita il clic per spostare", + "label": "Fai clic nella cornice per centrare la telecamera" + }, + "left": { + "label": "Sposta la telecamera PTZ a sinistra" + }, + "up": { + "label": "Sposta la telecamera PTZ verso l'alto" + }, + "down": { + "label": "Sposta la telecamera PTZ verso il basso" + }, + "right": { + "label": "Sposta la telecamera PTZ a destra" + } + }, + "zoom": { + "in": { + "label": "Ingrandisci la telecamera PTZ" + }, + "out": { + "label": "Riduci la telecamera PTZ" + } + }, + "frame": { + "center": { + "label": "Fai clic nella cornice per centrare la telecamera PTZ" + } + }, + "presets": "Preimpostazioni della telecamera PTZ" + }, + "camera": { + "enable": "Abilita telecamera", + "disable": "Disabilita telecamera" + }, + "muteCameras": { + "enable": "Muta tutte le telecamere", + "disable": "Attiva audio di tutte le telecamere" + }, + "detect": { + "enable": "Abilita rilevamento", + "disable": "Disabilita rilevamento" + }, + "recording": { + "enable": "Abilita registrazione", + "disable": "Disabilita registrazione" + }, + "audioDetect": { + "enable": "Abilita rilevamento audio", + "disable": "Disabilita rilevamento audio" + }, + "autotracking": { + "enable": "Abilita il tracciamento automatico", + "disable": "Disabilita il tracciamento automatico" + }, + "streamStats": { + "enable": "Mostra statistiche di trasmissione", + "disable": "Nascondi statistiche di trasmissione" + }, + "suspend": { + "forTime": "Sospendi per: " + }, + "stream": { + "title": "Trasmissione", + "audio": { + "tips": { + "title": "L'audio deve essere trasmesso dalla tua telecamera e configurato in go2rtc per questa trasmissione.", + "documentation": "Leggi la documentazione " + }, + "unavailable": "L'audio non è disponibile per questo flusso", + "available": "L'audio è disponibile per questo flusso" + }, + "twoWayTalk": { + "tips": "Il dispositivo deve supportare la funzionalità e WebRTC deve essere configurato per la comunicazione bidirezionale.", + "tips.documentation": "Leggi la documentazione ", + "unavailable": "La comunicazione bidirezionale non è disponibile per questo flusso", + "available": "La comunicazione bidirezionale è disponibile per questo flusso" + }, + "playInBackground": { + "tips": "Abilita questa opzione per continuare la trasmissione quando il lettore è nascosto.", + "label": "Riproduci in sottofondo" + }, + "lowBandwidth": { + "tips": "La visualizzazione dal vivo è in modalità a bassa larghezza di banda a causa di errori di caricamento o di trasmissione.", + "resetStream": "Reimposta flusso" + } + }, + "effectiveRetainMode": { + "modes": { + "all": "Tutto", + "motion": "Movimento", + "active_objects": "Oggetti attivi" + }, + "notAllTips": "La configurazione di conservazione della registrazione di {{source}} è impostata su mode: {{effectiveRetainMode}}, quindi questa registrazione su richiesta conserverà solo i segmenti con {{effectiveRetainModeName}}." + }, + "editLayout": { + "label": "Modifica formato", + "group": { + "label": "Modifica gruppo telecamere" + }, + "exitEdit": "Esci dalla modifica" + } +} diff --git a/web/public/locales/it/views/recording.json b/web/public/locales/it/views/recording.json new file mode 100644 index 000000000..411070bba --- /dev/null +++ b/web/public/locales/it/views/recording.json @@ -0,0 +1,12 @@ +{ + "calendar": "Calendario", + "export": "Esporta", + "filter": "Filtro", + "filters": "Filtri", + "toast": { + "error": { + "noValidTimeSelected": "Nessun intervallo di tempo valido selezionato", + "endTimeMustAfterStartTime": "L'ora di fine deve essere successiva all'ora di inizio" + } + } +} diff --git a/web/public/locales/it/views/search.json b/web/public/locales/it/views/search.json new file mode 100644 index 000000000..873ef007c --- /dev/null +++ b/web/public/locales/it/views/search.json @@ -0,0 +1,72 @@ +{ + "search": "Cerca", + "savedSearches": "Ricerche salvate", + "searchFor": "Cerca {{inputValue}}", + "button": { + "clear": "Cancella ricerca", + "save": "Salva ricerca", + "delete": "Elimina la ricerca salvata", + "filterInformation": "Informazioni sul filtro", + "filterActive": "Filtri attivi" + }, + "filter": { + "label": { + "has_snapshot": "Contiene istantanea", + "cameras": "Telecamere", + "search_type": "Tipo di ricerca", + "has_clip": "Contiene video", + "before": "Prima", + "labels": "Etichette", + "min_score": "Punteggio minimo", + "zones": "Zone", + "max_score": "Punteggio massimo", + "min_speed": "Velocità minima", + "time_range": "Intervallo di tempo", + "after": "Dopo", + "max_speed": "Velocità massima", + "recognized_license_plate": "Targa riconosciuta", + "sub_labels": "Sottoetichette" + }, + "tips": { + "desc": { + "step3": "Puoi utilizzare più filtri aggiungendoli uno dopo l'altro, lasciando uno spazio in mezzo.", + "step5": "Il filtro intervallo di tempo utilizza il formato {{exampleTime}}.", + "exampleLabel": "Esempio:", + "step1": "Digita un nome chiave di filtro seguito da due punti (ad esempio, \"telecamere:\").", + "step2": "Seleziona un valore dai suggerimenti oppure digita il tuo valore.", + "step4": "I filtri data (prima: e dopo:) utilizzano il formato {{DateFormat}}.", + "step6": "Rimuovi i filtri cliccando sulla \"x\" accanto ad essi.", + "text": "I filtri ti aiutano a restringere i risultati della ricerca. Ecco come usarli nel campo di inserimento:" + }, + "title": "Come utilizzare i filtri di testo" + }, + "toast": { + "error": { + "minScoreMustBeLessOrEqualMaxScore": "Il 'punteggio minimo' deve essere minore o uguale del 'punteggio massimo'.", + "beforeDateBeLaterAfter": "La data 'prima' deve essere successiva alla data 'dopo'.", + "minSpeedMustBeLessOrEqualMaxSpeed": "La 'velocità minima' deve essere minore o uguale della 'velocità massima'.", + "afterDatebeEarlierBefore": "La data 'dopo' deve essere precedente alla data 'prima'.", + "maxScoreMustBeGreaterOrEqualMinScore": "Il 'punteggio massimo' deve essere maggiore o uguale del 'punteggio minimo'.", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "La 'velocità massima' deve essere maggiore o uguale della 'velocità minima'." + } + }, + "searchType": { + "thumbnail": "Miniatura", + "description": "Descrizione" + }, + "header": { + "noFilters": "Filtri", + "activeFilters": "Filtri attivi", + "currentFilterType": "Valori del filtro" + } + }, + "similaritySearch": { + "clear": "Cancella ricerca di somiglianza", + "title": "Ricerca di somiglianza", + "active": "Ricerca di somiglianza attiva" + }, + "placeholder": { + "search": "Ricerca…" + }, + "trackedObjectId": "ID oggetto tracciato" +} diff --git a/web/public/locales/it/views/settings.json b/web/public/locales/it/views/settings.json new file mode 100644 index 000000000..0600bbf20 --- /dev/null +++ b/web/public/locales/it/views/settings.json @@ -0,0 +1,599 @@ +{ + "documentTitle": { + "authentication": "Impostazioni di autenticazione - Frigate", + "default": "Impostazioni - Frigate", + "classification": "Impostazioni di classificazione - Frigate", + "camera": "Impostazioni telecamera - Frigate", + "masksAndZones": "Editor di maschere e zone - Frigate", + "motionTuner": "Regolatore di movimento - Frigate", + "object": "Correzioni - Frigate", + "general": "Impostazioni generali - Frigate", + "frigatePlus": "Impostazioni Frigate+ - Frigate", + "notifications": "Impostazioni di notifiche - Frigate" + }, + "frigatePlus": { + "snapshotConfig": { + "cleanCopyWarning": "Alcune telecamere hanno le istantanee abilitate ma la copia pulita disabilitata. È necessario abilitare clean_copy nella configurazione delle istantanee per poter inviare le immagini da queste telecamere a Frigate+.", + "table": { + "snapshots": "Istantanee", + "camera": "Telecamera", + "cleanCopySnapshots": "clean_copy Istantanee" + }, + "desc": "Per inviare a Frigate+ è necessario che nella configurazione siano abilitate sia le istantanee che le istantanee clean_copy.", + "documentation": "Leggi la documentazione", + "title": "Configurazione istantanee" + }, + "apiKey": { + "title": "Chiave API Frigate+", + "validated": "La chiave API Frigate+ è stata rilevata e convalidata", + "notValidated": "La chiave API Frigate+ non è stata rilevata o non è stata convalidata", + "desc": "La chiave API Frigate+ consente l'integrazione con il servizio Frigate+.", + "plusLink": "Scopri di più su Frigate+" + }, + "modelInfo": { + "trainDate": "Data addestramento", + "baseModel": "Modello base", + "cameras": "Telecamere", + "plusModelType": { + "userModel": "Messa a punto fine", + "baseModel": "Modello base" + }, + "availableModels": "Modelli disponibili", + "loadingAvailableModels": "Caricamento dei modelli disponibili…", + "supportedDetectors": "Rilevatori supportati", + "error": "Impossibile caricare le informazioni sul modello", + "modelType": "Tipo di modello", + "modelSelect": "Qui puoi selezionare i modelli disponibili su Frigate+. Nota: puoi selezionare solo i modelli compatibili con la configurazione attuale del tuo rilevatore.", + "title": "Informazioni sul modello", + "loading": "Caricamento informazioni sul modello…" + }, + "toast": { + "error": "Impossibile salvare le modifiche alla configurazione: {{errorMessage}}", + "success": "Le impostazioni di Frigate+ sono state salvate. Riavvia Frigate per applicare le modifiche." + }, + "title": "Impostazioni Frigate+", + "restart_required": "Riavvio richiesto (modello Frigate+ modificato)" + }, + "debug": { + "timestamp": { + "desc": "Sovrapponi l'orario all'immagine", + "title": "Orario" + }, + "objectShapeFilterDrawing": { + "tips": "Abilita questa opzione per disegnare un rettangolo sull'immagine della telecamera per mostrarne l'area e il rapporto. Questi valori possono quindi essere utilizzati per impostare i parametri del filtro forma oggetto nella configurazione.", + "area": "Area", + "title": "Disegno del filtro della forma dell'oggetto", + "desc": "Disegna un rettangolo sull'immagine per visualizzare i dettagli dell'area e del rapporto", + "document": "Leggi la documentazione ", + "score": "Punteggio", + "ratio": "Rapporto" + }, + "detectorDesc": "Frigate utilizza i tuoi rilevatori ({{detectors}}) per rilevare oggetti nel flusso video della tua telecamera.", + "boundingBoxes": { + "colors": { + "info": "
  • All'avvio, a ciascuna etichetta dell'oggetto verranno assegnati colori diversi
  • Una linea sottile blu scuro indica che l'oggetto non è stato rilevato in questo momento
  • Una linea sottile grigia indica che l'oggetto è stato rilevato come stazionario
  • Una linea spessa indica che l'oggetto è oggetto di tracciamento automatico (se abilitato)
  • ", + "label": "Colori del riquadro di delimitazione dell'oggetto" + }, + "desc": "Mostra i riquadri di delimitazione attorno agli oggetti tracciati", + "title": "Riquadri di delimitazione" + }, + "regions": { + "tips": "

    Riquadri di regione


    I riquadri di colore verde brillante verranno sovrapposte alle aree di interesse nel fotogramma che viene inviato al rilevatore di oggetti.

    ", + "title": "Regioni", + "desc": "Mostra un riquadro della regione di interesse inviata al rilevatore di oggetti" + }, + "noObjects": "Nessun oggetto", + "title": "Correzioni", + "desc": "La vista di correzione mostra una vista in tempo reale degli oggetti tracciati e delle relative statistiche. L'elenco degli oggetti mostra un riepilogo ritardato degli oggetti rilevati.", + "debugging": "Correzioni", + "objectList": "Elenco degli oggetti", + "mask": { + "desc": "Mostra i poligoni della maschera di movimento", + "title": "Maschere di movimento" + }, + "motion": { + "title": "Riquadri di movimento", + "desc": "Mostra i riquadri attorno alle aree in cui viene rilevato il movimento", + "tips": "

    Riquadri di movimento


    I riquadri rossi verranno sovrapposti alle aree dell'inquadratura in cui viene attualmente rilevato un movimento

    " + }, + "zones": { + "title": "Zone", + "desc": "Mostra un contorno di tutte le zone definite" + } + }, + "masksAndZones": { + "motionMasks": { + "context": { + "title": "Le maschere di movimento vengono utilizzate per impedire che tipi di movimento indesiderati attivino il rilevamento (ad esempio: rami di alberi, orari di telecamere). Le maschere di movimento dovrebbero essere utilizzate con molta parsimonia: un uso eccessivo renderebbe più difficile il tracciamento degli oggetti.", + "documentation": "Leggi la documentazione" + }, + "desc": { + "title": "Le maschere di movimento vengono utilizzate per impedire che movimenti indesiderati attivino il rilevamento. Un mascheramento eccessivo renderà più difficile il tracciamento degli oggetti.", + "documentation": "Documentazione" + }, + "label": "Maschera di movimento", + "edit": "Modifica maschera di movimento", + "clickDrawPolygon": "Fai clic per disegnare un poligono sull'immagine.", + "polygonAreaTooLarge": { + "title": "La maschera di movimento copre il {{polygonArea}}% dell'inquadratura. Si sconsiglia di utilizzare maschere di movimento di grandi dimensioni.", + "documentation": "Leggi la documentazione", + "tips": "Le maschere di movimento non impediscono il rilevamento degli oggetti. È consigliabile utilizzare una zona specifica." + }, + "point_one": "{{count}} punto", + "point_many": "{{count}} punti", + "point_other": "{{count}} punti", + "documentTitle": "Modifica maschera movimento - Frigate", + "add": "Nuova maschera di movimento", + "toast": { + "success": { + "title": "{{polygonName}} è stato salvato. Riavvia Frigate per applicare le modifiche.", + "noName": "La maschera di movimento è stata salvata. Riavvia Frigate per applicare le modifiche." + } + } + }, + "form": { + "zoneName": { + "error": { + "hasIllegalCharacter": "Il nome della zona contiene caratteri non validi.", + "mustNotBeSameWithCamera": "Il nome della zona non deve essere uguale al nome della telecamera.", + "mustBeAtLeastTwoCharacters": "Il nome della zona deve essere composto da almeno 2 caratteri.", + "alreadyExists": "Per questa telecamera esiste già una zona con questo nome.", + "mustNotContainPeriod": "Il nome della zona non deve contenere punti." + } + }, + "distance": { + "error": { + "text": "La distanza deve essere maggiore o uguale a 0.1.", + "mustBeFilled": "Per utilizzare la stima della velocità è necessario compilare tutti i campi relativi alla distanza." + } + }, + "polygonDrawing": { + "delete": { + "title": "Conferma eliminazione", + "desc": "Sei sicuro di voler eliminare {{type}} {{name}}?", + "success": "{{name}} è stato eliminato." + }, + "removeLastPoint": "Rimuovi l'ultimo punto", + "reset": { + "label": "Cancella tutti i punti" + }, + "snapPoints": { + "true": "Aggancia punti", + "false": "Non agganciare punti" + }, + "error": { + "mustBeFinished": "Prima di salvare, è necessario terminare il disegno del poligono." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "L'inerzia deve essere superiore a 0." + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "Il tempo di permanenza deve essere maggiore o uguale a 0." + } + } + }, + "filter": { + "all": "Tutte le maschere e zone" + }, + "toast": { + "success": { + "copyCoordinates": "Coordinate per {{polyName}} copiate negli appunti." + }, + "error": { + "copyCoordinatesFailed": "Impossibile copiare le coordinate negli appunti." + } + }, + "zones": { + "speedEstimation": { + "desc": "Abilita la stima della velocità per gli oggetti in questa zona. La zona deve avere esattamente 4 punti.", + "title": "Stima della velocità" + }, + "add": "Aggiungi zona", + "speedThreshold": { + "desc": "Specifica una velocità minima affinché gli oggetti vengano presi in considerazione in questa zona.", + "toast": { + "error": { + "pointLengthError": "La stima della velocità è stata disattivata per questa zona. Le zone con stima della velocità devono avere esattamente 4 punti.", + "loiteringTimeError": "Le zone con tempi di permanenza superiori a 0 non devono essere utilizzate per la stima della velocità." + } + }, + "title": "Soglia di velocità ({{unit}})" + }, + "desc": { + "title": "Le zone consentono di definire un'area specifica dell'inquadratura, in modo da poter determinare se un oggetto si trova o meno all'interno di un'area particolare.", + "documentation": "Documentazione" + }, + "edit": "Modifica zona", + "name": { + "inputPlaceHolder": "Inserisci un nome…", + "title": "Nome", + "tips": "Il nome deve essere composto da almeno 2 caratteri e non deve essere il nome di una telecamera o di un'altra zona." + }, + "clickDrawPolygon": "Fai clic per disegnare un poligono sull'immagine.", + "point_one": "{{count}} punto", + "point_many": "{{count}} punti", + "point_other": "{{count}} punti", + "label": "Zone", + "documentTitle": "Modifica zona - Frigate", + "inertia": { + "title": "Inerzia", + "desc": "Specifica quanti fotogrammi deve avere un oggetto in una zona prima di essere considerato nella zona. Predefinito: 3" + }, + "loiteringTime": { + "title": "Tempo di permanenza", + "desc": "Imposta un intervallo di tempo minimo in secondi per cui l'oggetto deve trovarsi nella zona affinché venga attivato. Predefinito: 0" + }, + "objects": { + "title": "Oggetti", + "desc": "Elenco degli oggetti che si applicano a questa zona." + }, + "allObjects": "Tutti gli oggetti", + "toast": { + "success": "La zona ({{zoneName}}) è stata salvata. Riavvia Frigate per applicare le modifiche." + } + }, + "objectMasks": { + "desc": { + "title": "Le maschere di filtro degli oggetti vengono utilizzate per filtrare i falsi positivi per un determinato tipo di oggetto in base alla posizione.", + "documentation": "Documentazione" + }, + "context": "Le maschere di filtro degli oggetti vengono utilizzate per filtrare i falsi positivi per un determinato tipo di oggetto in base alla posizione.", + "point_one": "{{count}} punto", + "point_many": "{{count}} punti", + "point_other": "{{count}} punti", + "add": "Aggiungi maschera oggetti", + "clickDrawPolygon": "Fai clic per disegnare un poligono sull'immagine.", + "edit": "Modifica maschera oggetti", + "objects": { + "desc": "Il tipo di oggetto che si applica a questa maschera di oggetti.", + "title": "Oggetti", + "allObjectTypes": "Tutti i tipi di oggetti" + }, + "toast": { + "success": { + "noName": "La maschera oggetto è stata salvata. Riavvia Frigate per applicare le modifiche.", + "title": "{{polygonName}} è stato salvato. Riavvia Frigate per applicare le modifiche." + } + }, + "label": "Maschere di oggetti", + "documentTitle": "Modifica maschera oggetti - Frigate" + }, + "restart_required": "Riavvio richiesto (maschere/zone modificate)" + }, + "cameraSetting": { + "camera": "Telecamera", + "noCamera": "Nessuna telecamera" + }, + "camera": { + "reviewClassification": { + "limitDetections": "Limita i rilevamenti a zone specifiche", + "objectDetectionsTips": "Tutti gli oggetti {{detectionsLabels}} non categorizzati su {{cameraName}} verranno mostrati come Rilevamenti, indipendentemente dalla zona in cui si trovano.", + "zoneObjectDetectionsTips": { + "text": "Tutti gli oggetti {{detectionsLabels}} non categorizzati in {{zone}} su {{cameraName}} verranno mostrati come Rilevamenti.", + "notSelectDetections": "Tutti gli oggetti {{detectionsLabels}} rilevati in {{zone}} su {{cameraName}} non classificati come Avvisi verranno mostrati come Rilevamenti, indipendentemente dalla zona in cui si trovano.", + "regardlessOfZoneObjectDetectionsTips": "Tutti gli oggetti {{detectionsLabels}} non categorizzati su {{cameraName}} verranno mostrati come Rilevamenti, indipendentemente dalla zona in cui si trovano." + }, + "title": "Classificazione della revisione", + "desc": "Frigate categorizza gli elementi di revisione come Avvisi e Rilevamenti. Per impostazione predefinita, tutti gli oggetti persona e auto sono considerati Avvisi. Puoi perfezionare la categorizzazione degli elementi di revisione configurando le zone desiderate.", + "objectAlertsTips": "Tutti gli oggetti {{alertsLabels}} su {{cameraName}} verranno mostrati come Avvisi.", + "toast": { + "success": "La configurazione della classificazione di revisione è stata salvata. Riavvia Frigate per applicare le modifiche." + }, + "readTheDocumentation": "Leggi la documentazione", + "noDefinedZones": "Per questa telecamera non sono definite zone.", + "zoneObjectAlertsTips": "Tutti gli oggetti {{alertsLabels}} rilevati in {{zone}} su {{cameraName}} verranno visualizzati come Avvisi.", + "selectAlertsZones": "Seleziona le zone per gli Avvisi", + "selectDetectionsZones": "Seleziona le zone per i Rilevamenti" + }, + "streams": { + "desc": "La disattivazione completa di una telecamera interrompe l'elaborazione dei flussi da parte di Frigate. Rilevamento, registrazione e correzioni non saranno disponibili.
    Nota: questa operazione non disabilita le ritrasmissioni di go2rtc.", + "title": "Flussi" + }, + "title": "Impostazioni telecamera", + "review": { + "title": "Rivedi", + "desc": "Abilita/disabilita avvisi e rilevamenti per questa telecamera. Se disabilitati, non verranno generati nuovi elementi di revisione.", + "alerts": "Avvisi ", + "detections": "Rilevamenti " + } + }, + "menu": { + "motionTuner": "Regolatore di movimento", + "notifications": "Notifiche", + "ui": "Interfaccia utente", + "classification": "Classificazione", + "cameras": "Impostazioni telecamera", + "masksAndZones": "Maschere / Zone", + "debug": "Correzioni", + "users": "Utenti", + "frigateplus": "Frigate+" + }, + "users": { + "dialog": { + "changeRole": { + "roleInfo": { + "viewerDesc": "Limitato solo alle schermate dal vivo, alle revisioni, alle esplorazioni e alle esportazioni.", + "intro": "Seleziona il ruolo appropriato per questo utente:", + "admin": "Amministratore", + "adminDesc": "Accesso completo a tutte le funzionalità.", + "viewer": "Spettatore" + }, + "title": "Cambia ruolo utente", + "desc": "Aggiorna i permessi per {{username}}" + }, + "deleteUser": { + "warn": "Sei sicuro di voler eliminare {{username}}?", + "title": "Elimina utente", + "desc": "Questa azione non può essere annullata. L'account utente verrà eliminato definitivamente e tutti i dati associati verranno rimossi." + }, + "form": { + "user": { + "placeholder": "Inserisci il nome utente", + "title": "Nome utente", + "desc": "Sono consentiti solo lettere, numeri, punti e caratteri di sottolineatura." + }, + "password": { + "confirm": { + "title": "Conferma password", + "placeholder": "Conferma password" + }, + "strength": { + "title": "Forza della password: ", + "weak": "Debole", + "medium": "Media", + "strong": "Forte", + "veryStrong": "Molto forte" + }, + "title": "Password", + "placeholder": "Inserisci la password", + "match": "Le password corrispondono", + "notMatch": "Le password non corrispondono" + }, + "newPassword": { + "title": "Nuova password", + "placeholder": "Inserisci la nuova password", + "confirm": { + "placeholder": "Reinserisci la nuova password" + } + }, + "usernameIsRequired": "Il nome utente è obbligatorio" + }, + "createUser": { + "desc": "Aggiungi un nuovo account utente e specifica un ruolo per l'accesso alle aree dell'interfaccia utente di Frigate.", + "title": "Crea nuovo utente", + "usernameOnlyInclude": "Il nome utente può contenere solo lettere, numeri, . o _" + }, + "passwordSetting": { + "updatePassword": "Aggiorna la password per {{username}}", + "setPassword": "Imposta password", + "desc": "Crea una password complessa per proteggere questo account." + } + }, + "table": { + "password": "Password", + "username": "Nome utente", + "actions": "Azioni", + "role": "Ruolo", + "noUsers": "Nessun utente trovato.", + "changeRole": "Cambia ruolo utente", + "deleteUser": "Elimina utente" + }, + "toast": { + "error": { + "roleUpdateFailed": "Impossibile aggiornare il ruolo: {{errorMessage}}", + "setPasswordFailed": "Impossibile salvare la password: {{errorMessage}}", + "createUserFailed": "Impossibile creare l'utente: {{errorMessage}}", + "deleteUserFailed": "Impossibile eliminare l'utente: {{errorMessage}}" + }, + "success": { + "createUser": "Utente {{user}} creato con successo", + "updatePassword": "Password aggiornata con successo.", + "deleteUser": "Utente {{user}} eliminato con successo", + "roleUpdated": "Ruolo aggiornato per {{user}}" + } + }, + "title": "Utenti", + "management": { + "title": "Gestione utenti", + "desc": "Gestisci gli account utente di questa istanza Frigate." + }, + "addUser": "Aggiungi utente", + "updatePassword": "Aggiorna password" + }, + "general": { + "liveDashboard": { + "automaticLiveView": { + "desc": "Passa automaticamente alla visualizzazione dal vivodi una telecamera quando viene rilevata attività. Disattivando questa opzione, le immagini statiche della telecamera nella schermata dal vivo verranno aggiornate solo una volta al minuto.", + "label": "Visualizzazione automatica dal vivo" + }, + "playAlertVideos": { + "label": "Riproduci video di avvisi", + "desc": "Per impostazione predefinita, gli avvisi recenti nella schermata dal vivo vengono riprodotti come brevi video in ciclo. Disattiva questa opzione per visualizzare solo un'immagine statica degli avvisi recenti su questo dispositivo/browser." + }, + "title": "Schermata dal vivo" + }, + "title": "Impostazioni generali", + "storedLayouts": { + "title": "Formati memorizzati", + "desc": "La disposizione delle telecamere in un gruppo può essere trascinata/ridimensionata. Le posizioni vengono salvate nella memoria locale del browser.", + "clearAll": "Cancella tutti i formati" + }, + "cameraGroupStreaming": { + "title": "Impostazioni di trasmissione del gruppo di telecamere", + "desc": "Le impostazioni di trasmissione per ciascun gruppo di telecamere vengono salvate nella memoria locale del browser.", + "clearAll": "Cancella tutte le impostazioni di trasmissione" + }, + "recordingsViewer": { + "title": "Visualizzatore di registrazioni", + "defaultPlaybackRate": { + "label": "Velocità di riproduzione predefinita", + "desc": "Velocità di riproduzione predefinita per la riproduzione delle registrazioni." + } + }, + "calendar": { + "title": "Calendario", + "firstWeekday": { + "label": "Primo giorno della settimana", + "desc": "Giorno in cui iniziano le settimane del calendario di revisione.", + "sunday": "Domenica", + "monday": "Lunedi" + } + }, + "toast": { + "success": { + "clearStoredLayout": "Formato memorizzato cancellato per {{cameraName}}", + "clearStreamingSettings": "Cancellate le impostazioni di trasmissione per tutti i gruppi di telecamere." + }, + "error": { + "clearStoredLayoutFailed": "Impossibile cancellare il formato memorizzato: {{errorMessage}}", + "clearStreamingSettingsFailed": "Impossibile cancellare le impostazioni di trasmissione: {{errorMessage}}" + } + } + }, + "classification": { + "licensePlateRecognition": { + "desc": "Frigate può riconoscere le targhe dei veicoli e aggiungere automaticamente i caratteri rilevati al campo recognized_license_plate o un nome noto come sub_label agli oggetti di tipo \"automobile\". Un caso d'uso comune potrebbe essere la lettura delle targhe delle auto che entrano in un vialetto o che transitano lungo una strada.", + "title": "Riconoscimento della targa", + "readTheDocumentation": "Leggi la documentazione" + }, + "title": "Impostazioni di classificazione", + "semanticSearch": { + "title": "Ricerca semantica", + "desc": "La ricerca semantica in Frigate consente di trovare gli oggetti tracciati all'interno degli elementi della recensione utilizzando l'immagine stessa, una descrizione testuale definita dall'utente o una generata automaticamente.", + "readTheDocumentation": "Leggi la documentazione", + "modelSize": { + "large": { + "title": "grande", + "desc": "L'utilizzo di large sfrutta il modello Jina completo e, se applicabile, verrà eseguito automaticamente sulla GPU." + }, + "small": { + "desc": "L'utilizzo di small sfrutta una versione quantizzata del modello che utilizza meno RAM ed è più veloce sulla CPU con una differenza davvero trascurabile nella qualità di incorporamento.", + "title": "piccolo" + }, + "label": "Dimensioni del modello", + "desc": "Dimensioni del modello utilizzato per gli incorporamenti della ricerca semantica." + }, + "reindexNow": { + "label": "Reindicizza ora", + "desc": "La reindicizzazione rigenererà gli incorporamenti per tutti gli oggetti tracciati. Questo processo viene eseguito in sottofondo e potrebbe impegnare al massimo la CPU e richiedere un tempo considerevole, a seconda del numero di oggetti tracciati.", + "confirmTitle": "Conferma reindicizzazione", + "confirmDesc": "Vuoi davvero reindicizzare tutti gli incorporamenti di oggetti tracciati? Questo processo verrà eseguito in sottofondo, ma potrebbe impegnare al massimo la CPU e richiedere molto tempo. Puoi monitorare l'avanzamento nella pagina Esplora.", + "confirmButton": "Reindicizza", + "success": "Reindicizzazione avviata con successo.", + "alreadyInProgress": "La reindicizzazione è già in corso.", + "error": "Impossibile avviare la reindicizzazione: {{errorMessage}}" + } + }, + "faceRecognition": { + "title": "Riconoscimento facciale", + "desc": "Il riconoscimento facciale consente di assegnare un nome alle persone e, quando il volto viene riconosciuto, Frigate assegnerà il nome della persona come sottoetichetta. Queste informazioni sono incluse nell'interfaccia utente, nei filtri e nelle notifiche.", + "modelSize": { + "desc": "Dimensioni del modello utilizzato per il riconoscimento facciale.", + "small": { + "title": "piccolo", + "desc": "L'utilizzo di small sfrutta un modello di incorporamento di volti FaceNet che funziona in modo efficiente sulla maggior parte delle CPU." + }, + "large": { + "title": "grande", + "desc": "L'utilizzo di large sfrutta un modello di incorporamento di volti ArcFace e verrà eseguito automaticamente sulla GPU, se applicabile." + }, + "label": "Dimensioni del modello" + }, + "readTheDocumentation": "Leggi la documentazione" + }, + "toast": { + "error": "Impossibile salvare le modifiche alla configurazione: {{errorMessage}}", + "success": "Le impostazioni di classificazione sono state salvate. Riavvia Frigate per applicare le modifiche." + }, + "birdClassification": { + "desc": "La classificazione degli uccelli identifica gli uccelli noti utilizzando un modello Tensorflow quantizzato. Quando un uccello noto viene riconosciuto, il suo nome comune viene aggiunto come sub_label. Queste informazioni sono incluse nell'interfaccia utente, nei filtri e nelle notifiche.", + "title": "Classificazione degli uccelli" + }, + "restart_required": "Riavvio richiesto (impostazioni di classificazione modificate)" + }, + "dialog": { + "unsavedChanges": { + "title": "Ci sono modifiche non salvate.", + "desc": "Vuoi salvare le modifiche prima di continuare?" + } + }, + "motionDetectionTuner": { + "improveContrast": { + "title": "Migliora il contrasto", + "desc": "Migliora il contrasto nelle scene più scure. Predefinito: ATTIVO" + }, + "desc": { + "title": "Frigate utilizza il rilevamento del movimento come primo controllo per verificare se nell'inquadratura si verifica qualcosa che valga la pena verificare tramite il rilevamento degli oggetti.", + "documentation": "Leggi la Guida alla Regolazione del Movimento" + }, + "title": "Regolatore di rilevamento del movimento", + "contourArea": { + "title": "Area di contorno", + "desc": "Il valore dell'area di contorno viene utilizzato per decidere quali gruppi di pixel modificati possono essere considerati movimento. Predefinito: 10" + }, + "Threshold": { + "title": "Soglia", + "desc": "Il valore di soglia determina l'entità della variazione di luminanza di un pixel necessaria per essere considerato movimento. Predefinito: 30" + }, + "toast": { + "success": "Le impostazioni di movimento sono state salvate." + } + }, + "notification": { + "email": { + "placeholder": "es. esempio@email.com", + "desc": "È richiesto un indirizzo email valido che verrà utilizzato per avvisarti in caso di problemi con il servizio push.", + "title": "E-mail" + }, + "cameras": { + "title": "Telecamere", + "noCameras": "Nessuna telecamera disponibile", + "desc": "Seleziona per quali telecamere abilitare le notifiche." + }, + "unregisterDevice": "Annulla la registrazione di questo dispositivo", + "sendTestNotification": "Invia una notifica di prova", + "active": "Notifiche attive", + "suspended": "Notifiche sospese {{time}}", + "suspendTime": { + "5minutes": "Sospendi per 5 minuti", + "30minutes": "Sospendi per 30 minuti", + "10minutes": "Sospendi per 10 minuti", + "1hour": "Sospendi per 1 ora", + "12hours": "Sospendi per 12 ore", + "24hours": "Sospendi per 24 ore", + "untilRestart": "Sospendi fino al riavvio", + "suspend": "Sospendi" + }, + "globalSettings": { + "desc": "Sospendi temporaneamente le notifiche per telecamere specifiche su tutti i dispositivi registrati.", + "title": "Impostazioni globali" + }, + "registerDevice": "Registra questo dispositivo", + "notificationUnavailable": { + "desc": "Le notifiche push web richiedono un contesto sicuro (https://...). Questa è una limitazione del browser. Accedi a Frigate in modo sicuro per utilizzare le notifiche.", + "documentation": "Leggi la documentazione", + "title": "Notifiche non disponibili" + }, + "deviceSpecific": "Impostazioni specifiche del dispositivo", + "toast": { + "success": { + "registered": "Registrazione per le notifiche completata con successo. È necessario riavviare Frigate prima di poter inviare qualsiasi notifica (inclusa una notifica di prova).", + "settingSaved": "Le impostazioni di notifica sono state salvate." + }, + "error": { + "registerFailed": "Impossibile salvare la registrazione della notifica." + } + }, + "title": "Notifiche", + "notificationSettings": { + "title": "Impostazioni notifiche", + "desc": "Frigate può inviare notifiche push in modo nativo al tuo dispositivo quando è in esecuzione nel browser o installato come PWA.", + "documentation": "Leggi la documentazione" + }, + "cancelSuspension": "Annulla sospensione" + } +} diff --git a/web/public/locales/it/views/system.json b/web/public/locales/it/views/system.json new file mode 100644 index 000000000..319165eba --- /dev/null +++ b/web/public/locales/it/views/system.json @@ -0,0 +1,179 @@ +{ + "documentTitle": { + "cameras": "Statistiche telecamere - Frigate", + "enrichments": "Statistiche arricchimento - Frigate", + "storage": "Statistiche archiviazione - Frigate", + "general": "Statistiche generali - Frigate", + "logs": { + "frigate": "Registri Frigate - Frigate", + "go2rtc": "Registri Go2RTC - Frigate", + "nginx": "Registri Nginx - Frigate" + } + }, + "logs": { + "type": { + "timestamp": "Orario", + "label": "Tipo", + "tag": "Etichetta", + "message": "Messaggio" + }, + "tips": "I registri vengono trasmessi dal server", + "toast": { + "error": { + "whileStreamingLogs": "Errore durante la trasmissione dei registri: {{errorMessage}}", + "fetchingLogsFailed": "Errore durante il recupero dei registri: {{errorMessage}}" + } + }, + "download": { + "label": "Scarica registri" + }, + "copy": { + "label": "Copia negli appunti", + "success": "Registri copiati negli appunti", + "error": "Impossibile copiare i registri negli appunti" + } + }, + "general": { + "hardwareInfo": { + "gpuInfo": { + "nvidiaSMIOutput": { + "cudaComputerCapability": "Capacità di elaborazione CUDA: {{cuda_compute}}", + "title": "Risultati Nvidia SMI", + "name": "Nome: {{name}}", + "driver": "Driver: {{driver}}", + "vbios": "Informazioni VBios: {{vbios}}" + }, + "vainfoOutput": { + "title": "Risultati Vainfo", + "returnCode": "Codice di ritorno: {{code}}", + "processOutput": "Risultati del processo:", + "processError": "Errore del processo:" + }, + "closeInfo": { + "label": "Chiudi informazioni GPU" + }, + "copyInfo": { + "label": "Copia informazioni GPU" + }, + "toast": { + "success": "Informazioni GPU copiate negli appunti" + } + }, + "title": "Informazioni hardware", + "gpuDecoder": "Decodificatore GPU", + "gpuEncoder": "Codificatore GPU", + "gpuUsage": "Utilizzo GPU", + "gpuMemory": "Memoria GPU", + "npuUsage": "Utilizzo NPU", + "npuMemory": "Memoria NPU" + }, + "detector": { + "inferenceSpeed": "Velocità inferenza rilevatore", + "title": "Rilevatori", + "cpuUsage": "Utilizzo CPU rilevatore", + "memoryUsage": "Utilizzo memoria rilevatore", + "temperature": "Temperatura del rilevatore" + }, + "title": "Generale", + "otherProcesses": { + "title": "Altri processi", + "processCpuUsage": "Utilizzo CPU processo", + "processMemoryUsage": "Utilizzo memoria processo" + } + }, + "enrichments": { + "embeddings": { + "face_embedding_speed": "Velocità incorporazione volti", + "plate_recognition_speed": "Velocità riconoscimento targhe", + "image_embedding_speed": "Velocità incorporazione immagini", + "text_embedding_speed": "Velocità incorporazione testo", + "face_recognition_speed": "Velocità di riconoscimento facciale", + "face_recognition": "Riconoscimento facciale", + "plate_recognition": "Riconoscimento delle targhe", + "yolov9_plate_detection_speed": "Velocità di rilevamento della targa con YOLOv9", + "yolov9_plate_detection": "Rilevamento della targa con YOLOv9", + "image_embedding": "Incorporamento di immagini", + "text_embedding": "Incorporamento di testo" + }, + "title": "Arricchimenti", + "infPerSecond": "Inferenze al secondo" + }, + "cameras": { + "info": { + "fetching": "Recupero dati della telecamera", + "streamDataFromFFPROBE": "I dati del flusso vengono ottenuti con ffprobe.", + "cameraProbeInfo": "Informazioni analisi telecamera {{camera}}", + "stream": "Flusso {{idx}}", + "video": "Video:", + "codec": "Codec:", + "resolution": "Risoluzione:", + "fps": "FPS:", + "unknown": "Sconosciuto", + "audio": "Audio:", + "error": "Errore: {{error}}", + "tips": { + "title": "Informazioni analisi telecamera" + } + }, + "title": "Telecamere", + "overview": "Sommario", + "framesAndDetections": "Fotogrammi / Rilevamenti", + "label": { + "camera": "telecamera", + "detect": "rileva", + "skipped": "saltato", + "ffmpeg": "FFmpeg", + "capture": "cattura", + "overallFramesPerSecond": "fotogrammi totali al secondo", + "overallDetectionsPerSecond": "rilevamenti totali al secondo", + "overallSkippedDetectionsPerSecond": "rilevamenti totali saltati al secondo", + "cameraCapture": "{{camName}} cattura", + "cameraDetect": "{{camName}} rileva", + "cameraFramesPerSecond": "{{camName}} fotogrammi al secondo", + "cameraDetectionsPerSecond": "{{camName}} rilevamenti al secondo", + "cameraSkippedDetectionsPerSecond": "{{camName}} rilevamenti saltati al secondo", + "cameraFfmpeg": "{{camName}} FFmpeg" + }, + "toast": { + "success": { + "copyToClipboard": "Dati di analisi copiati negli appunti." + }, + "error": { + "unableToProbeCamera": "Impossibile analizzare la telecamera: {{errorMessage}}" + } + } + }, + "stats": { + "detectHighCpuUsage": "{{camera}} ha un utilizzo elevato della CPU con il rilevamento ({{detectAvg}}%)", + "ffmpegHighCpuUsage": "{{camera}} ha un elevato utilizzo della CPU con FFmpeg ({{ffmpegAvg}}%)", + "healthy": "Il sistema è integro", + "reindexingEmbeddings": "Reindicizzazione degli incorporamenti (completata al {{processed}}%)", + "cameraIsOffline": "{{camera}} è disconnessa", + "detectIsSlow": "{{detect}} è lento ({{speed}} ms)", + "detectIsVerySlow": "{{detect}} è molto lento ({{speed}} ms)" + }, + "title": "Sistema", + "metrics": "Metriche di sistema", + "storage": { + "title": "Archiviazione", + "overview": "Sommario", + "recordings": { + "title": "Registrazioni", + "tips": "Questo valore rappresenta lo spazio di archiviazione totale utilizzato dalle registrazioni nel database di Frigate. Frigate non tiene traccia dell'utilizzo dello spazio di archiviazione per tutti i file presenti sul disco.", + "earliestRecording": "Prima registrazione disponibile:" + }, + "cameraStorage": { + "title": "Archiviazione della telecamera", + "camera": "Telecamera", + "unusedStorageInformation": "Informazioni spazio di archiviazione non utilizzato", + "storageUsed": "Archiviazione", + "percentageOfTotalUsed": "Percentuale del totale", + "bandwidth": "Larghezza di banda", + "unused": { + "title": "Liberi", + "tips": "Questo valore potrebbe non rappresentare accuratamente lo spazio libero disponibile per Frigate se nel disco sono archiviati altri file oltre alle registrazioni di Frigate. Frigate non tiene traccia dell'utilizzo dello spazio di archiviazione al di fuori delle sue registrazioni." + } + } + }, + "lastRefreshed": "Ultimo aggiornamento: " +} diff --git a/web/public/locales/nb-NO/audio.json b/web/public/locales/nb-NO/audio.json new file mode 100644 index 000000000..289d8273f --- /dev/null +++ b/web/public/locales/nb-NO/audio.json @@ -0,0 +1,429 @@ +{ + "bird": "Fugl", + "door": "Dør", + "sink": "Vask", + "blender": "Blender", + "bicycle": "Sykkel", + "motorcycle": "Motorsykkel", + "car": "Bil", + "bus": "Buss", + "train": "Tog", + "boat": "Båt", + "cat": "Katt", + "dog": "Hund", + "horse": "Hest", + "sheep": "Sau", + "skateboard": "Skateboard", + "mouse": "Mus", + "keyboard": "Tastatur", + "clock": "Klokke", + "scissors": "Saks", + "hair_dryer": "Hårføner", + "toothbrush": "Tannbørste", + "vehicle": "Kjøretøy", + "animal": "Dyr", + "bark": "Bjeff", + "goat": "Geit", + "groan": "Stønn", + "throat_clearing": "Kremting", + "sneeze": "Nysing", + "applause": "Applaus", + "chatter": "Skravling", + "crowd": "Folkemengde", + "bow_wow": "Voff-voff", + "livestock": "Husdyr", + "clip_clop": "Klipp-klopp", + "cluck": "Kakling", + "cock_a_doodle_doo": "Kykeliky", + "wild_animals": "Ville dyr", + "roaring_cats": "Brølende kattedyr", + "dogs": "Hunder", + "whale_vocalization": "Hval-vokalisering", + "strum": "Strumming", + "gong": "Gong", + "tuning_fork": "Stemmegaffel", + "opera": "Opera", + "waterfall": "Foss", + "motor_vehicle": "Motorvogn", + "emergency_vehicle": "Utrykningskjøretøy", + "police_car": "Politibil", + "rail_transport": "Jernbanetransport", + "fixed-wing_aircraft": "Fly med faste vinger", + "engine": "Motor", + "bathtub": "Badekar", + "toilet_flush": "Toalettskylling", + "coin": "Mynt", + "mechanisms": "Mekanismer", + "field_recording": "Feltinnspilling", + "speech": "Tale", + "babbling": "Babling", + "yell": "Rop", + "bellow": "Brøl", + "whoop": "Jubelrop", + "whispering": "Hvisking", + "laughter": "Latter", + "snicker": "Fnising", + "crying": "Gråt", + "sigh": "Sukk", + "singing": "Sang", + "choir": "Kor", + "yodeling": "Jodling", + "chant": "Sangrop", + "mantra": "Mantra", + "child_singing": "Barnesang", + "synthetic_singing": "Syntetisk sang", + "rapping": "Rapping", + "humming": "Nynning", + "grunt": "Grynt", + "whistling": "Plystring", + "breathing": "Pusting", + "wheeze": "Hvesing", + "snoring": "Snorking", + "gasp": "Gisp", + "pant": "Pesing", + "snort": "Snøfting", + "cough": "Hoste", + "sniff": "Snufs", + "run": "Løping", + "shuffle": "Sleping (av føtter)", + "footsteps": "Fottrinn", + "chewing": "Tygging", + "biting": "Biting", + "gargling": "Gurgling", + "stomach_rumble": "Mageknurr", + "burping": "Raping", + "hiccup": "Hikke", + "fart": "Promp", + "hands": "Hender", + "finger_snapping": "Fingerknipsing", + "clapping": "Applaus", + "heartbeat": "Hjerteslag", + "heart_murmur": "Hjertelyd (unormal)", + "cheering": "Jubel", + "children_playing": "Barn som leker", + "pets": "Kjæledyr", + "yip": "Klynk", + "howl": "Uling", + "growling": "Knurring", + "whimper_dog": "Klynking (hund)", + "purr": "Malelyd", + "meow": "Mjauing", + "hiss": "Fres", + "caterwaul": "Kattemjau", + "neigh": "Vrinsk", + "cattle": "Storfe", + "moo": "Rauting", + "cowbell": "Kubjelle", + "pig": "Gris", + "oink": "Nøff", + "bleat": "Breking", + "fowl": "Fjærfe", + "chicken": "Kylling", + "turkey": "Kalkun", + "gobble": "Kalkunlyd", + "duck": "And", + "quack": "Kvakking", + "goose": "Gås", + "honk": "Gåselyd", + "roar": "Brøl", + "chirp": "Kvitre", + "squawk": "Skvatring", + "pigeon": "Due", + "coo": "Kurre", + "crow": "Kråke", + "caw": "Krah", + "owl": "Ugle", + "hoot": "Uglelyd", + "flapping_wings": "Vingeslag", + "rats": "Rotter", + "patter": "Tripping", + "insect": "Insekt", + "cricket": "Gresshoppe", + "mosquito": "Mygg", + "fly": "Flue", + "buzz": "Summing", + "frog": "Frosk", + "croak": "Kvekking", + "snake": "Slange", + "rattle": "Ranglelyd", + "music": "Musikk", + "musical_instrument": "Musikkinstrument", + "plucked_string_instrument": "Klimpreinstrument", + "guitar": "Gitar", + "electric_guitar": "Elektrisk gitar", + "bass_guitar": "Bassgitar", + "acoustic_guitar": "Akustisk gitar", + "steel_guitar": "Steelgitar", + "tapping": "Tapping", + "banjo": "Banjo", + "sitar": "Sitar", + "mandolin": "Mandolin", + "zither": "Siter", + "ukulele": "Ukulele", + "piano": "Piano", + "electric_piano": "Elektrisk piano", + "organ": "Orgel", + "electronic_organ": "Elektronisk orgel", + "hammond_organ": "Hammondorgel", + "synthesizer": "Synthesizer", + "sampler": "Sampler", + "harpsichord": "Cembalo", + "percussion": "Perkusjon", + "drum_kit": "Trommesett", + "drum_machine": "Trommemaskin", + "drum": "Tromme", + "snare_drum": "Skarptromme", + "rimshot": "Slag på trommekanten", + "drum_roll": "Trommevirvel", + "bass_drum": "Basstromme", + "timpani": "Pauker", + "tabla": "Tabla", + "cymbal": "Symbal", + "hi_hat": "Hi-hat", + "wood_block": "Treblokk", + "tambourine": "Tamburin", + "maraca": "Maracas", + "tubular_bells": "Rørklokker", + "mallet_percussion": "Slagverk med køller", + "marimba": "Marimba", + "glockenspiel": "Glockenspiel", + "vibraphone": "Vibrafon", + "steelpan": "Steelpan", + "orchestra": "Orkester", + "brass_instrument": "Messingblåseinstrument", + "french_horn": "Valthorn", + "trumpet": "Trompet", + "trombone": "Trombone", + "bowed_string_instrument": "Strykeinstrument", + "string_section": "Strykere", + "violin": "Fiolin", + "pizzicato": "Pizzicato", + "cello": "Cello", + "double_bass": "Kontrabass", + "wind_instrument": "Treblåseinstrument", + "flute": "Fløyte", + "saxophone": "Saksofon", + "clarinet": "Klarinett", + "harp": "Harpe", + "bell": "Klokke", + "church_bell": "Kirkeklokke", + "jingle_bell": "Bjelle", + "bicycle_bell": "Sykkelbjelle", + "chime": "Klokkespill", + "wind_chime": "Vindklokke", + "harmonica": "Munnspill", + "accordion": "Akkordeon", + "bagpipes": "Sekkepipe", + "didgeridoo": "Didgeridoo", + "theremin": "Theremin", + "singing_bowl": "Syngeskål", + "scratching": "Skraping", + "pop_music": "Popmusikk", + "hip_hop_music": "Hip-hop musikk", + "beatboxing": "Beatboxing", + "rock_music": "Rockemusikk", + "heavy_metal": "Heavy metal", + "punk_rock": "Punkrock", + "grunge": "Grunge", + "progressive_rock": "Progressiv rock", + "rock_and_roll": "Rock and roll", + "psychedelic_rock": "Psykedelisk rock", + "rhythm_and_blues": "Rhythm and blues", + "soul_music": "Soulmusikk", + "reggae": "Reggae", + "country": "Country", + "swing_music": "Swingmusikk", + "bluegrass": "Bluegrass", + "funk": "Funk", + "folk_music": "Folkemusikk", + "middle_eastern_music": "Midtøsten-musikk", + "jazz": "Jazz", + "disco": "Disco", + "classical_music": "Klassisk musikk", + "electronic_music": "Elektronisk musikk", + "house_music": "House-musikk", + "techno": "Techno", + "dubstep": "Dubstep", + "drum_and_bass": "Drum and bass", + "electronica": "Electronica", + "electronic_dance_music": "Elektronisk dansemusikk", + "trance_music": "Trancemusikk", + "ambient_music": "Ambient musikk", + "music_of_latin_america": "Latinamerikansk musikk", + "salsa_music": "Salsamusikk", + "flamenco": "Flamenco", + "blues": "Blues", + "music_for_children": "Musikk for barn", + "new-age_music": "New age-musikk", + "vocal_music": "Vokalmusikk", + "a_capella": "A cappella", + "music_of_africa": "Afrikansk musikk", + "afrobeat": "Afrobeat", + "christian_music": "Kristelig musikk", + "gospel_music": "Gospelmusikk", + "music_of_asia": "Asiatisk musikk", + "carnatic_music": "Karnatisk musikk", + "music_of_bollywood": "Bollywood-musikk", + "ska": "Ska", + "traditional_music": "Tradisjonell musikk", + "independent_music": "Indie-musikk", + "song": "Sang", + "background_music": "Bakgrunnsmusikk", + "theme_music": "Temamusikk", + "jingle": "Jingle", + "soundtrack_music": "Filmmusikk", + "lullaby": "Vuggevise", + "video_game_music": "Videospillmusikk", + "christmas_music": "Julemusikk", + "dance_music": "Dansemusikk", + "wedding_music": "Bryllupsmusikk", + "happy_music": "Glad musikk", + "sad_music": "Trist musikk", + "tender_music": "Vakker musikk", + "exciting_music": "Spennende musikk", + "angry_music": "Sint musikk", + "scary_music": "Skummel musikk", + "wind": "Vind", + "rustling_leaves": "Raslende blader", + "wind_noise": "Vindstøy", + "thunderstorm": "Tordenvær", + "thunder": "Torden", + "water": "Vann", + "rain": "Regn", + "raindrop": "Regndråpe", + "rain_on_surface": "Regn på overflate", + "stream": "Bekkeleie", + "ocean": "Hav", + "waves": "Bølger", + "steam": "Damp", + "gurgling": "Gurgling", + "fire": "Brann", + "crackle": "Knakking", + "sailboat": "Seilbåt", + "rowboat": "Robåt", + "motorboat": "Motorbåt", + "ship": "Skip", + "toot": "Tuting", + "car_alarm": "Bilalarm", + "power_windows": "Elektriske vinduer", + "skidding": "Skrens", + "tire_squeal": "Hvinende dekk", + "car_passing_by": "Bil som kjører forbi", + "race_car": "Racerbil", + "truck": "Lastebil", + "air_brake": "Luftbrems", + "air_horn": "Lufthorn", + "reversing_beeps": "Ryggesignal", + "ice_cream_truck": "Iskrembil", + "ambulance": "Ambulanse", + "fire_engine": "Brannbil", + "aircraft_engine": "Flymotor", + "traffic_noise": "Trafikkstøy", + "train_whistle": "Togfløyte", + "train_horn": "Toghorn", + "railroad_car": "Jernbanevogn", + "train_wheels_squealing": "Hvinende togskinner", + "subway": "T-bane", + "aircraft": "Fly", + "jet_engine": "Jetmotor", + "propeller": "Propell", + "helicopter": "Helikopter", + "light_engine": "Lett motor", + "dental_drill's_drill": "Tannlegebor", + "lawn_mower": "Gressklipper", + "chainsaw": "Motorsag", + "medium_engine": "Middels tung motor", + "heavy_engine": "Tung motor", + "engine_knocking": "Motorbanking", + "engine_starting": "Motorstart", + "idling": "Tomgang", + "accelerating": "Akselerasjon", + "doorbell": "Dørklokke", + "ding-dong": "Ding-dong", + "sliding_door": "Skyvedør", + "slam": "Smell", + "knock": "Bank", + "tap": "Tapp", + "squeak": "Knirk", + "cupboard_open_or_close": "Skapdør som åpnes eller lukkes", + "drawer_open_or_close": "Skuff som åpnes eller lukkes", + "dishes": "Oppvask", + "cutlery": "Bestikk", + "chopping": "Hugging", + "frying": "Steking", + "microwave_oven": "Mikrobølgeovn", + "water_tap": "Vannkran", + "electric_toothbrush": "Elektrisk tannbørste", + "vacuum_cleaner": "Støvsuger", + "zipper": "Glidelås", + "keys_jangling": "Klingende nøkler", + "electric_shaver": "Elektrisk barbermaskin", + "shuffling_cards": "Kortstokk som stokkes", + "typing": "Skriving (på tastatur)", + "typewriter": "Skrivemaskin", + "computer_keyboard": "Datatastatur", + "writing": "Skriving", + "alarm": "Alarm", + "telephone": "Telefon", + "telephone_bell_ringing": "Telefon som ringer", + "ringtone": "Ringetone", + "telephone_dialing": "Telefon som slås", + "dial_tone": "Summetone", + "busy_signal": "Opptattsignal", + "alarm_clock": "Vekkerklokke", + "siren": "Sirene", + "civil_defense_siren": "Luftsirene", + "buzzer": "Summer", + "smoke_detector": "Røykvarsler", + "fire_alarm": "Brannalarm", + "foghorn": "Tåkelur", + "whistle": "Fløyte", + "steam_whistle": "Dampfløyte", + "ratchet": "Skralle", + "tick": "Tikk", + "tick-tock": "Tikk-takk", + "gears": "Tannhjul", + "pulleys": "Trinser", + "sewing_machine": "Symaskin", + "mechanical_fan": "Mekanisk vifte", + "air_conditioning": "Klimaanlegg", + "cash_register": "Kasseapparat", + "printer": "Skriver", + "single-lens_reflex_camera": "Speilreflekskamera", + "camera": "Kamera", + "tools": "Verktøy", + "hammer": "Hammer", + "jackhammer": "Trykkluftbor", + "sawing": "Saging", + "filing": "Filing", + "sanding": "Pussing", + "power_tool": "Elektroverktøy", + "drill": "Boremaskin", + "explosion": "Eksplosjon", + "gunshot": "Skudd", + "machine_gun": "Maskingevær", + "fusillade": "Salver", + "artillery_fire": "Artilleriild", + "cap_gun": "Leketøyspistol", + "fireworks": "Fyrverkeri", + "firecracker": "Kinaputt", + "burst": "Spreng", + "eruption": "Utslipp", + "boom": "Drønn", + "wood": "Tre", + "chop": "Hakk", + "splinter": "Splint", + "crack": "Sprekk", + "glass": "Glass", + "chink": "Klirr", + "shatter": "Knuse", + "silence": "Stillhet", + "sound_effect": "Lydeffekt", + "environmental_noise": "Miljøstøy", + "static": "Statisk støy", + "white_noise": "Hvit støy", + "pink_noise": "Rosa støy", + "television": "Fjernsyn", + "radio": "Radio", + "scream": "Skrik" +} diff --git a/web/public/locales/nb-NO/common.json b/web/public/locales/nb-NO/common.json new file mode 100644 index 000000000..c6f40e7d6 --- /dev/null +++ b/web/public/locales/nb-NO/common.json @@ -0,0 +1,258 @@ +{ + "time": { + "yr": "{{time}} år", + "year_one": "{{time}} år", + "year_other": "{{time}} år", + "minute_one": "{{time}} minutt", + "minute_other": "{{time}} minutter", + "s": "{{time}}s", + "second_one": "{{time}} sekund", + "second_other": "{{time}} sekunder", + "formattedTimestampExcludeSeconds": { + "24hour": "%-d. %b, %H:%M", + "12hour": "%-d. %b, %I:%M %p" + }, + "untilForTime": "Inntil {{time}}", + "untilForRestart": "Inntil Frigate starter på nytt.", + "untilRestart": "Inntil omstart", + "ago": "{{timeAgo}} siden", + "justNow": "Akkurat nå", + "today": "I dag", + "yesterday": "I går", + "last7": "Siste 7 dager", + "last14": "Siste 14 dager", + "last30": "Siste 30 dager", + "thisWeek": "Denne uken", + "lastWeek": "Forrige uke", + "thisMonth": "Denne måneden", + "lastMonth": "Forrige måned", + "5minutes": "5 minutter", + "10minutes": "10 minutter", + "30minutes": "30 minutter", + "1hour": "1 time", + "12hours": "12 timer", + "24hours": "24 timer", + "pm": "pm", + "am": "am", + "mo": "{{time}} mnd", + "month_one": "{{time}} måned", + "month_other": "{{time}} måneder", + "d": "{{time}}d", + "day_one": "{{time}} dag", + "day_other": "{{time}} dager", + "h": "{{time}}t", + "hour_one": "{{time}} time", + "hour_other": "{{time}} timer", + "m": "{{time}}m", + "formattedTimestamp": { + "12hour": "d. MMM, h:mm:ss aaa", + "24hour": "d. MMM, HH:mm:ss" + }, + "formattedTimestamp2": { + "12hour": "dd/MM h:mm:ssa", + "24hour": "d. MMM HH:mm:ss" + }, + "formattedTimestampWithYear": { + "12hour": "%-d. %b %Y, %I:%M %p", + "24hour": "%-d. %b %Y, %H:%M" + }, + "formattedTimestampOnlyMonthAndDay": "%-d. %b", + "formattedTimestampHourMinute": { + "12hour": "h:mm aaa", + "24hour": "HH:mm" + }, + "formattedTimestampHourMinuteSecond": { + "12hour": "h:mm:ss aaa", + "24hour": "HH:mm:ss" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "d. MMM, h:mm aaa", + "24hour": "d. MMM, HH:mm" + }, + "formattedTimestampFilename": { + "12hour": "dd-MM-yy-h-mm-ss-a", + "24hour": "dd-MM-yy-HH-mm-ss" + }, + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "d. MMM yyyy, h:mm aaa", + "24hour": "d. MMM yyyy, HH:mm" + }, + "formattedTimestampMonthDay": "d. MMM" + }, + "button": { + "copy": "Kopier", + "delete": "Slett", + "apply": "Bruk", + "reset": "Tilbakestill", + "done": "Ferdig", + "enabled": "Aktivert", + "enable": "Aktiver", + "disabled": "Deaktivert", + "disable": "Deaktiver", + "save": "Lagre", + "saving": "Lagrer…", + "cancel": "Avbryt", + "close": "Lukk", + "back": "Tilbake", + "history": "Historikk", + "fullscreen": "Fullskjerm", + "exitFullscreen": "Avslutt fullskjerm", + "pictureInPicture": "Bilde-i-bilde", + "twoWayTalk": "Toveis tale", + "cameraAudio": "Kameralyd", + "on": "PÅ", + "off": "AV", + "edit": "Rediger", + "copyCoordinates": "Kopier koordinater", + "yes": "Ja", + "no": "Nei", + "download": "Last ned", + "info": "Info", + "suspended": "Suspendert", + "unsuspended": "Opphev suspensjon", + "play": "Spill av", + "unselect": "Fjern valg", + "export": "Eksporter", + "deleteNow": "Slett nå", + "next": "Neste" + }, + "menu": { + "help": "Hjelp", + "documentation": { + "title": "Dokumentasjon", + "label": "Frigate-dokumentasjon" + }, + "restart": "Start Frigate på nytt", + "live": { + "title": "Direkte", + "allCameras": "Alle kameraer", + "cameras": { + "title": "Kameraer", + "count_one": "{{count}} kamera", + "count_other": "{{count}} kameraer" + } + }, + "review": "Inspiser", + "explore": "Utforsk", + "export": "Eksporter", + "uiPlayground": "UI Sandkasse", + "faceLibrary": "Ansiktsbibliotek", + "user": { + "title": "Bruker", + "account": "Konto", + "current": "Nåværende bruker: {{user}}", + "anonymous": "anonym", + "logout": "Logg ut", + "setPassword": "Angi passord" + }, + "system": "System", + "systemMetrics": "Systemmålinger", + "configuration": "Konfigurasjon", + "systemLogs": "Systemlogger", + "settings": "Innstillinger", + "configurationEditor": "Rediger konfigurasjonen", + "languages": "Språk", + "language": { + "en": "English (Engelsk)", + "zhCN": "简体中文 (Forenklet kinesisk)", + "withSystem": { + "label": "Bruk systemets språkinnstillinger" + }, + "fr": "Français (Fransk)", + "es": "Español (Spansk)", + "hi": "हिन्दी (Hindi)", + "ar": "العربية (Arabisk)", + "pt": "Português (Portugisisk)", + "ru": "Русский (Russisk)", + "de": "Deutsch (Tysk)", + "ja": "日本語 (Japansk)", + "tr": "Türkçe (Tyrkisk)", + "it": "Italiano (Italiensk)", + "nl": "Nederlands (Nederlandsk)", + "sv": "Svenska (Svensk)", + "cs": "Čeština (Tsjekkisk)", + "nb": "Norsk Bokmål", + "ko": "한국어 (Koreansk)", + "vi": "Tiếng Việt (Vietnamesisk)", + "fa": "فارسی (Persisk)", + "he": "עברית (Hebraisk)", + "el": "Ελληνικά (Gresk)", + "ro": "Română (Rumensk)", + "hu": "Magyar (Ungarsk)", + "fi": "Suomi (Finsk)", + "da": "Dansk (Dansk)", + "sk": "Slovenčina (Slovensk)", + "pl": "Polski (Polsk)", + "uk": "Українська (Ukrainsk)", + "yue": "粵語 (Kantonesisk)" + }, + "appearance": "Utseende", + "darkMode": { + "label": "Mørk modus", + "light": "Lys", + "dark": "Mørk", + "withSystem": { + "label": "Bruk systemets innstillinger for lys eller mørk modus" + } + }, + "withSystem": "System", + "theme": { + "label": "Tema", + "blue": "Blå", + "green": "Grønn", + "nord": "Nord", + "red": "Rød", + "contrast": "Høy kontrast", + "default": "Standard", + "highcontrast": "Høy kontrast" + } + }, + "pagination": { + "next": { + "title": "Neste", + "label": "Gå til neste side" + }, + "label": "paginering", + "previous": { + "title": "Forrige", + "label": "Gå til forrige side" + }, + "more": "Flere sider" + }, + "unit": { + "speed": { + "mph": "mph", + "kph": "km/t" + } + }, + "label": { + "back": "Gå tilbake" + }, + "toast": { + "copyUrlToClipboard": "Nettadresse kopiert til utklippstavlen.", + "save": { + "title": "Lagre", + "error": { + "title": "Kunne ikke lagre endringer i konfigurasjonen: {{errorMessage}}", + "noMessage": "Kunne ikke lagre endringer i konfigurasjonen" + } + } + }, + "role": { + "title": "Rolle", + "admin": "Administrator", + "viewer": "Visningsbruker", + "desc": "Administratorer har full tilgang til alle funksjoner i Frigate brukergrensesnittet. Visningsbrukere er begrenset til å se kameraer, inspisere elementer og se historiske opptak." + }, + "accessDenied": { + "documentTitle": "Ingen tilgang – Frigate", + "title": "Ingen tilgang", + "desc": "Du har ikke tillatelse til å vise denne siden." + }, + "notFound": { + "documentTitle": "Ikke funnet – Frigate", + "title": "404", + "desc": "Siden ble ikke funnet" + }, + "selectItem": "Velg {{item}}" +} diff --git a/web/public/locales/nb-NO/components/auth.json b/web/public/locales/nb-NO/components/auth.json new file mode 100644 index 000000000..caf6a2ca6 --- /dev/null +++ b/web/public/locales/nb-NO/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "user": "Brukernavn", + "password": "Passord", + "login": "Logg inn", + "errors": { + "usernameRequired": "Brukernavn er påkrevd", + "passwordRequired": "Passord er påkrevd", + "rateLimit": "Grense for antall forsøk overskredet. Prøv igjen senere.", + "loginFailed": "Innlogging mislyktes", + "unknownError": "Ukjent feil. Sjekk loggene.", + "webUnknownError": "Ukjent feil. Sjekk konsoll-loggene." + } + } +} diff --git a/web/public/locales/nb-NO/components/camera.json b/web/public/locales/nb-NO/components/camera.json new file mode 100644 index 000000000..21596c716 --- /dev/null +++ b/web/public/locales/nb-NO/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "label": "Kameragrupper", + "name": { + "placeholder": "Skriv inn et navn…", + "errorMessage": { + "mustLeastCharacters": "Navnet på kameragruppen må være minst 2 tegn.", + "exists": "Navnet på kameragruppen finnes allerede.", + "nameMustNotPeriod": "Navnet på kameragruppen kan ikke inneholde punktum.", + "invalid": "Ugyldig navn på kameragruppe." + }, + "label": "Navn" + }, + "camera": { + "setting": { + "streamMethod": { + "method": { + "continuousStreaming": { + "label": "Kontinuerlig strømming", + "desc": { + "title": "Kamerabildet vil alltid være en direktestrøm når det vises på dashbordet, selv om ingen aktivitet oppdages.", + "warning": "Kontinuerlig strømming kan føre til høy båndbreddebruk og ytelsesproblemer. Bruk med forsiktighet." + } + }, + "noStreaming": { + "label": "Ingen strømming", + "desc": "Kamerabilder vil bare oppdateres én gang i minuttet, og ingen direktestrømming vil finne sted." + }, + "smartStreaming": { + "label": "Smart strømming (anbefalt)", + "desc": "Smart strømming oppdaterer kamerabilder én gang i minuttet når ingen aktivitet oppdages, for å spare båndbredde og ressurser. Når aktivitet oppdages, byttes bildet sømløst til direktestrøm." + } + }, + "label": "Strømmemetode" + }, + "compatibilityMode": { + "label": "Kompatibilitetsmodus", + "desc": "Aktiver dette alternativet kun hvis kameraets direktestrøm viser fargeforstyrrelser og har en diagonal linje på høyre side av bildet." + }, + "label": "Innstillinger for kamerastrømming", + "title": "{{cameraName}} strømmeinnstillinger", + "desc": "Endre direktestrømmingsalternativene for denne kameragruppens dashbord. Disse innstillingene er spesifikke for enhet/nettleser.", + "audioIsAvailable": "Lyd er tilgjengelig for denne strømmen", + "audioIsUnavailable": "Lyd er ikke tilgjengelig for denne strømmen", + "audio": { + "tips": { + "title": "Lyd må komme fra kameraet ditt og konfigureres i go2rtc for denne strømmen.", + "document": "Les dokumentasjonen " + } + } + } + }, + "add": "Legg til kameragruppe", + "edit": "Rediger kameragruppe", + "delete": { + "label": "Slett kameragruppe", + "confirm": { + "title": "Bekreft sletting", + "desc": "Er du sikker på at du vil slette kameragruppen {{name}}?" + } + }, + "cameras": { + "label": "Kameraer", + "desc": "Velg kameraer for denne gruppen." + }, + "icon": "Ikon", + "success": "Kameragruppen ({{name}}) er lagret." + }, + "debug": { + "options": { + "label": "Innstillinger", + "title": "Alternativer", + "showOptions": "Vis alternativer", + "hideOptions": "Skjul alternativer" + }, + "boundingBox": "Omsluttende boks", + "timestamp": "Tidsstempel", + "zones": "Soner", + "mask": "Maske", + "motion": "Bevegelse", + "regions": "Regioner" + } +} diff --git a/web/public/locales/nb-NO/components/dialog.json b/web/public/locales/nb-NO/components/dialog.json new file mode 100644 index 000000000..76641f33b --- /dev/null +++ b/web/public/locales/nb-NO/components/dialog.json @@ -0,0 +1,119 @@ +{ + "restart": { + "title": "Er du sikker på at du vil starte Frigate på nytt?", + "button": "Start på nytt", + "restarting": { + "title": "Frigate starter på nytt", + "button": "Tving omlasting nå", + "content": "Denne siden vil lastes inn på nytt om {{countdown}} sekunder." + } + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "Send til Frigate+", + "desc": "Objekter på steder du vil unngå er ikke falske positiver. Å sende dem som falske positiver vil forvirre modellen." + }, + "review": { + "true": { + "label": "Bekreft denne merkelappen for Frigate Plus", + "true_one": "Dette er en {{label}}", + "true_other": "Dette er en {{label}}" + }, + "state": { + "submitted": "Sendt inn" + }, + "false": { + "label": "Ikke bekreft denne merkelappen for Frigate Plus", + "false_one": "Dette er ikke en {{label}}", + "false_other": "Dette er ikke en {{label}}" + }, + "question": { + "label": "Bekreft denne merkelapp for Frigate Plus", + "ask_an": "Er dette objekt en {{label}}?", + "ask_a": "Er dette objektet en {{label}}?", + "ask_full": "Er dette objekt en {{untranslatedLabel}} ({{translatedLabel}})?" + } + } + }, + "video": { + "viewInHistory": "Vis i historikk" + } + }, + "export": { + "time": { + "lastHour_one": "Siste time", + "lastHour_other": "Siste {{count}} timer", + "custom": "Tilpasset", + "start": { + "title": "Starttid", + "label": "Velg starttid" + }, + "fromTimeline": "Velg fra tidslinje", + "end": { + "title": "Sluttid", + "label": "Velg sluttid" + } + }, + "toast": { + "success": "Eksporten startet. Se filen i /exports-mappen.", + "error": { + "failed": "Klarte ikke å starte eksport: {{error}}", + "noVaildTimeSelected": "Ingen gyldig tidsperiode valgt", + "endTimeMustAfterStartTime": "Sluttid må være etter starttid" + } + }, + "fromTimeline": { + "previewExport": "Forhåndsvis eksport", + "saveExport": "Lagre eksport" + }, + "name": { + "placeholder": "Gi eksporten et navn" + }, + "select": "Velg", + "export": "Eksporter", + "selectOrExport": "Velg eller eksporter" + }, + "streaming": { + "label": "Strøm", + "restreaming": { + "disabled": "Restrømming er ikke aktivert for dette kameraet.", + "desc": { + "readTheDocumentation": "Les dokumentasjonen", + "title": "Konfigurer go2rtc for flere direktestrømmingsalternativer og lyd for dette kameraet." + } + }, + "showStats": { + "label": "Vis strømmestatistikk", + "desc": "Aktiver dette alternativet for å vise strømmestatistikk som et overlegg på kamerabildet." + }, + "debugView": "Feilsøkingsvisning" + }, + "search": { + "saveSearch": { + "button": { + "save": { + "label": "Lagre dette søket" + } + }, + "label": "Lagre søk", + "desc": "Skriv inn et navn for dette lagrede søket.", + "placeholder": "Skriv inn et navn for søket", + "overwrite": "{{searchName}} finnes allerede. Lagring vil overskrive eksisterende verdi.", + "success": "Søk ({{searchName}}) er lagret." + } + }, + "recording": { + "confirmDelete": { + "title": "Bekreft sletting", + "desc": { + "selected": "Er du sikker på at du vil slette alle opptak knyttet til dette inspeksjonselementet?

    Hold inne Shift-tasten for å hoppe over denne dialogen i fremtiden." + } + }, + "button": { + "export": "Eksportér", + "markAsReviewed": "Merk som inspisert", + "deleteNow": "Slett nå" + } + } +} diff --git a/web/public/locales/nb-NO/components/filter.json b/web/public/locales/nb-NO/components/filter.json new file mode 100644 index 000000000..1e13b5c5f --- /dev/null +++ b/web/public/locales/nb-NO/components/filter.json @@ -0,0 +1,126 @@ +{ + "filter": "Filter", + "labels": { + "label": "Merkelapper", + "all": { + "title": "Alle masker / soner", + "short": "Merkelapper" + }, + "count": "{{count}} merkelapper", + "count_other": "{{count}} Merkelapper", + "count_one": "{{count}} Merkelapp" + }, + "features": { + "hasVideoClip": "Har et videoklipp", + "submittedToFrigatePlus": { + "label": "Sendt til Frigate+", + "tips": "Du må først filtrere på sporede objekter som har et øyeblikksbilde.

    Sporede objekter uten et øyeblikksbilde kan ikke sendes til Frigate+." + }, + "label": "Funksjoner", + "hasSnapshot": "Har et øyeblikksbilde" + }, + "sort": { + "label": "Sorter", + "dateAsc": "Dato (Stigende)", + "dateDesc": "Dato (Synkende)", + "scoreAsc": "Objektpoengsum (Stigende)", + "scoreDesc": "Objektpoengsum (Synkende)", + "speedAsc": "Estimert hastighet (Stigende)", + "speedDesc": "Estimert hastighet (Synkende)", + "relevance": "Relevans" + }, + "explore": { + "date": { + "selectDateBy": { + "label": "Velg en dato å filtrere etter" + } + }, + "settings": { + "title": "Innstillinger", + "defaultView": { + "title": "Standard visning", + "desc": "Når ingen filtre er valgt, vis et sammendrag av de nyeste sporede objektene per merkelapp, eller vis et ufiltrert rutenett.", + "summary": "Sammendrag", + "unfilteredGrid": "Ufiltrert rutenett" + }, + "gridColumns": { + "title": "Rutenett kolonner", + "desc": "Velg antall kolonner i rutenettvisningen." + }, + "searchSource": { + "label": "Søkekilde", + "desc": "Velg om du vil søke i bildene eller beskrivelsene av de sporede objektene dine.", + "options": { + "thumbnailImage": "Miniatyrbilde", + "description": "Beskrivelse" + } + } + } + }, + "logSettings": { + "label": "Filtrer loggnivå", + "filterBySeverity": "Filtrer logger etter alvorlighetsgrad", + "loading": { + "title": "Laster inn", + "desc": "Når loggvinduet rulles til bunnen, strømmes nye logger automatisk etter hvert som de legges til." + }, + "disableLogStreaming": "Deaktiver loggstrømming", + "allLogs": "Alle logger" + }, + "trackedObjectDelete": { + "title": "Bekreft sletting", + "desc": "Sletting av disse {{objectLength}} sporede objektene fjerner øyeblikksbildet, eventuelle lagrede vektorrepresentasjoner og tilhørende objekt livssyklusoppføringer. Opptak av disse sporede objektene i Historikkvisning vil IKKE bli slettet.

    Er du sikker på at du vil fortsette?

    Hold Shift-tasten for å unngå denne dialogboksen i fremtiden.", + "toast": { + "success": "Sporede objekter ble slettet.", + "error": "Kunne ikke slette sporede objekter: {{errorMessage}}" + } + }, + "zoneMask": { + "filterBy": "Filtrer etter sonemaske" + }, + "recognizedLicensePlates": { + "noLicensePlatesFound": "Ingen kjennemerker funnet.", + "selectPlatesFromList": "Velg ett eller flere kjennemerker fra listen.", + "title": "Gjenkjente kjennemerker", + "loadFailed": "Kunne ikke laste inn gjenkjente kjennemerker.", + "loading": "Laster inn gjenkjente kjennemerker…", + "placeholder": "Skriv for å søke etter kjennemerker…" + }, + "dates": { + "all": { + "title": "Alle datoer", + "short": "Datoer" + } + }, + "more": "Flere filtre", + "reset": { + "label": "Nullstill filtre til standardverdier" + }, + "timeRange": "Tidsrom", + "subLabels": { + "label": "Under-Merkelapper", + "all": "Alle under-Merkelapper" + }, + "score": "Poengsum", + "estimatedSpeed": "Estimert hastighet ({{unit}})", + "cameras": { + "all": { + "title": "Alle kameraer", + "short": "Kameraer" + }, + "label": "Kamerafilter" + }, + "review": { + "showReviewed": "Vis inspiserte" + }, + "motion": { + "showMotionOnly": "Vis kun bevegelse" + }, + "zones": { + "label": "Soner", + "all": { + "title": "Alle soner", + "short": "Soner" + } + } +} diff --git a/web/public/locales/nb-NO/components/icons.json b/web/public/locales/nb-NO/components/icons.json new file mode 100644 index 000000000..937a8d052 --- /dev/null +++ b/web/public/locales/nb-NO/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "Velg et ikon", + "search": { + "placeholder": "Søk etter et ikon…" + } + } +} diff --git a/web/public/locales/nb-NO/components/input.json b/web/public/locales/nb-NO/components/input.json new file mode 100644 index 000000000..eb03da4fa --- /dev/null +++ b/web/public/locales/nb-NO/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Last ned video", + "toast": { + "success": "Videoen for inspeksjonselementet ditt har startet nedlasting." + } + } + } +} diff --git a/web/public/locales/nb-NO/components/player.json b/web/public/locales/nb-NO/components/player.json new file mode 100644 index 000000000..5396af367 --- /dev/null +++ b/web/public/locales/nb-NO/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "Ingen opptak funnet for dette tidspunktet", + "stats": { + "streamType": { + "short": "Type", + "title": "Strømmetype:" + }, + "droppedFrames": { + "short": { + "title": "Tapt", + "value": "{{droppedFrames}} bilder" + }, + "title": "Tapte bilder:" + }, + "bandwidth": { + "title": "Båndbredde:", + "short": "Båndbredde" + }, + "latency": { + "title": "Forsinkelse:", + "value": "{{seconds}} sekunder", + "short": { + "title": "Forsinkelse", + "value": "{{seconds}} sek" + } + }, + "totalFrames": "Totalt antall bilder:", + "decodedFrames": "Dekodede bilder:", + "droppedFrameRate": "Tapte bilder per sekund:" + }, + "noPreviewFound": "Ingen forhåndsvisning funnet", + "noPreviewFoundFor": "Ingen forhåndsvisning funnet for {{cameraName}}", + "submitFrigatePlus": { + "title": "Send dette bildet til Frigate+?", + "submit": "Send" + }, + "livePlayerRequiredIOSVersion": "iOS 17.1 eller høyere kreves for denne typen direkte-strømming.", + "streamOffline": { + "title": "Strømmen er frakoblet", + "desc": "Ingen bilder er mottatt på {{cameraName}} detekt strømmen, sjekk feilloggene" + }, + "cameraDisabled": "Kameraet er deaktivert", + "toast": { + "success": { + "submittedFrigatePlus": "Bildet ble sendt til Frigate+" + }, + "error": { + "submitFrigatePlusFailed": "Kunne ikke sende bildet til Frigate+" + } + } +} diff --git a/web/public/locales/nb-NO/objects.json b/web/public/locales/nb-NO/objects.json new file mode 100644 index 000000000..8847a10fa --- /dev/null +++ b/web/public/locales/nb-NO/objects.json @@ -0,0 +1,120 @@ +{ + "motorcycle": "Motorsykkel", + "airplane": "Fly", + "bus": "Buss", + "train": "Tog", + "boat": "Båt", + "traffic_light": "Trafikklys", + "wine_glass": "Vinglass", + "cup": "Kopp", + "chair": "Stol", + "couch": "Sofa", + "potted_plant": "Potteplante", + "bed": "Seng", + "gls": "GLS", + "person": "Person", + "bicycle": "Sykkel", + "car": "Bil", + "fire_hydrant": "Brannhydrant", + "street_sign": "Gateskilt", + "stop_sign": "Stoppskilt", + "parking_meter": "Parkeringsautomat", + "bench": "Benk", + "bird": "Fugl", + "cat": "Katt", + "dog": "Hund", + "horse": "Hest", + "sheep": "Sau", + "cow": "Ku", + "elephant": "Elefant", + "bear": "Bjørn", + "zebra": "Sebra", + "giraffe": "Giraff", + "hat": "Hatt", + "backpack": "Ryggsekk", + "umbrella": "Paraply", + "shoe": "Sko", + "eye_glasses": "Briller", + "handbag": "Håndveske", + "tie": "Slips", + "suitcase": "Koffert", + "frisbee": "Frisbee", + "skis": "Ski", + "snowboard": "Snøbrett", + "sports_ball": "Ball", + "kite": "Drage", + "baseball_bat": "Baseballkølle", + "baseball_glove": "Baseballhanske", + "skateboard": "Skateboard", + "surfboard": "Surfebrett", + "tennis_racket": "Tennisracket", + "bottle": "Flaske", + "plate": "Tallerken", + "fork": "Gaffel", + "knife": "Kniv", + "spoon": "Skje", + "bowl": "Bolle", + "banana": "Banan", + "apple": "Eple", + "broccoli": "Brokkoli", + "sandwich": "Sandwich", + "orange": "Appelsin", + "carrot": "Gulrot", + "hot_dog": "Pølse i brød", + "pizza": "Pizza", + "donut": "Donut", + "cake": "Kake", + "mirror": "Speil", + "dining_table": "Spisebord", + "window": "Vindu", + "desk": "Skrivebord", + "toilet": "Toalett", + "door": "Dør", + "tv": "TV", + "laptop": "Bærbar datamaskin", + "mouse": "Mus", + "remote": "Fjernkontroll", + "keyboard": "Tastatur", + "cell_phone": "Mobiltelefon", + "sink": "Vask", + "microwave": "Mikrobølgeovn", + "oven": "Ovn", + "toaster": "Brødrister", + "refrigerator": "Kjøleskap", + "blender": "Blender", + "book": "Bok", + "clock": "Klokke", + "vase": "Vase", + "scissors": "Saks", + "teddy_bear": "Teddybjørn", + "hair_dryer": "Hårføner", + "toothbrush": "Tannbørste", + "hair_brush": "Hårbørste", + "vehicle": "Kjøretøy", + "squirrel": "Ekorn", + "deer": "Hjort", + "animal": "Dyr", + "bark": "Bjeff", + "fox": "Rev", + "goat": "Geit", + "rabbit": "Kanin", + "raccoon": "Vaskebjørn", + "robot_lawnmower": "Robotgressklipper", + "waste_bin": "Søppelbøtte", + "on_demand": "På forespørsel", + "face": "Ansikt", + "license_plate": "Kjennemerke", + "package": "Pakke", + "bbq_grill": "Grill", + "amazon": "Amazon", + "usps": "USPS", + "ups": "UPS", + "fedex": "FedEx", + "dhl": "DHL", + "an_post": "An Post", + "purolator": "Filter", + "postnl": "PostNL", + "nzpost": "NZPost", + "postnord": "PostNord", + "dpd": "DPD" +} diff --git a/web/public/locales/nb-NO/views/configEditor.json b/web/public/locales/nb-NO/views/configEditor.json new file mode 100644 index 000000000..55067d1a8 --- /dev/null +++ b/web/public/locales/nb-NO/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "documentTitle": "Konfigurasjonsredigering - Frigate", + "toast": { + "error": { + "savingError": "Feil ved lagring av konfigurasjon" + }, + "success": { + "copyToClipboard": "Konfigurasjonen ble kopiert til utklippstavlen." + } + }, + "configEditor": "Konfigurasjonsredigering", + "copyConfig": "Kopier konfigurasjon", + "saveAndRestart": "Lagre og omstart", + "saveOnly": "Kun lagre" +} diff --git a/web/public/locales/nb-NO/views/events.json b/web/public/locales/nb-NO/views/events.json new file mode 100644 index 000000000..8bf579502 --- /dev/null +++ b/web/public/locales/nb-NO/views/events.json @@ -0,0 +1,37 @@ +{ + "camera": "Kamera", + "empty": { + "alert": "Det er ingen varsler å inspisere", + "detection": "Det er ingen deteksjoner å inspisere", + "motion": "Ingen bevegelsesdata funnet" + }, + "timeline": "Tidslinje", + "events": { + "label": "Hendelser", + "aria": "Velg hendelser", + "noFoundForTimePeriod": "Ingen hendelser funnet for denne tidsperioden." + }, + "newReviewItems": { + "label": "Vis nye inspeksjonselementer", + "button": "Nye elementer å inspisere" + }, + "alerts": "Varsler", + "detections": "Deteksjoner", + "motion": { + "label": "Bevegelse", + "only": "Kun bevegelse" + }, + "allCameras": "Alle kameraer", + "timeline.aria": "Velg tidslinje", + "documentTitle": "Inspiser - Frigate", + "recordings": { + "documentTitle": "Opptak - Frigate" + }, + "calendarFilter": { + "last24Hours": "Siste 24 timer" + }, + "markAsReviewed": "Merk som inspisert", + "markTheseItemsAsReviewed": "Merk disse elementene som inspiserte", + "selected_one": "{{count}} valgt", + "selected_other": "{{count}} valgt" +} diff --git a/web/public/locales/nb-NO/views/explore.json b/web/public/locales/nb-NO/views/explore.json new file mode 100644 index 000000000..c8eafda04 --- /dev/null +++ b/web/public/locales/nb-NO/views/explore.json @@ -0,0 +1,200 @@ +{ + "documentTitle": "Utforsk - Frigate", + "generativeAI": "Generativ AI", + "exploreIsUnavailable": { + "title": "Utforsk er utilgjengelig", + "embeddingsReindexing": { + "startingUp": "Starter opp…", + "estimatedTime": "Estimert gjenværende tid:", + "context": "Utforsk kan brukes etter at reindekseringen av vektorrepresentasjoner for sporede objekter er fullført.", + "finishingShortly": "Avsluttes snart", + "step": { + "thumbnailsEmbedded": "Miniatyrbilder innebygd: ", + "descriptionsEmbedded": "Beskrivelser innebygd: ", + "trackedObjectsProcessed": "Sporede objekter behandlet: " + } + }, + "downloadingModels": { + "setup": { + "visionModel": "Visjonsmodell", + "visionModelFeatureExtractor": "Funksjonsekstraktor for visjonsmodell", + "textModel": "Tekstmodell", + "textTokenizer": "Tekst symbolbygger" + }, + "context": "Frigate laster ned de nødvendige vektorrepresentasjonsmodellene for å støtte funksjonen for semantisk søk. Dette kan ta flere minutter, avhengig av hastigheten på nettverksforbindelsen din.", + "tips": { + "context": "Du bør vurdere å reindeksere vektorrepresentasjoner for de sporede objektene dine når modellene er lastet ned.", + "documentation": "Les dokumentasjonen" + }, + "error": "En feil har oppstått. Sjekk Frigate-loggene." + } + }, + "objectLifecycle": { + "createObjectMask": "Lag objektmaske", + "adjustAnnotationSettings": "Juster annoteringsinnstillinger", + "scrollViewTips": "Rull for å se de viktigste øyeblikkene i dette objektets livssyklus.", + "autoTrackingTips": "Posisjoner for omsluttende boks vil være unøyaktige for kameraer med automatisk sporing.", + "lifecycleItemDesc": { + "visible": "{{label}} oppdaget", + "attribute": { + "other": "{{label}} gjenkjent som {{attribute}}", + "faceOrLicense_plate": "{{attribute}} oppdaget for {{label}}" + }, + "gone": "{{label}} forlot", + "heard": "{{label}} hørt", + "external": "{{label}} oppdaget", + "entered_zone": "{{label}} gikk inn i {{zones}}", + "active": "{{label}} ble aktiv", + "stationary": "{{label}} ble stasjonær", + "header": { + "zones": "Soner", + "ratio": "Forhold", + "area": "Areal" + } + }, + "annotationSettings": { + "title": "Annoteringsinnstillinger", + "showAllZones": { + "title": "Vis alle soner", + "desc": "Vis alltid soner på bilder der objekter har gått inn i en sone." + }, + "offset": { + "documentation": "Les dokumentasjonen ", + "label": "Annoteringsforskyvning", + "desc": "Disse dataene kommer fra kameraets deteksjonsstrøm, men legges over bilder fra opptaksstrømmen. Det er usannsynlig at de to strømmene er perfekt synkronisert. Som et resultat vil ikke den omsluttende boksen og opptakene stemme perfekt overens. Imidlertid kan feltet annotation_offset brukes til å justere dette.", + "millisecondsToOffset": "Millisekunder å forskyve annoteringsdata. Standard: 0", + "tips": "TIPS: Tenk deg et hendelsesklipp med en person som går fra venstre til høyre. Hvis den omsluttende boksen i hendelsestidslinjen konsekvent er til venstre for personen, bør verdien reduseres. Tilsvarende, hvis en person går fra venstre til høyre og den omsluttende boksen konsekvent er foran personen, bør verdien økes." + } + }, + "carousel": { + "previous": "Forrige lysbilde", + "next": "Neste lysbilde" + }, + "title": "Objektets livssyklus", + "noImageFound": "Ingen bilder funnet for dette tidsstempelet." + }, + "details": { + "item": { + "title": "Detaljer for inspeksjonelement", + "button": { + "share": "Del dette inspeksjonselementet", + "viewInExplore": "Vis i Utforsk" + }, + "toast": { + "success": { + "updatedSublabel": "Under-merkelapp oppdatert med suksess.", + "updatedLPR": "Vellykket oppdatering av kjennemerke.", + "regenerate": "En ny beskrivelse har blitt anmodet fra {{provider}}. Avhengig av hastigheten til leverandøren din, kan den nye beskrivelsen ta litt tid å regenerere." + }, + "error": { + "regenerate": "Feil ved anrop til {{provider}} for en ny beskrivelse: {{errorMessage}}", + "updatedLPRFailed": "Oppdatering av kjennemerke feilet: {{errorMessage}}", + "updatedSublabelFailed": "Feil ved oppdatering av under-merkelapp: {{errorMessage}}" + } + }, + "desc": "Detaljer for inspeksjonselement", + "tips": { + "mismatch_one": "{{count}} utilgjengelig objekt ble oppdaget og inkludert i dette inspeksjonselementet. Disse objektene kvalifiserte ikke som et varsel eller deteksjon, eller har allerede blitt ryddet opp/slettet.", + "mismatch_other": "{{count}} utilgjengelige objekter ble oppdaget og inkludert i dette inspeksjonselementet. Disse objektene kvalifiserte ikke som et varsel eller deteksjon, eller har allerede blitt ryddet opp/slettet.", + "hasMissingObjects": "Juster konfigurasjonen hvis du vil at Frigate skal lagre sporede objekter for følgende merkelapper: {{objects}}" + } + }, + "topScore": { + "info": "Den høyeste poengsummen er den høyeste medianpoengsummen for det sporede objektet, så dette kan avvike fra poengsummen som vises på miniatyrbildet for søkeresultatet.", + "label": "Høyeste poengsum" + }, + "estimatedSpeed": "Estimert hastighet", + "objects": "Objekter", + "button": { + "findSimilar": "Finn lignende", + "regenerate": { + "title": "Regenerer", + "label": "Regenerer beskrivelse for sporet objekt" + } + }, + "description": { + "placeholder": "Beskrivelse av det sporede objektet", + "aiTips": "Frigate vil ikke anmode om en beskrivelse fra din generative AI-leverandør før livssyklusen til det sporede objektet er avsluttet.", + "label": "Beskrivelse" + }, + "regenerateFromThumbnails": "Regenerer fra miniatyrbilder", + "tips": { + "descriptionSaved": "Beskrivelse lagret med suksess", + "saveDescriptionFailed": "Feil ved lagring av beskrivelse: {{errorMessage}}" + }, + "label": "Merkelapp", + "editLPR": { + "title": "Rediger kjennemerke", + "descNoLabel": "Skriv inn et nytt kjennemerke for dette sporede objekt", + "desc": "Skriv inn et nytt kjennemerke for denne {{label}}" + }, + "recognizedLicensePlate": "Gjenkjent kjennemerke", + "camera": "Kamera", + "zones": "Soner", + "timestamp": "Tidsstempel", + "expandRegenerationMenu": "Utvid regenereringsmenyen", + "regenerateFromSnapshot": "Regenerer fra øyeblikksbilde", + "editSubLabel": { + "title": "Rediger under-merkelapp", + "desc": "Skriv inn en ny under-merkelapp for dette {{label}}", + "descNoLabel": "Skriv inn en ny under-merkelapp for dette sporede objektet" + }, + "snapshotScore": { + "label": "Øyeblikksbilde poengsum" + } + }, + "itemMenu": { + "viewInHistory": { + "label": "Vis i Historikk", + "aria": "Vis i Historikk" + }, + "downloadVideo": { + "aria": "Last ned video", + "label": "Last ned video" + }, + "downloadSnapshot": { + "label": "Last ned øyeblikksbilde", + "aria": "Last ned øyeblikksbilde" + }, + "viewObjectLifecycle": { + "label": "Vis objektets livssyklus", + "aria": "Vis objektets livssyklus" + }, + "findSimilar": { + "label": "Finn lignende", + "aria": "Finn lignende sporede objekter" + }, + "deleteTrackedObject": { + "label": "Slett dette sporede objektet" + }, + "submitToPlus": { + "label": "Send til Frigate+", + "aria": "Send til Frigate Plus" + } + }, + "searchResult": { + "deleteTrackedObject": { + "toast": { + "error": "Feil ved sletting av sporet objekt: {{errorMessage}}", + "success": "Sporet objekt ble slettet med suksess." + } + } + }, + "trackedObjectDetails": "Detaljer om sporet objekt", + "type": { + "details": "detaljer", + "snapshot": "øyeblikksbilde", + "video": "video", + "object_lifecycle": "objektets livssyklus" + }, + "dialog": { + "confirmDelete": { + "title": "Bekreft sletting", + "desc": "Sletting av dette sporede objektet fjerner øyeblikksbildet, eventuelle lagrede vektorrepresentasjoner og alle tilknyttede livssykloppføringer for objektet. Opptak av dette sporede objektet i Historikk-visningen vil IKKE bli slettet.

    Er du sikker på at du vil fortsette?" + } + }, + "noTrackedObjects": "Fant ingen sporede objekter", + "fetchingTrackedObjectsFailed": "Feil ved henting av sporede objekter: {{errorMessage}}", + "trackedObjectsCount_one": "{{count}} sporet objekt ", + "trackedObjectsCount_other": "{{count}} sporede objekter " +} diff --git a/web/public/locales/nb-NO/views/exports.json b/web/public/locales/nb-NO/views/exports.json new file mode 100644 index 000000000..2c1fe59a7 --- /dev/null +++ b/web/public/locales/nb-NO/views/exports.json @@ -0,0 +1,17 @@ +{ + "documentTitle": "Eksport - Frigate", + "search": "Søk", + "noExports": "Ingen eksporter funnet", + "deleteExport": "Slett eksport", + "deleteExport.desc": "Er du sikker på at du vil slette {{exportName}}?", + "editExport": { + "title": "Gi nytt navn til eksport", + "desc": "Skriv inn et nytt navn for denne eksporten.", + "saveExport": "Lagre eksport" + }, + "toast": { + "error": { + "renameExportFailed": "Kunne ikke gi nytt navn til eksport: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/nb-NO/views/faceLibrary.json b/web/public/locales/nb-NO/views/faceLibrary.json new file mode 100644 index 000000000..5e7aa3c5f --- /dev/null +++ b/web/public/locales/nb-NO/views/faceLibrary.json @@ -0,0 +1,84 @@ +{ + "selectItem": "Velg {{item}}", + "description": { + "addFace": "Gå gjennom prosessen med å legge til en ny samling i ansiktsbiblioteket.", + "placeholder": "Skriv inn et navn for denne samlingen" + }, + "details": { + "person": "Person", + "confidence": "Konfidens", + "face": "Ansiktsdetaljer", + "faceDesc": "Detaljer for ansiktet og tilknyttet objekt", + "timestamp": "Tidsstempel" + }, + "documentTitle": "Ansiktsbibliotek – Frigate", + "createFaceLibrary": { + "new": "Opprett nytt ansikt", + "title": "Opprett samling", + "desc": "Opprett en ny samling", + "nextSteps": "For å bygge et sterkt grunnlag:
  • Bruk Tren-fanen for å velge og trene på bilder for hver oppdaget person.
  • Fokuser på bilder rett forfra for best resultat; unngå å trene bilder som fanger ansikter i vinkel.
  • " + }, + "train": { + "aria": "Velg tren", + "title": "Tren" + }, + "selectFace": "Velg ansikt", + "deleteFaceLibrary": { + "title": "Slett navn", + "desc": "Er du sikker på at du vil slette samlingen {{name}}? Dette vil permanent slette alle tilknyttede ansikter." + }, + "trainFace": "Tren ansikt", + "toast": { + "error": { + "deleteFaceFailed": "Kunne ikke slette: {{errorMessage}}", + "uploadingImageFailed": "Kunne ikke laste opp bilde: {{errorMessage}}", + "trainFailed": "Kunne ikke trene: {{errorMessage}}", + "updateFaceScoreFailed": "Kunne ikke oppdatere ansiktsskåring: {{errorMessage}}", + "addFaceLibraryFailed": "Kunne ikke angi ansiktsnavn: {{errorMessage}}", + "deleteNameFailed": "Kunne ikke slette navn: {{errorMessage}}", + "renameFaceFailed": "Kunne ikke gi nytt navn til ansikt: {{errorMessage}}" + }, + "success": { + "deletedFace_one": "Slettet {{count}} ansikt.", + "deletedFace_other": "Slettet {{count}} ansikter.", + "deletedName_one": "{{count}} ansikt ble slettet.", + "deletedName_other": "{{count}} ansikter ble slettet.", + "trainedFace": "Ansiktet ble trent.", + "updatedFaceScore": "Ansiktsskåring ble oppdatert.", + "uploadedImage": "Bildet ble lastet opp.", + "addFaceLibrary": "{{name}} ble lagt til i ansiktsbiblioteket!", + "renamedFace": "Nytt navn ble gitt til ansikt {{name}}" + } + }, + "imageEntry": { + "dropActive": "Slipp bildet her…", + "dropInstructions": "Dra og slipp et bilde her, eller klikk for å velge", + "maxSize": "Maks størrelse: {{size}}MB", + "validation": { + "selectImage": "Vennligst velg en bildefil." + } + }, + "readTheDocs": "Les dokumentasjonen", + "button": { + "addFace": "Legg til ansikt", + "uploadImage": "Last opp bilde", + "deleteFaceAttempts": "Slett ansiktsforsøk", + "reprocessFace": "Prosesser ansiktet på nytt", + "deleteFace": "Slett ansikt", + "renameFace": "Gi nytt navn til ansikt" + }, + "uploadFaceImage": { + "desc": "Last opp et bilde for å skanne etter ansikter og inkludere det for {{pageToggle}}", + "title": "Last opp ansiktsbilde" + }, + "trainFaceAs": "Tren ansikt som:", + "steps": { + "faceName": "Skriv inn ansiktsnavn", + "uploadFace": "Last opp ansiktsbilde", + "nextSteps": "Neste trinn" + }, + "renameFace": { + "desc": "Skriv inn et nytt navn for {{name}}", + "title": "Gi nytt navn til ansikt" + } +} diff --git a/web/public/locales/nb-NO/views/live.json b/web/public/locales/nb-NO/views/live.json new file mode 100644 index 000000000..d1d102878 --- /dev/null +++ b/web/public/locales/nb-NO/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "Direkte - Frigate", + "lowBandwidthMode": "Lav båndbreddemodus", + "documentTitle.withCamera": "{{camera}} - Direkte - Frigate", + "ptz": { + "move": { + "clickMove": { + "label": "Klikk i rammen for å sentrere kameraet", + "enable": "Aktiver klikk for å flytte", + "disable": "Deaktiver klikk for å flytte" + }, + "left": { + "label": "Flytt PTZ-kameraet til venstre" + }, + "up": { + "label": "Flytt PTZ-kameraet opp" + }, + "down": { + "label": "Flytt PTZ-kameraet ned" + }, + "right": { + "label": "Flytt PTZ-kameraet til høyre" + } + }, + "presets": "PTZ-kamera forhåndsinnstillinger", + "zoom": { + "in": { + "label": "Zoom inn på PTZ-kameraet" + }, + "out": { + "label": "Zoom ut på PTZ-kameraet" + } + }, + "frame": { + "center": { + "label": "Klikk i rammen for å sentrere PTZ-kameraet" + } + } + }, + "camera": { + "enable": "Aktiver kamera", + "disable": "Deaktiver kamera" + }, + "snapshots": { + "enable": "Aktiver øyeblikksbilder", + "disable": "Deaktiver øyeblikksbilder" + }, + "audioDetect": { + "enable": "Aktiver lydregistrering", + "disable": "Deaktiver lydregistrering" + }, + "autotracking": { + "enable": "Aktiver automatisk sporing", + "disable": "Deaktiver automatisk sporing" + }, + "manualRecording": { + "tips": "Start en manuell hendelse basert på kameraets innstillinger for opptaksbevaring.", + "playInBackground": { + "label": "Spill av i bakgrunnen", + "desc": "Aktiver dette alternativet for å fortsette strømming når spilleren er skjult." + }, + "showStats": { + "label": "Vis statistikk", + "desc": "Aktiver dette alternativet for å vise strømmestatistikk som et overlegg på kamerastrømmen." + }, + "started": "Startet manuelt opptak på forespørsel.", + "end": "Avslutt opptak på forespørsel", + "title": "Opptak på forespørsel", + "debugView": "Feilsøkingsvisning", + "start": "Start opptak på forespørsel", + "failedToStart": "Kunne ikke starte manuelt opptak på forespørsel.", + "recordDisabledTips": "Siden opptak er deaktivert eller begrenset i konfigurasjonen for dette kameraet, vil kun et øyeblikksbilde bli lagret.", + "ended": "Avsluttet manuelt opptak på forespørsel.", + "failedToEnd": "Kunne ikke avslutte manuelt opptak på forespørsel." + }, + "audio": "Lyd", + "suspend": { + "forTime": "Pause i: " + }, + "stream": { + "audio": { + "tips": { + "title": "Lyd må være aktivert på kameraet ditt og konfigurert i go2rtc for denne strømmen.", + "documentation": "Les dokumentasjonen " + }, + "available": "Lyd er tilgjengelig for denne strømmen", + "unavailable": "Lyd er ikke tilgjengelig for denne strømmen" + }, + "twoWayTalk": { + "tips": "Enheten din må støtte funksjonen og WebRTC må være konfigurert for toveis tale.", + "tips.documentation": "Les dokumentasjonen ", + "available": "Toveis tale er tilgjengelig for denne strømmen", + "unavailable": "Toveis tale er ikke tilgjengelig for denne strømmen" + }, + "lowBandwidth": { + "tips": "Direktevisning er i lav båndbreddemodus på grunn av buffering eller strømmefeil.", + "resetStream": "Tilbakestill strøm" + }, + "title": "Strøm", + "playInBackground": { + "label": "Spill av i bakgrunnen", + "tips": "Aktiver dette alternativet for å fortsette strømming når spilleren er skjult." + } + }, + "history": { + "label": "Vis historiske opptak" + }, + "effectiveRetainMode": { + "modes": { + "all": "Alle", + "motion": "Bevegelse", + "active_objects": "Aktive objekter" + }, + "notAllTips": "Konfigurasjonen for opptaksbevaring for {{source}} er satt til mode: {{effectiveRetainMode}}, så dette manuelle opptaket vil kun beholde segmenter med {{effectiveRetainModeName}}." + }, + "editLayout": { + "label": "Rediger oppsett", + "group": { + "label": "Rediger kameragruppe" + }, + "exitEdit": "Avslutt redigering" + }, + "twoWayTalk": { + "enable": "Aktiver toveis tale", + "disable": "Deaktiver toveis tale" + }, + "cameraAudio": { + "enable": "Aktiver kameralyd", + "disable": "Deaktiver kameralyd" + }, + "muteCameras": { + "enable": "Demp alle kameraer", + "disable": "Slå på lyd på alle kameraer" + }, + "detect": { + "enable": "Aktiver deteksjon", + "disable": "Deaktiver deteksjon" + }, + "recording": { + "enable": "Aktiver opptak", + "disable": "Deaktiver opptak" + }, + "streamStats": { + "enable": "Vis Strømmestatistikk", + "disable": "Skjul strømmestatistikk" + }, + "streamingSettings": "Strømmingsinnstillinger", + "notifications": "Meldingsvarsler", + "cameraSettings": { + "title": "{{camera}}-innstillinger", + "cameraEnabled": "Kamera aktivert", + "objectDetection": "Objektdeteksjon", + "recording": "Opptak", + "snapshots": "Øyeblikksbilder", + "audioDetection": "Lydregistrering", + "autotracking": "Automatisk sporing" + } +} diff --git a/web/public/locales/nb-NO/views/recording.json b/web/public/locales/nb-NO/views/recording.json new file mode 100644 index 000000000..262eb43b0 --- /dev/null +++ b/web/public/locales/nb-NO/views/recording.json @@ -0,0 +1,12 @@ +{ + "filter": "Filter", + "export": "Eksporter", + "calendar": "Kalender", + "filters": "Filtre", + "toast": { + "error": { + "noValidTimeSelected": "Ingen gyldig tidsperiode valgt", + "endTimeMustAfterStartTime": "Sluttid må være etter starttid" + } + } +} diff --git a/web/public/locales/nb-NO/views/search.json b/web/public/locales/nb-NO/views/search.json new file mode 100644 index 000000000..baf25a900 --- /dev/null +++ b/web/public/locales/nb-NO/views/search.json @@ -0,0 +1,74 @@ +{ + "search": "Søk", + "savedSearches": "Lagrede søk", + "searchFor": "Søk etter {{inputValue}}", + "button": { + "clear": "Fjern søk", + "save": "Lagre søk", + "delete": "Slett lagret søk", + "filterInformation": "Filterinformasjon", + "filterActive": "Filtre aktive" + }, + "filter": { + "label": { + "cameras": "Kameraer", + "labels": "Merkelapper", + "search_type": "Søketype", + "after": "Etter", + "min_score": "Min. poengsum", + "max_score": "Maks. poengsum", + "min_speed": "Min. hastighet", + "zones": "Soner", + "sub_labels": "Under-merkelapper", + "time_range": "Tidsintervall", + "before": "Før", + "max_speed": "Maks. hastighet", + "recognized_license_plate": "Gjenkjent kjennemerke", + "has_clip": "Har videoklipp", + "has_snapshot": "Har øyeblikksbilde" + }, + "searchType": { + "thumbnail": "Miniatyrbilde", + "description": "Beskrivelse" + }, + "toast": { + "error": { + "minSpeedMustBeLessOrEqualMaxSpeed": "Minimum hastighet 'min_speed' må være mindre enn eller lik maksimum hastighet 'max_speed'.", + "beforeDateBeLaterAfter": "Før-datoen 'before' må være senere enn etter-datoen 'after'.", + "afterDatebeEarlierBefore": "Etter-datoen 'after' må være tidligere enn før-datoen 'before'.", + "minScoreMustBeLessOrEqualMaxScore": "Minimum poengsum 'min_score' må være mindre enn eller lik maksimum poengsum 'max_score'.", + "maxScoreMustBeGreaterOrEqualMinScore": "Maksimum poengsum 'max_score' må være større enn eller lik minimum poengsum 'min_score'.", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "Maksimum hastighet 'max_speed' må være større enn eller lik minimum hastighet 'min_speed'." + } + }, + "tips": { + "title": "Hvordan bruke tekstfiltre", + "desc": { + "text": "Filtre hjelper deg med å begrense søkeresultatene dine. Slik bruker du dem i inndatafeltet:", + "example": "Eksempel: cameras:inngangsdør label:person before:01012024 time_range:3:00PM-4:00PM ", + "step": "
    • Skriv inn et filternavn etterfulgt av et kolon (f.eks. \"cameras:\").
    • Velg en verdi fra forslagene eller skriv inn din egen.
    • Bruk flere filtre ved å legge dem til etter hverandre med mellomrom imellom.
    • Dato-filtre (before: og after:) bruker {{DateFormat}}-formatet.
    • Tidsintervall-filteret bruker {{exampleTime}}-formatet.
    • Fjern filtre ved å klikke på 'x' ved siden av dem.
    ", + "step2": "Velg en verdi fra forslagene eller skriv inn din egen.", + "step4": "Dato-filtre (before: and after:) bruker {{DateFormat}} format.", + "step5": "Tidsintervall-filter bruker {{exampleTime}} format.", + "step6": "Fjern filtre ved å klikke på 'x'en ved siden av dem.", + "exampleLabel": "Eksempel:", + "step1": "Skriv inn et filter-nøkkelnavn etterfulgt av et kolon (f.eks \"cameras:\").", + "step3": "Bruk flere filtre ved å legge dem til en etter en, med mellomrom." + } + }, + "header": { + "currentFilterType": "Filterverdier", + "noFilters": "Filtre", + "activeFilters": "Aktive filtre" + } + }, + "placeholder": { + "search": "Søk…" + }, + "trackedObjectId": "Sporings-ID for objekt", + "similaritySearch": { + "title": "Søk etter likhet", + "active": "Søk etter likhet er aktivt", + "clear": "Fjern søk etter likhet" + } +} diff --git a/web/public/locales/nb-NO/views/settings.json b/web/public/locales/nb-NO/views/settings.json new file mode 100644 index 000000000..a68f765f8 --- /dev/null +++ b/web/public/locales/nb-NO/views/settings.json @@ -0,0 +1,597 @@ +{ + "documentTitle": { + "default": "Innstillinger - Frigate", + "authentication": "Autentiseringsinnstillinger - Frigate", + "camera": "Kamerainnstillinger - Frigate", + "masksAndZones": "Maske- og soneeditor - Frigate", + "motionTuner": "Bevegelsesjustering - Frigate", + "object": "Test og feilsøk - Frigate", + "general": "Generelle innstillinger - Frigate", + "classification": "Klassifiseringsinnstillinger - Frigate", + "frigatePlus": "Frigate+ innstillinger - Frigate", + "notifications": "Meldingsvarsler Innstillinger - Frigate" + }, + "menu": { + "classification": "Klassifisering", + "cameras": "Kamerainnstillinger", + "masksAndZones": "Masker / Soner", + "motionTuner": "Finjustering av bevegelse", + "debug": "Test og feilsøk", + "users": "Brukere", + "frigateplus": "Frigate+", + "ui": "Brukergrensesnitt", + "notifications": "Meldingsvarsler" + }, + "dialog": { + "unsavedChanges": { + "title": "Du har ulagrede endringer.", + "desc": "Vil du lagre endringene dine før du fortsetter?" + } + }, + "cameraSetting": { + "camera": "Kamera", + "noCamera": "Ingen kamera" + }, + "general": { + "liveDashboard": { + "playAlertVideos": { + "label": "Spill av varselvideoer", + "desc": "Som standard vises nylige varsler på Direkte-dashbord som små videoer som gjentas. Deaktiver dette alternativet for kun å vise et statisk bilde av nylige varsler på denne enheten/nettleseren." + }, + "title": "Direkte-dashbord", + "automaticLiveView": { + "label": "Automatisk direktevisning", + "desc": "Bytt automatisk til et kameras direktevisning når aktivitet oppdages. Deaktivering av dette valget gjør at statiske kamerabilder i Direkte-dashbord kun oppdateres én gang i minuttet." + } + }, + "storedLayouts": { + "title": "Lagrede oppsett", + "desc": "Kameraplasseringer i en gruppe kan dras og endres. Posisjonene lagres lokalt i nettleseren.", + "clearAll": "Fjern alle oppsett" + }, + "recordingsViewer": { + "title": "Opptaksvisning", + "defaultPlaybackRate": { + "label": "Standard avspillingshastighet", + "desc": "Standard hastighet for avspilling av opptak." + } + }, + "calendar": { + "firstWeekday": { + "sunday": "Søndag", + "label": "Første ukedag", + "desc": "Dagen ukene starter på i inspeksjonskalenderen.", + "monday": "Mandag" + }, + "title": "Kalender" + }, + "toast": { + "success": { + "clearStreamingSettings": "Strømmingsinnstillinger for alle kameragrupper ble fjernet.", + "clearStoredLayout": "Lagret oppsett for {{cameraName}} ble fjernet" + }, + "error": { + "clearStoredLayoutFailed": "Kunne ikke fjerne lagret oppsett: {{errorMessage}}", + "clearStreamingSettingsFailed": "Kunne ikke fjerne strømmingsinnstillinger: {{errorMessage}}" + } + }, + "title": "Generelle innstillinger", + "cameraGroupStreaming": { + "title": "Strømmingsinnstillinger for kameragrupper", + "desc": "Strømmingsinnstillingene lagres lokalt i nettleseren.", + "clearAll": "Fjern alle strømmingsinnstillinger" + } + }, + "classification": { + "semanticSearch": { + "title": "Semantisk søk", + "desc": "Semantisk søk i Frigate lar deg finne sporede objekter i inspeksjonselementene ved hjelp av enten bildet, en egendefinert tekstbeskrivelse eller en automatisk generert beskrivelse.", + "reindexNow": { + "confirmTitle": "Bekreft reindeksering", + "error": "Kunne ikke starte reindeksering: {{errorMessage}}", + "label": "Reindekser nå", + "confirmButton": "Reindekser", + "success": "Reindeksering startet.", + "alreadyInProgress": "Reindeksering pågår allerede.", + "desc": "Reindeksering vil regenerere vektorrepresentasjoner for alle sporede objekter. Prosessen kjøres i bakgrunnen, kan belaste CPU-en maksimalt og ta mye tid avhengig av antall sporede objekter.", + "confirmDesc": "Er du sikker på at du vil reindeksere vektorrepresentasjoner for alle sporede objekter? Dette vil kjøres i bakgrunnen, men kan bruke all CPU og ta tid. Du kan følge fremdriften på Utforsk-siden." + }, + "readTheDocumentation": "Les dokumentasjonen", + "modelSize": { + "label": "Modellstørrelse", + "small": { + "title": "liten", + "desc": "Ved å bruke liten brukes en kvantisert modell som bruker mindre RAM og er raskere, med ubetydelig tap av kvalitet for vektorrepresentasjoner." + }, + "large": { + "title": "stor", + "desc": "Ved å bruke stor brukes hele Jina-modellen og den vil automatisk bruke GPU hvis tilgjengelig." + }, + "desc": "Størrelsen på modellen som brukes for vektorrepresentasjoner for semantiske søk." + } + }, + "faceRecognition": { + "title": "Ansiktsgjenkjenning", + "modelSize": { + "small": { + "title": "liten", + "desc": "Liten bruker en FaceNet-modell for vektorrepresentasjoner som fungerer effektivt på de fleste CPU-er." + }, + "large": { + "title": "stor", + "desc": "Stor bruker en ArcFace-modell for vektorrepresentasjoner og vil automatisk kjøre på GPU hvis tilgjengelig." + }, + "label": "Modellstørrelse", + "desc": "Størrelsen på modellen brukt for ansiktsgjenkjenning." + }, + "readTheDocumentation": "Les dokumentasjonen", + "desc": "Ansiktsgjenkjenning lar deg tilordne navn til personer. Når et ansikt gjenkjennes, legges navnet til som under-merkelapp. Denne informasjonen vises i brukergrensesnittet, i filtre, samt i meldingsvarsler." + }, + "licensePlateRecognition": { + "title": "Gjenkjenning av kjennemerker", + "readTheDocumentation": "Les dokumentasjonen", + "desc": "Frigate kan gjenkjenne kjennemerker og automatisk legge inn tall/bokstaver i 'recognized_license_plate'-feltet, eller et kjent navn som under-merkelapp til objekter av typen bil. Vanlig bruk er å lese kjennemerker ved innkjørsel eller på vei." + }, + "title": "Klassifiseringsinnstillinger", + "toast": { + "success": "Klassifiseringsinnstillinger lagret. Start Frigate på nytt for å bruke endringene.", + "error": "Kunne ikke lagre konfigurasjonsendringer: {{errorMessage}}" + }, + "birdClassification": { + "title": "Artsbestemmelse for fugler", + "desc": "Artsbestemmelse identifiserer kjente fugler ved hjelp av en kvantisert TensorFlow-modell. Når en kjent fugl gjenkjennes, legges det vanlige navnet til som en under-merkelapp. Denne informasjonen vises i brukergrensesnittet, i filtre, samt i meldingsvarsler." + }, + "restart_required": "Omstart påkrevd (Klassifiseringsinnstillinger endret)" + }, + "camera": { + "streams": { + "desc": "Deaktivering av et kamera stopper Frigates behandling av dette kameraets strømmer fullstendig. Deteksjon, opptak og feilsøking vil være utilgjengelig.
    Merk: Dette deaktiverer ikke go2rtc-restrømming.", + "title": "Strømmer" + }, + "reviewClassification": { + "title": "Inspeksjonssklassifisering", + "zoneObjectAlertsTips": "Alle {{alertsLabels}}-objekter oppdaget i {{zone}} på {{cameraName}} vises som varsler.", + "zoneObjectDetectionsTips": { + "text": "Alle {{detectionsLabels}}-objekter som ikke er kategorisert i {{zone}} på {{cameraName}}, vises som deteksjoner.", + "regardlessOfZoneObjectDetectionsTips": "Alle {{detectionsLabels}}-objekter som ikke er kategorisert på {{cameraName}}, vises som deteksjoner uavhengig av sone.", + "notSelectDetections": "Alle {{detectionsLabels}}-objekter oppdaget i {{zone}} på {{cameraName}} som ikke er kategorisert som Varsler, vises som deteksjoner uavhengig av sone." + }, + "selectAlertsZones": "Velg soner for varsler", + "desc": "Frigate kategoriserer inspeksjonselementer som Varsler og Deteksjoner. Som standard regnes alle person- og bil-objekter som Varsler. Du kan finjustere klassifiseringen ved å konfigurere nødvendige soner.", + "readTheDocumentation": "Les dokumentasjonen", + "noDefinedZones": "Ingen soner er definert for dette kameraet.", + "objectAlertsTips": "Alle {{alertsLabels}}-objekter på {{cameraName}} vises som varsler.", + "objectDetectionsTips": "Alle {{detectionsLabels}}-objekter som ikke er kategorisert på {{cameraName}}, vises som deteksjoner uavhengig av sone.", + "selectDetectionsZones": "Velg soner for deteksjoner", + "limitDetections": "Avgrens deteksjoner til bestemte soner", + "toast": { + "success": "Konfigurasjon for inspeksjonsklassifisering er lagret. Start Frigate på nytt for å bruke endringer." + } + }, + "title": "Kamerainnstillinger", + "review": { + "title": "Inspeksjon", + "desc": "Aktiver/deaktiver varsler og deteksjoner for dette kameraet. Når deaktivert, vil det ikke genereres nye inspeksjonselementer.", + "alerts": "Varsler ", + "detections": "Deteksjoner " + } + }, + "masksAndZones": { + "filter": { + "all": "Alle masker og soner" + }, + "toast": { + "success": { + "copyCoordinates": "Koordinater for {{polyName}} kopiert til utklippstavlen." + }, + "error": { + "copyCoordinatesFailed": "Kunne ikke kopiere koordinater til utklippstavlen." + } + }, + "form": { + "zoneName": { + "error": { + "mustNotBeSameWithCamera": "Sonenavnet kan ikke være det samme som kameranavnet.", + "alreadyExists": "En sone med dette navnet finnes allerede for dette kameraet.", + "mustBeAtLeastTwoCharacters": "Sonenavnet må være minst 2 tegn langt.", + "mustNotContainPeriod": "Sonenavnet kan ikke inneholde punktum.", + "hasIllegalCharacter": "Sonenavnet inneholder ugyldige tegn." + } + }, + "distance": { + "error": { + "mustBeFilled": "Alle avstandsfeltene må fylles ut for å bruke hastighetsestimering.", + "text": "Avstanden må være større enn eller lik 0,1." + } + }, + "polygonDrawing": { + "delete": { + "title": "Bekreft sletting", + "desc": "Er du sikker på at du vil slette {{type}} {{name}}?", + "success": "{{name}} har blitt slettet." + }, + "removeLastPoint": "Fjern siste punkt", + "reset": { + "label": "Fjern alle punkter" + }, + "snapPoints": { + "true": "Fest punkter", + "false": "Ikke fest punkter" + }, + "error": { + "mustBeFinished": "Tegningen av polygonet må fullføres før lagring." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "Treghet må være over 0." + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "Oppholdstid må være større enn eller lik 0." + } + } + }, + "zones": { + "label": "Soner", + "documentTitle": "Rediger sone - Frigate", + "edit": "Rediger sone", + "point_one": "{{count}} punkt", + "point_other": "{{count}} punkter", + "clickDrawPolygon": "Klikk for å tegne et polygon på bildet.", + "inertia": { + "title": "Treghet", + "desc": "Angir hvor mange bilder et objekt må være i en sone før det regnes som en del av sonen. Standard: 3" + }, + "desc": { + "title": "Soner lar deg definere et spesifikt område i bildet, slik at du kan bestemme om et objekt er innenfor et bestemt område.", + "documentation": "Dokumentasjon" + }, + "add": "Legg til sone", + "name": { + "title": "Navn", + "inputPlaceHolder": "Skriv inn et navn…", + "tips": "Navnet må være minst 2 tegn langt og må ikke være det samme som et kamera- eller sone-navn." + }, + "loiteringTime": { + "title": "Oppholdstid", + "desc": "Setter minimumstid i sekunder som objektet må være i sonen for at den skal aktiveres. Standard: 0" + }, + "objects": { + "title": "Objekter", + "desc": "Liste over objekter som gjelder for denne sonen." + }, + "allObjects": "Alle objekter", + "speedEstimation": { + "title": "Hastighetsestimering", + "desc": "Aktiver hastighetsestimering for objekter i denne sonen. Sonen må ha nøyaktig 4 punkter." + }, + "speedThreshold": { + "title": "Hastighetsgrense ({{unit}})", + "desc": "Angir en minimumshastighet for objekter for at de skal anses som en del av denne sonen.", + "toast": { + "error": { + "pointLengthError": "Hastighetsestimering er deaktivert for denne sonen. Soner med hastighetsestimering må ha nøyaktig 4 punkter.", + "loiteringTimeError": "Soner med oppholdstider større enn 0 bør ikke brukes til hastighetsestimering." + } + } + }, + "toast": { + "success": "Sone ({{zoneName}}) er lagret. Start Frigate på nytt for å bruke endringer." + } + }, + "motionMasks": { + "label": "Bevegelsesmasker", + "desc": { + "documentation": "Dokumentasjon", + "title": "Bevegelsesmasker brukes til å hindre uønsket type bevegelse fra å utløse deteksjon. For mye maskering kan gjøre det vanskeligere å spore objekter." + }, + "add": "Ny bevegelsesmaske", + "documentTitle": "Rediger bevegelsesmaske - Frigate", + "edit": "Rediger bevegelsesmaske", + "context": { + "title": "Bevegelsesmasker brukes til å hindre uønsket type bevegelse fra å utløse deteksjon (eksempel: tregrener, kameratidsstempler). Bevegelsesmasker bør brukes svært sparsomt, for mye maskering vil gjøre det vanskeligere å spore objekter.", + "documentation": "Les dokumentasjonen" + }, + "point_one": "{{count}} punkt", + "point_other": "{{count}} punkter", + "clickDrawPolygon": "Klikk for å tegne et polygon på bildet.", + "polygonAreaTooLarge": { + "title": "Bevegelsesmasken dekker {{polygonArea}}% av kameraets bilde. Store bevegelsesmasker anbefales ikke.", + "tips": "Bevegelsesmasker hindrer ikke objektene fra å bli detektert. Du bør bruke en påkrevd sone i stedet.", + "documentation": "Les dokumentasjonen" + }, + "toast": { + "success": { + "title": "{{polygonName}} er lagret. Start Frigate på nytt for å bruke endringene.", + "noName": "Bevegelsesmasken er lagret. Start Frigate på nytt for å bruke endringene." + } + } + }, + "objectMasks": { + "clickDrawPolygon": "Klikk for å tegne et polygon på bildet.", + "point_one": "{{count}} punkt", + "point_other": "{{count}} punkter", + "label": "Objektmasker", + "documentTitle": "Rediger objektmaske - Frigate", + "desc": { + "title": "Objektfiltermasker brukes for å filtrere ut falske positiver for en gitt objekttype basert på plassering.", + "documentation": "Dokumentasjon" + }, + "add": "Legg til objektmaske", + "edit": "Rediger objektmaske", + "context": "Objektfiltermasker brukes for å filtrere ut falske positiver for en gitt objekttype basert på plassering.", + "objects": { + "title": "Objekter", + "desc": "Objekttypen som gjelder for denne objektmasken.", + "allObjectTypes": "Alle objekttyper" + }, + "toast": { + "success": { + "title": "{{polygonName}} er lagret. Start Frigate på nytt for å bruke endringene.", + "noName": "Objektmasken er lagret. Start Frigate på nytt for å bruke endringene." + } + } + }, + "restart_required": "Omstart påkrevd (masker/soner endret)" + }, + "motionDetectionTuner": { + "title": "Finjustering av bevegelsesdeteksjon", + "Threshold": { + "title": "Terskel", + "desc": "Terskelverdien bestemmer hvor mye endring i en piksels lysstyrke som kreves for å bli betraktet som bevegelse. Standard: 30" + }, + "contourArea": { + "title": "Konturområde", + "desc": "Konturområdets verdi brukes til å bestemme hvilke grupper av endrede piksler som kvalifiserer som bevegelse. Standard: 10" + }, + "improveContrast": { + "desc": "Forbedre kontrasten for mørkere scener. Standard: PÅ", + "title": "Forbedre kontrast" + }, + "desc": { + "title": "Frigate bruker bevegelsesdeteksjon som en første sjekk for å se om det skjer noe i bildet som er verdt å sjekke med objektdeteksjon.", + "documentation": "Les guiden for bevegelsesjustering" + }, + "toast": { + "success": "Bevegelsesinnstillingene er lagret." + } + }, + "debug": { + "title": "Test og feilsøking", + "objectList": "Objektliste", + "noObjects": "Ingen objekter", + "boundingBoxes": { + "title": "Omsluttende bokser", + "desc": "Vis omsluttende bokser rundt sporede objekter", + "colors": { + "label": "Farge på omsluttende bokser for objekt", + "info": "
  • Ved oppstart vil forskjellige farger bli tildelt hver objekttype
  • En mørkeblå tynn linje indikerer at objektet ikke er detektert på dette tidspunktet
  • En grå tynn linje indikerer at objektet er detektert som stasjonært
  • En tykk linje indikerer at objektet er under autosporing (når aktivert)
  • " + } + }, + "timestamp": { + "title": "Tidsstempel", + "desc": "Legg et tidsstempel over bildet" + }, + "zones": { + "title": "Soner", + "desc": "Vis en kontur av alle definerte soner" + }, + "motion": { + "desc": "Vis bokser rundt områder der bevegelse er detektert", + "tips": "

    Bevegelsesbokser


    Røde bokser vil vises på områder i bildet hvor bevegelse for øyeblikket blir detektert

    ", + "title": "Bevegelsesbokser" + }, + "regions": { + "tips": "

    Regionbokser


    Lysegrønne bokser vil vises på områder av interesse i bildet som blir sendt til objektdetektoren.

    ", + "title": "Regioner", + "desc": "Vis en boks for interesseområdet sendt til objektdetektoren" + }, + "objectShapeFilterDrawing": { + "document": "Les dokumentasjonen ", + "score": "Poengsum", + "ratio": "Forhold", + "area": "Område", + "title": "Tegning av objektformfilter", + "desc": "Tegn et rektangel på bildet for å vise areal- og størrelsesforhold", + "tips": "Aktiver dette alternativet for å tegne et rektangel på kamerabildet for å vise området og forholdet. Disse verdiene kan deretter brukes til å sette filterparametere for objektform i konfigurasjonen." + }, + "detectorDesc": "Frigate bruker dine detektorer ({{detectors}}) for å oppdage objekter i kameraets videostrøm.", + "desc": "Test og feilsøk viser sporede objekter i sanntid og deres statistikk. Objektlisten viser en tidsforsinket oppsummering av detekterte objekter.", + "debugging": "Test og feilsøk", + "mask": { + "title": "Bevegelsesmasker", + "desc": "Vis polygoner for bevegelsesmasker" + } + }, + "users": { + "title": "Brukere", + "management": { + "title": "Brukeradministrasjon", + "desc": "Administrer brukerprofiler for denne Frigate-instansen." + }, + "addUser": "Legg til bruker", + "updatePassword": "Oppdater passord", + "toast": { + "success": { + "deleteUser": "Bruker {{user}} ble slettet", + "updatePassword": "Passordet ble oppdatert.", + "createUser": "Bruker {{user}} ble opprettet", + "roleUpdated": "Rolle oppdatert for {{user}}" + }, + "error": { + "deleteUserFailed": "Kunne ikke slette bruker: {{errorMessage}}", + "setPasswordFailed": "Kunne ikke lagre passord: {{errorMessage}}", + "createUserFailed": "Kunne ikke opprette bruker: {{errorMessage}}", + "roleUpdateFailed": "Kunne ikke oppdatere rolle: {{errorMessage}}" + } + }, + "dialog": { + "form": { + "user": { + "placeholder": "Skriv inn brukernavn", + "title": "Brukernavn", + "desc": "Bare bokstaver, tall, punktum og understreker tillatt." + }, + "password": { + "title": "Passord", + "placeholder": "Skriv inn passord", + "confirm": { + "placeholder": "Bekreft passord", + "title": "Bekreft passord" + }, + "strength": { + "title": "Passordstyrke: ", + "veryStrong": "Veldig sterkt", + "weak": "Svakt", + "medium": "Medium", + "strong": "Sterkt" + }, + "match": "Passordene samsvarer", + "notMatch": "Passordene samsvarer ikke" + }, + "newPassword": { + "title": "Nytt passord", + "placeholder": "Skriv inn nytt passord", + "confirm": { + "placeholder": "Skriv inn nytt passord igjen" + } + }, + "usernameIsRequired": "Brukernavn er påkrevd" + }, + "changeRole": { + "desc": "Oppdater tillatelser for {{username}}", + "title": "Endre brukerrolle", + "roleInfo": { + "intro": "Velg en passende rolle for denne bruker:", + "admin": "Administrator", + "adminDesc": "Full tilgang til alle funksjoner.", + "viewer": "Visningsbruker", + "viewerDesc": "Begrenset til kun Direkte-dashbord, Inspiser, Utforsk og Eksporter." + } + }, + "createUser": { + "title": "Opprett ny bruker", + "desc": "Legg til en ny brukerkonto og spesifiser en rolle for tilgang til Frigate-brukergrensesnittet.", + "usernameOnlyInclude": "Brukernavn kan bare inneholde bokstaver, tall, punktum eller _" + }, + "deleteUser": { + "title": "Slett bruker", + "desc": "Denne handlingen kan ikke angres. Dette vil permanent slette brukerkontoen og fjerne alle tilknyttede data.", + "warn": "Er du sikker på at du vil slette {{username}}?" + }, + "passwordSetting": { + "updatePassword": "Oppdater passord for {{username}}", + "setPassword": "Angi passord", + "desc": "Opprett et sterkt passord for å sikre denne kontoen." + } + }, + "table": { + "username": "Brukernavn", + "actions": "Handlinger", + "role": "Rolle", + "changeRole": "Endre brukerrolle", + "password": "Passord", + "deleteUser": "Slett bruker", + "noUsers": "Ingen brukere funnet." + } + }, + "notification": { + "notificationSettings": { + "desc": "Frigate kan sende push-varsler til enheten din når den kjører i nettleseren eller er installert som en progressiv webapplikasjon (PWA).", + "documentation": "Les dokumentasjonen", + "title": "Innstillinger for meldingsvarsler" + }, + "notificationUnavailable": { + "documentation": "Les dokumentasjonen", + "title": "Meldingsvarsler utilgjengelig", + "desc": "Nettleser push-varsler krever et sikkert miljø (https://…). Dette er en nettleserbegrensning. Få tilgang til Frigate på en sikker måte for å bruke meldingsvarsler." + }, + "email": { + "title": "E-post", + "placeholder": "f.eks. eksempel@email.com", + "desc": "En gyldig e-postadresse kreves og vil bli brukt til å varsle deg om det skulle oppstå problemer med push-tjenesten." + }, + "cameras": { + "title": "Kameraer", + "noCameras": "Ingen kameraer tilgjengelig", + "desc": "Velg hvilke kameraer meldingsvarsler skal aktiveres for." + }, + "deviceSpecific": "Enhetsspesifikke innstillinger", + "registerDevice": "Registrer denne enheten", + "unregisterDevice": "Fjern registrering av enheten", + "suspendTime": { + "5minutes": "Suspender i 5 minutter", + "10minutes": "Suspender i 10 minutter", + "30minutes": "Suspender i 30 minutter", + "1hour": "Suspender i 1 time", + "12hours": "Suspender i 12 timer", + "24hours": "Suspender i 24 timer", + "untilRestart": "Suspender til omstart", + "suspend": "Suspender" + }, + "suspended": "Meldingsvarsler suspendert {{time}}", + "toast": { + "success": { + "registered": "Registrering for meldingsvarsler var vellykket. En omstart av Frigate er nødvendig før noen meldingsvarsler (inkludert et testvarsel) kan sendes.", + "settingSaved": "Innstillinger for meldingsvarsler er lagret." + }, + "error": { + "registerFailed": "Kunne ikke lagre registrering for meldingsvarsler." + } + }, + "globalSettings": { + "title": "Globale innstillinger", + "desc": "Midlertidig suspender meldingsvarsler for spesifikke kameraer på alle registrerte enheter." + }, + "cancelSuspension": "Avbryt suspensjon", + "title": "Meldingsvarsler", + "sendTestNotification": "Send en meldingsvarsel for test", + "active": "Meldingsvarsler aktivert" + }, + "frigatePlus": { + "apiKey": { + "notValidated": "Frigate+ API-nøkkel er ikke detektert eller validert", + "title": "Frigate+ API-nøkkel", + "validated": "Frigate+ API-nøkkel er detektert og validert", + "desc": "Frigate+ API-nøkkelen muliggjør integrasjon med Frigate+ tjenesten.", + "plusLink": "Les mer om Frigate+" + }, + "modelInfo": { + "trainDate": "Treningsdato", + "baseModel": "Basismodell", + "loading": "Laster modellinformasjon…", + "error": "Kunne ikke laste modellinformasjon", + "loadingAvailableModels": "Laster tilgjengelige modeller…", + "title": "Modellinformasjon", + "modelType": "Modelltype", + "supportedDetectors": "Støttede detektorer", + "dimensions": "Dimensjoner", + "cameras": "Kameraer", + "availableModels": "Tilgjengelige modeller", + "modelSelect": "Dine tilgjengelige modeller på Frigate+ kan velges her. Merk at bare modeller som er kompatible med din nåværende detektorkonfigurasjon kan velges.", + "plusModelType": { + "userModel": "Finjustert", + "baseModel": "Basismodell" + } + }, + "title": "Frigate+ Innstillinger", + "snapshotConfig": { + "title": "Konfigurasjon av øyeblikksbilde", + "desc": "Innsending til Frigate+ krever at både øyeblikksbilder og clean_copy-øyeblikksbilder er aktivert i konfigurasjonen din.", + "documentation": "Les dokumentasjonen", + "table": { + "camera": "Kamera", + "snapshots": "Øyeblikksbilder", + "cleanCopySnapshots": "clean_copy-øyeblikksbilder" + }, + "cleanCopyWarning": "Noen kameraer har øyeblikksbilder aktivert, men ren kopi er deaktivert. Du må aktivere clean_copy i øyeblikksbilde-konfigurasjonen for å kunne sende bilder fra disse kameraene til Frigate+." + }, + "toast": { + "success": "Frigate+ innstillingene er lagret. Start Frigate på nytt for å bruke endringene.", + "error": "Kunne ikke lagre konfigurasjonsendringer: {{errorMessage}}" + }, + "restart_required": "Omstart påkrevd (Frigate+ modell endret)" + } +} diff --git a/web/public/locales/nb-NO/views/system.json b/web/public/locales/nb-NO/views/system.json new file mode 100644 index 000000000..31d8d0183 --- /dev/null +++ b/web/public/locales/nb-NO/views/system.json @@ -0,0 +1,179 @@ +{ + "documentTitle": { + "cameras": "Kamerastatistikk - Frigate", + "storage": "Lagringsstatistikk - Frigate", + "logs": { + "frigate": "Frigate-logger - Frigate", + "go2rtc": "Go2RTC-logger - Frigate", + "nginx": "Nginx-logger - Frigate" + }, + "general": "Generell statistikk - Frigate", + "enrichments": "Statistikk for utvidelser - Frigate" + }, + "logs": { + "copy": { + "success": "Logger kopiert til utklippstavlen", + "error": "Kunne ikke kopiere logger til utklippstavlen", + "label": "Kopier til utklippstavle" + }, + "type": { + "label": "Type", + "timestamp": "Tidsstempel", + "tag": "Merke", + "message": "Melding" + }, + "toast": { + "error": { + "fetchingLogsFailed": "Feil ved henting av logger: {{errorMessage}}", + "whileStreamingLogs": "Feil under strømming av logger: {{errorMessage}}" + } + }, + "download": { + "label": "Last ned logger" + }, + "tips": "Logger strømmer fra serveren" + }, + "general": { + "title": "Generelt", + "detector": { + "inferenceSpeed": "Detektor inferenshastighet", + "title": "Detektorer", + "cpuUsage": "Detektor CPU-belastning", + "memoryUsage": "Detektor minnebruk", + "temperature": "Detektor temperatur" + }, + "hardwareInfo": { + "gpuMemory": "GPU-minne", + "gpuEncoder": "GPU-enkoder", + "gpuDecoder": "GPU-dekoder", + "gpuInfo": { + "nvidiaSMIOutput": { + "driver": "Driver: {{driver}}", + "cudaComputerCapability": "CUDA beregningsevne: {{cuda_compute}}", + "vbios": "VBios-info: {{vbios}}", + "title": "Nvidia SMI-utdata", + "name": "Navn: {{name}}" + }, + "copyInfo": { + "label": "Kopier GPU-informasjon" + }, + "toast": { + "success": "GPU-informasjon kopiert til utklippstavlen" + }, + "vainfoOutput": { + "title": "Vainfo-utdata", + "returnCode": "Returkode: {{code}}", + "processOutput": "Prosessutdata:", + "processError": "Prosessfeil:" + }, + "closeInfo": { + "label": "Lukk GPU-informasjon" + } + }, + "title": "Maskinvareinformasjon", + "gpuUsage": "GPU-belastning", + "npuMemory": "NPU minne", + "npuUsage": "NPU belastning" + }, + "otherProcesses": { + "title": "Andre prosesser", + "processCpuUsage": "Prosessenes CPU-belastning", + "processMemoryUsage": "Prosessenes minnebruk" + } + }, + "storage": { + "overview": "Oversikt", + "recordings": { + "earliestRecording": "Tidligste opptak tilgjengelig:", + "title": "Opptak", + "tips": "Denne verdien representerer total lagringsplass brukt av opptakene i Frigates database. Frigate sporer ikke lagringsbruk for alle filer på disken din." + }, + "cameraStorage": { + "storageUsed": "Lagringsbruk", + "bandwidth": "Båndbredde", + "title": "Kameralagring", + "camera": "Kamera", + "unusedStorageInformation": "Ubrukt lagringsinformasjon", + "percentageOfTotalUsed": "Prosentandel av tilgjengelig", + "unused": { + "title": "Ubrukt", + "tips": "Denne verdien representerer kanskje ikke nøyaktig den ledige plassen Frigate har tilgang til, dersom det finnes andre filer lagret på disken. Frigate sporer kun lagring brukt av egne opptak." + } + }, + "title": "Lagring" + }, + "cameras": { + "info": { + "codec": "Kodek:", + "resolution": "Oppløsning:", + "audio": "Lyd:", + "error": "Feil: {{error}}", + "cameraProbeInfo": "{{camera}} - kamerainformasjon", + "streamDataFromFFPROBE": "Strømmedata er hentet med ffprobe.", + "fetching": "Henter kameradata", + "stream": "Strøm {{idx}}", + "video": "Video:", + "fps": "Bilder per sekund:", + "unknown": "Ukjent", + "tips": { + "title": "Kamerainformasjon" + } + }, + "framesAndDetections": "Bilder / Deteksjoner", + "title": "Kameraer", + "overview": "Oversikt", + "label": { + "camera": "kamera", + "detect": "detekter", + "skipped": "forkastet", + "ffmpeg": "FFmpeg", + "capture": "fangst", + "cameraDetectionsPerSecond": "{{camName}} deteksjoner per sekund", + "cameraSkippedDetectionsPerSecond": "{{camName}} forkastede deteksjoner per sekund", + "cameraFramesPerSecond": "{{camName}} bilder per sekund", + "cameraCapture": "{{camName}} fangst", + "cameraDetect": "{{camName}} detekt", + "cameraFfmpeg": "{{camName}} FFmpeg", + "overallDetectionsPerSecond": "totale deteksjoner per sekund", + "overallSkippedDetectionsPerSecond": "totalt forkastede deteksjoner per sekund", + "overallFramesPerSecond": "totalt bilder per sekund" + }, + "toast": { + "success": { + "copyToClipboard": "Kameradata kopiert til utklippstavlen." + }, + "error": { + "unableToProbeCamera": "Kunne ikke hente informasjon fra kamera: {{errorMessage}}" + } + } + }, + "enrichments": { + "embeddings": { + "plate_recognition_speed": "Hastighet for kjennemerkegjenkjenning", + "face_embedding_speed": "Hastighet ansikt-vektorrepresentasjon", + "text_embedding_speed": "Hastighet tekst-vektorrepresentasjoner", + "image_embedding_speed": "Hastighet bilde-vektorrepresentasjoner", + "face_recognition_speed": "Hastighet for ansiktsgjenkjenning", + "image_embedding": "Bilde-vektorrepresentasjoner", + "face_recognition": "Ansiktsgjenkjenning", + "text_embedding": "Tekst-vektorrepresentasjoner", + "plate_recognition": "Kjennemerke gjenkjenning", + "yolov9_plate_detection_speed": "Hastighet for YOLOv9 kjennemerkedeteksjon", + "yolov9_plate_detection": "YOLOv9 kjennemerkedeteksjon" + }, + "title": "Utvidelser", + "infPerSecond": "Inferenser per sekund" + }, + "title": "System", + "metrics": "Systemmålinger", + "lastRefreshed": "Sist oppdatert: ", + "stats": { + "ffmpegHighCpuUsage": "{{camera}} har høy CPU-belastning for FFmpeg ({{ffmpegAvg}}%)", + "detectHighCpuUsage": "{{camera}} har høy CPU-belastning for detektering ({{detectAvg}}%)", + "healthy": "Systemet fungerer som det skal", + "reindexingEmbeddings": "Reindeksering av vektorrepresentasjoner ({{processed}}% fullført)", + "cameraIsOffline": "{{camera}} er frakoblet", + "detectIsSlow": "{{detect}} er treg ({{speed}} ms)", + "detectIsVerySlow": "{{detect}} er veldig treg ({{speed}} ms)" + } +} diff --git a/web/public/locales/nl/audio.json b/web/public/locales/nl/audio.json new file mode 100644 index 000000000..709be4435 --- /dev/null +++ b/web/public/locales/nl/audio.json @@ -0,0 +1,429 @@ +{ + "babbling": "Brabbelen", + "bellow": "Brullen", + "laughter": "Gelach", + "snicker": "Grinniken", + "crying": "Huilen", + "sigh": "Zucht", + "singing": "Zingen", + "choir": "Koor", + "yodeling": "Jodelen", + "mantra": "Mantra", + "child_singing": "Zingend kind", + "rapping": "Rappen", + "breathing": "Ademhaling", + "wheeze": "Piepen", + "snoring": "Snurken", + "gasp": "Snakken naar adem", + "pant": "Hijgen", + "snort": "Snorren", + "sneeze": "Niezen", + "shuffle": "Schudden", + "footsteps": "Voetstappen", + "gargling": "Gorgelen", + "stomach_rumble": "Maag rommelt", + "burping": "Boeren", + "fart": "Scheet", + "finger_snapping": "Vingerknippen", + "applause": "Applaus", + "chatter": "Geklets", + "howl": "Huilkreet", + "bow_wow": "Woef woef", + "growling": "Grommen", + "whimper_dog": "Hondengejank", + "meow": "Miauw", + "hiss": "Sissen", + "livestock": "Vee", + "horse": "Paard", + "clip_clop": "Hoefslagen", + "neigh": "Hinniken", + "cattle": "Runderen", + "moo": "loeien", + "cowbell": "Koeienbel", + "pig": "Varkens", + "oink": "Knorren", + "bleat": "Blaten", + "chicken": "Kip", + "cluck": "Tok", + "turkey": "Kalkoen", + "quack": "Kwak", + "goose": "Gans", + "honk": "gakken", + "wild_animals": "Wilde dieren", + "roaring_cats": "Schreeuwende kat", + "roar": "Brul", + "bird": "Vogel", + "chirp": "Tjilpen", + "squawk": "Gekrijs", + "pigeon": "Duif", + "coo": "Koeren", + "crow": "Kraai", + "caw": "Kauw", + "owl": "Uil", + "hoot": "uilengeroep", + "flapping_wings": "Flapperende vleugels", + "rats": "Ratten", + "mouse": "Muis", + "patter": "Getrippel", + "insect": "Insect", + "mosquito": "Mug", + "buzz": "Gezoem", + "frog": "Kikker", + "croak": "Kwaken", + "snake": "Slang", + "rattle": "Ratel", + "music": "Muziek", + "plucked_string_instrument": "Snaarinstrument", + "guitar": "Gitaar", + "electric_guitar": "Elektrische gitaar", + "bass_guitar": "Basgitaar", + "acoustic_guitar": "Akoestische gitaar", + "steel_guitar": "Steel Guitar", + "tapping": "Tikken", + "strum": "Aanslaan", + "sitar": "Sitar", + "mandolin": "Mandoline", + "zither": "Citer", + "sniff": "Snuif", + "yell": "Schreeuwen", + "whoop": "Gejuich", + "chant": "Lied", + "whistling": "Gefluit", + "hands": "Handen", + "sheep": "Schaap", + "synthetic_singing": "Synthetisch zingen", + "run": "Ren", + "humming": "Zoemen", + "chewing": "Kauwen", + "bark": "Blaffen", + "animal": "Dier", + "cough": "Hoest", + "throat_clearing": "Keel schrapen", + "biting": "Bijten", + "heart_murmur": "Hartruis", + "crowd": "Menigte", + "pets": "Huisdieren", + "heartbeat": "Hartslag", + "children_playing": "Kinderen spelen", + "purr": "Spinnen", + "speech": "Spraak", + "whispering": "Fluisteren", + "yip": "Kef", + "groan": "Kreunen", + "fowl": "Gevogelte", + "grunt": "brommend", + "cock_a_doodle_doo": "Kukeleku", + "cheering": "Juichen", + "caterwaul": "Kattengehuil", + "hiccup": "Hik", + "clapping": "Klappen", + "dogs": "Honden", + "cat": "Kat", + "dog": "Hond", + "goat": "Geit", + "cricket": "Krekel", + "musical_instrument": "Muziek Instrument", + "duck": "Eend", + "banjo": "Banjo", + "gobble": "kalkoenroep", + "fly": "Vlieg", + "whale_vocalization": "Vocalisatie van walvissen", + "keyboard": "Klavier", + "piano": "Piano", + "ukulele": "Ukulele", + "electric_piano": "Elektrische piano", + "organ": "Orgel", + "sampler": "Sampler", + "harpsichord": "Klavecimbel", + "percussion": "Slagwerk", + "drum_kit": "Drumstel", + "snare_drum": "Snaartrommel", + "drum_roll": "Tromgeroffel", + "bass_drum": "Basdrum", + "tabla": "Tabla", + "cymbal": "Bekken", + "hi_hat": "Hi-Hat", + "maraca": "Sambabal", + "tubular_bells": "Buisklokken", + "mallet_percussion": "Mallet instrumenten", + "marimba": "Marimba", + "glockenspiel": "Klokkenspel", + "steelpan": "Steeldrum", + "brass_instrument": "Koperblaasinstrumenten", + "french_horn": "Waldhoorn", + "trombone": "Trombone", + "string_section": "Snaar sectie", + "wind_instrument": "Blaasinstrument", + "clarinet": "Klarinet", + "harp": "Harp", + "bell": "Klok", + "church_bell": "Kerkklok", + "jingle_bell": "Klingelbel", + "bicycle_bell": "Fietsbel", + "tuning_fork": "Stemvork", + "chime": "Bel", + "wind_chime": "Windgong", + "accordion": "Accordeon", + "bagpipes": "Doedelzakken", + "didgeridoo": "Didgeridoo", + "theremin": "Theremin", + "singing_bowl": "Klankschaal", + "rock_music": "Rockmuziek", + "rhythm_and_blues": "Rhythm-and-blues", + "soul_music": "Soulmuziek", + "reggae": "Reggae", + "country": "Countrymuziek", + "bluegrass": "Bluegrass", + "funk": "Funk", + "middle_eastern_music": "Midden-Oosterse muziek", + "jazz": "Jazz", + "cello": "Cello", + "swing_music": "Swingmuziek", + "gong": "gong", + "synthesizer": "Synthesizer", + "punk_rock": "Punkrock", + "wood_block": "Houten klankblok", + "double_bass": "Contrabas", + "beatboxing": "Beatbox", + "orchestra": "Orkest", + "progressive_rock": "Progressieve rock", + "pop_music": "Popmuziek", + "folk_music": "Volksmuziek", + "drum_machine": "Drum", + "pizzicato": "Pizzicato", + "grunge": "Grunge", + "heavy_metal": "Heavy Metal", + "timpani": "Pauken", + "electronic_organ": "Elektronisch orgel", + "trumpet": "Trompet", + "hip_hop_music": "Hip-Hop Muziek", + "hammond_organ": "Hammondorgel", + "drum": "Trommel", + "rimshot": "Rimshot", + "harmonica": "Mondharmonica", + "tambourine": "Tamboerijn", + "psychedelic_rock": "Psychedelische rock", + "vibraphone": "Vibrafoon", + "bowed_string_instrument": "Strijkinstrument", + "violin": "Viool", + "flute": "Fluit", + "saxophone": "Saxofoon", + "scratching": "Krabben", + "rock_and_roll": "Rock 'n Roll", + "disco": "Disco", + "classical_music": "Klassieke muziek", + "opera": "Opera", + "electronic_music": "Elektronische muziek", + "techno": "Techno", + "dubstep": "Dubstep", + "drum_and_bass": "Drum en bas", + "electronic_dance_music": "Elektronische dansmuziek", + "electronica": "Electronica", + "ambient_music": "Ambientmuziek", + "house_music": "Housemuziek", + "trance_music": "Trance Music", + "salsa_music": "Salsamuziek", + "flamenco": "Flamenco", + "blues": "Blues", + "music_of_bollywood": "Music of Bollywood", + "ska": "Ska", + "independent_music": "Onafhankelijke muziek", + "soundtrack_music": "Soundtrack", + "bathtub": "Bad", + "keys_jangling": "Sleutels rinkelen", + "coin": "Munt", + "dial_tone": "Kiestoon", + "busy_signal": "In-gesprektoon", + "buzzer": "Zoemer", + "foghorn": "Misthoorn", + "whistle": "Fluiten", + "steam_whistle": "Stoomfluit", + "ratchet": "Ratel", + "gears": "Tandwielen", + "air_conditioning": "Airconditioning", + "single-lens_reflex_camera": "Spiegelreflexcamera", + "machine_gun": "Geweerschot", + "fusillade": "Schotenwisseling", + "artillery_fire": "Artillerievuur", + "firecracker": "Vuurwerkknaller", + "burst": "Knal", + "boom": "Boem", + "chop": "Hout Hakken", + "splinter": "Splinter", + "chink": "Spleet", + "shatter": "Stukslaan", + "static": "Statisch geluid", + "white_noise": "Witte ruis", + "pink_noise": "Roze ruis", + "television": "Televisie", + "radio": "Radio", + "field_recording": "Veldopname", + "music_for_children": "Muziek voor kinderen", + "vocal_music": "Vocal Music", + "a_capella": "A capella", + "christian_music": "Christelijke Muziek", + "crackle": "Gekraak", + "cupboard_open_or_close": "Kast open of dicht", + "motor_vehicle": "Motorvoertuig", + "police_car": "Politieauto", + "knock": "Klop", + "music_of_asia": "Muziek uit Azië", + "dance_music": "Dansmuziek", + "light_engine": "Lichte motor", + "frying": "Frituren", + "gospel_music": "Gospelmuziek", + "ice_cream_truck": "IJscowagen", + "engine_starting": "Motor starten", + "new-age_music": "New age (muziek)", + "wedding_music": "Bruiloftsmuziek", + "music_of_africa": "Muziek van Afrika", + "thunder": "Donder", + "waterfall": "Waterval", + "skidding": "Slippen", + "truck": "Vrachtwagen", + "ambulance": "Ambulance", + "jet_engine": "Straalmotor", + "lullaby": "Slaapliedje", + "sad_music": "Droevige muziek", + "video_game_music": "Videogamemuziek", + "angry_music": "Boze muziek", + "steam": "Stromend water", + "vehicle": "Voertuig", + "boat": "Boot", + "rowboat": "Roeiboot", + "emergency_vehicle": "Hulpverleningsvoertuig", + "slam": "Slag", + "chopping": "Hakken", + "happy_music": "Vrolijke muziek", + "raindrop": "Regendruppel", + "dental_drill's_drill": "Tandartsboor", + "scissors": "Schaar", + "shuffling_cards": "Kaarten schudden", + "printer": "Printer", + "afrobeat": "Afrobeat", + "traditional_music": "Traditionele muziek", + "gurgling": "Gorgelend", + "train_wheels_squealing": "Piepende treinwielen", + "subway": "Metro", + "bicycle": "Fiets", + "medium_engine": "Middelgrote motor", + "squeak": "Piep", + "dishes": "Borden", + "zipper": "Rits", + "tick-tock": "Ticktack", + "race_car": "Raceauto", + "railroad_car": "Spoorwagon", + "music_of_latin_america": "Muziek uit Latijns-Amerika", + "carnatic_music": "Carnatische muziek", + "helicopter": "Helikopter", + "chainsaw": "Kettingzaag", + "ding-dong": "Ding-Dong", + "sink": "Wasbak", + "wind_noise": "Windgeruis", + "wind": "Wind", + "sailboat": "Zeilboot", + "song": "Liedje", + "toot": "Toeteren", + "bus": "Bus", + "traffic_noise": "Verkeerslawaai", + "train_horn": "Treinhoorn", + "thunderstorm": "Onweer", + "typewriter": "Typemachine", + "background_music": "Achtergrondmuziek", + "car": "Auto", + "ringtone": "Beltoon", + "theme_music": "Themamuziek", + "sliding_door": "Schuifdeur", + "jingle": "Jingle", + "waves": "Golven", + "stream": "Stromend water", + "sewing_machine": "Naaimachine", + "mechanical_fan": "Mechanische ventilator", + "camera": "Camera", + "cap_gun": "Speelgoedpistool", + "tender_music": "Tedere muziek", + "ship": "Schip", + "explosion": "Explosie", + "christmas_music": "Kerstmuziek", + "microwave_oven": "Magnetron", + "toilet_flush": "Toilet doorspoelen", + "exciting_music": "Spannende muziek", + "scary_music": "Enge muziek", + "rustling_leaves": "Ritselende bladeren", + "tire_squeal": "Piepende banden", + "fire_engine": "Brandweerwagen", + "water_tap": "Waterkraan", + "water": "Water", + "rain": "Regen", + "motorcycle": "Motorfiets", + "aircraft_engine": "Vliegtuigmotor", + "rain_on_surface": "Regen op een oppervlakte", + "motorboat": "Motorboot", + "car_passing_by": "Passerende auto", + "reversing_beeps": "Achteruitrijsignalen", + "train": "Trein", + "doorbell": "Deurbel", + "drawer_open_or_close": "Lade open of dicht", + "fire": "Vuur", + "power_windows": "Elektrische ramen", + "train_whistle": "Treinfluitje", + "fixed-wing_aircraft": "Vliegtuig met vaste vleugels", + "engine_knocking": "Motorklopgeluid", + "ocean": "Oceaan", + "rail_transport": "Spoorvervoer", + "aircraft": "Vliegtuigen", + "car_alarm": "Autoalarm", + "idling": "Stationair", + "door": "Deur", + "air_brake": "Luchtrem", + "propeller": "Propeller", + "air_horn": "Luchthoorn", + "skateboard": "Skateboard", + "engine": "Motor", + "accelerating": "Versnellen", + "blender": "Blender", + "gunshot": "Schot", + "lawn_mower": "Grasmaaier", + "heavy_engine": "Zware motor", + "tap": "Tik op", + "hair_dryer": "Föhn", + "cash_register": "Kassa", + "cutlery": "Bestek", + "power_tool": "Elektrisch gereedschap", + "computer_keyboard": "Computertoetsenbord", + "vacuum_cleaner": "Stofzuiger", + "tick": "Teek", + "alarm": "Alarm", + "toothbrush": "Tandenborstel", + "electric_shaver": "Scheerapparaat", + "writing": "Schrijven", + "telephone": "Telefoon", + "jackhammer": "Drilboor", + "alarm_clock": "Wekker", + "civil_defense_siren": "Luchtalarm", + "typing": "Typen", + "pulleys": "Katrollen", + "drill": "Boor", + "telephone_dialing": "Telefoonnummer draaien", + "telephone_bell_ringing": "Rinkelen van de telefoon", + "electric_toothbrush": "Elektrische tandenborstel", + "hammer": "Hamer", + "sanding": "Schuren", + "siren": "Sirene", + "smoke_detector": "Rookmelder", + "fire_alarm": "Brandalarm", + "mechanisms": "Mechanismen", + "filing": "Vijlen", + "clock": "Klok", + "glass": "Glas", + "sawing": "Zagen", + "tools": "Hulpmiddelen", + "wood": "Hout", + "fireworks": "Vuurwerk", + "eruption": "Uitbarsting", + "crack": "Scheur", + "environmental_noise": "Omgevingsgeluid", + "silence": "Stilte", + "sound_effect": "Geluidseffect", + "scream": "Schreeuw" +} diff --git a/web/public/locales/nl/common.json b/web/public/locales/nl/common.json new file mode 100644 index 000000000..6de5b1227 --- /dev/null +++ b/web/public/locales/nl/common.json @@ -0,0 +1,258 @@ +{ + "time": { + "untilForTime": "Totdat {{time}}", + "untilForRestart": "Totdat Frigate herstart.", + "untilRestart": "Tot herstart", + "12hours": "12 uur", + "lastWeek": "Vorige week", + "last7": "Afgelopen 7 dagen", + "last30": "Afgelopen 30 dagen", + "yr": "{{time}} jaar", + "5minutes": "5 minuten", + "10minutes": "10 minuten", + "24hours": "24 uur", + "30minutes": "30 minuten", + "ago": "{{timeAgo}} geleden", + "justNow": "Zojuist", + "today": "Vandaag", + "yesterday": "Gisteren", + "last14": "Afgelopen 14 dagen", + "thisWeek": "Deze week", + "thisMonth": "Deze maand", + "lastMonth": "Vorige maand", + "1hour": "1 uur", + "pm": "pm", + "am": "am", + "year_one": "{{time}} Jaar", + "year_other": "{{time}} Jaren", + "mo": "{{time}} maand", + "month_one": "{{time}} maand", + "month_other": "{{time}} maanden", + "formattedTimestamp2": { + "12hour": "dd-MM HH:mm:ss", + "24hour": "d MMM HH:mm:ss" + }, + "s": "{{time}}s", + "formattedTimestamp": { + "12hour": "d MMMM, HH:mm:ss", + "24hour": "d MMM, HH:mm:ss" + }, + "formattedTimestampOnlyMonthAndDay": "%-d %b", + "d": "{{time}}dag", + "day_one": "{{time}} dag", + "day_other": "{{time}} dagen", + "h": "{{time}}u", + "hour_one": "{{time}} uur", + "hour_other": "{{time}} uren", + "m": "{{time}}min", + "formattedTimestampWithYear": { + "12hour": "%-d %b %Y, %H:%M", + "24hour": "%-d %b %Y, %H:%M" + }, + "formattedTimestampExcludeSeconds": { + "24hour": "%-d %b, %H:%M", + "12hour": "%-d %b, %H:%M" + }, + "minute_one": "{{time}} minuut", + "minute_other": "{{time}} minuten", + "second_one": "{{time}} seconde", + "second_other": "{{time}} seconden", + "formattedTimestampHourMinute": { + "24hour": "HH:mm", + "12hour": "HH:mm" + }, + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "d MMMM yyyy, HH:mm", + "24hour": "d MMMM yyyy, HH:mm" + }, + "formattedTimestampMonthDay": "d MMM", + "formattedTimestampFilename": { + "12hour": "dd-MM-yy-HH-mm-ss", + "24hour": "dd-MM-yy-HH-mm-ss" + }, + "formattedTimestampHourMinuteSecond": { + "12hour": "HH:mm:ss", + "24hour": "HH:mm:ss" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "d MMMM, HH:mm", + "24hour": "d MMMM, HH:mm" + } + }, + "button": { + "enabled": "Ingeschakeld", + "back": "Terug", + "apply": "Toepassen", + "reset": "Opnieuw instellen", + "enable": "Inschakelen", + "disabled": "Uitgeschakeld", + "cancel": "Annuleren", + "close": "Sluiten", + "copy": "Kopieer", + "done": "Klaar", + "saving": "Opslaan…", + "disable": "Uitschakelen", + "save": "Opslaan", + "history": "Geschiedenis", + "fullscreen": "Volledig scherm", + "pictureInPicture": "Pop-up venster", + "twoWayTalk": "Tweerichtingsgesprek", + "cameraAudio": "Camera geluid", + "on": "aan", + "copyCoordinates": "Coördinaten kopiëren", + "delete": "Verwijder", + "yes": "Ja", + "no": "Nee", + "suspended": "Opgeschort", + "unsuspended": "Heractiveren", + "export": "Exporteren", + "exitFullscreen": "Verlaat volledig scherm", + "play": "Speel", + "off": "uit", + "info": "Info", + "edit": "Bewerken", + "download": "Download", + "unselect": "Deselecteren", + "next": "Volgende", + "deleteNow": "Nu verwijderen" + }, + "unit": { + "speed": { + "mph": "mph", + "kph": "km/u" + } + }, + "label": { + "back": "Ga terug" + }, + "menu": { + "system": "Systeem", + "systemMetrics": "Systeemstatistieken", + "settings": "Instellingen", + "configuration": "Configuratie", + "systemLogs": "Systeem logboeken", + "configurationEditor": "Configuratie bewerker", + "languages": "Talen", + "language": { + "en": "English (Engels)", + "zhCN": "简体中文 (Vereenvoudigd Chinees)", + "withSystem": { + "label": "Gebruik de systeeminstellingen voor de taal" + }, + "ar": "العربية (Arabisch)", + "pt": "Português (Portugees)", + "ru": "Русский (Russisch)", + "de": "Deutsch (Duits)", + "tr": "Türkçe (Turks)", + "it": "Italiano (Italiaans)", + "nl": "Nederlands (Nederlands)", + "sv": "Svenska (Zweeds)", + "cs": "Čeština (Tsjechisch)", + "fa": "فارسی (Perzisch)", + "pl": "Polski (Pools)", + "he": "עברית (Hebreeuws)", + "el": "Ελληνικά (Grieks)", + "ro": "Română (Roemeense)", + "hu": "Magyar (Hongaars)", + "fi": "Suomi (Fins)", + "da": "Dansk (Deens)", + "sk": "Slovenčina (Slowaaks)", + "ko": "한국어 (Koreaans)", + "nb": "Norsk Bokmål (Noors Bokmål)", + "fr": "Français (Frans)", + "uk": "Українська (Oekraïens)", + "es": "Español (Spaans)", + "vi": "Tiếng Việt (Vietnamees)", + "hi": "हिन्दी (Hindi)", + "ja": "日本語 (Japans)", + "yue": "粵語 (Kantonees)" + }, + "darkMode": { + "label": "Donkere modus", + "light": "Licht", + "dark": "Donker", + "withSystem": { + "label": "Gebruik de systeeminstellingen voor de lichte of donkere modus" + } + }, + "appearance": "Opmaak", + "theme": { + "blue": "Blauw", + "contrast": "Hoog contrast", + "label": "Thema", + "green": "Groen", + "nord": "Nord", + "red": "Rood", + "default": "Standaard", + "highcontrast": "Hoog contrast" + }, + "withSystem": "Systeem", + "help": "Help", + "live": { + "title": "Live", + "allCameras": "Alle Camera's", + "cameras": { + "title": "Camera's", + "count_one": "{{count}} Camera", + "count_other": "{{count}} Camera's" + } + }, + "restart": "Herstart Frigate", + "documentation": { + "title": "Documentatie", + "label": "Frigate documentatie" + }, + "review": "Beoordelen", + "explore": "Verkennen", + "export": "Exporteren", + "uiPlayground": "Testgebied voor gebruikersinterface", + "faceLibrary": "Gezichtenbibliotheek", + "user": { + "title": "Gebruik", + "current": "Huidige gebruiker: {{user}}", + "logout": "Uitloggen", + "setPassword": "Wachtwoord instellen", + "account": "Account", + "anonymous": "anoniem" + } + }, + "toast": { + "copyUrlToClipboard": "URL naar klembord gekopieerd.", + "save": { + "title": "Opslaan", + "error": { + "title": "Opslaan van configuratiewijzigingen mislukt: {{errorMessage}}", + "noMessage": "Het opslaan van configuratiewijzigingen is mislukt" + } + } + }, + "role": { + "title": "Rol", + "admin": "Beheerder", + "viewer": "Gebruiker", + "desc": "Beheerders hebben volledige toegang tot alle functies in de Frigate-interface. Kijkers kunnen alleen camera’s bekijken, items beoordelen en historische beelden terugkijken." + }, + "pagination": { + "previous": { + "title": "Vorig", + "label": "Ga naar de vorige pagina" + }, + "more": "Meer pagina's", + "label": "Paginering", + "next": { + "title": "Volgende", + "label": "Ga naar volgende pagina" + } + }, + "accessDenied": { + "documentTitle": "Toegang geweigerd - Frigate", + "desc": "Je hebt geen toestemming om deze pagina te bekijken.", + "title": "Toegang geweigerd" + }, + "notFound": { + "desc": "Pagina niet gevonden", + "title": "404", + "documentTitle": "Niet gevonden - Frigate" + }, + "selectItem": "Selecteer {{item}}" +} diff --git a/web/public/locales/nl/components/auth.json b/web/public/locales/nl/components/auth.json new file mode 100644 index 000000000..78ae8e55e --- /dev/null +++ b/web/public/locales/nl/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "password": "Wachtwoord", + "login": "Inloggen", + "errors": { + "rateLimit": "Limiet overschreden. Probeer het later opnieuw.", + "loginFailed": "Inloggen mislukt", + "usernameRequired": "Gebruikersnaam is vereist", + "passwordRequired": "Wachtwoord is vereist", + "unknownError": "Onbekende fout. Bekijk de logs.", + "webUnknownError": "Onbekende fout. Controleer consolelogboeken." + }, + "user": "Gebruikersnaam" + } +} diff --git a/web/public/locales/nl/components/camera.json b/web/public/locales/nl/components/camera.json new file mode 100644 index 000000000..a7f5e2f5a --- /dev/null +++ b/web/public/locales/nl/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "label": "Cameragroepen", + "add": "Cameragroep toevoegen", + "edit": "Cameragroep bewerken", + "delete": { + "label": "Cameragroep verwijderen", + "confirm": { + "title": "Bevestig Verwijderen", + "desc": "Weet u zeker dat u de cameragroep {{name}} wilt verwijderen?" + } + }, + "name": { + "label": "Naam", + "placeholder": "Voer een naam in…", + "errorMessage": { + "exists": "De cameragroepnaam bestaat al.", + "invalid": "Ongeldige cameragroepnaam.", + "nameMustNotPeriod": "De naam van de cameragroep mag geen punt bevatten.", + "mustLeastCharacters": "De naam van de cameragroep moet minimaal 2 tekens lang zijn." + } + }, + "cameras": { + "desc": "Selecteer camera's voor deze groep.", + "label": "Camera's" + }, + "success": "Cameragroep ({{name}}) is opgeslagen.", + "camera": { + "setting": { + "audioIsAvailable": "Audio is beschikbaar voor deze stream", + "audioIsUnavailable": "Audio is niet beschikbaar voor deze stream", + "audio": { + "tips": { + "document": "Lees de documentatie ", + "title": "Audio moet worden uitgevoerd vanaf je camera en geconfigureerd in go2rtc voor deze stream." + } + }, + "streamMethod": { + "method": { + "smartStreaming": { + "label": "Slim streamen (aanbevolen)", + "desc": "Slim streamen werkt het camerabeeld één keer per minuut bij wanneer er geen detecteerbare activiteit is, om bandbreedte en systeembronnen te besparen. Zodra er activiteit wordt gedetecteerd, schakelt het beeld automatisch over naar een livestream." + }, + "continuousStreaming": { + "label": "Continue streaming", + "desc": { + "title": "Het camerabeeld is altijd een live stream wanneer het zichtbaar is op het dashboard, zelfs als er geen activiteit wordt gedetecteerd.", + "warning": "Let op: continu streamen kan leiden tot hoog bandbreedtegebruik en prestatieproblemen." + } + }, + "noStreaming": { + "label": "Geen streaming", + "desc": "Camerabeelden worden slechts één keer per minuut bijgewerkt en er vindt geen livestreaming plaats." + } + }, + "label": "Streamingmethode" + }, + "compatibilityMode": { + "desc": "Schakel deze optie alleen in als de live stream van je camera kleurvervormingen toont en een diagonale lijn aan de rechterkant van het beeld heeft.", + "label": "Compatibiliteitsmodus" + }, + "desc": "Wijzig de live streaming-opties voor het dashboard van deze cameragroep. Deze instellingen zijn specifiek voor het apparaat en de browser.", + "label": "Camera streaming-instellingen", + "title": "{{cameraName}} Streaming-instellingen" + } + }, + "icon": "Icon" + }, + "debug": { + "options": { + "label": "Instellingen", + "title": "Opties", + "showOptions": "Opties weergeven", + "hideOptions": "Opties verbergen" + }, + "mask": "Masker", + "motion": "Beweging", + "zones": "Zones", + "boundingBox": "Objectkader", + "timestamp": "Tijdstempel", + "regions": "Regio's" + } +} diff --git a/web/public/locales/nl/components/dialog.json b/web/public/locales/nl/components/dialog.json new file mode 100644 index 000000000..da8f36797 --- /dev/null +++ b/web/public/locales/nl/components/dialog.json @@ -0,0 +1,119 @@ +{ + "restart": { + "title": "Weet je zeker dat je Frigate opnieuw wilt opstarten?", + "button": "Herstart", + "restarting": { + "title": "Frigate wordt opnieuw gestart", + "button": "Forceer herladen nu", + "content": "Deze pagina zal herladen in {{countdown}} seconden." + } + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "Verzenden naar Frigate+", + "desc": "Objecten op locaties die je wilt vermijden, zijn geen valspositieven. Als je ze als valspositieven indient, brengt dit het model in verwarring." + }, + "review": { + "true": { + "true_one": "Dit is een {{label}}", + "true_other": "Dit zijn {{label}}", + "label": "Bevestig dit label voor Frigate Plus" + }, + "false": { + "false_one": "Dit is geen {{label}}", + "false_other": "Dit zijn geen {{label}}", + "label": "Bevestig dit label niet voor Frigate Plus" + }, + "state": { + "submitted": "Ingediend" + }, + "question": { + "ask_an": "Is dit object een {{label}}?", + "label": "Bevestig dit label voor Frigate Plus", + "ask_a": "Is dit object een {{label}}?", + "ask_full": "Is dit object een {{untranslatedLabel}} ({{translatedLabel}})?" + } + } + }, + "video": { + "viewInHistory": "Bekijk in Geschiedenis" + } + }, + "export": { + "time": { + "fromTimeline": "Selecteer uit tijdlijn", + "end": { + "label": "Selecteer eindtijd", + "title": "Eindtijd" + }, + "lastHour_one": "Afgelopen uur", + "lastHour_other": "Afgelopen {{count}} uren", + "custom": "Aangepast", + "start": { + "title": "Starttijd", + "label": "Selecteer starttijd" + } + }, + "name": { + "placeholder": "Geef de export een naam" + }, + "select": "Selecteer", + "toast": { + "error": { + "failed": "Exporteren is mislukt: {{error}}", + "noVaildTimeSelected": "Geen geldig tijdsbereik geselecteerd", + "endTimeMustAfterStartTime": "Eindtijd moet na starttijd zijn" + }, + "success": "Export is succesvol gestart. Bekijk het bestand in de map /exports." + }, + "fromTimeline": { + "saveExport": "Export opslaan", + "previewExport": "Export vooraf bekijken" + }, + "export": "Exporteren", + "selectOrExport": "Selecteren of exporteren" + }, + "streaming": { + "label": "Stream", + "restreaming": { + "desc": { + "title": "Stel go2rtc in voor extra liveweergaveopties en audio voor deze camera.", + "readTheDocumentation": "Lees de documentatie" + }, + "disabled": "Herstreamen is niet ingeschakeld voor deze camera." + }, + "showStats": { + "label": "Streamstatistieken tonen", + "desc": "Schakel deze optie in om streamstatistieken als overlay op de camerafeed weer te geven." + }, + "debugView": "Debugweergave" + }, + "search": { + "saveSearch": { + "label": "Zoekopdracht opslaan", + "desc": "Geef een naam op voor deze opgeslagen zoekopdracht.", + "success": "Zoekopdracht ({{searchName}}) is opgeslagen.", + "button": { + "save": { + "label": "Bewaar deze zoekopdracht" + } + }, + "overwrite": "{{searchName}} bestaat al. Opslaan overschrijft de bestaande waarde.", + "placeholder": "Voer een naam in voor uw zoekopdracht" + } + }, + "recording": { + "button": { + "deleteNow": "Nu verwijderen", + "export": "Exporteren", + "markAsReviewed": "Markeren als beoordeeld" + }, + "confirmDelete": { + "desc": { + "selected": "Weet u zeker dat u alle opgenomen videobeelden wilt verwijderen die aan dit beoordelingsitem zijn gekoppeld?

    Houd de Shift-toets ingedrukt om dit dialoogvenster in de toekomst over te slaan." + }, + "title": "Bevestig Verwijderen" + } + } +} diff --git a/web/public/locales/nl/components/filter.json b/web/public/locales/nl/components/filter.json new file mode 100644 index 000000000..306d6e502 --- /dev/null +++ b/web/public/locales/nl/components/filter.json @@ -0,0 +1,126 @@ +{ + "labels": { + "count": "{{count}} Labels", + "all": { + "short": "Labels", + "title": "Alle labels" + }, + "label": "Labels", + "count_one": "{{count}} Label", + "count_other": "{{count}} Labels" + }, + "zones": { + "label": "Zones", + "all": { + "title": "Alle zones", + "short": "Zones" + } + }, + "dates": { + "all": { + "title": "Alle datums", + "short": "Datums" + } + }, + "features": { + "hasVideoClip": "Heeft een videoclip", + "label": "Functies", + "hasSnapshot": "Heeft een snapshot", + "submittedToFrigatePlus": { + "label": "Ingediend bij Frigate+", + "tips": "Je moet eerst filteren op gevolgde objecten met een snapshot.

    Gevolgde objecten zonder snapshot kunnen niet worden verzonden naar Frigate+." + } + }, + "review": { + "showReviewed": "Toon beoordeelde items" + }, + "motion": { + "showMotionOnly": "Alleen bewegingen weergeven" + }, + "explore": { + "settings": { + "title": "Instellingen", + "defaultView": { + "title": "Standaardweergave", + "unfilteredGrid": "Ongefilterd overzicht", + "summary": "Samenvatting", + "desc": "Wanneer er geen filters zijn geselecteerd, wordt er een samenvatting van de meest recent gevolgde objecten per label weergegeven, of wordt er een ongefilterd overzicht weergegeven." + }, + "gridColumns": { + "title": "Overzichtskolommen", + "desc": "Selecteer het aantal kolommen in het overzicht." + }, + "searchSource": { + "options": { + "description": "Beschrijving", + "thumbnailImage": "Thumbnail afbeelding" + }, + "desc": "Kies of u wilt zoeken in de thumbnails of beschrijvingen van de objecten die u volgt.", + "label": "Zoekbron" + } + }, + "date": { + "selectDateBy": { + "label": "Selecteer een datum om op te filteren" + } + } + }, + "zoneMask": { + "filterBy": "Filteren op zonemasker" + }, + "recognizedLicensePlates": { + "loadFailed": "Het laden van herkende kentekenplaten is mislukt.", + "placeholder": "Type om kentekens te zoeken…", + "title": "Herkende kentekenplaten", + "noLicensePlatesFound": "Geen kentekenplaten gevonden.", + "selectPlatesFromList": "Selecteer een of meer kentekens uit de lijst.", + "loading": "Herkende kentekenplaten laden…" + }, + "score": "Score", + "sort": { + "scoreAsc": "Objectscore (oplopend)", + "dateAsc": "Datum (oplopend)", + "speedAsc": "Geschatte snelheid (oplopend)", + "label": "Sorteer", + "relevance": "Relevantie", + "dateDesc": "Datum (aflopend)", + "scoreDesc": "Objectscore (aflopend)", + "speedDesc": "Geschatte snelheid (aflopend)" + }, + "cameras": { + "all": { + "title": "Alle camera's", + "short": "Camera's" + }, + "label": "Camerafilter" + }, + "subLabels": { + "label": "Sublabels", + "all": "Alle sublabels" + }, + "logSettings": { + "loading": { + "title": "Bezig met laden", + "desc": "Wanneer u het logvenster naar beneden scrolt, worden nieuwe logs automatisch weergegeven terwijl ze worden toegevoegd." + }, + "disableLogStreaming": "Logstreaming uitschakelen", + "allLogs": "Alle logs", + "label": "Filterlogniveau", + "filterBySeverity": "Filter logs op ernst" + }, + "filter": "Filter", + "timeRange": "Tijdsbereik", + "trackedObjectDelete": { + "toast": { + "success": "Gevolgde objecten succesvol verwijderd.", + "error": "Het verwijderen van gevolgde objecten is mislukt: {{errorMessage}}" + }, + "title": "Bevestig Verwijderen", + "desc": "Het verwijderen van deze {{objectLength}} gevolgde objecten verwijdert de snapshot, eventuele opgeslagen embeddings en bijbehorende levenscyclusgegevens van het object. Opgenomen videobeelden van deze objecten in de geschiedenisweergave worden NIET verwijderd.

    Weet je zeker dat je wilt doorgaan?

    Houd de Shift-toets ingedrukt om deze melding in de toekomst over te slaan." + }, + "reset": { + "label": "Filters resetten naar standaardwaarden" + }, + "more": "Meer filters", + "estimatedSpeed": "Geschatte snelheid ({{unit}})" +} diff --git a/web/public/locales/nl/components/icons.json b/web/public/locales/nl/components/icons.json new file mode 100644 index 000000000..af65664d6 --- /dev/null +++ b/web/public/locales/nl/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "Selecteer een pictogram", + "search": { + "placeholder": "Zoek naar een pictogram…" + } + } +} diff --git a/web/public/locales/nl/components/input.json b/web/public/locales/nl/components/input.json new file mode 100644 index 000000000..fa5707a78 --- /dev/null +++ b/web/public/locales/nl/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Video downloaden", + "toast": { + "success": "Het downloaden van uw beoordelingsvideo is gestart." + } + } + } +} diff --git a/web/public/locales/nl/components/player.json b/web/public/locales/nl/components/player.json new file mode 100644 index 000000000..ff0dd1065 --- /dev/null +++ b/web/public/locales/nl/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "Geen opnames gevonden voor deze tijd", + "stats": { + "latency": { + "value": "{{seconds}} seconden", + "short": { + "title": "Latentie", + "value": "{{seconds}} s" + }, + "title": "Latentie:" + }, + "totalFrames": "Totaal aantal frames:", + "droppedFrames": { + "title": "Overgeslagen frames:", + "short": { + "value": "{{droppedFrames}} frames", + "title": "Overgeslagen" + } + }, + "droppedFrameRate": "Frequentie van overgeslagen frames:", + "bandwidth": { + "short": "Bandbreedte", + "title": "Bandbreedte:" + }, + "streamType": { + "short": "Type", + "title": "Stream Type:" + }, + "decodedFrames": "Gedecodeerde frames:" + }, + "submitFrigatePlus": { + "title": "Dit frame indienen bij Frigate+?", + "submit": "Indienen" + }, + "streamOffline": { + "title": "Stream is Offline", + "desc": "Er zijn geen frames ontvangen in de detect-stream van {{cameraName}}, controleer de error logs" + }, + "noPreviewFound": "Geen voorbeeld gevonden", + "noPreviewFoundFor": "Geen voorbeeld gevonden voor {{cameraName}}", + "livePlayerRequiredIOSVersion": "Voor dit type livestream is iOS 17.1 of hoger vereist.", + "cameraDisabled": "Camera is uitgeschakeld", + "toast": { + "success": { + "submittedFrigatePlus": "Frame succesvol ingediend bij Frigate+" + }, + "error": { + "submitFrigatePlusFailed": "Het is niet gelukt om een frame naar Frigate+ te sturen" + } + } +} diff --git a/web/public/locales/nl/objects.json b/web/public/locales/nl/objects.json new file mode 100644 index 000000000..46db6892a --- /dev/null +++ b/web/public/locales/nl/objects.json @@ -0,0 +1,120 @@ +{ + "cat": "Kat", + "horse": "Paard", + "bird": "Vogel", + "bark": "Blaffen", + "goat": "Geit", + "sheep": "Schaap", + "animal": "Dier", + "mouse": "Muis", + "dog": "Hond", + "keyboard": "Klavier", + "person": "Persoon", + "airplane": "Vliegtuig", + "traffic_light": "Verkeerslicht", + "street_sign": "Verkeersbord", + "stop_sign": "Stopbord", + "parking_meter": "Parkeer Meter", + "bench": "Bankje", + "cow": "Koe", + "giraffe": "Giraffe", + "hat": "Hoed", + "backpack": "Rugzak", + "shoe": "Schoen", + "baseball_bat": "Honkbalknuppel", + "baseball_glove": "Honkbalhandschoen", + "tennis_racket": "Tennis Racket", + "bottle": "Fles", + "plate": "Bord", + "fork": "Vork", + "spoon": "Lepel", + "bowl": "Schaal", + "sandwich": "Sandwich", + "broccoli": "Broccoli", + "hot_dog": "Hot Dog", + "cake": "Taart", + "chair": "Stoel", + "potted_plant": "Potplant", + "bed": "Bed", + "mirror": "Spiegel", + "laptop": "Laptop", + "cell_phone": "Mobiele telefoon", + "oven": "Oven", + "toaster": "Broodrooster", + "refrigerator": "Koelkast", + "book": "Boek", + "clock": "Klok", + "vase": "Vaas", + "toothbrush": "Tandenborstel", + "teddy_bear": "Teddybeer", + "vehicle": "Voertuig", + "squirrel": "Eekhoorn", + "deer": "Hert", + "fox": "Vos", + "rabbit": "Konijn", + "raccoon": "Wasbeer", + "waste_bin": "Afvalbak", + "on_demand": "Op aanvraag", + "ups": "UPS", + "nzpost": "NZPost", + "postnord": "PostNord", + "gls": "GLS", + "dpd": "DPD", + "skateboard": "Skateboard", + "boat": "Boot", + "scissors": "Schaar", + "bicycle": "Fiets", + "sink": "Wasbak", + "bus": "Bus", + "car": "Auto", + "motorcycle": "Motorfiets", + "train": "Trein", + "door": "Deur", + "blender": "Blender", + "hair_dryer": "Föhn", + "banana": "Banaan", + "umbrella": "Paraplu", + "suitcase": "Koffer", + "license_plate": "Kentekenplaat", + "orange": "Oranje", + "postnl": "PostNL", + "snowboard": "Snowboard", + "sports_ball": "Bal", + "donut": "Donut", + "couch": "Bank", + "package": "Pakket", + "dining_table": "Etenstafel", + "microwave": "Magnetron", + "toilet": "Toilet", + "cup": "Beker", + "carrot": "Wortel", + "eye_glasses": "Brillen", + "bear": "Beer", + "zebra": "Zebra", + "handbag": "Handtas", + "surfboard": "Surfplank", + "wine_glass": "Wijnglas", + "hair_brush": "Haarborstel", + "fire_hydrant": "Brandkraan", + "elephant": "Olifant", + "remote": "Op afstand", + "tie": "Stropdas", + "kite": "Vlieger", + "frisbee": "Frisbee", + "skis": "Ski's", + "desk": "Bureau", + "knife": "Mes", + "apple": "Appel", + "pizza": "Pizza", + "window": "Raam", + "fedex": "FedEx", + "tv": "TV", + "robot_lawnmower": "Robot grasmaaier", + "usps": "USPS", + "dhl": "DHL", + "bbq_grill": "BBQ-grill", + "amazon": "Amazon", + "face": "Gezicht", + "an_post": "An Post", + "purolator": "Purolator" +} diff --git a/web/public/locales/nl/views/configEditor.json b/web/public/locales/nl/views/configEditor.json new file mode 100644 index 000000000..2ce3a8eb4 --- /dev/null +++ b/web/public/locales/nl/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "documentTitle": "Configuratie-bewerken - Frigate", + "copyConfig": "Configuratie kopiëren", + "saveAndRestart": "Opslaan en opnieuw opstarten", + "toast": { + "error": { + "savingError": "Fout bij het opslaan van de configuratie" + }, + "success": { + "copyToClipboard": "Configuratie gekopieerd naar klembord." + } + }, + "configEditor": "Configuratie Bewerken", + "saveOnly": "Alleen opslaan" +} diff --git a/web/public/locales/nl/views/events.json b/web/public/locales/nl/views/events.json new file mode 100644 index 000000000..2ae919a34 --- /dev/null +++ b/web/public/locales/nl/views/events.json @@ -0,0 +1,37 @@ +{ + "documentTitle": "Beoordelen - Frigate", + "camera": "Camera", + "newReviewItems": { + "button": "Nieuwe items om te beoordelen", + "label": "Bekijk nieuwe beoordelingsitems" + }, + "timeline.aria": "Selecteer tijdlijn", + "recordings": { + "documentTitle": "Opnamen - Frigate" + }, + "timeline": "Tijdlijn", + "empty": { + "alert": "Er zijn geen meldingen om te beoordelen", + "detection": "Er zijn geen detecties om te beoordelen", + "motion": "Geen bewegingsgegevens gevonden" + }, + "events": { + "aria": "Selecteer activiteiten", + "noFoundForTimePeriod": "Er zijn geen activiteiten gevonden voor deze periode.", + "label": "Activiteiten" + }, + "calendarFilter": { + "last24Hours": "Laatste 24 uur" + }, + "alerts": "Meldingen", + "motion": { + "label": "Bewegingen", + "only": "Alleen bewegingen" + }, + "allCameras": "Alle camera's", + "markAsReviewed": "Markeren als beoordeeld", + "detections": "Detecties", + "markTheseItemsAsReviewed": "Markeer deze items als beoordeeld", + "selected_other": "{{count}} geselecteerd", + "selected_one": "{{count}} geselecteerd" +} diff --git a/web/public/locales/nl/views/explore.json b/web/public/locales/nl/views/explore.json new file mode 100644 index 000000000..dfe37ea13 --- /dev/null +++ b/web/public/locales/nl/views/explore.json @@ -0,0 +1,200 @@ +{ + "generativeAI": "Generatieve AI", + "exploreIsUnavailable": { + "embeddingsReindexing": { + "finishingShortly": "Bijna klaar", + "step": { + "trackedObjectsProcessed": "Gevolgde objecten verwerkt: ", + "descriptionsEmbedded": "Beschrijving ingesloten: ", + "thumbnailsEmbedded": "Thumbnails ingesloten: " + }, + "context": "Verkennen kan worden gebruikt nadat de embeddings van gevolgde objecten opnieuw zijn geïndexeerd.", + "estimatedTime": "Geschatte resterende tijd:", + "startingUp": "Opstarten…" + }, + "downloadingModels": { + "setup": { + "textTokenizer": "Teksttokenizer", + "visionModel": "Visiemodel", + "visionModelFeatureExtractor": "kenmerkextractie van een visiemodel", + "textModel": "Tekstmodel" + }, + "error": "Er is iets misgegaan. Raadpleeg de Frigate-logs.", + "context": "Frigate downloadt de vereiste inbedmodellen om de functie Semantisch zoeken te ondersteunen. Dit kan enkele minuten duren, afhankelijk van de snelheid van je netwerkverbinding.", + "tips": { + "context": "Je wilt misschien de embeddings van je gevolgde objecten opnieuw indexeren zodra de modellen zijn gedownload.", + "documentation": "Lees de documentatie" + } + }, + "title": "Verkennen is niet beschikbaar" + }, + "trackedObjectDetails": "Details getraceerd object", + "type": { + "details": "Details", + "video": "video", + "snapshot": "snapshot", + "object_lifecycle": "objectlevenscyclus" + }, + "objectLifecycle": { + "createObjectMask": "Objectmasker maken", + "lifecycleItemDesc": { + "visible": "{{label}} Gedetecteerd", + "entered_zone": "{{label}} ingevoerd {{zones}}", + "attribute": { + "other": "{{label}} Herkend als {{attribute}}", + "faceOrLicense_plate": "{{attribute}} Gedetecteerd voor {{label}}" + }, + "heard": "{{label}} gehoord", + "gone": "{{label}} Links", + "active": "{{label}} Werd actief", + "stationary": "{{label}} werd stationair", + "external": "{{label}} gedetecteerd", + "header": { + "zones": "Zones", + "ratio": "Verhouding", + "area": "Gebied" + } + }, + "annotationSettings": { + "title": "Annotatie-instellingen", + "offset": { + "millisecondsToOffset": "Aantal milliseconden om objectkader mee te verschuiven. Standaard: 0", + "desc": "Deze gegevens zijn afkomstig van de detectiestroom van je camera, maar worden weergegeven op beelden uit de opnamestroom. Het is onwaarschijnlijk dat deze twee streams perfect gesynchroniseerd zijn. Hierdoor zullen het objectkader en het beeld niet exact op elkaar aansluiten. Het veld annotation_offset kan echter worden gebruikt om deze annotatie-afwijking te corrigeren.", + "documentation": "Lees de documentatie ", + "label": "Annotatie-afwijking", + "tips": "TIP: Stel je voor dat er een clip is waarin een persoon van links naar rechts loopt. Als het objectkader in de tijdlijn van het object steeds links van de persoon ligt, dan moet de waarde verlaagd worden. Op dezelfde manier als het objectkader consequent vóór de persoon ligt dus vooruitloopt, moet de waarde verhoogd worden." + }, + "showAllZones": { + "title": "Toon alle zones", + "desc": "Toon altijd zones op frames waar objecten een zone zijn binnengegaan." + } + }, + "noImageFound": "Er is geen afbeelding beschikbaar voor dit tijdstip.", + "title": "Objectlevenscyclus", + "adjustAnnotationSettings": "Annotatie-instellingen aanpassen", + "scrollViewTips": "Scroll om de belangrijke momenten uit de levenscyclus van dit object te bekijken.", + "autoTrackingTips": "Als u een automatische objectvolgende camera gebruikt, zal het objectkader onnauwkeurig zijn.", + "carousel": { + "previous": "Vorige dia", + "next": "Volgende dia" + } + }, + "documentTitle": "Verken - Frigate", + "details": { + "item": { + "button": { + "viewInExplore": "Bekijk in Verkennen", + "share": "Deel dit beoordelingsitem" + }, + "title": "Details van item bekijken", + "desc": "Details van item bekijken", + "tips": { + "hasMissingObjects": "Pas je configuratie aan als je wilt dat Frigate gevolgde objecten opslaat voor de volgende labels: {{objects}}", + "mismatch_one": "{{count}} Niet-beschikbaar object werd gedetecteerd en opgenomen in dit beoordelingsitem. Het voldeed mogelijk niet aan de criteria voor een waarschuwing of detectie, of is inmiddels opgeschoond of verwijderd.", + "mismatch_other": "{{count}} Niet-beschikbare objecten zijn gedetecteerd en opgenomen in dit beoordelingsitem. Deze objecten voldeden mogelijk niet aan de voorwaarden voor een waarschuwing of detectie, of zijn inmiddels verwijderd of opgeruimd." + }, + "toast": { + "success": { + "regenerate": "Er is een nieuwe beschrijving aangevraagd bij {{provider}}. Afhankelijk van de snelheid van je provider kan het regenereren van de nieuwe beschrijving enige tijd duren.", + "updatedSublabel": "Sublabel succesvol bijgewerkt.", + "updatedLPR": "Kenteken succesvol bijgewerkt." + }, + "error": { + "updatedSublabelFailed": "Het is niet gelukt om het sublabel bij te werken: {{errorMessage}}", + "regenerate": "Het is niet gelukt om {{provider}} aan te roepen voor een nieuwe beschrijving: {{errorMessage}}", + "updatedLPRFailed": "Kentekenplaat bijwerken mislukt: {{errorMessage}}" + } + } + }, + "label": "Label", + "editSubLabel": { + "title": "Sublabel bewerken", + "descNoLabel": "Voer een nieuw sublabel in voor dit gevolgde object", + "desc": "Voer een nieuw sublabel in voor deze {{label}}" + }, + "topScore": { + "label": "Hoogste score", + "info": "De topscore is de hoogste mediaanscore voor het gevolgde object, waardoor deze kan afwijken van de score die wordt weergegeven op de thumbnail van het zoekresultaat." + }, + "objects": "Objecten", + "zones": "Zones", + "button": { + "findSimilar": "Vind vergelijkbare", + "regenerate": { + "label": "Regenereer de beschrijving van het gevolgde object", + "title": "Regenereren" + } + }, + "description": { + "placeholder": "Beschrijving van het gevolgde object", + "label": "Beschrijving", + "aiTips": "Frigate vraagt pas om een beschrijving van uw Generative AI-provider als de levenscyclus van het gevolgde object is afgelopen." + }, + "expandRegenerationMenu": "Regeneratiemenu uitbreiden", + "regenerateFromSnapshot": "Regenereren vanuit Snapshot", + "tips": { + "descriptionSaved": "Beschrijving succesvol opgeslagen", + "saveDescriptionFailed": "Het is niet gelukt om de beschrijving bij te werken: {{errorMessage}}" + }, + "timestamp": "Tijdstempel", + "regenerateFromThumbnails": "Regeneratie van Thumbnails", + "camera": "Camera", + "estimatedSpeed": "Geschatte snelheid", + "editLPR": { + "title": "Kenteken bewerken", + "desc": "Voer een nieuwe kentekenwaarde in voor deze {{label}}", + "descNoLabel": "Voer een nieuwe kentekenwaarde in voor dit gevolgde object" + }, + "recognizedLicensePlate": "Erkende kentekenplaat", + "snapshotScore": { + "label": "Snapshot scoren" + } + }, + "itemMenu": { + "downloadVideo": { + "label": "Download video", + "aria": "Download video" + }, + "viewObjectLifecycle": { + "aria": "Toon de levenscyclus van het object", + "label": "Levenscyclus van object bekijken" + }, + "submitToPlus": { + "label": "Verzenden naar Frigate+", + "aria": "Verzenden naar Frigate Plus" + }, + "viewInHistory": { + "aria": "Bekijk in Geschiedenis", + "label": "Bekijk in Geschiedenis" + }, + "deleteTrackedObject": { + "label": "Verwijder dit gevolgde object" + }, + "findSimilar": { + "label": "Vind vergelijkbare", + "aria": "Vind vergelijkbare gevolgde objecten" + }, + "downloadSnapshot": { + "label": "Download snapshot", + "aria": "Download snapshot" + } + }, + "noTrackedObjects": "Geen gevolgde objecten gevonden", + "trackedObjectsCount_one": "{{count}} gevolgd object ", + "trackedObjectsCount_other": "{{count}} gevolgde objecten ", + "searchResult": { + "deleteTrackedObject": { + "toast": { + "success": "Het gevolgde object is succesvol verwijderd.", + "error": "Verwijderen van gevolgd object mislukt: {{errorMessage}}" + } + } + }, + "dialog": { + "confirmDelete": { + "title": "Bevestig Verwijderen", + "desc": "Het verwijderen van dit gevolgde object verwijdert de snapshot, alle opgeslagen embeddings en eventuele bijbehorende levenscyclusgegevens van het object. Opgenomen videobeelden van dit object in de Geschiedenisweergave worden NIET verwijderd.

    Weet je zeker dat je wilt doorgaan?" + } + }, + "fetchingTrackedObjectsFailed": "Fout bij het ophalen van gevolgde objecten: {{errorMessage}}" +} diff --git a/web/public/locales/nl/views/exports.json b/web/public/locales/nl/views/exports.json new file mode 100644 index 000000000..2589f37c7 --- /dev/null +++ b/web/public/locales/nl/views/exports.json @@ -0,0 +1,17 @@ +{ + "documentTitle": "Exporteren - Frigate", + "search": "Zoek", + "toast": { + "error": { + "renameExportFailed": "Het is niet gelukt om de export te hernoemen: {{errorMessage}}" + } + }, + "editExport": { + "title": "Hernoemen Export", + "saveExport": "Export opslaan", + "desc": "Voer een nieuwe naam in voor deze export." + }, + "noExports": "Geen export gevonden", + "deleteExport": "Verwijder Export", + "deleteExport.desc": "Weet je zeker dat je dit wilt wissen: {{exportName}}?" +} diff --git a/web/public/locales/nl/views/faceLibrary.json b/web/public/locales/nl/views/faceLibrary.json new file mode 100644 index 000000000..3a9b3d2fe --- /dev/null +++ b/web/public/locales/nl/views/faceLibrary.json @@ -0,0 +1,84 @@ +{ + "selectItem": "Selecteer {{item}}", + "details": { + "timestamp": "Tijdstempel", + "person": "Persoon", + "confidence": "Vertrouwen", + "face": "Gezicht Details", + "faceDesc": "Details van het gezicht en het bijbehorende object" + }, + "documentTitle": "Gezichtsbibliotheek - Frigate", + "description": { + "placeholder": "Voer een naam in voor deze verzameling", + "addFace": "Doorloop het toevoegen van een nieuwe collectie aan de gezichtenbibliotheek." + }, + "train": { + "title": "Train", + "aria": "Selecteer trainen" + }, + "selectFace": "Selecteer gezicht", + "toast": { + "error": { + "addFaceLibraryFailed": "Het is niet gelukt om de gezichtsnaam in te stellen: {{errorMessage}}", + "deleteFaceFailed": "Verwijderen mislukt: {{errorMessage}}", + "deleteNameFailed": "Naam verwijderen is niet gelukt: {{errorMessage}}", + "updateFaceScoreFailed": "Niet gelukt om gezichtsscore bij te werken: {{errorMessage}}", + "uploadingImageFailed": "Afbeelding uploaden mislukt: {{errorMessage}}", + "trainFailed": "Trainen mislukt: {{errorMessage}}", + "renameFaceFailed": "Het is niet gelukt om het gezicht te hernoemen: {{errorMessage}}" + }, + "success": { + "deletedFace_one": "{{count}} gezicht is succesvol verwijderd.", + "deletedFace_other": "{{count}} gezichten zijn succesvol verwijderd.", + "trainedFace": "Met succes getraind gezicht.", + "updatedFaceScore": "De gezichtsscore is succesvol bijgewerkt.", + "deletedName_one": "{{count}} gezicht is succesvol verwijderd.", + "deletedName_other": "{{count}} gezichten zijn succesvol verwijderd.", + "uploadedImage": "Afbeelding succesvol geüpload.", + "addFaceLibrary": "{{name}} is succesvol toegevoegd aan de Gezichtenbibliotheek!", + "renamedFace": "Gezicht succesvol hernoemd naar {{name}}" + } + }, + "imageEntry": { + "dropActive": "Zet de afbeelding hier neer…", + "dropInstructions": "Sleep een afbeelding hierheen of klik om te selecteren", + "maxSize": "Maximale grootte: {{size}}MB", + "validation": { + "selectImage": "Selecteer een afbeeldingbestand." + } + }, + "createFaceLibrary": { + "title": "Collectie maken", + "desc": "Een nieuwe collectie maken", + "new": "Creëer een nieuw gezicht", + "nextSteps": "Om een sterke basis op te bouwen:
  • Gebruik het tabblad Trainen om per gedetecteerd persoon afbeeldingen te selecteren en te trainen.
  • Richt je op frontale afbeeldingen voor het beste resultaat; vermijd trainingsbeelden waarop gezichten vanuit een hoek te zien zijn.
  • " + }, + "button": { + "addFace": "Gezicht toevoegen", + "uploadImage": "Afbeelding uploaden", + "deleteFaceAttempts": "Pogingen tot gezichtsherkenning verwijderen", + "reprocessFace": "Herverwerk gezicht", + "renameFace": "Gezicht hernoemen", + "deleteFace": "Gezicht verwijderen" + }, + "uploadFaceImage": { + "desc": "Upload een afbeelding om te scannen op gezichten en op te nemen voor {{pageToggle}}", + "title": "Upload een afbeelding van het gezicht" + }, + "deleteFaceLibrary": { + "title": "Verwijder Naam", + "desc": "Weet je zeker dat je de collectie {{name}} wilt verwijderen? Dit zal permanent alle geassocieerde gezichten verwijderen." + }, + "trainFaceAs": "Train Face als:", + "trainFace": "Train Face", + "readTheDocs": "Lees de documentatie", + "steps": { + "nextSteps": "Volgende stappen", + "faceName": "Voer een naam in", + "uploadFace": "Upload een afbeelding van het gezicht" + }, + "renameFace": { + "title": "Gezicht hernoemen", + "desc": "Voer een nieuwe naam in voor {{name}}" + } +} diff --git a/web/public/locales/nl/views/live.json b/web/public/locales/nl/views/live.json new file mode 100644 index 000000000..d09f4c699 --- /dev/null +++ b/web/public/locales/nl/views/live.json @@ -0,0 +1,158 @@ +{ + "lowBandwidthMode": "Modus voor lage bandbreedte", + "twoWayTalk": { + "enable": "Tweerichtingsgesprek inschakelen", + "disable": "Tweerichtingsgesprek uitschakelen" + }, + "cameraAudio": { + "enable": "Camera geluid inschakelen", + "disable": "Camera geluid uitschakelen" + }, + "ptz": { + "move": { + "clickMove": { + "label": "Klik in het frame om de camera te centreren", + "enable": "Klikken om te bewegen inschakelen", + "disable": "Klikken om te bewegen uitschakelen" + }, + "right": { + "label": "Beweeg de PTZ-camera naar rechts" + }, + "down": { + "label": "Beweeg de PTZ-camera naar beneden" + }, + "up": { + "label": "Beweeg de PTZ-camera naar boven" + }, + "left": { + "label": "Beweeg de PTZ-camera naar links" + } + }, + "zoom": { + "in": { + "label": "Zoom de PTZ-camera in" + }, + "out": { + "label": "Zoom de PTZ-camera uit" + } + }, + "frame": { + "center": { + "label": "Klik in het frame om de PTZ-camera te centreren" + } + }, + "presets": "PTZ-camerapresets" + }, + "camera": { + "enable": "Camera inschakelen", + "disable": "Camera uitschakelen" + }, + "muteCameras": { + "enable": "Alle camera's dempen", + "disable": "Dempen van alle camera's opheffen" + }, + "detect": { + "disable": "Detectie uitschakelen", + "enable": "Detectie inschakelen" + }, + "snapshots": { + "enable": "Momentopnamen inschakelen", + "disable": "Schakel snapshots uit" + }, + "audioDetect": { + "disable": "Audiodetectie uitschakelen", + "enable": "Audiodetectie inschakelen" + }, + "streamStats": { + "disable": "Verberg streamstatistieken", + "enable": "Streamstatistieken weergeven" + }, + "manualRecording": { + "showStats": { + "label": "Statistieken weergeven", + "desc": "Schakel deze optie in om streamstatistieken als overlay op de camerafeed weer te geven." + }, + "started": "Handmatige opname gestart.", + "start": "Handmatige opname starten", + "debugView": "Debug weergave", + "end": "Handmatige opname stoppen", + "ended": "Handmatige opname gestopt.", + "failedToEnd": "Het beëindigen van de handmatige opname is mislukt.", + "playInBackground": { + "label": "Speel op de achtergrond", + "desc": "Schakel deze optie in om te blijven streamen wanneer de speler verborgen is." + }, + "recordDisabledTips": "Aangezien opnemen is uitgeschakeld of beperkt in de configuratie van deze camera, zal alleen een momentopname worden opgeslagen.", + "title": "Opname op aanvraag", + "tips": "Start een handmatige gebeurtenis op basis van de opnamebehoudinstellingen van deze camera.", + "failedToStart": "Handmatige opname starten mislukt." + }, + "notifications": "Meldingen", + "audio": "Geluid", + "documentTitle": "Live - Frigate", + "documentTitle.withCamera": "{{camera}} - Live - Frigate", + "autotracking": { + "enable": "Automatisch volgen inschakelen", + "disable": "Automatisch volgen uitschakelen" + }, + "recording": { + "disable": "Opname uitschakelen", + "enable": "Opname inschakelen" + }, + "suspend": { + "forTime": "Onderbreken voor: " + }, + "streamingSettings": "Streaming-instellingen", + "stream": { + "twoWayTalk": { + "tips.documentation": "Lees de documenten ", + "tips": "Uw apparaat moet deze functie ondersteunen en WebRTC moet geconfigureerd zijn voor tweerichtingsgesprekken.", + "unavailable": "Tweerichtingsgesprek is niet beschikbaar voor deze stream", + "available": "Voor deze stream is tweerichtingsgesprek beschikbaar" + }, + "lowBandwidth": { + "resetStream": "Stream resetten", + "tips": "Liveweergave staat in de lagebandbreedtemodus vanwege buffering of streamfouten." + }, + "title": "Stream", + "audio": { + "tips": { + "documentation": "Lees de documentatie ", + "title": "Audio moet via je camera komen en in go2rtc geconfigureerd zijn voor deze stream." + }, + "unavailable": "Audio is niet beschikbaar voor deze stroom", + "available": "Audio is beschikbaar voor deze stream" + }, + "playInBackground": { + "label": "Afspelen op de achtergrond", + "tips": "Schakel deze optie in om te blijven streamen wanneer de speler verborgen is." + } + }, + "cameraSettings": { + "title": "{{camera}} Instellingen", + "objectDetection": "Objectdetectie", + "recording": "Opname", + "audioDetection": "Audiodetectie", + "autotracking": "Automatisch volgen", + "snapshots": "Momentopnames", + "cameraEnabled": "Camera ingeschakeld" + }, + "history": { + "label": "Historische beelden weergeven" + }, + "effectiveRetainMode": { + "modes": { + "all": "Alle", + "active_objects": "Actieve objecten", + "motion": "Beweging" + }, + "notAllTips": "De bewaarbeleid-configuratie voor {{source}} is ingesteld op modus: {{effectiveRetainMode}}, dus deze opname op aanvraag bewaart alleen segmenten met {{effectiveRetainModeName}}." + }, + "editLayout": { + "label": "Lay-out bewerken", + "exitEdit": "Bewerken verlaten", + "group": { + "label": "Cameragroep bewerken" + } + } +} diff --git a/web/public/locales/nl/views/recording.json b/web/public/locales/nl/views/recording.json new file mode 100644 index 000000000..5a40650c9 --- /dev/null +++ b/web/public/locales/nl/views/recording.json @@ -0,0 +1,12 @@ +{ + "export": "Exporteren", + "toast": { + "error": { + "endTimeMustAfterStartTime": "De eindtijd moet na de starttijd zijn", + "noValidTimeSelected": "Er is geen geldig tijdsbereik geselecteerd" + } + }, + "filter": "Filter", + "calendar": "Kalender", + "filters": "Filters" +} diff --git a/web/public/locales/nl/views/search.json b/web/public/locales/nl/views/search.json new file mode 100644 index 000000000..d91159fd7 --- /dev/null +++ b/web/public/locales/nl/views/search.json @@ -0,0 +1,74 @@ +{ + "button": { + "delete": "Opgeslagen zoekopdracht verwijderen", + "save": "Zoekopdracht opslaan", + "clear": "Duidelijk zoeken", + "filterInformation": "Filter informatie", + "filterActive": "Filters actief" + }, + "search": "Zoek", + "savedSearches": "Opgeslagen zoekopdrachten", + "searchFor": "Zoeken naar {{inputValue}}", + "trackedObjectId": "Getraceerd object-ID", + "filter": { + "label": { + "cameras": "Camera's", + "labels": "Labels", + "sub_labels": "Sublabels", + "time_range": "Tijdsbereik", + "before": "Voor", + "min_score": "Min Score", + "max_score": "Max Score", + "min_speed": "Min snelheid", + "recognized_license_plate": "Herkend kenteken", + "has_snapshot": "Heeft Snapshot", + "has_clip": "Heeft Clip", + "search_type": "Zoektype", + "zones": "Zones", + "max_speed": "Max snelheid", + "after": "Na" + }, + "toast": { + "error": { + "maxSpeedMustBeGreaterOrEqualMinSpeed": "De ‘max_speed’ moet groter zijn dan of gelijk aan de ‘min_speed’.", + "beforeDateBeLaterAfter": "De 'voor' datum moet later zijn dan de 'na' datum.", + "afterDatebeEarlierBefore": "De ‘na’ datum moet eerder zijn dan de ‘voor’ datum.", + "minScoreMustBeLessOrEqualMaxScore": "De ‘min_score’ moet kleiner zijn dan of gelijk aan de ‘max_score’.", + "maxScoreMustBeGreaterOrEqualMinScore": "De ‘max_score’ moet groter zijn dan of gelijk aan de ‘min_score’.", + "minSpeedMustBeLessOrEqualMaxSpeed": "De ‘min_snelheid’ moet kleiner zijn dan of gelijk aan de ‘max_snelheid’." + } + }, + "tips": { + "title": "Hoe tekstfilters te gebruiken", + "desc": { + "example": "Voorbeeld: camera's:voordeur label:persoon vóór:01012024 tijdsbereik:15:00-16:00", + "text": "Filters helpen je om je zoekresultaten te beperken. Zo gebruik je ze in het invoerveld:", + "step": "
    • Typ een filternaam gevolgd door een dubbele punt (bijv. \"cameras:\").
    • Selecteer een waarde uit de suggesties of typ je eigen waarde.
    • Gebruik meerdere filters door ze achter elkaar toe te voegen, gescheiden door een spatie.
    • Datumfilters (before: en after:) gebruiken {{DateFormat}} formaat
    • Het tijdsfilter gebruikt {{exampleTime}} formaat
    • Verwijder filters door op de 'x' ernaast te klikken.
    ", + "step3": "Gebruik meerdere filters door ze achter elkaar toe te voegen met een spatie ertussen.", + "step4": "Datumfilters (voor: en na:) gebruiken het {{DateFormat}} formaat.", + "step5": "Het tijdsfilter gebruikt het {{exampleTime}} als formaat.", + "step2": "Selecteer een waarde uit de suggesties of voer je eigen waarde in.", + "step1": "Typ een filtersleutelnaam gevolgd door een dubbele punt (bijv. \"camera's:\").", + "step6": "Verwijder filters door op de 'x' naast de filteroptie te klikken.", + "exampleLabel": "Voorbeeld:" + } + }, + "searchType": { + "thumbnail": "Thumbnail", + "description": "Beschrijving" + }, + "header": { + "currentFilterType": "Filterwaarden", + "noFilters": "Filters", + "activeFilters": "Actieve filters" + } + }, + "similaritySearch": { + "active": "Gelijkenis zoeken actief", + "title": "Gelijkenis zoeken", + "clear": "Gelijksoortige zoekopdracht wissen" + }, + "placeholder": { + "search": "Zoek…" + } +} diff --git a/web/public/locales/nl/views/settings.json b/web/public/locales/nl/views/settings.json new file mode 100644 index 000000000..847b01c93 --- /dev/null +++ b/web/public/locales/nl/views/settings.json @@ -0,0 +1,597 @@ +{ + "documentTitle": { + "default": "Instellingen - Frigate", + "camera": "Camera-instellingen - Frigate", + "authentication": "Authenticatie-instellingen - Frigate", + "motionTuner": "Motion Tuner - Frigate", + "classification": "Classificatie-instellingen - Frigate", + "masksAndZones": "Masker- en zone-editor - Frigate", + "object": "Foutopsporing Frigate", + "general": "Algemene instellingen - Frigate", + "frigatePlus": "Frigate+ Instellingen - Frigate", + "notifications": "Meldingsinstellingen - Frigate" + }, + "menu": { + "ui": "Gebruikersinterface", + "classification": "Classificatie", + "masksAndZones": "Maskers / Zones", + "motionTuner": "Bewegingsdetectie-afstellen", + "debug": "foutopsporing", + "users": "Gebruikers", + "notifications": "Meldingen", + "cameras": "Camera-instellingen", + "frigateplus": "Frigate+" + }, + "dialog": { + "unsavedChanges": { + "title": "Je hebt niet-opgeslagen wijzigingen.", + "desc": "Wilt je jouw wijzigingen opslaan voordat u verdergaat?" + } + }, + "cameraSetting": { + "camera": "Camera", + "noCamera": "Geen camera" + }, + "general": { + "liveDashboard": { + "title": "Live-dashboard", + "automaticLiveView": { + "label": "Automatische liveweergave", + "desc": "Schakel automatisch over naar de liveweergave van een camera wanneer er activiteit wordt gedetecteerd. Als u deze optie uitschakelt, worden de statische camerabeelden op het live dashboard slechts eenmaal per minuut bijgewerkt." + }, + "playAlertVideos": { + "label": "Meldingen afspelen", + "desc": "Standaard worden recente meldingen op het Live dashboard afgespeeld als kleine lusvideo's. Schakel deze optie uit om alleen een statische afbeelding van recente meldingen weer te geven op dit apparaat/browser." + } + }, + "title": "Algemene instellingen", + "storedLayouts": { + "title": "Opgeslagen indelingen", + "clearAll": "Alle indelingen wissen", + "desc": "De indeling van camera's in een cameragroep kan worden versleept en in formaat worden aangepast. De posities en afmetingen worden opgeslagen in de lokale opslag van je browser." + }, + "cameraGroupStreaming": { + "title": "Streaminginstellingen voor cameragroep", + "desc": "De streaminginstellingen voor elke cameragroep worden opgeslagen in de lokale opslag van uw browser.", + "clearAll": "Alle streaminginstellingen wissen" + }, + "recordingsViewer": { + "title": "Opnamebekijker", + "defaultPlaybackRate": { + "label": "Standaard afspeelsnelheid", + "desc": "Standaard afspeelsnelheid voor het afspelen van opnames." + } + }, + "calendar": { + "firstWeekday": { + "label": "Eerste weekdag", + "sunday": "Zondag", + "monday": "Maandag", + "desc": "De eerste dag van de week die in de kalender in de interface wordt weergegeven." + }, + "title": "Kalender" + }, + "toast": { + "success": { + "clearStoredLayout": "Verwijderde opgeslagen indeling voor {{cameraName}}", + "clearStreamingSettings": "Verwijderde streaming-instellingen voor alle cameragroepen." + }, + "error": { + "clearStoredLayoutFailed": "Het wissen van de opgeslagen indelingen is mislukt: {{errorMessage}}", + "clearStreamingSettingsFailed": "Het wissen van de streaminginstellingen is mislukt: {{errorMessage}}" + } + } + }, + "classification": { + "semanticSearch": { + "title": "Semantisch zoeken", + "reindexNow": { + "label": "Nu opnieuw indexeren", + "confirmTitle": "Bevestig herindexering", + "confirmButton": "Opnieuw indexeren", + "alreadyInProgress": "Het herindexeren is al bezig.", + "success": "Het herindexeren is succesvol gestart.", + "error": "Het opnieuw indexeren is mislukt: {{errorMessage}}", + "desc": "Opnieuw indexeren zal embeddings regenereren voor alle gevolgde objecten. Dit proces wordt op de achtergrond uitgevoerd en kan je CPU zwaar belasten en een behoorlijke hoeveelheid tijd in beslag nemen, afhankelijk van het aantal gevolgde objecten dat je hebt.", + "confirmDesc": "Weet u zeker dat u alle gevolgde object-embeddings opnieuw wilt indexeren? Dit proces wordt op de achtergrond uitgevoerd, maar kan uw CPU zwaar belasten en enige tijd in beslag nemen. U kunt de voortgang bekijken op de pagina Verkennen." + }, + "modelSize": { + "label": "Modelgrootte", + "desc": "De grootte van het model dat wordt gebruikt voor semantische zoekopdrachten.", + "small": { + "title": "klein", + "desc": "Het gebruik van small maakt gebruik van een gequantiseerde versie van het model die minder RAM verbruikt en sneller draait op de CPU, met een verwaarloosbaar verschil in embeddingkwaliteit." + }, + "large": { + "title": "groot", + "desc": "Het gebruik van large maakt gebruik van het volledige Jina-model en wordt automatisch op de GPU uitgevoerd als die beschikbaar is." + } + }, + "readTheDocumentation": "Lees de documentatie", + "desc": "Met semantisch zoeken in Frigate kun je getraceerde objecten in je overzichtsitems vinden aan de hand van de afbeelding zelf, een door de gebruiker gedefinieerde tekstbeschrijving of een automatisch gegenereerde beschrijving." + }, + "faceRecognition": { + "title": "Gezichtsherkenning", + "modelSize": { + "label": "Modelgrootte", + "desc": "De grootte van het model dat gebruikt wordt voor gezichtsherkenning.", + "small": { + "title": "klein", + "desc": "Met small wordt een FaceNet-model voor gezichtsinbedding gebruikt dat efficiënt werkt op de meeste CPU's." + }, + "large": { + "desc": "Het gebruik van groot maakt gebruik van een ArcFace-gezichtsembeddingmodel en wordt automatisch op de GPU uitgevoerd als die beschikbaar is.", + "title": "groot" + } + }, + "desc": "Gezichtsherkenning maakt het mogelijk om namen aan mensen toe te wijzen. Wanneer hun gezicht wordt herkend, wijst Frigate de naam van de persoon toe als sublabel. Deze informatie is opgenomen in de gebruikersinterface, filters en meldingen.", + "readTheDocumentation": "Lees de documentatie" + }, + "title": "Classificatie-instellingen", + "licensePlateRecognition": { + "title": "Kentekenherkenning", + "readTheDocumentation": "Lees de documentatie", + "desc": "Frigate kan kentekenplaten op voertuigen herkennen en automatisch de gedetecteerde tekens toevoegen aan het veld recognized_license_plate of een bekende naam als sublabel toekennen aan objecten van het type auto. Een veelvoorkomende toepassing is het uitlezen van kentekens van auto's die een oprit oprijden of voorbijrijden op straat." + }, + "toast": { + "success": "Classificatie-instellingen zijn opgeslagen. Start Frigate opnieuw op om de wijzigingen toe te passen.", + "error": "Configuratiewijzigingen konden niet worden opgeslagen: {{errorMessage}}" + }, + "birdClassification": { + "title": "Vogelclassificatie", + "desc": "Vogelclassificatie herkent bekende vogels met behulp van een gequantiseerd TensorFlow-model. Wanneer een bekende vogel wordt herkend, wordt de algemene naam toegevoegd als sublabel. Deze informatie wordt weergegeven in de interface, is beschikbaar in filters en wordt ook opgenomen in meldingen." + }, + "restart_required": "Opnieuw opstarten vereist (Classificatie-instellingen gewijzigd)" + }, + "camera": { + "review": { + "title": "Beoordeel", + "alerts": "Meldingen ", + "detections": "Detecties ", + "desc": "Schakel waarschuwingen en detecties voor deze camera in of uit. Wanneer deze zijn uitgeschakeld, worden er geen nieuwe beoordelingsitems aangemaakt." + }, + "reviewClassification": { + "objectAlertsTips": "Alle {{alertsLabels}}-objecten op {{cameraName}} worden weergegeven als meldingen.", + "zoneObjectAlertsTips": "Alle {{alertsLabels}}-objecten die zijn gedetecteerd in {{zone}} op {{cameraName}} worden weergegeven als meldingen.", + "zoneObjectDetectionsTips": { + "text": "Alle {{detectionsLabels}}-objecten die in {{zone}} op {{cameraName}} niet zijn gecategoriseerd, worden weergegeven als detecties.", + "notSelectDetections": "Alle {{detectionsLabels}}-objecten die in {{zone}} op {{cameraName}} worden gedetecteerd en niet als waarschuwing zijn gecategoriseerd, worden weergegeven als detecties – ongeacht in welke zone ze zich bevinden.", + "regardlessOfZoneObjectDetectionsTips": "Alle {{detectionsLabels}}-objecten die op {{cameraName}} niet zijn gecategoriseerd, worden weergegeven als detecties – ongeacht in welke zone ze zich bevinden." + }, + "selectAlertsZones": "Zones selecteren voor meldingen", + "selectDetectionsZones": "Selecteer zones voor detecties", + "limitDetections": "Beperk detecties tot specifieke zones", + "toast": { + "success": "Configuratie voor beoordelingsclassificatie is opgeslagen. Herstart Frigate om de wijzigingen toe te passen." + }, + "readTheDocumentation": "Lees de documentatie", + "noDefinedZones": "Voor deze camera zijn nog geen zones ingesteld.", + "desc": "Frigate categoriseert beoordelingsitems als waarschuwingen en detecties.Standaard worden alle person- en car-objecten als waarschuwingen beschouwd. Je kunt de categorisatie verfijnen door zones te configureren waarin uitsluitend deze objecten gedetecteerd moeten worden.", + "title": "Beoordelingsclassificatie", + "objectDetectionsTips": "Alle {{detectionsLabels}}-objecten die op {{cameraName}} niet zijn gecategoriseerd, worden weergegeven als detecties, ongeacht in welke zone ze zich bevinden." + }, + "streams": { + "desc": "Het uitschakelen van een camera laat Frigate volledig stoppen met het verwerken van de stream van die camera. Detectie, opname en foutopsporing zijn dan niet beschikbaar.
    Opmerking: dit schakelt de go2rtc-restreams niet uit.", + "title": "Streams" + }, + "title": "Camera-instellingen" + }, + "masksAndZones": { + "filter": { + "all": "Alle maskers en zones" + }, + "toast": { + "success": { + "copyCoordinates": "Coördinaten voor {{polyName}} gekopieerd naar klembord." + }, + "error": { + "copyCoordinatesFailed": "De coördinaten konden niet naar het klembord worden gekopieerd." + } + }, + "form": { + "zoneName": { + "error": { + "mustBeAtLeastTwoCharacters": "De zonenaam moet minimaal 2 tekens lang zijn.", + "mustNotContainPeriod": "De zonenaam mag geen punten bevatten.", + "hasIllegalCharacter": "De zonenaam bevat ongeldige tekens.", + "mustNotBeSameWithCamera": "De zonenaam mag niet gelijk zijn aan de cameranaam.", + "alreadyExists": "Er bestaat al een zone met deze naam voor deze camera." + } + }, + "distance": { + "error": { + "text": "Afstand moet groter dan of gelijk zijn aan 0,1.", + "mustBeFilled": "Alle afstandsvelden moeten worden ingevuld om de snelheid te kunnen schatten." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "De minimale snelheid moet meer zijn dan 0." + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "De verblijftijd moet groter dan of gelijk aan 0 zijn." + } + }, + "polygonDrawing": { + "removeLastPoint": "Laatste punt verwijderen", + "snapPoints": { + "true": "Verbind punten", + "false": "Punten niet verbinden" + }, + "delete": { + "title": "Bevestig Verwijderen", + "desc": "Weet je zeker dat je de {{type}} {{name}} wilt verwijderen?", + "success": "{{name}} is verwijderd." + }, + "error": { + "mustBeFinished": "De polygoontekening moet voltooid zijn voordat u deze kunt opslaan." + }, + "reset": { + "label": "Alle punten wissen" + } + } + }, + "zones": { + "documentTitle": "Bewerkingszone - Frigate", + "desc": { + "title": "Zones stellen je in staat om een specifiek gedeelte van het beeld te definiëren, zodat je kunt bepalen of een object zich binnen dat gebied bevindt of niet.", + "documentation": "Documentatie" + }, + "edit": "Bewerk zone", + "clickDrawPolygon": "Klik om een polygoon op de afbeelding te tekenen.", + "name": { + "title": "Naam", + "inputPlaceHolder": "Voer een naam in…", + "tips": "De naam moet minimaal 2 tekens lang zijn en mag niet gelijk zijn aan de naam van een camera of een andere zone." + }, + "inertia": { + "title": "Traagheid", + "desc": "Geeft aan hoeveel frames een object in een zone moet zijn voordat het als 'in de zone' wordt beschouwd. Standaard: 3" + }, + "loiteringTime": { + "title": "Stationaire tijd", + "desc": "Stelt de minimale tijd in (in seconden) die een object in de zone moet blijven voordat deze wordt geactiveerd. Standaard: 0" + }, + "objects": { + "title": "Objecten", + "desc": "Lijst met objecten die van toepassing zijn op deze zone." + }, + "speedEstimation": { + "desc": "Snelheidsschatting inschakelen voor objecten in deze zone. De zone moet precies 4 punten hebben.", + "title": "Snelheidsschatting" + }, + "speedThreshold": { + "desc": "Geeft een minimumsnelheid op voor objecten die in deze zone moeten worden beschouwd.", + "toast": { + "error": { + "pointLengthError": "De snelheidsschatting is uitgeschakeld voor deze zone. Zones met snelheidsschatting moeten precies 4 punten hebben.", + "loiteringTimeError": "Zones met een stationaire tijd groter dan 0 mogen niet worden gebruikt in combinatie met snelheidsschatting." + } + }, + "title": "Snelheidsdrempel ({{unit}})" + }, + "point_one": "{{count}} punt", + "point_other": "{{count}} punten", + "label": "Zones", + "add": "Zone toevoegen", + "allObjects": "Alle objecten", + "toast": { + "success": "Zone ({{zoneName}}) is opgeslagen. Start Frigate opnieuw om de wijzigingen toe te passen." + } + }, + "motionMasks": { + "label": "Bewegingsmasker", + "documentTitle": "Bewerken Bewegingsmasker - Frigate", + "desc": { + "documentation": "Documentatie", + "title": "Bewegingsmaskers worden gebruikt om te voorkomen dat ongewenste vormen van beweging een detectie activeren. Te veel maskeren maakt het moeilijker om objecten te volgen." + }, + "edit": "Bewerk bewegingsmasker", + "context": { + "documentation": "Lees de documentatie", + "title": "Bewegingsmaskers worden gebruikt om te voorkomen dat ongewenste soorten beweging een detectie activeren (bijvoorbeeld: bewegende boomtakken of tijdstempels in het camerabeeld). Bewegingsmaskers moeten zeer spaarzaam worden gebruikt – te veel maskeren maakt het moeilijker om objecten te volgen." + }, + "clickDrawPolygon": "Klik om een polygoon op de afbeelding te tekenen.", + "polygonAreaTooLarge": { + "documentation": "Lees de documentatie", + "title": "Het bewegingsmasker bedekt {{polygonArea}}% van het camerabeeld. Grote bewegingsmaskers worden niet aanbevolen.", + "tips": "Bewegingsmaskers voorkomen niet dat objecten worden gedetecteerd. Gebruik in plaats daarvan een objectmasker." + }, + "point_one": "{{count}} punt", + "point_other": "{{count}} punten", + "toast": { + "success": { + "title": "{{polygonName}} is opgeslagen. Herstart Frigate om de wijzigingen toe te passen.", + "noName": "Bewegingsmasker is opgeslagen. Herstart Frigate om de wijzigingen toe te passen." + } + }, + "add": "Nieuw bewegingsmasker" + }, + "objectMasks": { + "label": "Objectmaskers", + "documentTitle": "Objectmasker bewerken - Frigate", + "desc": { + "title": "Objectfiltermaskers worden gebruikt om valse positieven uit te filteren voor een bepaald objecttype op basis van locatie.", + "documentation": "Documentatie" + }, + "add": "Objectmasker toevoegen", + "objects": { + "desc": "Het objecttype dat van toepassing is op dit objectmasker.", + "allObjectTypes": "Alle objecttypen", + "title": "Objecten" + }, + "toast": { + "success": { + "title": "{{polygonName}} is opgeslagen. Herstart Frigate om de wijzigingen toe te passen.", + "noName": "Objectmasker is opgeslagen. Herstart Frigate om de wijzigingen toe te passen." + } + }, + "point_one": "{{count}} punt", + "point_other": "{{count}} punten", + "clickDrawPolygon": "Klik om een polygoon op de afbeelding te tekenen.", + "context": "Objectfiltermaskers worden gebruikt om valse positieven uit te filteren voor een bepaald objecttype op basis van locatie.", + "edit": "Objectmasker bewerken" + }, + "restart_required": "Herstart vereist (maskers/zones gewijzigd)" + }, + "motionDetectionTuner": { + "title": "Bewegingsdetectie-afsteller", + "desc": { + "title": "Frigate gebruikt bewegingsdetectie als eerste controle om te zien of er iets gebeurt in het frame dat de moeite waard is om te controleren met objectdetectie.", + "documentation": "Lees de handleiding voor bewegingsafstelling" + }, + "Threshold": { + "title": "Drempelwaarde", + "desc": "De drempelwaarde bepaalt hoeveel verandering in de luminantie van een pixel nodig is om als beweging te worden beschouwd. Standaard: 30" + }, + "contourArea": { + "title": "Contourgebied", + "desc": "De waarde voor het contourgebied wordt gebruikt om te bepalen welke groepen gewijzigde pixels in aanmerking komen als beweging. Standaard: 10" + }, + "improveContrast": { + "title": "Contrast verbeteren", + "desc": "Verbeter het contrast bij weinig licht. Standaard: AAN" + }, + "toast": { + "success": "De bewegingsinstellingen zijn opgeslagen." + } + }, + "debug": { + "title": "Foutopsporing", + "desc": "De debugweergave toont een realtime overzicht van gevolgde objecten en hun statistieken. De objectlijst toont een samenvatting van gedetecteerde objecten met een tijdsvertraging.", + "debugging": "Foutopsporing", + "objectList": "Objectenlijst", + "noObjects": "Geen objecten", + "boundingBoxes": { + "title": "Objectkaders", + "desc": "Toon objectkaders rond gevolgde objecten", + "colors": { + "label": "Kleuren van objectkaders", + "info": "
  • Bij het opstarten wordt er een andere kleur toegewezen aan elk objectlabel.
  • Een dunne donkerblauwe lijn geeft aan dat het object op dit moment niet wordt gedetecteerd.
  • Een dunne grijze lijn geeft aan dat het object als stilstaand wordt herkend.
  • Een dikke lijn geeft aan dat het object het doelwit is van automatische tracking (indien ingeschakeld).
  • " + } + }, + "timestamp": { + "title": "Tijdstempel", + "desc": "Toon een tijdstempel als overlay op het beeld" + }, + "zones": { + "desc": "Toon een overzicht van alle gedefinieerde zones", + "title": "Zones" + }, + "mask": { + "title": "Bewegingsmaskers", + "desc": "Toon bewegingsmasker-polygonen" + }, + "motion": { + "title": "Bewegingskaders", + "desc": "Toon kaders rondom gebieden waar beweging wordt gedetecteerd", + "tips": "

    Bewegingskaders


    Rode kaders worden over het beeld geplaatst op de plekken waar momenteel beweging wordt gedetecteerd.

    " + }, + "regions": { + "title": "Regio's", + "desc": "Toon een kader rond het interessegebied dat naar de objectdetector wordt gestuurd", + "tips": "

    Interessekaders


    Heldergroene kaders worden over het beeld geplaatst op de interessegebieden die naar de objectdetector worden gestuurd.

    " + }, + "objectShapeFilterDrawing": { + "title": "Objectvormfilter tekenen", + "desc": "Teken een rechthoek op het beeld om details over oppervlakte en verhouding te bekijken", + "document": "Lees de documentatie ", + "area": "Gebied", + "tips": "Schakel deze optie in om een rechthoek op het camerabeeld te tekenen die de oppervlakte en verhouding weergeeft. Deze waarden kunnen vervolgens worden gebruikt om parameters voor het objectvormfilter in je configuratie in te stellen.", + "score": "Score", + "ratio": "Verhouding" + }, + "detectorDesc": "Frigate gebruikt je detectoren ({{detectors}}) om objecten in de videostream van je camera te detecteren." + }, + "users": { + "title": "Gebruikers", + "management": { + "desc": "Beheer de gebruikersaccounts van deze Frigate-installatie.", + "title": "Gebruikersbeheer" + }, + "addUser": "Gebruiker toevoegen", + "updatePassword": "Wachtwoord bijwerken", + "toast": { + "success": { + "createUser": "Gebruiker {{user}} succesvol aangemaakt", + "deleteUser": "Gebruiker {{user}} succesvol verwijderd", + "updatePassword": "Wachtwoord succesvol bijgewerkt.", + "roleUpdated": "De rol bijgewerkt voor {{user}}" + }, + "error": { + "setPasswordFailed": "Het wachtwoord kon niet worden opgeslagen: {{errorMessage}}", + "createUserFailed": "Gebruiker aanmaken mislukt: {{errorMessage}}", + "deleteUserFailed": "Gebruiker verwijderen mislukt: {{errorMessage}}", + "roleUpdateFailed": "Rol bijwerken mislukt: {{errorMessage}}" + } + }, + "table": { + "actions": "Acties", + "role": "Rol", + "noUsers": "Geen gebruikers gevonden.", + "changeRole": "Gebruikersrol wijzigen", + "password": "Wachtwoord", + "deleteUser": "Verwijder gebruiker", + "username": "Gebruikersnaam" + }, + "dialog": { + "form": { + "user": { + "desc": "Alleen letters, cijfers, punten en onderstrepingstekens zijn toegestaan.", + "title": "Gebruikersnaam", + "placeholder": "Gebruikersnaam invoeren" + }, + "password": { + "title": "Wachtwoord", + "strength": { + "medium": "Matig", + "strong": "Sterk", + "veryStrong": "Zeer sterk", + "title": "Wachtwoordsterkte: ", + "weak": "Zwak" + }, + "match": "Wachtwoorden komen overeen", + "confirm": { + "title": "Wachtwoord bevestigen", + "placeholder": "Wachtwoord bevestigen" + }, + "placeholder": "Wachtwoord invoeren", + "notMatch": "Wachtwoorden komen niet overeen" + }, + "newPassword": { + "title": "Nieuw wachtwoord", + "placeholder": "Voer een nieuw wachtwoord in", + "confirm": { + "placeholder": "Voer het nieuwe wachtwoord opnieuw in" + } + }, + "usernameIsRequired": "Gebruikersnaam is vereist" + }, + "createUser": { + "title": "Nieuwe gebruiker aanmaken", + "desc": "Voeg een nieuw gebruikersaccount toe en geef een rol op voor toegang tot onderdelen van de Frigate-interface.", + "usernameOnlyInclude": "Gebruikersnaam mag alleen letters, cijfers, . of _ bevatten" + }, + "deleteUser": { + "title": "Verwijder gebruiker", + "warn": "Weet je zeker dat je {{username}} wilt verwijderen?", + "desc": "Deze actie kan niet ongedaan worden gemaakt. Het gebruikersaccount wordt permanent verwijderd, samen met alle bijbehorende gegevens." + }, + "changeRole": { + "desc": "Machtigingen bijwerken voor {{username}}", + "title": "Gebruikersrol wijzigen", + "roleInfo": { + "intro": "Selecteer een gepaste rol voor deze gebruiker:", + "admin": "Beheerder", + "adminDesc": "Volledige toegang tot alle functies.", + "viewer": "Gebruiker", + "viewerDesc": "Alleen toegang tot Live-dashboards, Beoordelen, Verkennen en Exports." + } + }, + "passwordSetting": { + "setPassword": "Wachtwoord instellen", + "updatePassword": "Wachtwoord bijwerken voor {{username}}", + "desc": "Maak een sterk wachtwoord aan om dit account te beveiligen." + } + } + }, + "notification": { + "notificationSettings": { + "title": "Meldingen instellen", + "desc": "Frigate kan rechtstreeks pushmeldingen naar uw apparaat verzenden als het in de browser actief is of als een PWA geïnstalleerd is.", + "documentation": "Lees de documentatie" + }, + "notificationUnavailable": { + "title": "Meldingen niet beschikbaar", + "documentation": "Lees de documentatie", + "desc": "Webpushmeldingen vereisen een veilige omgeving (https://…). Dit is een beperking van de browser. Open Frigate via een beveiligde verbinding om meldingen te kunnen ontvangen." + }, + "globalSettings": { + "title": "Globale instellingen", + "desc": "Meldingen voor specifieke camera's op alle geregistreerde apparaten tijdelijk uitschakelen." + }, + "email": { + "title": "E-mail", + "placeholder": "bijv. voorbeeld@email.com", + "desc": "Een geldig e-mailadres is verplicht en wordt gebruikt om je te waarschuwen als er problemen zijn met de pushmeldingsdienst." + }, + "cameras": { + "noCameras": "Geen camera's beschikbaar", + "desc": "Selecteer voor welke camera's je meldingen wilt inschakelen.", + "title": "Camera's" + }, + "deviceSpecific": "Apparaatspecifieke instellingen", + "active": "Meldingen actief", + "suspendTime": { + "5minutes": "Onderbreek voor 5 minuten", + "30minutes": "Onderbreek voor 30 minuten", + "1hour": "Onderbreek voor 1 uur", + "12hours": "Onderbreek voor 12 uur", + "24hours": "Onderbreek voor 24 uur", + "untilRestart": "Opschorten tot herstart", + "10minutes": "Onderbreek voor 10 minuten", + "suspend": "Pauzeren" + }, + "cancelSuspension": "Onderbreking annuleren", + "toast": { + "success": { + "settingSaved": "De instellingen voor meldingen zijn opgeslagen.", + "registered": "Succesvol geregistreerd voor meldingen. Het opnieuw starten van Frigate is vereist voordat meldingen kunnen worden verzonden (inclusief een testmelding)." + }, + "error": { + "registerFailed": "Het opslaan van de meldingsregistratie is mislukt." + } + }, + "title": "Meldingen", + "sendTestNotification": "Stuur een testmelding", + "registerDevice": "Registreer dit apparaat", + "unregisterDevice": "Dit apparaat afmelden", + "suspended": "Meldingen onderbroken {{time}}" + }, + "frigatePlus": { + "title": "Frigate+ Instellingen", + "apiKey": { + "title": "Frigate+ API-sleutel", + "plusLink": "Lees meer over Frigate+", + "validated": "Frigate+ API-sleutel is gedetecteerd en gevalideerd", + "desc": "Met de Frigate+ API-sleutel is integratie met de Frigate+ service mogelijk.", + "notValidated": "Frigate+ API-sleutel wordt niet gedetecteerd of niet gevalideerd" + }, + "snapshotConfig": { + "title": "Snapshot-configuratie", + "desc": "Om te verzenden naar Frigate+ moeten zowel snapshots als clean_copy-snapshots ingeschakeld zijn in je configuratie.", + "documentation": "Lees de documentatie", + "table": { + "camera": "Camera", + "snapshots": "Snapshots", + "cleanCopySnapshots": "clean_copy Snapshots" + }, + "cleanCopyWarning": "Bij sommige camera's zijn snapshots ingeschakeld, maar ontbreekt de 'clean_copy'. Om afbeeldingen van deze camera's naar Frigate+ te kunnen verzenden, moet clean_copy zijn ingeschakeld in de snapshotconfiguratie." + }, + "modelInfo": { + "title": "Modelinformatie", + "modelType": "Type model", + "trainDate": "Trainingsdatum", + "baseModel": "Basismodel", + "cameras": "Camera's", + "error": "Het laden van modelinformatie is mislukt", + "loadingAvailableModels": "Beschikbare modellen laden…", + "modelSelect": "Je beschikbare modellen op Frigate+ kunnen hier worden geselecteerd. Houd er rekening mee dat alleen modellen die compatibel zijn met je huidige detectorconfiguratie geselecteerd kunnen worden.", + "dimensions": "Afmetingen", + "supportedDetectors": "Ondersteunde detectoren", + "availableModels": "Beschikbare modellen", + "loading": "Modelinformatie laden…", + "plusModelType": { + "baseModel": "Basismodel", + "userModel": "Verfijnd" + } + }, + "toast": { + "success": "Frigate+ instellingen zijn opgeslagen. Herstart Frigate om de wijzigingen toe te passen.", + "error": "Configuratiewijzigingen konden niet worden opgeslagen: {{errorMessage}}" + }, + "restart_required": "Herstart vereist (Frigate+ model gewijzigd)" + } +} diff --git a/web/public/locales/nl/views/system.json b/web/public/locales/nl/views/system.json new file mode 100644 index 000000000..073786f9d --- /dev/null +++ b/web/public/locales/nl/views/system.json @@ -0,0 +1,179 @@ +{ + "documentTitle": { + "general": "Algemene Statistieken - Frigate", + "logs": { + "nginx": "Nginx Logboeken - Frigate", + "go2rtc": "Go2RTC Logboeken - Frigate", + "frigate": "Frigate Logboek - Frigate" + }, + "storage": "Opslag Statistieken - Frigate", + "cameras": "Camera Statistieken - Frigate", + "enrichments": "Verrijkings Statistieken - Frigate" + }, + "title": "Systeem", + "metrics": "Systeem statistieken", + "logs": { + "download": { + "label": "Logs Downloaden" + }, + "copy": { + "label": "Kopieeren naar klembord", + "success": "Logs zijn gekopieerd naar klembord", + "error": "Logs kopieeren naar klembord mislukt" + }, + "type": { + "timestamp": "Tijdsvermelding", + "message": "Bericht", + "tag": "Tag", + "label": "Type" + }, + "toast": { + "error": { + "whileStreamingLogs": "Fout bij streamen van logs: {{errorMessage}}", + "fetchingLogsFailed": "Fout bij ophalen van logs: {{errorMessage}}" + } + }, + "tips": "Logs worden gestreamd vanaf de server" + }, + "general": { + "detector": { + "title": "Detectoren", + "cpuUsage": "Detector CPU-verbruik", + "memoryUsage": "Detector Geheugen Gebruik", + "inferenceSpeed": "Detector Interferentie Snelheid", + "temperature": "Detectortemperatuur" + }, + "hardwareInfo": { + "title": "Systeem Gegevens", + "gpuUsage": "GPU-verbruik", + "gpuInfo": { + "vainfoOutput": { + "title": "Vainfo Resultaat", + "returnCode": "Terugvoer Code: {{code}}", + "processError": "Process Fout:", + "processOutput": "Process Resultaat:" + }, + "nvidiaSMIOutput": { + "name": "Naam: {{name}}", + "vbios": "VBios Informatie: {{vbios}}", + "cudaComputerCapability": "CUDA Verwerking Capaciteit: {{cuda_compute}}", + "driver": "Stuurprogramma: {{driver}}", + "title": "Nvidia SMI Uitvoer" + }, + "closeInfo": { + "label": "Sluit GPU info" + }, + "copyInfo": { + "label": "Kopieer GPU Info" + }, + "toast": { + "success": "GPU info gekopieerd naar klembord" + } + }, + "gpuDecoder": "GPU Decodeerder", + "gpuEncoder": "GPU Encodeerder", + "gpuMemory": "GPU-geheugen", + "npuUsage": "NPU-gebruik", + "npuMemory": "NPU-geheugen" + }, + "otherProcesses": { + "processMemoryUsage": "Process Geheugen Gebruik", + "processCpuUsage": "Process CPU-verbruik", + "title": "Verdere Processen" + }, + "title": "Algemeen" + }, + "storage": { + "overview": "Overzicht", + "recordings": { + "title": "Opnames", + "earliestRecording": "Oudste beschikbare opname:", + "tips": "Deze waarde laat het totale opslag ruimte gebruik voor opnames zien in de database van Frigate. Frigate houdt geen opslag gebruiks gegevens bij van alle bestanden op uw schijf." + }, + "cameraStorage": { + "title": "Camera Opslag", + "unusedStorageInformation": "Ongebruikte opslagruimte informatie", + "storageUsed": "Opslag", + "percentageOfTotalUsed": "Percentage van Totaal", + "unused": { + "title": "Ongebruikt", + "tips": "Deze waarde kan de beschikbare opslag ruimte voor Frigate niet goed weergeven indien er ook andere bestanden op de schijf staan. Frigate houdt geen opslag gegevens bij van bestanden buiten haar eigen opnames." + }, + "camera": "Camera", + "bandwidth": "Bandbreedte" + }, + "title": "Opslag" + }, + "cameras": { + "title": "Cameras", + "overview": "Overzicht", + "info": { + "cameraProbeInfo": "{{camera}} Informatie opgehaald uit de camerastream", + "streamDataFromFFPROBE": "Streamgegevens zijn ontvangen via ffprobe.", + "stream": "Stream {{idx}}", + "resolution": "Resolutie:", + "unknown": "Onbekend", + "error": "Fout: {{error}}", + "tips": { + "title": "Informatie ophalen uit de camerastream" + }, + "fps": "FPS:", + "codec": "Codec:", + "video": "Video:", + "fetching": "Camera Gegevens Opvragen", + "audio": "Audio:" + }, + "framesAndDetections": "Frames / Detecties", + "label": { + "camera": "camera", + "detect": "detectie", + "skipped": "overgeslagen", + "ffmpeg": "FFmpeg", + "capture": "registratie", + "overallSkippedDetectionsPerSecond": "totaal aantal overgeslagen detecties per seconde", + "overallFramesPerSecond": "totale aantal frames per seconde", + "overallDetectionsPerSecond": "totale aantal detecties per seconde", + "cameraFfmpeg": "{{camName}} FFmpeg", + "cameraFramesPerSecond": "{{camName}} frames per seconde", + "cameraDetectionsPerSecond": "{{camName}} detecties per seconde", + "cameraSkippedDetectionsPerSecond": "{{camName}} overgeslagen detecties per seconde", + "cameraCapture": "{{camName}} opname", + "cameraDetect": "{{camName}} detecteren" + }, + "toast": { + "success": { + "copyToClipboard": "Uitvraag gegevens naar klembord gekopieerd." + }, + "error": { + "unableToProbeCamera": "Kan camera niet uitvragen: {{errorMessage}}" + } + } + }, + "lastRefreshed": "Voor het laatst vernieuwd: ", + "stats": { + "ffmpegHighCpuUsage": "{{camera}} zorgt voor hoge FFmpeg CPU belasting ({{ffmpegAvg}}%)", + "detectHighCpuUsage": "{{camera}} zorgt voor hoge detectie CPU belasting ({{detectAvg}}%)", + "healthy": "Systeem is gezond", + "reindexingEmbeddings": "Herindexering van inbeddingen ({{processed}}% compleet)", + "detectIsSlow": "{{detect}} is traag ({{speed}} ms)", + "detectIsVerySlow": "{{detect}} is erg traag ({{speed}} ms)", + "cameraIsOffline": "{{camera}} is offline" + }, + "enrichments": { + "title": "Verrijkingen", + "infPerSecond": "Interferenties Per Seconde", + "embeddings": { + "image_embedding_speed": "Afbeelding Inplaatsings Snelheid", + "face_embedding_speed": "Gezicht Inplaatsings Snelheid", + "text_embedding_speed": "Text Inplaatsing Snelheid", + "plate_recognition_speed": "Kentekenplaat Herkenning Snelheid", + "face_recognition_speed": "Snelheid van gezichtsherkenning", + "image_embedding": "Afbeelding Inbedden", + "text_embedding": "Tekstinbedden", + "face_recognition": "Gezichtsherkenning", + "yolov9_plate_detection_speed": "YOLOv9 Kentekenplaat Detectiesnelheid", + "yolov9_plate_detection": "YOLOv9 Kentekenplaatdetectie", + "plate_recognition": "Kentekenherkenning" + } + } +} diff --git a/web/public/locales/pl/audio.json b/web/public/locales/pl/audio.json new file mode 100644 index 000000000..62cd7b465 --- /dev/null +++ b/web/public/locales/pl/audio.json @@ -0,0 +1,429 @@ +{ + "speech": "Mowa", + "babbling": "Gaworzenie", + "yell": "Krzyk", + "bellow": "Ryk", + "whoop": "Okrzyk", + "whispering": "Szept", + "laughter": "Śmiech", + "snicker": "Chichot", + "crying": "Płacz", + "sigh": "Westchnienie", + "singing": "Śpiewanie", + "choir": "Chór", + "yodeling": "Jodłowanie", + "chant": "Skandowanie", + "mantra": "Mantra", + "child_singing": "Śpiew dziecka", + "synthetic_singing": "Śpiew syntetyczny", + "rapping": "Rapowanie", + "humming": "Nucenie", + "groan": "Jęk", + "grunt": "Chrząknięcie", + "whistling": "Gwizdanie", + "breathing": "Oddychanie", + "wheeze": "Świszczący oddech", + "snoring": "Chrapanie", + "gasp": "Sapnięcie", + "pant": "Dyszenie", + "snort": "Prychnięcie", + "cough": "Kaszel", + "throat_clearing": "Odchrząkiwanie", + "sneeze": "Kichnięcie", + "sniff": "Pociągnięcie nosem", + "run": "Bieg", + "shuffle": "Szuranie", + "footsteps": "Kroki", + "chewing": "Żucie", + "biting": "Gryzienie", + "gargling": "Płukanie gardła", + "stomach_rumble": "Burczenie w brzuchu", + "burping": "Bekanie", + "hiccup": "Czkawka", + "pets": "Zwierzęta domowe", + "finger_snapping": "Pstrykanie palcami", + "heartbeat": "Bicie serca", + "dog": "Pies", + "heart_murmur": "Szmer serca", + "chatter": "Gwar", + "children_playing": "Bawiące się dzieci", + "animal": "Zwierzę", + "applause": "Oklaski", + "cheering": "Wiwatowanie", + "bark": "Szczekanie", + "fart": "Pierdnięcie", + "hands": "Dłonie", + "clapping": "Klaskanie", + "crowd": "Tłum", + "hiss": "Syczenie", + "purr": "Mruczenie", + "yip": "Poszczekiwanie", + "howl": "Wycie", + "growling": "Warczenie", + "meow": "Miauczenie", + "bow_wow": "Hau hau", + "whimper_dog": "Skomlenie psa", + "cat": "Kot", + "caterwaul": "Koci wrzask", + "livestock": "Zwierzęta hodowlane", + "horse": "Koń", + "clip_clop": "Stukot kopyt", + "neigh": "Rżenie", + "cattle": "Bydło", + "moo": "Muczenie", + "cowbell": "Krowi dzwonek", + "goat": "Koza", + "bleat": "Beczenie", + "pig": "Świnia", + "oink": "Chrumkanie", + "sheep": "Owca", + "fowl": "Drób", + "chicken": "Kura", + "cluck": "Gdakanie", + "cock_a_doodle_doo": "Kukuryku", + "turkey": "Indyk", + "gobble": "Gulgotanie", + "duck": "Kaczka", + "quack": "Kwakanie", + "goose": "Gęś", + "honk": "Gęganie", + "wild_animals": "Dzikie zwierzęta", + "roaring_cats": "Ryczące koty", + "roar": "Ryk", + "bird": "Ptak", + "chirp": "Ćwierkanie", + "squawk": "Skrzeczenie", + "pigeon": "Gołąb", + "coo": "Gruchanie", + "crow": "Wrona", + "caw": "Krakanie", + "owl": "Sowa", + "hoot": "Pohukiwanie", + "flapping_wings": "Trzepot skrzydeł", + "insect": "Owad", + "cricket": "Świerszcz", + "mosquito": "Komar", + "fly": "Mucha", + "buzz": "Bzyczenie", + "frog": "Żaba", + "croak": "Kumkanie", + "snake": "Wąż", + "rattle": "Grzechotanie", + "whale_vocalization": "Wokalizacja wieloryba", + "music": "Muzyka", + "plucked_string_instrument": "Instrument strunowy szarpany", + "guitar": "Gitara", + "electric_guitar": "Gitara elektryczna", + "bass_guitar": "Gitara basowa", + "acoustic_guitar": "Gitara akustyczna", + "steel_guitar": "Gitara stalowa", + "tapping": "Tapowanie", + "strum": "Szarpnięcie strun", + "sitar": "Sitar", + "mandolin": "Mandolina", + "zither": "Cytra", + "ukulele": "Ukulele", + "keyboard": "Klawiatura", + "rimshot": "Rimshot", + "drum_roll": "Werbel (tremolo)", + "bass_drum": "Bęben basowy", + "timpani": "Kotły", + "tabla": "Tabla", + "cymbal": "Talerz", + "hi_hat": "Hi-hat", + "wood_block": "Pudełko drewniane", + "tambourine": "Tamburyn", + "maraca": "Marakasy", + "gong": "Gong", + "brass_instrument": "Instrument dęty blaszany", + "french_horn": "Waltornia", + "tubular_bells": "Dzwony rurowe", + "mallet_percussion": "Instrumenty perkusyjne pałkowe", + "marimba": "Marimba", + "glockenspiel": "Dzwonki", + "vibraphone": "Wibrafon", + "steelpan": "Instrument z beczek", + "orchestra": "Orkiestra", + "trumpet": "Trąbka", + "trombone": "Puzon", + "bowed_string_instrument": "Instrument strunowy smyczkowy", + "string_section": "Sekcja smyczkowa", + "violin": "Skrzypce", + "pizzicato": "Pizzicato", + "double_bass": "Kontrabas", + "wind_instrument": "Instrument dęty", + "saxophone": "Saksofon", + "clarinet": "Klarnet", + "harp": "Harfa", + "bell": "Dzwonek", + "church_bell": "Dzwon kościelny", + "jingle_bell": "Dzwoneczek", + "bicycle_bell": "Dzwonek rowerowy", + "tuning_fork": "Kamerton", + "chime": "Dzwonki", + "wind_chime": "Dzwonki wietrzne", + "harmonica": "Harmonijka", + "accordion": "Akordeon", + "bagpipes": "Dudy", + "didgeridoo": "Didgeridoo", + "theremin": "Theremin", + "singing_bowl": "Misa dźwiękowa", + "scratching": "Scratching", + "pop_music": "Muzyka pop", + "hip_hop_music": "Muzyka hip-hopowa", + "beatboxing": "Beatbox", + "rock_music": "Muzyka rockowa", + "heavy_metal": "Heavy metal", + "punk_rock": "Punk rock", + "grunge": "Grunge", + "progressive_rock": "Rock progresywny", + "rock_and_roll": "Rock and roll", + "psychedelic_rock": "Rock psychodeliczny", + "rhythm_and_blues": "Rhythm and blues", + "soul_music": "Muzyka soul", + "reggae": "Reggae", + "country": "Country", + "swing_music": "Muzyka swingowa", + "bluegrass": "Bluegrass", + "funk": "Funk", + "folk_music": "Muzyka folkowa", + "middle_eastern_music": "Muzyka bliskowschodnia", + "jazz": "Jazz", + "disco": "Disco", + "classical_music": "Muzyka klasyczna", + "opera": "Opera", + "electronic_music": "Muzyka elektroniczna", + "house_music": "Muzyka house", + "electronica": "Electronica", + "electronic_dance_music": "Muzyka elektroniczna taneczna", + "ambient_music": "Muzyka ambient", + "techno": "Techno", + "dubstep": "Dubstep", + "drum_and_bass": "Drum and bass", + "trance_music": "Muzyka trance", + "music_of_latin_america": "Muzyka Latynowska", + "salsa_music": "Muzyka salsa", + "flamenco": "Flamenco", + "blues": "Blues", + "music_for_children": "Muzyka dla dzieci", + "new-age_music": "Muzyka new age", + "vocal_music": "Muzyka wokalna", + "a_capella": "A cappella", + "music_of_africa": "Muzyka afrykańska", + "afrobeat": "Afrobeat", + "christian_music": "Muzyka chrześcijańska", + "gospel_music": "Muzyka gospel", + "music_of_asia": "Muzyka azjatycka", + "carnatic_music": "Muzyka karnatycka", + "music_of_bollywood": "Muzyka bollywood", + "ska": "Ska", + "independent_music": "Muzyka niezależna", + "song": "Piosenka", + "background_music": "Muzyka tła", + "theme_music": "Muzyka tematyczna", + "jingle": "Dżingiel", + "soundtrack_music": "Muzyka filmowa", + "lullaby": "Kołysanka", + "video_game_music": "Muzyka z gier wideo", + "christmas_music": "Muzyka świąteczna", + "dance_music": "Muzyka taneczna", + "wedding_music": "Muzyka weselna", + "happy_music": "Muzyka radosna", + "sad_music": "Muzyka smutna", + "tender_music": "Muzyka łagodna", + "exciting_music": "Muzyka ekscytująca", + "angry_music": "Muzyka gniewna", + "scary_music": "Muzyka straszna", + "wind": "Wiatr", + "rustling_leaves": "Szeleszczące liście", + "wind_noise": "Szum wiatru", + "thunderstorm": "Burza", + "thunder": "Grzmot", + "water": "Woda", + "rain": "Deszcz", + "raindrop": "Kropla deszczu", + "rain_on_surface": "Deszcz na powierzchni", + "stream": "Strumień", + "waterfall": "Wodospad", + "ocean": "Ocean", + "fire": "Ogień", + "boat": "Łódź", + "sailboat": "Żaglówka", + "motorboat": "Motorówka", + "ship": "Statek", + "motor_vehicle": "Pojazd silnikowy", + "car": "Samochód", + "toot": "Klakson", + "car_alarm": "Alarm samochodowy", + "power_windows": "Elektryczne szyby", + "skidding": "Poślizg", + "tire_squeal": "Pisk opon", + "ambulance": "Karetka", + "fire_engine": "Wóz strażacki", + "motorcycle": "Motocykl", + "traffic_noise": "Hałas uliczny", + "rail_transport": "Transport kolejowy", + "train": "Pociąg", + "train_whistle": "Gwizd pociągu", + "train_horn": "Sygnał dźwiękowy pociągu", + "railroad_car": "Wagon kolejowy", + "train_wheels_squealing": "Pisk kół pociągu", + "subway": "Metro", + "aircraft": "Statek powietrzny", + "aircraft_engine": "Silnik samolotu", + "jet_engine": "Silnik odrzutowy", + "propeller": "Śmigło", + "helicopter": "Helikopter", + "fixed-wing_aircraft": "Samolot", + "bicycle": "Rower", + "skateboard": "Deskorolka", + "engine": "Silnik", + "light_engine": "Lekki silnik", + "dental_drill's_drill": "Wiertło dentystyczne", + "lawn_mower": "Kosiarka do trawy", + "chainsaw": "Piła łańcuchowa", + "medium_engine": "Średni silnik", + "heavy_engine": "Ciężki silnik", + "engine_knocking": "Stukanie silnika", + "engine_starting": "Uruchamianie silnika", + "idling": "Praca na biegu jałowym", + "accelerating": "Przyspieszanie", + "door": "Drzwi", + "doorbell": "Dzwonek do drzwi", + "ding-dong": "Ding-dong", + "sliding_door": "Drzwi przesuwne", + "slam": "Trzaśnięcie", + "knock": "Pukanie", + "tap": "Stukanie", + "frying": "Smażenie", + "microwave_oven": "Kuchenka mikrofalowa", + "blender": "Blender", + "water_tap": "Kran", + "sink": "Zlew", + "bathtub": "Wanna", + "hair_dryer": "Suszarka do włosów", + "toilet_flush": "Spłuczka toalety", + "toothbrush": "Szczoteczka do zębów", + "electric_toothbrush": "Elektryczna szczoteczka do zębów", + "vacuum_cleaner": "Odkurzacz", + "zipper": "Zamek błyskawiczny", + "keys_jangling": "Brzęk kluczy", + "coin": "Moneta", + "shuffling_cards": "Tasowanie kart", + "typing": "Pisanie na klawiaturze", + "typewriter": "Maszyna do pisania", + "computer_keyboard": "Klawiatura komputerowa", + "writing": "Pisanie", + "alarm": "Alarm", + "telephone": "Telefon", + "telephone_bell_ringing": "Dzwonek telefonu", + "ringtone": "Dzwonek", + "telephone_dialing": "Wybieranie numeru", + "dial_tone": "Sygnał wybierania", + "busy_signal": "Sygnał zajętości", + "alarm_clock": "Budzik", + "siren": "Syrena", + "civil_defense_siren": "Syrena obrony cywilnej", + "buzzer": "Brzęczyk", + "smoke_detector": "Czujnik dymu", + "fire_alarm": "Alarm pożarowy", + "foghorn": "Sygnał mgłowy", + "whistle": "Gwizdek", + "steam_whistle": "Gwizdek parowy", + "drum_machine": "Automat perkusyjny", + "rats": "Szczury", + "harpsichord": "Klawesyn", + "musical_instrument": "Instrument muzyczny", + "organ": "Organy", + "dogs": "Psy", + "piano": "Fortepian", + "synthesizer": "Syntezator", + "sampler": "Sampler", + "electronic_organ": "Organy elektroniczne", + "patter": "Tupot", + "drum": "Bęben", + "banjo": "Banjo", + "snare_drum": "Werbel", + "mouse": "Mysz", + "electric_piano": "Pianino elektryczne", + "percussion": "Perkusja", + "hammond_organ": "Organy Hammonda", + "drum_kit": "Zestaw perkusyjny", + "air_brake": "Hamulec pneumatyczny", + "flute": "Flet", + "rowboat": "Łódź wiosłowa", + "squeak": "Skrzypienie", + "cupboard_open_or_close": "Otwieranie lub zamykanie szafki", + "chopping": "Siekanie", + "cello": "Wiolonczela", + "dishes": "Naczynia", + "cutlery": "Sztućce", + "car_passing_by": "Przejeżdżający samochód", + "ice_cream_truck": "Samochód z lodami", + "waves": "Fale", + "race_car": "Samochód wyścigowy", + "steam": "Para", + "reversing_beeps": "Sygnał cofania", + "police_car": "Radiowóz", + "bus": "Autobus", + "emergency_vehicle": "Pojazd uprzywilejowany", + "drawer_open_or_close": "Otwieranie lub zamykanie szuflady", + "traditional_music": "Muzyka tradycyjna", + "electric_shaver": "Elektryczna golarka", + "gurgling": "Bulgotanie", + "crackle": "Trzask", + "vehicle": "Pojazd", + "air_horn": "Klakson pneumatyczny", + "truck": "Ciężarówka", + "scissors": "Nożyczki", + "mechanisms": "Mechanizmy", + "ratchet": "Zapadka", + "tick-tock": "Tik-tak", + "gears": "Przekładnie", + "sewing_machine": "Maszyna do szycia", + "mechanical_fan": "Wentylator mechaniczny", + "air_conditioning": "Klimatyzacja", + "cash_register": "Kasa fiskalna", + "printer": "Drukarka", + "camera": "Kamera", + "single-lens_reflex_camera": "Lustrzanka jednooobiektywowa", + "tools": "Narzędzia", + "hammer": "Młotek", + "jackhammer": "Młot pneumatyczny", + "sawing": "Piłowanie", + "filing": "Pilnikowanie", + "power_tool": "Elektronarzędzie", + "drill": "Wiertarka", + "explosion": "Eksplozja", + "gunshot": "Strzał", + "machine_gun": "Karabin maszynowy", + "fusillade": "Kanonada", + "artillery_fire": "Ogień artyleryjski", + "cap_gun": "Pistolet na kapiszony", + "fireworks": "Fajerwerki", + "firecracker": "Petarda", + "burst": "Wybuch", + "eruption": "Erupcja", + "boom": "Huk", + "wood": "Drewno", + "chop": "Rąbanie", + "splinter": "Drzazga", + "crack": "Pęknięcie", + "glass": "Szkło", + "chink": "Brzęk", + "shatter": "Rozbicie", + "silence": "Cisza", + "sound_effect": "Efekt dźwiękowy", + "environmental_noise": "Hałas otoczenia", + "static": "Szum", + "white_noise": "Biały szum", + "pink_noise": "Różowy szum", + "television": "Telewizor", + "radio": "Radio", + "field_recording": "Nagranie terenowe", + "scream": "Wrzask", + "pulleys": "Bloczki", + "sanding": "Szlifowanie", + "clock": "Zegar", + "tick": "Tykanie" +} diff --git a/web/public/locales/pl/common.json b/web/public/locales/pl/common.json new file mode 100644 index 000000000..4b3915685 --- /dev/null +++ b/web/public/locales/pl/common.json @@ -0,0 +1,263 @@ +{ + "time": { + "12hours": "12 godzin", + "1hour": "1 godzina", + "24hours": "24 godziny", + "last7": "Ostatnie 7 dni", + "last14": "Ostatnie 14 dni", + "last30": "Ostatnie 30 dni", + "thisWeek": "Ten tydzień", + "lastWeek": "Ostatni tydzień", + "thisMonth": "Ten miesiąc", + "lastMonth": "Ostatni miesiąc", + "5minutes": "5 minut", + "10minutes": "10 minut", + "30minutes": "30 minut", + "untilForTime": "Do {{time}}", + "untilForRestart": "Do czasu restartu Frigate.", + "untilRestart": "Do restartu", + "ago": "{{timeAgo}} temu", + "justNow": "Właśnie teraz", + "today": "Dzisiaj", + "yesterday": "Wczoraj", + "pm": "po południu", + "am": "przed południem", + "yr": "{{time}}r.", + "year_one": "{{time}} rok", + "year_few": "{{time}} lata", + "year_many": "{{time}} lat", + "mo": "{{time}}m.", + "d": "{{time}}d.", + "day_one": "{{time}} dzień", + "day_few": "{{time}} dni", + "day_many": "{{time}} dni", + "h": "{{time}}godz.", + "m": "{{time}}min.", + "s": "{{time}}s.", + "month_one": "{{time}} miesiąc", + "month_few": "{{time}} miesiące", + "month_many": "{{time}} miesięcy", + "hour_one": "{{time}} godzina", + "hour_few": "{{time}} godziny", + "hour_many": "{{time}} godzin", + "minute_one": "{{time}} minuta", + "minute_few": "{{time}} minuty", + "minute_many": "{{time}} minut", + "formattedTimestamp": { + "12hour": "d MMM, h:mm:ss aaa", + "24hour": "MMM d, HH:mm:ss" + }, + "formattedTimestamp2": { + "12hour": "MM/dd h:mm:ssa", + "24hour": "d MMM HH:mm:ss" + }, + "formattedTimestampExcludeSeconds": { + "12hour": "%b %-d, %I:%M %p", + "24hour": "%b %-d, %H:%M" + }, + "formattedTimestampWithYear": { + "12hour": "%b %-d %Y, %I:%M %p", + "24hour": "%b %-d %Y, %H:%M" + }, + "formattedTimestampOnlyMonthAndDay": "%b %-d", + "second_one": "{{time}} sekunda", + "second_few": "{{time}} sekundy", + "second_many": "{{time}} sekund", + "formattedTimestampHourMinute": { + "12hour": "h:mm aaa", + "24hour": "HH:mm" + }, + "formattedTimestampHourMinuteSecond": { + "12hour": "h:mm:ss aaa", + "24hour": "HH:mm:ss" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "d MMM, h:mm aaa", + "24hour": "d MMM, HH:mm" + }, + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "d MMM yyyy, h:mm aaa", + "24hour": "d MMM yyyy, HH:mm" + }, + "formattedTimestampMonthDay": "d MMM", + "formattedTimestampFilename": { + "12hour": "dd-MM-yy-h-mm-ss-a", + "24hour": "dd-MM-yy-HH-mm-ss" + } + }, + "unit": { + "speed": { + "mph": "mph", + "kph": "km/h" + } + }, + "label": { + "back": "Wróć" + }, + "button": { + "apply": "Zastosuj", + "reset": "Resetuj", + "done": "Gotowe", + "enabled": "Włączone", + "enable": "Włącz", + "disable": "Wyłącz", + "save": "Zapisz", + "history": "Historia", + "fullscreen": "Pełny ekran", + "exitFullscreen": "Wyjdź z pełnego ekranu", + "pictureInPicture": "Obraz w obrazie", + "delete": "Usuń", + "yes": "Tak", + "no": "Nie", + "download": "Pobierz", + "info": "Informacje", + "suspended": "Wstrzymane", + "unsuspended": "Wznów", + "play": "Odtwórz", + "unselect": "Odznacz", + "export": "Eksportuj", + "deleteNow": "Usuń teraz", + "next": "Dalej", + "disabled": "Wyłączone", + "back": "Wstecz", + "saving": "Zapisywanie…", + "on": "WŁĄCZ", + "cancel": "Anuluj", + "twoWayTalk": "Komunikacja dwustronna", + "close": "Zamknij", + "copy": "Kopiuj", + "cameraAudio": "Dźwięk kamery", + "off": "WYŁĄCZ", + "edit": "Edytuj", + "copyCoordinates": "Kopiuj współrzędne" + }, + "menu": { + "system": "System", + "systemMetrics": "Metryki systemowe", + "configuration": "Konfiguracja", + "systemLogs": "Logi systemowe", + "languages": "Języki", + "language": { + "en": "English (Angielski)", + "zhCN": "简体中文 (Uproszczony Chiński)", + "withSystem": { + "label": "Użyj ustawień systemowych dla języka" + }, + "es": "Español (Hiszpański)", + "cs": "Čeština (Czeski)", + "pl": "Polski (Polski)", + "hi": "हिन्दी (hinduski)", + "ar": "العربية (arabski)", + "fr": "Français (francuski)", + "pt": "Português (portugalski)", + "ru": "Русский (rosyjski)", + "de": "Deutsch (niemiecki)", + "ja": "日本語 (japoński)", + "tr": "Türkçe (Turecki)", + "it": "Italiano (Włoski)", + "nl": "Nederlands (Holenderski)", + "sv": "Svenska (Szwedzki)", + "nb": "Norsk Bokmål (Norweski)", + "ko": "한국어 (Koreański)", + "fa": "فارسی (Perski)", + "uk": "Українська (Ukraiński)", + "he": "עברית (Hebrajski)", + "el": "Ελληνικά (Grecki)", + "hu": "Magyar (Węgierski)", + "da": "Dansk (Duński)", + "sk": "Slovenčina (Słowacki)", + "vi": "Tiếng Việt (Wietnamski)", + "ro": "Română (Rumuński)", + "fi": "Suomi (Fiński)" + }, + "appearance": "Wygląd", + "darkMode": { + "label": "Tryb ciemny", + "light": "Jasny", + "dark": "Ciemny", + "withSystem": { + "label": "Użyj ustawień systemowych dla trybu jasnego/ciemnego" + } + }, + "withSystem": "System", + "theme": { + "label": "Motyw", + "blue": "Niebieski", + "green": "Zielony", + "contrast": "Wysoki kontrast", + "default": "Domyślny", + "red": "Czerwony", + "nord": "Nordycki" + }, + "restart": "Uruchom ponownie Frigate", + "live": { + "title": "Na żywo", + "allCameras": "Wszystkie kamery", + "cameras": { + "title": "Kamery", + "count_one": "{{count}} Kamera", + "count_few": "{{count}} Kamer", + "count_many": "{{count}} Kamery" + } + }, + "review": "Przegląd", + "uiPlayground": "Plac testowy UI", + "faceLibrary": "Biblioteka twarzy", + "user": { + "account": "Konto", + "current": "Aktualny użytkownik: {{user}}", + "anonymous": "anonimowy", + "logout": "Wyloguj", + "setPassword": "Ustaw hasło", + "title": "Użytkownik" + }, + "documentation": { + "title": "Dokumentacja", + "label": "Dokumentacja Frigate" + }, + "explore": "Przeglądaj", + "configurationEditor": "Edytor konfiguracji", + "help": "Pomoc", + "settings": "Ustawienia", + "export": "Eksportuj" + }, + "role": { + "viewer": "Przeglądający", + "desc": "Administratorzy mają pełny dostęp do wszystkich funkcji w interfejsie Frigate. Przeglądający mają ograniczony dostęp tylko do podglądu kamer, przeglądania nagrań i historycznych materiałów w interfejsie.", + "title": "Rola", + "admin": "Administrator" + }, + "pagination": { + "label": "paginacja", + "previous": { + "title": "Poprzednia", + "label": "Przejdź do poprzedniej strony" + }, + "next": { + "title": "Następna", + "label": "Przejdź do następnej strony" + }, + "more": "Więcej stron" + }, + "accessDenied": { + "title": "Dostęp Zabroniony", + "desc": "Nie masz uprawnień do wyświetlenia tej strony.", + "documentTitle": "Dostęp Zabroniony - Frigate" + }, + "notFound": { + "title": "404", + "desc": "Strona nie znaleziona", + "documentTitle": "Nie Znaleziono - Frigate" + }, + "selectItem": "Wybierz {{item}}", + "toast": { + "copyUrlToClipboard": "Skopiowano URL do schowka.", + "save": { + "error": { + "title": "Nie udało się zapisać zmian konfiguracji: {{errorMessage}}", + "noMessage": "Nie udało się zapisać zmian konfiguracji" + }, + "title": "Zapisz" + } + } +} diff --git a/web/public/locales/pl/components/auth.json b/web/public/locales/pl/components/auth.json new file mode 100644 index 000000000..094e0ca97 --- /dev/null +++ b/web/public/locales/pl/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "user": "Nazwa użytkownika", + "password": "Hasło", + "login": "Login", + "errors": { + "usernameRequired": "Nazwa użytkownika jest wymagana", + "passwordRequired": "Hasło jest wymagane", + "loginFailed": "Logowanie nieudane", + "unknownError": "Nieznany błąd. Sprawdź logi.", + "webUnknownError": "Nieznany błąd. Sprawdź konsolę.", + "rateLimit": "Przekroczono limit częstotliwości. Spróbuj ponownie później." + } + } +} diff --git a/web/public/locales/pl/components/camera.json b/web/public/locales/pl/components/camera.json new file mode 100644 index 000000000..7ad57e5ab --- /dev/null +++ b/web/public/locales/pl/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "label": "Grupy kamer", + "add": "Dodaj grupę kamer", + "edit": "Edytuj grupę kamer", + "delete": { + "label": "Usuń grupę kamer", + "confirm": { + "title": "Potwierdź usuwanie", + "desc": "Czy jesteś pewny że chcesz usunąć grupę kamer {{name}}?" + } + }, + "name": { + "placeholder": "Wprowadź nazwę…", + "label": "Nazwa", + "errorMessage": { + "mustLeastCharacters": "Nazwa grupy kamer musi mieć co najmniej 2 znaki.", + "exists": "Grupa kamer o takiej nazwie już istnieje.", + "nameMustNotPeriod": "Nazwa grupy kamer nie może zawierać kropki.", + "invalid": "Niepoprawna nazwa grupy kamer." + } + }, + "cameras": { + "label": "Kamery", + "desc": "Wykierz kamery dla tej grupy." + }, + "icon": "Ikona", + "success": "Grupa kamer ({{name}}) została zapisana.", + "camera": { + "setting": { + "audio": { + "tips": { + "document": "Czytaj dokumentację ", + "title": "Dźwięk musi być wysyłany z kamery i skonfigurowany w go2rtc dla tego strumienia." + } + }, + "label": "Ustawienia Strumieniowania Kamery", + "title": "Ustawienia Strumieniowania {{cameraName}}", + "desc": "Zmień opcje strumieniowania na żywo dla pulpitu tej grupy kamer. Te ustawienia są specyficzne dla urządzenia/przeglądarki.", + "audioIsAvailable": "Dźwięk jest dostępny dla tego strumienia", + "audioIsUnavailable": "Dźwięk jest niedostępny dla tego strumienia", + "streamMethod": { + "label": "Metoda Strumieniowania", + "method": { + "noStreaming": { + "label": "Brak Strumieniowania", + "desc": "Obrazy z kamery będą aktualizowane tylko raz na minutę, bez strumieniowania na żywo." + }, + "smartStreaming": { + "label": "Inteligentne Strumieniowanie (zalecane)", + "desc": "Inteligentne strumieniowanie aktualizuje obraz kamery raz na minutę gdy nie wykryto aktywności, aby oszczędzać przepustowość i zasoby. Gdy aktywność zostanie wykryta, obraz płynnie przełącza się na transmisję na żywo." + }, + "continuousStreaming": { + "desc": { + "title": "Obraz kamery będzie zawsze strumieniowany na żywo, gdy jest widoczny na pulpicie, nawet jeśli nie wykryto aktywności.", + "warning": "Ciągłe strumieniowanie może powodować wysokie zużycie przepustowości i problemy z wydajnością. Używaj ostrożnie." + }, + "label": "Ciągłe Strumieniowanie" + } + } + }, + "compatibilityMode": { + "label": "Tryb kompatybilności", + "desc": "Włącz tę opcję tylko jeśli transmisja na żywo z kamery wyświetla artefakty kolorów i ma ukośną linię po prawej stronie obrazu." + } + } + } + }, + "debug": { + "options": { + "label": "Ustawienia", + "title": "Opcje", + "showOptions": "Pokaż Opcje", + "hideOptions": "Ukryj Opcje" + }, + "timestamp": "Znacznik czasu", + "zones": "Strefy", + "mask": "Maski", + "regions": "Regiony", + "motion": "Ruch", + "boundingBox": "Ramka Ograniczająca" + } +} diff --git a/web/public/locales/pl/components/dialog.json b/web/public/locales/pl/components/dialog.json new file mode 100644 index 000000000..b36d38560 --- /dev/null +++ b/web/public/locales/pl/components/dialog.json @@ -0,0 +1,122 @@ +{ + "restart": { + "title": "Czy na pewno chcesz ponownie uruchomić Frigate?", + "button": "Uruchom ponownie", + "restarting": { + "title": "Frigate uruchamia się ponownie", + "content": "Strona odświeży się za {{countdown}} sekund.", + "button": "Wymuś odświeżenie" + } + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "Wyślij do Frigate+", + "desc": "Obiekty w miejscach, których chcesz unikać, nie są fałszywymi alarmami. Zgłaszanie ich jako fałszywe alarmy zdezorientuje model." + }, + "review": { + "true": { + "label": "Potwierdź tę etykietę dla Frigate Plus", + "true_one": "To jest {{label}}", + "true_few": "To są {{label}}", + "true_many": "To są {{label}}" + }, + "false": { + "label": "Nie potwierdzaj tej etykiety dla Frigate Plus", + "false_one": "To nie jest {{label}}", + "false_few": "To nie są {{label}}", + "false_many": "To nie są {{label}}" + }, + "state": { + "submitted": "Przesłano" + }, + "question": { + "ask_a": "Czy ten obiekt to {{label}}?", + "ask_an": "Czy ten obiekt to {{label}}?", + "ask_full": "Czy ten obiekt to {{untranslatedLabel}} ({{translatedLabel}})?", + "label": "Potwierdź tę etykietę dla Frigate Plus" + } + } + }, + "video": { + "viewInHistory": "Zobacz w Historii" + } + }, + "export": { + "time": { + "lastHour_one": "Ostatnia godzina", + "lastHour_few": "Ostatnie {{count}} godziny", + "lastHour_many": "Ostatnie {{count}} godzin", + "fromTimeline": "Wybierz z Osi Czasu", + "custom": "Niestandardowy", + "start": { + "title": "Czas Rozpoczęcia", + "label": "Wybierz Czas Rozpoczęcia" + }, + "end": { + "title": "Czas Zakończenia", + "label": "Wybierz Czas Zakończenia" + } + }, + "name": { + "placeholder": "Nazwij Eksport" + }, + "select": "Wybierz", + "export": "Eksportuj", + "selectOrExport": "Wybierz lub Eksportuj", + "toast": { + "success": "Pomyślnie rozpoczęto eksport. Zobacz plik w folderze /exports.", + "error": { + "failed": "Nie udało się rozpocząć eksportu: {{error}}", + "endTimeMustAfterStartTime": "Czas zakończenia musi być późniejszy niż czas rozpoczęcia", + "noVaildTimeSelected": "Nie wybrano prawidłowego zakresu czasu" + } + }, + "fromTimeline": { + "saveExport": "Zapisz Eksport", + "previewExport": "Podgląd Eksportu" + } + }, + "recording": { + "button": { + "markAsReviewed": "Oznacz jako sprawdzone", + "deleteNow": "Usuń teraz", + "export": "Eksportuj" + }, + "confirmDelete": { + "title": "Potwierdź Usunięcie", + "desc": { + "selected": "Czy na pewno chcesz usunąć wszystkie nagrane wideo powiązane z tym elementem recenzji?

    Przytrzymaj klawisz Shift, aby pominąć to okno dialogowe w przyszłości." + } + } + }, + "streaming": { + "label": "Strumień", + "restreaming": { + "disabled": "Restreaming nie jest włączony dla tej kamery.", + "desc": { + "title": "Skonfiguruj go2rtc dla dodatkowych opcji podglądu na żywo i dźwięku dla tej kamery.", + "readTheDocumentation": "Przeczytaj dokumentację" + } + }, + "showStats": { + "label": "Pokaż statystyki strumienia", + "desc": "Włącz tę opcję, aby wyświetlać statystyki strumienia jako nakładkę na obrazie z kamery." + }, + "debugView": "Widok Debugowania" + }, + "search": { + "saveSearch": { + "label": "Zapisz Wyszukiwanie", + "desc": "Podaj nazwę dla tego zapisanego wyszukiwania.", + "placeholder": "Wprowadź nazwę dla swojego wyszukiwania", + "overwrite": "{{searchName}} już istnieje. Zapisanie nadpisze istniejącą wartość.", + "success": "Wyszukiwanie ({{searchName}}) zostało zapisane.", + "button": { + "save": { + "label": "Zapisz to wyszukiwanie" + } + } + } + } +} diff --git a/web/public/locales/pl/components/filter.json b/web/public/locales/pl/components/filter.json new file mode 100644 index 000000000..e85cd00e6 --- /dev/null +++ b/web/public/locales/pl/components/filter.json @@ -0,0 +1,125 @@ +{ + "filter": "Filtr", + "labels": { + "label": "Etykiety", + "all": { + "title": "Wszystkie Etykiety", + "short": "Etykiety" + }, + "count_one": "{{count}} Etykieta", + "count_other": "{{count}} Etykiet" + }, + "zones": { + "label": "Strefy", + "all": { + "title": "Wszystkie Strefy", + "short": "Strefy" + } + }, + "subLabels": { + "all": "Wszystkie Podetykiety", + "label": "Podetykiety" + }, + "score": "Wynik", + "estimatedSpeed": "Szacowana Prędkość ({{unit}})", + "features": { + "label": "Funkcje", + "hasSnapshot": "Posiada zrzut ekranu", + "hasVideoClip": "Posiada klip wideo", + "submittedToFrigatePlus": { + "label": "Przesłano do Frigate+", + "tips": "Musisz najpierw filtrować obiekty śledzone, które mają zrzut ekranu.

    Obiekty śledzone bez zrzutu ekranu nie mogą być przesłane do Frigate+." + } + }, + "sort": { + "dateDesc": "Data (Malejąco)", + "scoreAsc": "Wynik Obiektu (Rosnąco)", + "scoreDesc": "Wynik Obiektu (Malejąco)", + "speedAsc": "Szacowana Prędkość (Rosnąco)", + "speedDesc": "Szacowana Prędkość (Malejąco)", + "label": "Sortuj", + "dateAsc": "Data (Rosnąco)", + "relevance": "Trafność" + }, + "explore": { + "settings": { + "gridColumns": { + "desc": "Wybierz liczbę kolumn w widoku siatki.", + "title": "Kolumny Siatki" + }, + "searchSource": { + "label": "Źródło Wyszukiwania", + "desc": "Wybierz, czy przeszukiwać miniatury czy opisy śledzonych obiektów.", + "options": { + "description": "Opis", + "thumbnailImage": "Obraz Miniatury" + } + }, + "defaultView": { + "title": "Domyślny Widok", + "summary": "Podsumowanie", + "unfilteredGrid": "Niefiltrowana Siatka", + "desc": "Gdy nie wybrano filtrów, wyświetl podsumowanie najnowszych śledzonych obiektów dla każdej etykiety lub wyświetl niefiltrowaną siatkę." + }, + "title": "Ustawienia" + }, + "date": { + "selectDateBy": { + "label": "Wybierz datę do filtrowania" + } + } + }, + "logSettings": { + "label": "Filtruj poziom logów", + "filterBySeverity": "Filtruj logi według ważności", + "loading": { + "title": "Ładowanie", + "desc": "Gdy panel logów jest przewinięty do dołu, nowe logi są automatycznie strumieniowane w miarę ich dodawania." + }, + "disableLogStreaming": "Wyłącz strumieniowanie logów", + "allLogs": "Wszystkie logi" + }, + "recognizedLicensePlates": { + "loading": "Ładowanie rozpoznanych tablic rejestracyjnych…", + "placeholder": "Wpisz, aby wyszukać tablice rejestracyjne…", + "noLicensePlatesFound": "Nie znaleziono tablic rejestracyjnych.", + "title": "Rozpoznane Tablice Rejestracyjne", + "loadFailed": "Nie udało się załadować rozpoznanych tablic rejestracyjnych.", + "selectPlatesFromList": "Wybierz jedną lub więcej tablic z listy." + }, + "dates": { + "all": { + "title": "Wszystkie Daty", + "short": "Daty" + } + }, + "more": "Więcej Filtrów", + "reset": { + "label": "Resetuj filtry do wartości domyślnych" + }, + "timeRange": "Zakres Czasu", + "cameras": { + "label": "Filtr Kamer", + "all": { + "title": "Wszystkie Kamery", + "short": "Kamery" + } + }, + "review": { + "showReviewed": "Pokaż Przejrzane" + }, + "motion": { + "showMotionOnly": "Pokaż Tylko Ruch" + }, + "trackedObjectDelete": { + "toast": { + "success": "Śledzone obiekty zostały pomyślnie usunięte.", + "error": "Nie udało się usunąć śledzonych obiektów: {{errorMessage}}" + }, + "title": "Potwierdź Usunięcie", + "desc": "Usunięcie tych {{objectLength}} śledzonych obiektów usuwa zrzut ekranu, wszelkie zapisane osadzenia i wszystkie powiązane wpisy cyklu życia obiektu. Nagrane materiały tych śledzonych obiektów w widoku Historii NIE zostaną usunięte.

    Czy na pewno chcesz kontynuować?

    Przytrzymaj klawisz Shift, aby pominąć to okno dialogowe w przyszłości." + }, + "zoneMask": { + "filterBy": "Filtruj według maski strefy" + } +} diff --git a/web/public/locales/pl/components/icons.json b/web/public/locales/pl/components/icons.json new file mode 100644 index 000000000..35cbdc1c4 --- /dev/null +++ b/web/public/locales/pl/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "Wybierz ikonę", + "search": { + "placeholder": "Wyszukaj ikonę…" + } + } +} diff --git a/web/public/locales/pl/components/input.json b/web/public/locales/pl/components/input.json new file mode 100644 index 000000000..1216c7a00 --- /dev/null +++ b/web/public/locales/pl/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Pobierz Wideo", + "toast": { + "success": "Rozpoczęto pobieranie nagrania do przeglądu." + } + } + } +} diff --git a/web/public/locales/pl/components/player.json b/web/public/locales/pl/components/player.json new file mode 100644 index 000000000..227813f9c --- /dev/null +++ b/web/public/locales/pl/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "Nie znaleziono żadnych nagrań w tym czasie", + "cameraDisabled": "Kamera jest wyłączona", + "stats": { + "latency": { + "title": "Opóźnienie:", + "value": "{{seconds}} sekund", + "short": { + "title": "Opóźnienie", + "value": "{{seconds}} s" + } + }, + "totalFrames": "Całkowita liczba klatek:", + "streamType": { + "title": "Typ transmisji:", + "short": "Typ" + }, + "bandwidth": { + "title": "Przepustowość:", + "short": "Przepustowość" + }, + "droppedFrames": { + "title": "Porzucone klatki:", + "short": { + "title": "Porzucone", + "value": "{{droppedFrames}} klatek" + } + }, + "decodedFrames": "Zdekodowane klatki:", + "droppedFrameRate": "Współczynnik porzuconych klatek:" + }, + "noPreviewFound": "Nie znaleziono podglądu", + "noPreviewFoundFor": "Nie znaleziono podglądu dla {{cameraName}}", + "submitFrigatePlus": { + "title": "Wyślij tę klatkę do Frigate+?", + "submit": "Wyślij" + }, + "livePlayerRequiredIOSVersion": "Wymagana wersja iOS 17.1 lub nowsza dla tego typu transmisji na żywo.", + "streamOffline": { + "title": "Transmisja offline", + "desc": "Nie otrzymano klatek na strumieniu {{cameraName}} detect, sprawdź logi błędów" + }, + "toast": { + "success": { + "submittedFrigatePlus": "Pomyślnie wysłano klatkę do Frigate+" + }, + "error": { + "submitFrigatePlusFailed": "Nie udało się wysłać klatki do Frigate+" + } + } +} diff --git a/web/public/locales/pl/objects.json b/web/public/locales/pl/objects.json new file mode 100644 index 000000000..3923ec726 --- /dev/null +++ b/web/public/locales/pl/objects.json @@ -0,0 +1,120 @@ +{ + "bird": "Ptak", + "boat": "Łódź", + "car": "Samochód", + "bus": "Autobus", + "motorcycle": "Motocykl", + "train": "Pociąg", + "bicycle": "Rower", + "sheep": "Owca", + "mouse": "Mysz", + "keyboard": "Klawiatura", + "door": "Drzwi", + "blender": "Blender", + "sink": "Zlew", + "vehicle": "Pojazd", + "hair_dryer": "Suszarka do włosów", + "toothbrush": "Szczoteczka do zębów", + "scissors": "Nożyczki", + "goat": "Koza", + "skateboard": "Deskorolka", + "dog": "Pies", + "cat": "Kot", + "horse": "Koń", + "clock": "Zegar", + "animal": "Zwierzę", + "bark": "Szczekanie", + "person": "Osoba", + "airplane": "Samolot", + "traffic_light": "Światła Uliczne", + "fire_hydrant": "Hydrant", + "street_sign": "Znak Drogowy", + "stop_sign": "Znak Stopu", + "parking_meter": "Parkometr", + "bench": "Ławka", + "cow": "Krowa", + "bear": "Niedźwiedź", + "giraffe": "Żyrafa", + "backpack": "Plecak", + "umbrella": "Parasolka", + "shoe": "But", + "eye_glasses": "Okulary Przeciwsłoneczne", + "tie": "Krawat", + "skis": "Narty", + "tennis_racket": "Rakieta Tenisowa", + "bottle": "Butelka", + "plate": "Tależ", + "wine_glass": "Kieliszek do Wina", + "cup": "Kubek", + "fork": "Widelec", + "banana": "Banan", + "apple": "Jabłko", + "carrot": "Marchewka", + "hot_dog": "Hot Dog", + "pizza": "Pizza", + "cake": "Ciastko", + "chair": "Krzesło", + "bed": "Łóżko", + "mirror": "Lustro", + "dining_table": "Stół Jadalny", + "window": "Okno", + "toilet": "Toaleta", + "tv": "Telewizor", + "laptop": "Laptop", + "remote": "Pilot", + "toaster": "Toster", + "refrigerator": "Lodówka", + "book": "Książka", + "vase": "Waza", + "hair_brush": "Szczotka do Włosów", + "squirrel": "Wiewiórka", + "fox": "Lis", + "waste_bin": "Kosz na Śmieci", + "face": "Twarz", + "license_plate": "Tablica Rejestracyjna", + "package": "Paczka", + "bbq_grill": "Grill", + "amazon": "Amazon", + "dhl": "DHL", + "gls": "GLS", + "dpd": "DPD", + "baseball_glove": "Rękawica Bejsbolowa", + "baseball_bat": "Kij Bejsbolowy", + "bowl": "Miska", + "spoon": "Łyżka", + "sandwich": "Kanapka", + "zebra": "Zebra", + "snowboard": "Snowboard", + "knife": "Nóż", + "broccoli": "Brokuł", + "elephant": "Śłoń", + "desk": "Biurko", + "orange": "Pomarańcza", + "cell_phone": "Telefon Komórkowy", + "microwave": "Mikrofalówka", + "oven": "Piekarnik", + "hat": "Kapelusz", + "handbag": "Torebka", + "suitcase": "Walizka", + "sports_ball": "Piłka sportowa", + "kite": "Latawiec", + "surfboard": "Deska surfingowa", + "donut": "Pączek", + "couch": "Kanapa", + "potted_plant": "Roślina doniczkowa", + "teddy_bear": "Miś pluszowy", + "deer": "Jeleń", + "rabbit": "Królik", + "raccoon": "Szop pracz", + "robot_lawnmower": "Robot koszący", + "usps": "USPS (Poczta Amerykańska)", + "on_demand": "Na żądanie", + "ups": "UPS", + "fedex": "FedEx", + "an_post": "An Post (Poczta Irlandzka)", + "purolator": "Purolator", + "postnl": "PostNL (Poczta Holenderska)", + "nzpost": "NZPost (Poczta Nowozelandzka)", + "postnord": "PostNord (Poczta Skandynawska)", + "frisbee": "Frisbee" +} diff --git a/web/public/locales/pl/views/configEditor.json b/web/public/locales/pl/views/configEditor.json new file mode 100644 index 000000000..ec3056c53 --- /dev/null +++ b/web/public/locales/pl/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "documentTitle": "Edytor konfiguracji - Frigate", + "configEditor": "Edytor konfiguracji", + "copyConfig": "Skopiuj konfigurację", + "toast": { + "success": { + "copyToClipboard": "Konfiguracja skopiowana do schowka." + }, + "error": { + "savingError": "Błąd podczas zapisywanie konfiguracji" + } + }, + "saveOnly": "Tylko zapisz", + "saveAndRestart": "Zapisz i uruchom ponownie" +} diff --git a/web/public/locales/pl/views/events.json b/web/public/locales/pl/views/events.json new file mode 100644 index 000000000..1f4721aed --- /dev/null +++ b/web/public/locales/pl/views/events.json @@ -0,0 +1,37 @@ +{ + "camera": "Kamera", + "alerts": "Alerty", + "detections": "Wykrycia", + "motion": { + "label": "Ruch", + "only": "Tylko ruch" + }, + "allCameras": "Wszystkie kamery", + "empty": { + "alert": "Brak alertów do przejrzenia", + "detection": "Brak detekcji do przejrzenia", + "motion": "Nie znaleziono danych o ruchu" + }, + "timeline": "Oś czasu", + "timeline.aria": "Wybierz oś czasu", + "events": { + "label": "Zdarzenia", + "aria": "Wybierz zdarzenia", + "noFoundForTimePeriod": "Brak zdarzeń w tym okresie czasu." + }, + "documentTitle": "Przegląd - Frigate", + "recordings": { + "documentTitle": "Nagrania - Frigate" + }, + "markAsReviewed": "Oznacz jako przejrzane", + "markTheseItemsAsReviewed": "Oznacz te elementy jako przejrzane", + "calendarFilter": { + "last24Hours": "Ostatnie 24 godziny" + }, + "newReviewItems": { + "label": "Zobacz nowe elementy do przeglądu", + "button": "Nowe elementy do przeglądu" + }, + "selected_one": "{{count}} wybrane", + "selected_other": "{{count}} wybrane" +} diff --git a/web/public/locales/pl/views/explore.json b/web/public/locales/pl/views/explore.json new file mode 100644 index 000000000..dd344b34e --- /dev/null +++ b/web/public/locales/pl/views/explore.json @@ -0,0 +1,202 @@ +{ + "generativeAI": "Generatywna SI", + "documentTitle": "Eksploruj - Frigate", + "details": { + "timestamp": "Znacznik czasu", + "item": { + "desc": "Szczegóły elementu do przeglądu", + "title": "Szczegóły Elementu do Przeglądu", + "button": { + "share": "Udostępnij ten element", + "viewInExplore": "Zobacz w Eksploracji" + }, + "tips": { + "hasMissingObjects": "Dostosuj swoją konfigurację, jeśli chcesz, aby Frigate zapisywał śledzone obiekty dla następujących etykiet: {{objects}}", + "mismatch_one": "{{count}} niedostępny obiekt został wykryty i uwzględniony w tym elemencie przeglądu. Ten obiekt albo nie kwalifikował się jako alert lub detekcja, albo został już wyczyszczont/usunięty.", + "mismatch_few": "{{count}} niedostępne obiekty zostały wykryte i uwzględnione w tym elemencie przeglądu. Te obiekty albo nie kwalifikowały się jako alert lub detekcja, albo zostały już wyczyszczone/usunięte.", + "mismatch_many": "{{count}} niedostępnych obiektów zostało wykrytych i uwzględnionych w tym elemencie przeglądu. Te obiekty albo nie kwalifikowały się jako alert lub detekcja, albo zostały już wyczyszczone/usunięte." + }, + "toast": { + "success": { + "regenerate": "Zażądano nowego opisu od {{provider}}. W zależności od szybkości twojego dostawcy, wygenerowanie nowego opisu może zająć trochę czasu.", + "updatedSublabel": "Pomyślnie zaktualizowano podetykietę.", + "updatedLPR": "Pomyślnie zaktualizowano tablicę rejestracyjną." + }, + "error": { + "regenerate": "Nie udało się wezwać {{provider}} dla nowego opisu: {{errorMessage}}", + "updatedSublabelFailed": "Nie udało się zaktualizować podetykiety: {{errorMessage}}", + "updatedLPRFailed": "Nie udało się zaktualizować tablicy rejestracyjnej: {{errorMessage}}" + } + } + }, + "topScore": { + "info": "Najwyższy wynik to najwyższa mediana wyniku dla śledzonego obiektu, więc może się różnić od wyniku pokazanego na miniaturze wyników wyszukiwania.", + "label": "Najwyższy wynik" + }, + "editSubLabel": { + "descNoLabel": "Wprowadź nową podetykietę dla tego śledzonego obiektu", + "title": "Edytuj podetykietę", + "desc": "Wprowadź nową podetykietę dla tego {{label}}" + }, + "estimatedSpeed": "Szacowana prędkość", + "label": "Etykieta", + "button": { + "regenerate": { + "title": "Regeneruj", + "label": "Regeneruj opis śledzonego obiektu" + }, + "findSimilar": "Znajdź Podobne" + }, + "objects": "Obiekty", + "camera": "Kamera", + "zones": "Strefy", + "expandRegenerationMenu": "Rozwiń menu regeneracji", + "description": { + "label": "Opis", + "placeholder": "Opis śledzonego obiektu", + "aiTips": "Frigate nie poprosi o opis od twojego dostawcy AI, dopóki cykl życia śledzonego obiektu nie dobiegnie końca." + }, + "editLPR": { + "title": "Edytuj tablicę rejestracyjną", + "desc": "Wprowadź nową wartość tablicy rejestracyjnej dla tego {{label}}", + "descNoLabel": "Wprowadź nową wartość tablicy rejestracyjnej dla tego śledzonego obiektu" + }, + "tips": { + "descriptionSaved": "Pomyślnie zapisano opis", + "saveDescriptionFailed": "Nie udało się zaktualizować opisu: {{errorMessage}}" + }, + "recognizedLicensePlate": "Rozpoznana tablica rejestracyjna", + "regenerateFromSnapshot": "Regeneruj ze zrzutu ekranu", + "regenerateFromThumbnails": "Regeneruj z miniatur", + "snapshotScore": { + "label": "Wynik zrzutu" + } + }, + "objectLifecycle": { + "annotationSettings": { + "title": "Ustawienia adnotacji", + "showAllZones": { + "title": "Pokaż wszystkie strefy", + "desc": "Zawsze pokazuj strefy na klatkach, w których obiekty weszły do strefy." + }, + "offset": { + "desc": "Te dane pochodzą z kanału detekcji kamery, ale są nakładane na obrazy z kanału nagrywania. Mało prawdopodobne, aby oba strumienie były idealnie zsynchronizowane. W rezultacie ramka ograniczająca i nagranie mogą nie być idealnie dopasowane. Jednak pole annotation_offset może być użyte do regulacji tego.", + "documentation": "Przeczytaj dokumentację ", + "label": "Przesunięcie adnotacji", + "millisecondsToOffset": "Milisekundy do przesunięcia adnotacji detekcji. Domyślnie: 0", + "tips": "WSKAZÓWKA: Wyobraź sobie, że istnieje klip zdarzenia z osobą idącą od lewej do prawej. Jeśli na osi czasu zdarzenia ramka ograniczająca jest konsekwentnie na lewo od osoby, wartość powinna być zmniejszona. Podobnie, jeśli osoba idzie od lewej do prawej, a ramka ograniczająca jest konsekwentnie przed osobą, wartość powinna być zwiększona." + } + }, + "title": "Cykl życia obiektu", + "noImageFound": "Nie znaleziono obrazu dla tego znacznika czasu.", + "scrollViewTips": "Przewiń, aby zobaczyć kluczowe momenty cyklu życia tego obiektu.", + "autoTrackingTips": "Pozycje ramek ograniczających mogą być niedokładne dla kamer z automatycznym śledzeniem.", + "lifecycleItemDesc": { + "visible": "{{label}} wykryty", + "entered_zone": "{{label}} wszedł w strefę {{zones}}", + "active": "{{label}} stał się aktywny", + "stationary": "{{label}} stał się nieruchomy", + "attribute": { + "faceOrLicense_plate": "{{attribute}} wykryty dla {{label}}", + "other": "{{label}} rozpoznany jako {{attribute}}" + }, + "gone": "{{label}} zniknął", + "heard": "{{label}} usłyszany", + "external": "{{label}} wykryty", + "header": { + "ratio": "Współczynnik", + "area": "Obszar", + "zones": "Strefy" + } + }, + "carousel": { + "previous": "Poprzedni slajd", + "next": "Następny slajd" + }, + "createObjectMask": "Utwórz maskę obiektu", + "adjustAnnotationSettings": "Dostosuj ustawienia adnotacji" + }, + "exploreIsUnavailable": { + "title": "Eksploracja jest niedostępna", + "embeddingsReindexing": { + "context": "Eksploracja będzie dostępna po zakończeniu ponownego indeksowania osadzenia śledzonych obiektów.", + "startingUp": "Uruchamianie…", + "estimatedTime": "Szacowany pozostały czas:", + "finishingShortly": "Zakańczanie", + "step": { + "thumbnailsEmbedded": "Osadzone miniatury: ", + "descriptionsEmbedded": "Osadzone opisy: ", + "trackedObjectsProcessed": "Przetworzone śledzone obiekty: " + } + }, + "downloadingModels": { + "context": "Frigate pobiera niezbędne modele osadzenia do obsługi funkcji wyszukiwania semantycznego. Może to potrwać kilka minut, w zależności od prędkości Twojego połączenia sieciowego.", + "setup": { + "visionModelFeatureExtractor": "Ekstraktor cech modelu wizyjnego", + "textModel": "Model tekstowy", + "visionModel": "Model wizyjny", + "textTokenizer": "Tokenizer tekstu" + }, + "tips": { + "context": "Po pobraniu modeli warto ponownie zindeksować osadzenia śledzonych obiektów.", + "documentation": "Przeczytaj dokumentację" + }, + "error": "Wystąpił błąd. Sprawdź logi Frigate." + } + }, + "trackedObjectDetails": "Szczegóły śledzonego obiektu", + "type": { + "details": "szczegóły", + "snapshot": "zrzut ekranu", + "video": "wideo", + "object_lifecycle": "cykl życia obiektu" + }, + "itemMenu": { + "downloadSnapshot": { + "aria": "Pobierz zrzut ekranu", + "label": "Pobierz zrzut ekranu" + }, + "viewObjectLifecycle": { + "label": "Wyświetl cykl życia obiektu", + "aria": "Pokaż cykl życia obiektu" + }, + "downloadVideo": { + "label": "Pobierz wideo", + "aria": "Pobierz wideo" + }, + "findSimilar": { + "label": "Znajdź podobne", + "aria": "Znajdź podobne śledzone obiekty" + }, + "submitToPlus": { + "label": "Prześlij do Frigate+", + "aria": "Prześlij do Frigate Plus" + }, + "viewInHistory": { + "label": "Wyświetl w Historii", + "aria": "Wyświetl w Historii" + }, + "deleteTrackedObject": { + "label": "Usuń ten śledzony obiekt" + } + }, + "trackedObjectsCount_one": "{{count}} śledzony obiekt ", + "trackedObjectsCount_few": "{{count}} śledzone obiekty ", + "trackedObjectsCount_many": "{{count}} śledzonych obiektów ", + "noTrackedObjects": "Nie znaleziono śledzonych obiektów", + "dialog": { + "confirmDelete": { + "desc": "Usunięcie tego śledzonego obiektu usuwa zrzut ekranu, wszelkie zapisane osadzenia i wszystkie powiązane wpisy cyklu życia obiektu. Nagrany materiał tego śledzonego obiektu w widoku Historii NIE zostanie usunięty.

    Czy na pewno chcesz kontynuować?", + "title": "Potwierdź usunięcie" + } + }, + "fetchingTrackedObjectsFailed": "Błąd pobierania śledzonych obiektów: {{errorMessage}}", + "searchResult": { + "deleteTrackedObject": { + "toast": { + "success": "Śledzony obiekt usunięty pomyślnie.", + "error": "Nie udało się usunąć śledzonego obiektu: {{errorMessage}}" + } + } + } +} diff --git a/web/public/locales/pl/views/exports.json b/web/public/locales/pl/views/exports.json new file mode 100644 index 000000000..11bb6ab04 --- /dev/null +++ b/web/public/locales/pl/views/exports.json @@ -0,0 +1,17 @@ +{ + "search": "Szukaj", + "documentTitle": "Eksport - Frigate", + "noExports": "Nie znaleziono eksportów", + "deleteExport": "Usuń eksport", + "deleteExport.desc": "Czy na pewno chcesz usunąć {{exportName}}?", + "editExport": { + "title": "Zmień nazwę eksportu", + "desc": "Wprowadź nową nazwę dla tego eksportu.", + "saveExport": "Zapisz eksport" + }, + "toast": { + "error": { + "renameExportFailed": "Nie udało się zmienić nazwy eksportu: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/pl/views/faceLibrary.json b/web/public/locales/pl/views/faceLibrary.json new file mode 100644 index 000000000..130dec17f --- /dev/null +++ b/web/public/locales/pl/views/faceLibrary.json @@ -0,0 +1,86 @@ +{ + "selectItem": "Wybierz {{item}}", + "description": { + "addFace": "Poznaj proces dodawania nowej kolekcji do biblioteki twarzy.", + "placeholder": "Wprowadź nazwę tej kolekcji" + }, + "details": { + "person": "Osoba", + "confidence": "Pewność", + "face": "Szczegóły twarzy", + "faceDesc": "Szczegóły twarzy i powiązanego obiektu", + "timestamp": "Znacznik czasu" + }, + "documentTitle": "Biblioteka twarzy - Frigate", + "uploadFaceImage": { + "title": "Wgraj zdjęcie twarzy", + "desc": "Wgraj obraz do skanowania twarzy i dołącz do {{pageToggle}}" + }, + "createFaceLibrary": { + "title": "Utwórz kolekcję", + "desc": "Utwórz nową kolekcję", + "new": "Utwórz nową twarz", + "nextSteps": "Aby zbudować solidną podstawę:
  • Użyj zakładki Trenuj, aby wybrać i trenować na obrazach dla każdej wykrytej osoby.
  • Skup się na zdjęciach twarzy na wprost dla najlepszych wyników; unikaj trenowania na zdjęciach, które pokazują twarze pod kątem.
  • " + }, + "train": { + "aria": "Wybierz trenowanie", + "title": "Trenuj" + }, + "selectFace": "Wybierz twarz", + "deleteFaceLibrary": { + "title": "Usuń nazwę", + "desc": "Czy na pewno chcesz usunąć kolekcję {{name}}? Spowoduje to trwałe usunięcie wszystkich powiązanych twarzy." + }, + "button": { + "addFace": "Dodaj twarz", + "uploadImage": "Wgraj obraz", + "reprocessFace": "Przetwórz twarz ponownie", + "deleteFaceAttempts": "Usuń próby rozpoznania twarzy", + "renameFace": "Zmień nazwę twarzy", + "deleteFace": "Usuń twarz" + }, + "imageEntry": { + "validation": { + "selectImage": "Proszę wybrać plik obrazu." + }, + "dropActive": "Upuść obraz tutaj…", + "dropInstructions": "Przeciągnij i upuść obraz tutaj lub kliknij, aby wybrać", + "maxSize": "Maksymalny rozmiar: {{size}}MB" + }, + "toast": { + "success": { + "deletedName_one": "{{count}} twarz została pomyślnie usunięta.", + "deletedName_few": "{{count}} twarze zostały pomyślnie usunięte.", + "deletedName_many": "{{count}} twarzy zostało pomyślnie usuniętych.", + "deletedFace_one": "Pomyślnie usunięto {{count}} twarz.", + "deletedFace_few": "Pomyślnie usunięto {{count}} twarze.", + "deletedFace_many": "Pomyślnie usunięto {{count}} twarzy.", + "uploadedImage": "Pomyślnie wgrano obraz.", + "addFaceLibrary": "{{name}} został pomyślnie dodany do Biblioteki Twarzy!", + "trainedFace": "Pomyślnie wytrenowano twarz.", + "updatedFaceScore": "Pomyślnie zaktualizowano wynik twarzy.", + "renamedFace": "Pomyślnie zmieniono nazwę twarzy na {{name}}" + }, + "error": { + "addFaceLibraryFailed": "Nie udało się ustawić nazwy twarzy: {{errorMessage}}", + "deleteFaceFailed": "Nie udało się usunąć: {{errorMessage}}", + "deleteNameFailed": "Nie udało się usunąć nazwy: {{errorMessage}}", + "trainFailed": "Nie udało się przeprowadzić treningu: {{errorMessage}}", + "updateFaceScoreFailed": "Nie udało się zaktualizować wyniku twarzy: {{errorMessage}}", + "uploadingImageFailed": "Nie udało się wgrać obrazu: {{errorMessage}}", + "renameFaceFailed": "Nie udało się zmienić nazwy twarzy: {{errorMessage}}" + } + }, + "readTheDocs": "Przeczytaj dokumentację", + "trainFaceAs": "Trenuj twarz jako:", + "trainFace": "Trenuj twarz", + "steps": { + "faceName": "Wprowadź nazwę twarzy", + "uploadFace": "Prześlij obraz twarzy", + "nextSteps": "Kolejne kroki" + }, + "renameFace": { + "title": "Zmień nazwę twarzy", + "desc": "Wprowadź nową nazwę dla {{name}}" + } +} diff --git a/web/public/locales/pl/views/live.json b/web/public/locales/pl/views/live.json new file mode 100644 index 000000000..87b0af4ab --- /dev/null +++ b/web/public/locales/pl/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "Na żywo - Frigate", + "documentTitle.withCamera": "{{camera}}- Na żywo - Frigate", + "lowBandwidthMode": "Tryb niskiej przepustowości", + "twoWayTalk": { + "enable": "Włącz komunikację dwukierunkową", + "disable": "Wyłącz komunikację dwukierunkową" + }, + "cameraAudio": { + "enable": "Włącz dźwięk kamery", + "disable": "Wyłącz dźwięk kamery" + }, + "ptz": { + "move": { + "clickMove": { + "label": "Kliknij w ramce, aby wyśrodkować kamerę", + "enable": "Włącz kliknięcie do przesuwania", + "disable": "Wyłącz kliknięcie do przesuwania" + }, + "left": { + "label": "Przesuń kamerę PTZ w lewo" + }, + "right": { + "label": "Przesuń kamerę PTZ w prawo" + }, + "down": { + "label": "Przesuń kamerę PTZ w dół" + }, + "up": { + "label": "Przesuń kamerę PTZ w górę" + } + }, + "zoom": { + "in": { + "label": "Przybliż kamerę PTZ" + }, + "out": { + "label": "Oddal kamerę PTZ" + } + }, + "frame": { + "center": { + "label": "Kliknij w ramce, aby wyśrodkować kamerę PTZ" + } + }, + "presets": "Presety kamery PTZ" + }, + "recording": { + "enable": "Włącz nagrywanie", + "disable": "Wyłącz nagrywanie" + }, + "snapshots": { + "enable": "Włącz zrzuty ekranu", + "disable": "Wyłącz zrzuty ekranu" + }, + "streamStats": { + "disable": "Ukryj statystyki strumienia", + "enable": "Pokaż statystyki strumienia" + }, + "manualRecording": { + "title": "Nagrywanie na żądanie", + "tips": "Rozpocznij ręczne zdarzenie w oparciu o ustawienia przechowywania nagrań tej kamery.", + "playInBackground": { + "label": "Odtwarzaj w tle", + "desc": "Włącz tę opcję, aby kontynuować transmisję, gdy odtwarzacz jest ukryty." + }, + "showStats": { + "label": "Pokaż statystyki", + "desc": "Włącz tę opcję, aby pokazać statystyki strumienia jako nakładkę na podgląd kamery." + }, + "debugView": "Widok debugowania", + "start": "Rozpocznij nagrywanie na żądanie", + "started": "Rozpoczęto ręczne nagrywanie na żądanie.", + "failedToStart": "Nie udało się rozpocząć ręcznego nagrywania na żądanie.", + "recordDisabledTips": "Ponieważ nagrywanie jest wyłączone lub ograniczone w konfiguracji tej kamery, zostanie zapisany tylko zrzut ekranu.", + "end": "Zakończ nagrywanie na żądanie", + "ended": "Zakończono ręczne nagrywanie na żądanie.", + "failedToEnd": "Nie udało się zakończyć ręcznego nagrywania na żądanie." + }, + "notifications": "Powiadomienia", + "audio": "Dźwięk", + "suspend": { + "forTime": "Zawieś na: " + }, + "stream": { + "title": "Strumień", + "audio": { + "tips": { + "title": "Dźwięk musi być wysyłany z kamery i skonfigurowany w go2rtc dla tego strumienia.", + "documentation": "Przeczytaj dokumentację " + }, + "available": "Dźwięk jest dostępny dla tego strumienia", + "unavailable": "Dźwięk nie jest dostępny dla tego strumienia" + }, + "twoWayTalk": { + "tips.documentation": "Przeczytaj dokumentację ", + "tips": "Twoje urządzenie musi obsługiwać tę funkcję, a WebRTC musi być skonfigurowany dla komunikacji dwukierunkowej.", + "unavailable": "Komunikacja dwukierunkowa jest niedostępna dla tego strumienia", + "available": "Komunikacja dwukierunkowa jest dostępna dla tego strumienia" + }, + "lowBandwidth": { + "resetStream": "Zresetuj strumień", + "tips": "Podgląd na żywo jest w trybie niskiej przepustowości z powodu buforowania lub błędów strumienia." + }, + "playInBackground": { + "tips": "Włącz tę opcję, aby kontynuować transmisję, gdy odtwarzacz jest ukryty.", + "label": "Odtwarzaj w tle" + } + }, + "cameraSettings": { + "title": "Ustawienia {{camera}}", + "cameraEnabled": "Kamera włączona", + "objectDetection": "Wykrywanie obiektów", + "recording": "Nagrywanie", + "snapshots": "Zrzuty ekranu", + "audioDetection": "Wykrywanie dźwięku", + "autotracking": "Automatyczne śledzenie" + }, + "effectiveRetainMode": { + "modes": { + "all": "Wszystkie", + "active_objects": "Aktywne obiekty", + "motion": "Ruch" + }, + "notAllTips": "Twoja konfiguracja przechowywania nagrań {{source}} jest ustawiona na tryb: {{effectiveRetainMode}}, więc to nagrywanie na żądanie zachowa tylko segmenty z {{effectiveRetainModeName}}." + }, + "editLayout": { + "label": "Edytuj układ", + "group": { + "label": "Edytuj grupę kamer" + }, + "exitEdit": "Zakończ edycję" + }, + "muteCameras": { + "enable": "Wycisz wszystkie kamery", + "disable": "Wyłącz wyciszenie wszystkich kamer" + }, + "camera": { + "disable": "Wyłącz kamerę", + "enable": "Włącz kamerę" + }, + "autotracking": { + "enable": "Włącz automatyczne śledzenie", + "disable": "Wyłącz automatyczne śledzenie" + }, + "detect": { + "disable": "Wyłącz wykrywanie", + "enable": "Włącz wykrywanie" + }, + "audioDetect": { + "enable": "Włącz wykrywanie dźwięku", + "disable": "Wyłącz wykrywanie dźwięku" + }, + "streamingSettings": "Ustawienia transmisji", + "history": { + "label": "Pokaż nagrania archiwalne" + } +} diff --git a/web/public/locales/pl/views/recording.json b/web/public/locales/pl/views/recording.json new file mode 100644 index 000000000..dfaf0c33e --- /dev/null +++ b/web/public/locales/pl/views/recording.json @@ -0,0 +1,12 @@ +{ + "filter": "Filtr", + "export": "Eksportuj", + "calendar": "Kalendarz", + "filters": "Filtry", + "toast": { + "error": { + "noValidTimeSelected": "Nie wybrano poprawnego zakresu czasu", + "endTimeMustAfterStartTime": "Czas końca musi być po czasie początku" + } + } +} diff --git a/web/public/locales/pl/views/search.json b/web/public/locales/pl/views/search.json new file mode 100644 index 000000000..175b42a80 --- /dev/null +++ b/web/public/locales/pl/views/search.json @@ -0,0 +1,74 @@ +{ + "search": "Szukaj", + "savedSearches": "Zapisane wyszukiwania", + "searchFor": "Szukaj {{inputValue}}", + "button": { + "clear": "Wyczyść wyszukiwanie", + "save": "Zapisz wyszukiwanie", + "delete": "Usuń zapisane wyszukiwanie", + "filterInformation": "Informacje o filtrze", + "filterActive": "Aktywne filtry" + }, + "trackedObjectId": "ID śledzonego obiektu", + "filter": { + "label": { + "cameras": "Kamery", + "labels": "Etykiety", + "zones": "Strefy", + "sub_labels": "Podetykiety", + "min_score": "Min. wynik", + "max_score": "Maks. wynik", + "min_speed": "Min. prędkość", + "max_speed": "Maks. prędkość", + "recognized_license_plate": "Rozpoznana tablica rejestracyjna", + "has_clip": "Posiada klip", + "has_snapshot": "Posiada zrzut ekranu", + "after": "Po", + "search_type": "Typ wyszukiwania", + "time_range": "Zakres czasu", + "before": "Przed" + }, + "searchType": { + "thumbnail": "Miniatura", + "description": "Opis" + }, + "toast": { + "error": { + "beforeDateBeLaterAfter": "Data 'przed' musi być późniejsza niż data 'po'.", + "afterDatebeEarlierBefore": "Data 'po' musi być wcześniejsza niż data 'przed'.", + "minScoreMustBeLessOrEqualMaxScore": "'Min. wynik' musi być mniejszy lub równy 'maks. wynikowi'.", + "maxScoreMustBeGreaterOrEqualMinScore": "'Maks. wynik' musi być większy lub równy 'min. wynikowi'.", + "minSpeedMustBeLessOrEqualMaxSpeed": "'Min. prędkość' musi być mniejsza lub równa 'maks. prędkości'.", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "'Maks. prędkość' musi być większa lub równa 'min. prędkości'." + } + }, + "tips": { + "title": "Jak używać filtrów tekstowych", + "desc": { + "text": "Filtry pomagają zawęzić wyniki wyszukiwania. Oto jak używać ich w polu wejściowym:", + "example": "Przykład: cameras:front_door label:person before:01012024 time_range:3:00PM-4:00PM ", + "step": "
    • Wpisz nazwę filtra, a następnie dwukropek (np., \"kamery:\").
    • Wybierz wartość z sugestii lub wpisz własną.
    • Używaj wielu filtrów, dodając je jeden po drugim z odstępem pomiędzy.
    • Filtry dat (przed: i po:) używają formatu {{DateFormat}}.
    • Filtr zakresu czasu używa formatu {{exampleTime}}.
    • Usuwaj filtry klikając 'x' obok nich.
    ", + "step2": "Wybierz wartość z sugestii lub wpisz własną.", + "step3": "Użyj kilku filtrów dodając jeden po drugim i oddzielając je spacją.", + "exampleLabel": "Przykład:", + "step1": "Wprowadź nazwę filtra z dwukropkiem (np.: \"cameras:\").", + "step4": "Filtry dat (before: i after:) użyj formatu {{DateFormat}}.", + "step5": "Filtr zakresu czasu wykorzystuje format {{exampleTime}}.", + "step6": "Usuń filtry klikając 'x' obok nich." + } + }, + "header": { + "currentFilterType": "Wartości filtrów", + "noFilters": "Filtry", + "activeFilters": "Aktywne filtry" + } + }, + "similaritySearch": { + "title": "Wyszukiwanie podobieństw", + "active": "Wyszukiwanie podobieństw aktywne", + "clear": "Wyczyść wyszukiwanie podobieństw" + }, + "placeholder": { + "search": "Szukaj…" + } +} diff --git a/web/public/locales/pl/views/settings.json b/web/public/locales/pl/views/settings.json new file mode 100644 index 000000000..5cf1371d1 --- /dev/null +++ b/web/public/locales/pl/views/settings.json @@ -0,0 +1,598 @@ +{ + "menu": { + "users": "Użytkownicy", + "notifications": "Powiadomienia", + "ui": "Interfejs Użytkownika", + "classification": "Klasyfikacja", + "cameras": "Ustawienia Kamery", + "frigateplus": "Frigate+", + "masksAndZones": "Maski / Strefy", + "motionTuner": "Konfigurator Ruchu", + "debug": "Debugowanie" + }, + "dialog": { + "unsavedChanges": { + "title": "Masz niezapisane zmiany.", + "desc": "Czy chcesz zapisać swoje zmiany przed kontynuowaniem?" + } + }, + "cameraSetting": { + "camera": "Kamera", + "noCamera": "Brak Kamery" + }, + "general": { + "title": "Ustawienia Ogólne", + "storedLayouts": { + "title": "Zapisane Układy", + "clearAll": "Wyczyść Wszystkie Układy", + "desc": "Układ kamer w grupie można przeciągać/zmieniać rozmiar. Pozycje są zapisywane w lokalnej pamięci przeglądarki." + }, + "calendar": { + "title": "Kalendarz", + "firstWeekday": { + "label": "Pierwszy dzień tygodnia", + "sunday": "Niedziela", + "monday": "Poniedziałek", + "desc": "Dzień od którego zaczyna się kalendarz przeglądu." + } + }, + "liveDashboard": { + "automaticLiveView": { + "label": "Automatyczny Podgląd na Żywo", + "desc": "Automatycznie przełącz na podgląd na żywo kamery, gdy wykryta zostanie aktywność. Wyłączenie tej opcji spowoduje, że statyczne obrazy kamer na panelu Na Żywo będą aktualizowane tylko raz na minutę." + }, + "title": "Panel Na Żywo", + "playAlertVideos": { + "label": "Odtwarzaj Filmy Alarmowe", + "desc": "Domyślnie, ostatnie alerty na panelu Na Żywo są odtwarzane jako małe zapętlone filmy. Wyłącz tę opcję, aby pokazywać tylko statyczny obraz ostatnich alertów na tym urządzeniu/przeglądarce." + } + }, + "cameraGroupStreaming": { + "title": "Ustawienia Strumieniowania Grup Kamer", + "desc": "Ustawienia strumieniowania dla każdej grupy kamer są przechowywane w lokalnej pamięci przeglądarki.", + "clearAll": "Wyczyść Wszystkie Ustawienia Strumieniowania" + }, + "recordingsViewer": { + "title": "Przeglądarka Nagrań", + "defaultPlaybackRate": { + "label": "Domyślna Prędkość Odtwarzania", + "desc": "Domyślna prędkość odtwarzania dla odtwarzania nagrań." + } + }, + "toast": { + "success": { + "clearStoredLayout": "Wyczyszczono zapisany układ dla {{cameraName}}", + "clearStreamingSettings": "Wyczyszczono ustawienia strumieniowania dla wszystkich grup kamer." + }, + "error": { + "clearStoredLayoutFailed": "Nie udało się wyczyścić zapisanego układu: {{errorMessage}}", + "clearStreamingSettingsFailed": "Nie udało się wyczyścić ustawień strumieniowania: {{errorMessage}}" + } + } + }, + "documentTitle": { + "default": "Ustawienia - Frigate", + "camera": "Ustawienia Kamery - Frigate", + "masksAndZones": "Edytor Masek i Stref - Frigate", + "frigatePlus": "Ustawienia Frigate+ - Frigate", + "classification": "Ustawienia Klasyfikacji - Frigate", + "general": "Ustawienia Ogólne - Frigate", + "authentication": "Ustawienia Uwierzytelniania - Frigate", + "motionTuner": "Konfigurator Ruchu - Frigate", + "object": "Ustawienia Obiektów - Frigate" + }, + "classification": { + "title": "Ustawienia Klasyfikacji", + "semanticSearch": { + "modelSize": { + "small": { + "title": "mały", + "desc": "Używanie małego modelu wykorzystuje skwantyzowaną wersję, która zużywa mniej pamięci RAM i działa szybciej na procesorze przy bardzo nieznacznej różnicy w jakości osadzeń." + }, + "large": { + "title": "duży", + "desc": "Używanie dużego modelu wykorzystuje pełny model Jina i automatycznie uruchomi się na GPU, jeśli jest dostępny." + }, + "desc": "Rozmiar modelu używanego do osadzeń wyszukiwania semantycznego.", + "label": "Rozmiar Modelu" + }, + "title": "Wyszukiwanie Semantyczne", + "desc": "Wyszukiwanie semantyczne w Frigate pozwala znaleźć śledzone obiekty w elementach przeglądu za pomocą samego obrazu, zdefiniowanego przez użytkownika opisu tekstowego lub automatycznie wygenerowanego opisu.", + "readTheDocumentation": "Przeczytaj Dokumentację", + "reindexNow": { + "label": "Przeindeksuj Teraz", + "desc": "Przeindeksowanie wygeneruje ponownie osadzenia dla wszystkich śledzonych obiektów. Ten proces działa w tle i może maksymalnie obciążyć procesor oraz zająć sporo czasu w zależności od liczby śledzonych obiektów.", + "confirmButton": "Przeindeksuj", + "success": "Przeindeksowanie rozpoczęte pomyślnie.", + "alreadyInProgress": "Przeindeksowanie jest już w toku.", + "error": "Nie udało się rozpocząć przeindeksowania: {{errorMessage}}", + "confirmTitle": "Potwierdź Przeindeksowanie", + "confirmDesc": "Czy na pewno chcesz przeindeksować osadzenia wszystkich śledzonych obiektów? Ten proces będzie działał w tle, ale może maksymalnie obciążyć procesor i zająć sporo czasu. Możesz śledzić postęp na stronie Eksploruj." + } + }, + "faceRecognition": { + "title": "Rozpoznawanie Twarzy", + "desc": "Rozpoznawanie twarzy pozwala na przypisanie imion do osób przez Frigate jako podrzędna etykieta. Ta informacja jest zawarta w interfejsie użytkownika, filtrach jak i w powiadomieniach.", + "modelSize": { + "label": "Rozmiar Modelu", + "desc": "Rozmiar modelu używanego do rozpoznawania twarzy.", + "small": { + "title": "mały", + "desc": "Używanie małego modelu wykorzystuje model osadzania twarzy FaceNet, który działa efektywnie na większości procesorów." + }, + "large": { + "title": "duży", + "desc": "Używanie dużego modelu wykorzystuje model osadzania twarzy ArcFace i automatycznie uruchomi się na GPU, jeśli jest dostępny." + } + }, + "readTheDocumentation": "Przeczytaj Dokumentację" + }, + "licensePlateRecognition": { + "title": "Rozpoznawanie Tablic Rejestracyjnych", + "desc": "Frigate może rozpoznawać tablice rejestracyjne pojazdów i automatycznie dodawać wykryte znaki do pola recognized_license_plate albo znaną nazwę jako etykietę podrzędną do obiektów typu samochód. Częstym przypadkiem użycia może być odczytywanie tablic rejestracyjnych samochodów wjeżdżających na podjazd albo przejeżdżających ulicą.", + "readTheDocumentation": "Przeczytaj Dokumentację" + }, + "toast": { + "error": "Nie udało się zapisać zmian w konfiguracji: {{errorMessage}}", + "success": "Ustawienia klasyfikacji zostały zapisane. Uruchom ponownie Frigate aby wprowadzić swoje zmiany." + }, + "birdClassification": { + "desc": "Klasyfikacja ptaków identyfikuje znane ptaki przy użyciu skwantyzowanego modelu Tensorflow. Gdy znany ptak zostanie rozpoznany, jego popularna nazwa zostanie dodana jako sub_label. Ta informacja jest uwzględniana w interfejsie użytkownika, filtrach oraz powiadomieniach.", + "title": "Klasyfikacja Ptaków" + }, + "restart_required": "Wymagane ponowne uruchomienie (Zmienione ustawienia klasyfikacji)" + }, + "camera": { + "title": "Ustawienia Kamery", + "reviewClassification": { + "noDefinedZones": "Brak stref zdefiniowanych dla tej kamery.", + "selectAlertsZones": "Wybierz strefy dla Alertów", + "title": "Klasyfikacja Przeglądu", + "desc": "Frigate kategoryzuje elementy przeglądu jako Alerty i Wykrycia. Domyślnie wszystkie obiekty osoba i samochód są traktowane jako Alerty. Możesz doprecyzować kategoryzację elementów przeglądu, konfigurując dla nich wymagane strefy.", + "readTheDocumentation": "Przeczytaj Dokumentację", + "objectAlertsTips": "Wszystkie obiekty {{alertsLabels}} na {{cameraName}} będą wyświetlane jako Alerty.", + "zoneObjectAlertsTips": "Wszystkie obiekty {{alertsLabels}} wykryte w strefie {{zone}} na {{cameraName}} będą wyświetlane jako Alerty.", + "zoneObjectDetectionsTips": { + "notSelectDetections": "Wszystkie obiekty {{detectionsLabels}} wykryte w strefie {{zone}} na {{cameraName}}, które nie są skategoryzowane jako Alerty, będą wyświetlane jako Wykrycia niezależnie od strefy, w której się znajdują.", + "regardlessOfZoneObjectDetectionsTips": "Wszystkie nieskategoryzowane obiekty {{detectionsLabels}} na {{cameraName}} będą wyświetlane jako Wykrycia niezależnie od strefy, w której się znajdują.", + "text": "Wszystkie nieskategoryzowane obiekty {{detectionsLabels}} w strefie {{zone}} na {{cameraName}} będą wyświetlane jako Wykrycia." + }, + "toast": { + "success": "Konfiguracja klasyfikacji przeglądu została zapisana. Uruchom ponownie Frigate, aby zastosować zmiany." + }, + "objectDetectionsTips": "Wszystkie nieskategoryzowane obiekty {{detectionsLabels}} na {{cameraName}} będą wyświetlane jako Wykrycia niezależnie od strefy, w której się znajdują.", + "limitDetections": "Ogranicz wykrycia do określonych stref", + "selectDetectionsZones": "Wybierz strefy dla Wykryć" + }, + "review": { + "alerts": "Alerty ", + "title": "Przegląd", + "detections": "Wykrycia ", + "desc": "Włącz/wyłącz alerty i wykrywania dla tej kamery. Po wyłączeniu nie będą generowane nowe elementy do przeglądu." + }, + "streams": { + "desc": "Wyłączenie kamery całkowicie zatrzymuje przetwarzanie strumieni tej kamery przez Frigate. Wykrywanie, nagrywanie i debugowanie będą niedostępne.
    Uwaga: Nie wyłącza to przekazywania strumieni go2rtc.", + "title": "Strumienie" + } + }, + "masksAndZones": { + "filter": { + "all": "Wszystkie Maski i Strefy" + }, + "form": { + "zoneName": { + "error": { + "mustBeAtLeastTwoCharacters": "Nazwa strefy musi mieć co najmniej 2 znaki.", + "mustNotBeSameWithCamera": "Nazwa strefy nie może być taka sama jak nazwa kamery.", + "alreadyExists": "Strefa z tą nazwą już istnieje dla tej kamery.", + "hasIllegalCharacter": "Nazwa strefy zawiera niedozwolone znaki.", + "mustNotContainPeriod": "Nazwa strefy nie może zawierać kropki." + } + }, + "distance": { + "error": { + "text": "Odległość musi być większa lub równa 0.1.", + "mustBeFilled": "Wszystkie pola odległości muszą być wypełnione, aby używać szacowania prędkości." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "Bezwładność musi być większa od 0." + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "Czas przebywania musi być większy lub równy 0." + } + }, + "polygonDrawing": { + "snapPoints": { + "false": "Nie przyciągaj punktów", + "true": "Przyciągaj punkty" + }, + "removeLastPoint": "Usuń ostatni punkt", + "reset": { + "label": "Wyczyść wszystkie punkty" + }, + "delete": { + "title": "Potwierdź usunięcie", + "success": "{{name}} został usunięty.", + "desc": "Czy na pewno chcesz usunąć {{type}} {{name}}?" + }, + "error": { + "mustBeFinished": "Rysowanie wielokąta musi być zakończone przed zapisaniem." + } + } + }, + "zones": { + "label": "Strefy", + "documentTitle": "Edytuj Strefę - Frigate", + "desc": { + "title": "Strefy pozwalają na zdefiniowanie konkretnych obszarów kadru, dzięki czemu można sprawdzić, czy obiekt znajduje się w danym obszarze.", + "documentation": "Dokumentacja" + }, + "add": "Dodaj Strefę", + "clickDrawPolygon": "Kliknij aby narysować wielokąt na obrazie.", + "edit": "Edytuj Strefę", + "name": { + "title": "Nazwa", + "inputPlaceHolder": "Wprowadź nazwę…", + "tips": "Nazwa musi mieć co najmniej 2 znaki i nie może być taka sama jak nazwa kamery lub innej strefy." + }, + "objects": { + "title": "Obiekty", + "desc": "Lista obiektów dla tej strefy." + }, + "allObjects": "Wszystkie Obiekty", + "point_one": "{{count}} punkt", + "point_few": "{{count}} punkty", + "point_many": "{{count}} punktów", + "inertia": { + "title": "Bezwładność", + "desc": "Określa, przez ile klatek obiekt musi znajdować się w strefie, zanim zostanie uznany za będący w strefie. Domyślnie: 3" + }, + "loiteringTime": { + "title": "Czas przebywania", + "desc": "Ustala minimalny czas w sekundach, przez który obiekt musi znajdować się w strefie, aby ją aktywować. Domyślnie: 0" + }, + "speedThreshold": { + "title": "Próg prędkości ({{unit}})", + "desc": "Określa minimalną prędkość, przy której obiekty są uwzględniane w tej strefie.", + "toast": { + "error": { + "loiteringTimeError": "Strefy z czasem przebywania większym niż 0 nie powinny być używane z szacowaniem prędkości.", + "pointLengthError": "Szacowanie prędkości zostało wyłączone dla tej strefy. Strefy z szacowaniem prędkości muszą mieć dokładnie 4 punkty." + } + } + }, + "speedEstimation": { + "title": "Szacowanie prędkości", + "desc": "Włącz szacowanie prędkości dla obiektów w tej strefie. Strefa musi mieć dokładnie 4 punkty." + }, + "toast": { + "success": "Strefa ({{zoneName}}) została zapisana. Uruchom ponownie Frigate, aby zastosować zmiany." + } + }, + "motionMasks": { + "desc": { + "documentation": "Dokumentacja", + "title": "Maski ruchu służą do zapobiegania wykrywaniu niepożądanych typów ruchu. Zbyt intensywne maskowanie utrudni śledzenie obiektów." + }, + "point_one": "{{count}} punkt", + "point_few": "{{count}} punkty", + "point_many": "{{count}} punktów", + "clickDrawPolygon": "Kliknij aby narysować wielokąt na obrazie.", + "documentTitle": "Edytuj maskę ruchu - Frigate", + "add": "Nowa Maska Ruchu", + "polygonAreaTooLarge": { + "tips": "Maski ruchu nie zapobiegają wykrywaniu obiektów. Powinieneś użyć wymaganej strefy zamiast tego.", + "documentation": "Przeczytaj dokumentację", + "title": "Maska ruchu pokrywa {{polygonArea}}% ramki kamery. Duże maski ruchu nie są zalecane." + }, + "toast": { + "success": { + "title": "{{polygonName}} został zapisany. Uruchom ponownie Frigate, aby zastosować zmiany.", + "noName": "Maska Ruchu została zapisana. Uruchom ponownie Frigate, aby zastosować zmiany." + } + }, + "label": "Maska ruchu", + "edit": "Edytuj Maskę Ruchu", + "context": { + "documentation": "Przeczytaj dokumentację", + "title": "Maski ruchu są używane do zapobiegania niepożądanym typom ruchu przed wyzwalaniem detekcji (przykład: gałęzie drzew, znaczniki czasowe kamery). Maski ruchu powinny być używane bardzo oszczędnie, nadmierne maskowanie utrudni śledzenie obiektów." + } + }, + "objectMasks": { + "toast": { + "success": { + "title": "{{polygonName}} został zapisany. Uruchom ponownie Frigate aby wprowadzić zmiany.", + "noName": "Maska Obiektu została zapisana. Uruchom ponownie Frigate, aby zastosować zmiany." + } + }, + "objects": { + "title": "Obiekty", + "allObjectTypes": "Wszystkie typy obiektów", + "desc": "Typ obiektu, który ma zastosowanie do tej maski obiektu." + }, + "point_one": "{{count}} punkt", + "point_few": "{{count}} punkty", + "point_many": "{{count}} punktów", + "label": "Maski Obiektów", + "documentTitle": "Edytuj Maskę Obiektu - Frigate", + "desc": { + "title": "Maski filtrujące obiekty są używane do filtrowania fałszywych detekcji dla danego typu obiektu na podstawie lokalizacji.", + "documentation": "Dokumentacja" + }, + "add": "Dodaj Maskę Obiektu", + "edit": "Edytuj Maskę Obiektu", + "clickDrawPolygon": "Kliknij, aby narysować wielokąt na obrazie.", + "context": "Maski filtrujące obiekty są używane do filtrowania fałszywych detekcji dla danego typu obiektu na podstawie lokalizacji." + }, + "toast": { + "success": { + "copyCoordinates": "Skopiowano współrzędne dla {{polyName}} do schowka." + }, + "error": { + "copyCoordinatesFailed": "Nie udało się skopiować współrzędnych do schowka." + } + }, + "restart_required": "Wymagane ponowne uruchomienie (maski/strefy zmienione)" + }, + "debug": { + "objectList": "Lista Obiektów", + "debugging": "Debugowanie", + "title": "Debugowanie", + "detectorDesc": "Frigate używa twoich detektorów ({{detectors}}) do wykrywania obiektów w strumieniu wideo kamery.", + "boundingBoxes": { + "desc": "Pokaż ramki ograniczające wokół śledzonych obiektów", + "colors": { + "label": "Kolory Ramek Ograniczających Obiekty", + "info": "
  • Przy uruchomieniu, różne kolory zostaną przypisane do każdej etykiety obiektu
  • Ciemnoniebieska cienka linia oznacza, że obiekt nie jest wykrywany w tym momencie
  • Szara cienka linia oznacza, że obiekt jest wykrywany jako nieruchomy
  • Gruba linia oznacza, że obiekt jest przedmiotem automatycznego śledzenia (gdy włączone)
  • " + }, + "title": "Ramki ograniczające" + }, + "zones": { + "desc": "Pokaż kontur zdefiniowanych stref", + "title": "Strefy" + }, + "desc": "Widok debugowania pokazuje podgląd śledzonych obiektów w czasie rzeczywistym i ich statystyki. Lista obiektów pokazuje opóźnione podsumowanie wykrytych obiektów.", + "noObjects": "Brak obiektów", + "timestamp": { + "title": "Znacznik czasu", + "desc": "Nałóż znacznik czasu na obraz" + }, + "mask": { + "title": "Maski ruchu", + "desc": "Pokaż wielokąty maski ruchu" + }, + "motion": { + "title": "Ramki ruchu", + "desc": "Pokaż ramki wokół obszarów, gdzie wykryto ruch", + "tips": "

    Ramki Ruchu


    Czerwone ramki będą nakładane na obszary kadru, gdzie aktualnie wykrywany jest ruch

    " + }, + "regions": { + "title": "Regiony", + "desc": "Pokaż ramkę regionu zainteresowania wysyłanego do detektora obiektów", + "tips": "

    Ramki Regionów


    Jasnozielone ramki będą nakładane na obszary zainteresowania w kadrze, które są wysyłane do detektora obiektów.

    " + }, + "objectShapeFilterDrawing": { + "document": "Przeczytaj dokumentację ", + "title": "Rysowanie Filtra Kształtu Obiektu", + "ratio": "Proporcja", + "score": "Wynik", + "tips": "Włącz tę opcję, aby narysować prostokąt na obrazie kamery w celu pokazania jego obszaru i proporcji. Te wartości mogą być następnie użyte do ustawienia parametrów filtra kształtu obiektu w twojej konfiguracji.", + "desc": "Narysuj prostokąt na obrazie, aby zobaczyć szczegóły obszaru i proporcji", + "area": "Obszar" + } + }, + "motionDetectionTuner": { + "title": "Tuner Wykrywania Ruchu", + "desc": { + "title": "Frigate używa wykrywania ruchu jako pierwszej linii sprawdzenia, czy w kadrze dzieje się coś wartego sprawdzenia przez detekcję obiektów.", + "documentation": "Przeczytaj Przewodnik Dostrajania Ruchu" + }, + "Threshold": { + "desc": "Wartość progowa określa, jak duża zmiana jasności piksela jest wymagana, aby uznać ją za ruch. Domyślnie: 30", + "title": "Próg" + }, + "contourArea": { + "title": "Obszar Konturu", + "desc": "Wartość obszaru konturu służy do określenia, które grupy zmienionych pikseli kwalifikują się jako ruch. Domyślnie: 10" + }, + "improveContrast": { + "desc": "Popraw kontrast dla ciemniejszych scen. Domyślnie: WŁĄCZONE", + "title": "Popraw Kontrast" + }, + "toast": { + "success": "Ustawienia ruchu zostały zapisane." + } + }, + "users": { + "addUser": "Dodaj Użytkownika", + "updatePassword": "Aktualizuj Hasło", + "toast": { + "success": { + "createUser": "Użytkownik {{user}} został utworzony pomyślnie", + "deleteUser": "Użytkownik {{user}} został usunięty pomyślnie", + "updatePassword": "Hasło zaktualizowane pomyślnie.", + "roleUpdated": "Rola zaktualizowana dla {{user}}" + }, + "error": { + "setPasswordFailed": "Nie udało się zapisać hasła: {{errorMessage}}", + "createUserFailed": "Nie udało się utworzyć użytkownika: {{errorMessage}}", + "deleteUserFailed": "Nie udało się usunąć użytkownika: {{errorMessage}}", + "roleUpdateFailed": "Nie udało się zaktualizować roli: {{errorMessage}}" + } + }, + "table": { + "username": "Nazwa użytkownika", + "actions": "Akcje", + "role": "Rola", + "noUsers": "Nie znaleziono użytkowników.", + "changeRole": "Zmień rolę użytkownika", + "password": "Hasło", + "deleteUser": "Usuń użytkownika" + }, + "dialog": { + "form": { + "user": { + "title": "Nazwa użytkownika", + "desc": "Dozwolone są tylko litery, cyfry, kropki i podkreślenia.", + "placeholder": "Wprowadź nazwę użytkownika" + }, + "password": { + "strength": { + "strong": "Silne", + "title": "Siła hasła: ", + "weak": "Słabe", + "medium": "Średnie", + "veryStrong": "Bardzo silne" + }, + "match": "Hasła pasują", + "confirm": { + "placeholder": "Potwierdź hasło", + "title": "Potwierdź hasło" + }, + "title": "Hasło", + "placeholder": "Wprowadź hasło", + "notMatch": "Hasła nie pasują" + }, + "newPassword": { + "placeholder": "Wprowadź nowe hasło", + "title": "Nowe hasło", + "confirm": { + "placeholder": "Wprowadź ponownie nowe hasło" + } + }, + "usernameIsRequired": "Nazwa użytkownika jest wymagana" + }, + "changeRole": { + "desc": "Aktualizuj uprawnienia dla {{username}}", + "roleInfo": { + "intro": "Wybierz właściwą rolę dla tego użytkownika:", + "admin": "Admin", + "adminDesc": "Pełny dostęp do wszystkich funkcjonalności.", + "viewerDesc": "Ograniczony wyłącznie do pulpitów na żywo, przeglądania, eksploracji i eksportu.", + "viewer": "Przeglądający" + }, + "title": "Zmień rolę użytkownika" + }, + "createUser": { + "title": "Utwórz nowego użytkownika", + "desc": "Dodaj nowe konto użytkownika i określ rolę dla dostępu do obszarów interfejsu Frigate.", + "usernameOnlyInclude": "Nazwa użytkownika może zawierać tylko litery, cyfry lub znak _" + }, + "deleteUser": { + "title": "Usuń użytkownika", + "desc": "Tej akcji nie można cofnąć. Spowoduje to trwałe usunięcie konta użytkownika i wszystkich powiązanych danych.", + "warn": "Czy na pewno chcesz usunąć {{username}}?" + }, + "passwordSetting": { + "updatePassword": "Aktualizuj hasło dla {{username}}", + "setPassword": "Ustaw hasło", + "desc": "Utwórz silne hasło, aby zabezpieczyć to konto." + } + }, + "management": { + "title": "Zarządzanie Użytkownikami", + "desc": "Zarządzaj kontami użytkowników tej instancji Frigate." + }, + "title": "Użytkownicy" + }, + "notification": { + "title": "Powiadomienia", + "notificationSettings": { + "title": "Ustawienia powiadomień", + "desc": "Frigate może wysyłać natywne powiadomienia push na twoje urządzenie, gdy działa w przeglądarce lub jest zainstalowany jako PWA.", + "documentation": "Przeczytaj dokumentację" + }, + "notificationUnavailable": { + "title": "Powiadomienia niedostępne", + "desc": "Powiadomienia push w przeglądarce wymagają bezpiecznego kontekstu (https://…). To jest ograniczenie przeglądarki. Uzyskaj dostęp do Frigate przez bezpieczne połączenie, aby korzystać z powiadomień.", + "documentation": "Przeczytaj dokumentację" + }, + "globalSettings": { + "title": "Ustawienia globalne", + "desc": "Tymczasowo wstrzymaj powiadomienia dla określonych kamer na wszystkich zarejestrowanych urządzeniach." + }, + "suspendTime": { + "12hours": "Zawieś na 12 godzin", + "24hours": "Zawieś na 24 godziny", + "untilRestart": "Zawieś do restartu", + "1hour": "Zawieś na 1 godzinę", + "5minutes": "Zawieś na 5 minut", + "10minutes": "Zawieś na 10 minut", + "30minutes": "Zawieś na 30 minut" + }, + "cancelSuspension": "Anuluj zawieszenie", + "toast": { + "error": { + "registerFailed": "Nie udało się zapisać rejestracji powiadomień." + }, + "success": { + "settingSaved": "Ustawienia powiadomień zostały zapisane.", + "registered": "Rejestracja powiadomień zakończona powodzeniem. Przed wysłaniem jakichkolwiek powiadomień (włącznie z testowym) wymagane jest ponowne uruchomienie Frigate." + } + }, + "email": { + "title": "Email", + "placeholder": "np. przyklad@email.com", + "desc": "Wymagany jest prawidłowy adres email, który będzie używany do powiadamiania Cię w przypadku problemów z usługą push." + }, + "cameras": { + "title": "Kamery", + "noCameras": "Brak dostępnych kamer", + "desc": "Wybierz kamery, dla których chcesz włączyć powiadomienia." + }, + "deviceSpecific": "Ustawienia specyficzne dla urządzenia", + "registerDevice": "Zarejestruj to urządzenie", + "active": "Powiadomienia aktywne", + "suspended": "Powiadomienia zawieszone {{time}}", + "unregisterDevice": "Wyrejestruj to urządzenie", + "sendTestNotification": "Wyślij testowe powiadomienie" + }, + "frigatePlus": { + "title": "Ustawienia Frigate+", + "apiKey": { + "title": "Klucz API Frigate+", + "validated": "Klucz API Frigate+ został wykryty i zweryfikowany", + "plusLink": "Dowiedz się więcej o Frigate+", + "notValidated": "Klucz API Frigate+ nie został wykryty lub nie został zweryfikowany", + "desc": "Klucz API Frigate+ umożliwia integrację z usługą Frigate+." + }, + "snapshotConfig": { + "title": "Konfiguracja zrzutów ekranu", + "documentation": "Przeczytaj dokumentację", + "desc": "Aby wysyłać dane do Frigate+, w konfiguracji muszą być włączone zarówno zwykłe zrzuty ekranu, jak i zrzuty typu clean_copy.", + "table": { + "snapshots": "Zrzuty ekranu", + "cleanCopySnapshots": "Zrzuty ekranu clean_copy", + "camera": "Kamera" + }, + "cleanCopyWarning": "Niektóre kamery mają włączone zrzuty ekranu, ale mają wyłączoną funkcję czystej kopii. Musisz włączyć clean_copy w konfiguracji zrzutów ekranu, aby móc przesyłać obrazy z tych kamer do Frigate+." + }, + "modelInfo": { + "title": "Informacje o modelu", + "modelType": "Typ modelu", + "trainDate": "Data treningu", + "supportedDetectors": "Wspierane detektory", + "dimensions": "Wymiary", + "cameras": "Kamery", + "loading": "Ładowanie informacji o modelu…", + "error": "Nie udało się załadować informacji o modelu", + "availableModels": "Dostępne modele", + "loadingAvailableModels": "Ładowanie dostępnych modeli…", + "baseModel": "Model bazowy", + "modelSelect": "Tutaj możesz wybrać swoje dostępne modele w Frigate+. Pamiętaj, że można wybrać tylko modele kompatybilne z Twoją aktualną konfiguracją detektora.", + "plusModelType": { + "baseModel": "Model bazowy", + "userModel": "Dostrojony" + } + }, + "toast": { + "success": "Ustawienia Frigate+ zostały zapisane. Uruchom ponownie Frigate, aby zastosować zmiany.", + "error": "Nie udało się zapisać zmian konfiguracji: {{errorMessage}}" + }, + "restart_required": "Wymagane ponowne uruchomienie (Zmieniony model Frigate+)" + } +} diff --git a/web/public/locales/pl/views/system.json b/web/public/locales/pl/views/system.json new file mode 100644 index 000000000..ac55bc60d --- /dev/null +++ b/web/public/locales/pl/views/system.json @@ -0,0 +1,169 @@ +{ + "documentTitle": { + "cameras": "Statystyki kamer - Frigate", + "storage": "Statystyki Magazynowania - Frigate", + "general": "Statystyki Ogólne - Frigate", + "enrichments": "Statystyki Wzbogaceń - Frigate", + "logs": { + "frigate": "Logi Frigate - Frigate", + "go2rtc": "Logi Go2RTC - Frigate", + "nginx": "Logi Nginx - Frigate" + } + }, + "general": { + "hardwareInfo": { + "gpuInfo": { + "vainfoOutput": { + "title": "Wynik Vainfo", + "returnCode": "Kod zwrotny: {{code}}", + "processOutput": "Wynik procesu:", + "processError": "Błąd procesu:" + }, + "nvidiaSMIOutput": { + "title": "Wynik Nvidia SMI", + "name": "Nazwa: {{name}}", + "driver": "Sterownik: {{driver}}", + "cudaComputerCapability": "Możliwości obliczeniowe CUDA: {{cuda_compute}}", + "vbios": "Informacje VBios: {{vbios}}" + }, + "closeInfo": { + "label": "Zamknij informacje o GPU" + }, + "copyInfo": { + "label": "Kopiuj informacje o GPU" + }, + "toast": { + "success": "Skopiowano informacje o GPU do schowka" + } + }, + "title": "Informacje o sprzęcie", + "gpuEncoder": "Enkoder GPU", + "gpuDecoder": "Dekoder GPU", + "gpuMemory": "Pamięć GPU", + "gpuUsage": "Użycie GPU", + "npuUsage": "Użycie NPU", + "npuMemory": "Pamięć NPU" + }, + "title": "Ogólne", + "detector": { + "title": "Detektory", + "inferenceSpeed": "Szybkość wnioskowania detektora", + "cpuUsage": "Użycie CPU przez detektor", + "memoryUsage": "Użycie pamięci przez detektor" + }, + "otherProcesses": { + "title": "Inne procesy", + "processCpuUsage": "Użycie CPU przez proces", + "processMemoryUsage": "Użycie pamięci przez proces" + } + }, + "cameras": { + "info": { + "stream": "Strumień {{idx}}", + "cameraProbeInfo": "{{camera}} Informacje o sondowaniu kamery", + "streamDataFromFFPROBE": "Dane strumienia są pozyskiwane za pomocą ffprobe.", + "video": "Wideo:", + "codec": "Kodek:", + "resolution": "Rozdzielczość:", + "fps": "FPS:", + "unknown": "Nieznany", + "audio": "Audio:", + "error": "Błąd: {{error}}", + "tips": { + "title": "Informacje o sondowaniu kamery" + }, + "fetching": "Pobieranie danych kamery" + }, + "toast": { + "success": { + "copyToClipboard": "Skopiowano dane sondowania do schowka." + }, + "error": { + "unableToProbeCamera": "Nie można sondować kamery: {{errorMessage}}" + } + }, + "title": "Kamery", + "overview": "Przegląd", + "framesAndDetections": "Klatki / Detekcje", + "label": { + "camera": "kamera", + "detect": "wykryj", + "skipped": "pominięte", + "ffmpeg": "ffmpeg", + "capture": "przechwytywanie" + } + }, + "storage": { + "cameraStorage": { + "unused": { + "title": "Niewykorzystane", + "tips": "Ta wartość może niedokładnie przedstawiać wolne miejsce dostępne dla Frigate, jeśli masz inne pliki przechowywane na dysku poza nagraniami Frigate. Frigate nie śledzi wykorzystania magazynu poza swoimi nagraniami." + }, + "title": "Magazyn kamery", + "camera": "Kamera", + "storageUsed": "Wykorzystany magazyn", + "percentageOfTotalUsed": "Procent całości", + "bandwidth": "Przepustowość", + "unusedStorageInformation": "Informacja o niewykorzystanym magazynie" + }, + "title": "Magazyn", + "overview": "Przegląd", + "recordings": { + "title": "Nagrania", + "tips": "Ta wartość reprezentuje całkowite miejsce zajmowane przez nagrania w bazie danych Frigate. Frigate nie śledzi wykorzystania magazynu dla wszystkich plików na twoim dysku.", + "earliestRecording": "Najwcześniejsze dostępne nagranie:" + } + }, + "logs": { + "copy": { + "error": "Nie udało się skopiować logów do schowka", + "label": "Kopiuj do Schowka", + "success": "Skopiowano logi do schowka" + }, + "download": { + "label": "Pobierz Logi" + }, + "type": { + "label": "Typ", + "timestamp": "Znacznik czasu", + "tag": "Tag", + "message": "Wiadomość" + }, + "tips": "Logi są przesyłane strumieniowo z serwera", + "toast": { + "error": { + "fetchingLogsFailed": "Błąd pobierania logów: {{errorMessage}}", + "whileStreamingLogs": "Błąd podczas strumieniowania logów: {{errorMessage}}" + } + } + }, + "title": "System", + "metrics": "Metryki systemowe", + "lastRefreshed": "Ostatnie odświeżenie: ", + "stats": { + "ffmpegHighCpuUsage": "{{camera}} ma wysokie użycie CPU przez FFMPEG ({{ffmpegAvg}}%)", + "detectHighCpuUsage": "{{camera}} ma wysokie użycie CPU przez detekcję ({{detectAvg}}%)", + "healthy": "System jest sprawny", + "reindexingEmbeddings": "Ponowne indeksowanie osadzeń ({{processed}}% ukończone)", + "detectIsSlow": "{{detect}} jest wolne ({{speed}} ms)", + "detectIsVerySlow": "{{detect}} jest bardzo wolne ({{speed}} ms)", + "cameraIsOffline": "{{camera}} jest niedostępna" + }, + "enrichments": { + "title": "Wzbogacenia", + "infPerSecond": "Wnioskowania na sekundę", + "embeddings": { + "image_embedding_speed": "Szybkość osadzania obrazów", + "face_embedding_speed": "Szybkość osadzania twarzy", + "plate_recognition_speed": "Szybkość rozpoznawania tablic rejestracyjnych", + "text_embedding_speed": "Szybkość osadzania tekstu", + "face_recognition_speed": "Szybkość rozpoznawania twarzy", + "image_embedding": "Osadzenie obrazu", + "plate_recognition": "Rozpoznawanie rejestracji samochodowych", + "yolov9_plate_detection_speed": "Prędkość detekcji rejestracji samochodowych YOLOv9", + "yolov9_plate_detection": "Detekcja rejestracji samochodowych YOLOv9", + "text_embedding": "Osadzenie tekstu", + "face_recognition": "Rozpoznawanie twarzy" + } + } +} diff --git a/web/public/locales/pt/audio.json b/web/public/locales/pt/audio.json new file mode 100644 index 000000000..c82fa9b0e --- /dev/null +++ b/web/public/locales/pt/audio.json @@ -0,0 +1,157 @@ +{ + "babbling": "Balbuciando", + "speech": "Discurso", + "whoop": "Gritar", + "bellow": "Abaixo", + "yell": "Gritar", + "whispering": "Sussurando", + "child_singing": "Criança Cantando", + "crying": "Chorando", + "singing": "Cantando", + "laughter": "Risada", + "breathing": "Respirando", + "applause": "Aplausos", + "meow": "Miau", + "run": "Corrida", + "sheep": "Ovelha", + "motorcycle": "Motocicleta", + "car": "Carro", + "cat": "Gato", + "horse": "Cavalo", + "bus": "Ônibus", + "boat": "Barco", + "bicycle": "Bicicleta", + "skateboard": "Skate", + "door": "Porta", + "bird": "Pássaro", + "train": "Trem", + "dog": "Cão", + "mantra": "Mantra", + "humming": "Cantarolando", + "sigh": "Suspiro", + "grunt": "Grunhido", + "whistling": "Assobio", + "wheeze": "Chiado", + "gasp": "Suspiro", + "cough": "Tosse", + "sneeze": "Espirro", + "footsteps": "Passos", + "chewing": "Mastigação", + "biting": "Morder", + "gargling": "Gargarejar", + "stomach_rumble": "Ronco no estômago", + "burping": "Arroto", + "hiccup": "Soluço", + "fart": "Peido", + "hands": "Mãos", + "finger_snapping": "Estalo de dedos", + "clapping": "Aplausos", + "heartbeat": "Batimento cardíaco", + "heart_murmur": "Sopro cardíaco", + "cheering": "Torcendo", + "chatter": "Conversa fiada", + "crowd": "Multidão", + "snoring": "Ronco", + "choir": "Coro", + "yodeling": "Yodeling", + "chant": "Canto", + "synthetic_singing": "Canto sintético", + "rapping": "Cantando rap", + "groan": "Gemido", + "snicker": "Risada", + "animal": "Animal", + "pets": "Animais de estimação", + "bark": "Latido", + "howl": "Uivo", + "bow_wow": "Au au", + "growling": "Rosnando", + "whimper_dog": "Cachorro choramingando", + "pig": "Porco", + "goat": "Bode", + "fowl": "Galinha", + "chicken": "Galinha", + "turkey": "Peru", + "duck": "Pato", + "quack": "Quac", + "goose": "Ganso", + "wild_animals": "Animais selvagens", + "pigeon": "Pombo", + "dogs": "Cachorros", + "insect": "Inseto", + "cricket": "Grilo", + "mosquito": "Mosquito", + "fly": "Mosca", + "frog": "Sapo", + "snake": "Cobra", + "rattle": "Chocalho", + "music": "Música", + "musical_instrument": "Instrumento musical", + "banjo": "Banjo", + "keyboard": "Teclado", + "piano": "Piano", + "organ": "Órgão", + "synthesizer": "Sintetizador", + "tambourine": "Pandeiro", + "clarinet": "Clarinete", + "harp": "Harpa", + "psychedelic_rock": "Rock psicodélico", + "waterfall": "Cachoeira", + "ocean": "Oceano", + "fire": "Fogo", + "ship": "Navio", + "car_alarm": "Alarme de carro", + "race_car": "Carro de corrida", + "truck": "Caminhão", + "ice_cream_truck": "Caminhão do sorvete", + "emergency_vehicle": "Veículo de emergência", + "police_car": "Carro da polícia", + "ambulance": "Ambulância", + "helicopter": "Helicóptero", + "engine": "Motor", + "coin": "Moeda", + "scissors": "Tesoura", + "electric_shaver": "Barbeador elétrico", + "computer_keyboard": "Teclado de computador", + "alarm": "Alarme", + "telephone": "Telefone", + "siren": "Sirene", + "smoke_detector": "Detector de fumaça", + "fire_alarm": "Alarme de incêndio", + "whistle": "Assobio", + "clock": "Relógio", + "tools": "Ferramentas", + "camera": "Câmera", + "chink": "Fenda", + "sound_effect": "Efeito sonoro", + "static": "Estático", + "pink_noise": "Ruído rosa", + "television": "Televisão", + "scream": "Grito", + "glass": "Vidro", + "wood": "Madeira", + "crack": "Rachadura", + "silence": "Silêncio", + "steam": "Vapor", + "progressive_rock": "Rock progressivo", + "white_noise": "Ruído branco", + "maraca": "Maraca", + "percussion": "Percussão", + "rats": "Ratos", + "oink": "Oinc", + "waves": "Ondas", + "shatter": "Quebrar", + "radio": "Rádio", + "splinter": "Lasca", + "owl": "Coruja", + "mouse": "Rato", + "vehicle": "Veículo", + "hair_dryer": "Secador de cabelo", + "toothbrush": "Escova de dentes", + "sink": "Pia", + "blender": "Liquidificador", + "pant": "Calça", + "snort": "Espirro", + "throat_clearing": "Limpeza de garganta", + "sniff": "Cheirar", + "shuffle": "Embaralhar" +} diff --git a/web/public/locales/pt/common.json b/web/public/locales/pt/common.json new file mode 100644 index 000000000..2e92a03ce --- /dev/null +++ b/web/public/locales/pt/common.json @@ -0,0 +1,204 @@ +{ + "time": { + "last30": "Últimos 30 dias", + "12hours": "12 horas", + "justNow": "Agora", + "yesterday": "Ontem", + "today": "Hoje", + "last7": "Últimos 7 dias", + "last14": "Últimos 14 dias", + "thisWeek": "Essa semana", + "lastWeek": "Semana passada", + "5minutes": "5 minutos", + "10minutes": "10 minutos", + "30minutes": "30 minutos", + "24hours": "24 horas", + "pm": "pm", + "am": "am", + "year_one": "{{time}} anos", + "year_many": "", + "year_other": "", + "month_one": "{{time}} meses", + "month_many": "", + "month_other": "", + "day_one": "{{time}} dias", + "day_many": "", + "day_other": "", + "thisMonth": "Esse mês", + "lastMonth": "Mês passado", + "1hour": "1 hora", + "hour_one": "{{time}} horas", + "hour_many": "", + "hour_other": "", + "minute_one": "{{time}} minutos", + "minute_many": "", + "minute_other": "", + "second_one": "{{time}} segundos", + "second_many": "", + "second_other": "", + "untilForTime": "Até {{time}}", + "untilForRestart": "Até que o Frigate reinicie.", + "untilRestart": "Até reiniciar", + "ago": "{{timeAgo}} atrás", + "d": "{{time}}d", + "h": "{{time}}h", + "m": "{{time}}m", + "s": "{{time}}s", + "yr": "{{time}}ano", + "mo": "{{time}}mês", + "formattedTimestamp": { + "12hour": "%b %-d, %I:%M:%S %p", + "24hour": "%b %-d, %H:%M:%S" + }, + "formattedTimestamp2": { + "12hour": "%m/%d %I:%M:%S%P", + "24hour": "%d %b %H:%M:%S" + }, + "formattedTimestampExcludeSeconds": { + "12hour": "%b %-d, %I:%M %p", + "24hour": "%b %-d, %H:%M" + }, + "formattedTimestampWithYear": { + "12hour": "%b %-d %Y, %I:%M %p", + "24hour": "%b %-d %Y, %H:%M" + }, + "formattedTimestampOnlyMonthAndDay": "%b %-d" + }, + "unit": { + "speed": { + "kph": "kph", + "mph": "mph" + } + }, + "button": { + "enabled": "Habilitado", + "enable": "Habilitar", + "done": "Feito", + "reset": "Reiniciar", + "disabled": "Desabilitado", + "saving": "Salvando…", + "apply": "Aplicar", + "disable": "Desabilitar", + "save": "Salvar", + "copy": "Cópia", + "cancel": "Cancelar", + "close": "Fechar", + "history": "Histórico", + "back": "Voltar", + "fullscreen": "Tela cheia", + "exitFullscreen": "Sair da tela cheia", + "twoWayTalk": "Conversa bidirecional", + "cameraAudio": "Áudio da câmera", + "edit": "Editar", + "off": "DESLIGADO", + "copyCoordinates": "Copiar coordenadas", + "on": "LIGADO", + "delete": "Excluir", + "download": "Download", + "info": "Informações", + "no": "Não", + "suspended": "Suspenso", + "yes": "Sim", + "unselect": "Desmarcar", + "unsuspended": "Dessuspender", + "deleteNow": "Excluir agora", + "export": "Exportar", + "next": "Próximo" + }, + "label": { + "back": "Voltar" + }, + "menu": { + "user": { + "logout": "Sair", + "account": "Conta", + "current": "Usuário atual: {{user}}", + "setPassword": "Definir senha", + "title": "Usuário", + "anonymous": "anônimo" + }, + "faceLibrary": "Biblioteca de rostos", + "withSystem": "Sistema", + "theme": { + "label": "Tema", + "blue": "Azul", + "green": "Verde", + "red": "Vermelho", + "contrast": "Alto contraste", + "default": "Padrão" + }, + "system": "Sistema", + "systemMetrics": "Métricas do sistema", + "configuration": "Configuração", + "systemLogs": "Logs do sistema", + "settings": "Configurações", + "configurationEditor": "Editor de configuração", + "languages": "Idiomas", + "language": { + "en": "Inglês", + "zhCN": "Chinês simplificado", + "withSystem": { + "label": "Use as configurações do sistema para idioma" + } + }, + "appearance": "Aparência", + "darkMode": { + "label": "Modo escuro", + "withSystem": { + "label": "Use as configurações do sistema para o modo claro ou escuro" + }, + "light": "Claro", + "dark": "Escuro" + }, + "help": "Ajuda", + "documentation": { + "title": "Documentação", + "label": "Documentação do Frigate" + }, + "restart": "Reiniciar Frigate", + "live": { + "title": "Ao vivo", + "allCameras": "Todas as câmeras", + "cameras": { + "title": "Câmeras" + } + }, + "export": "Exportar", + "explore": "Explorar", + "review": "Análise" + }, + "pagination": { + "previous": { + "label": "Ir para a página anterior", + "title": "Anterior" + }, + "label": "paginação", + "next": { + "title": "Próximo", + "label": "Ir para a próxima página" + }, + "more": "Mais páginas" + }, + "role": { + "admin": "Administrador", + "viewer": "Visualizador", + "title": "Regra" + }, + "toast": { + "copyUrlToClipboard": "URL copiada para a área de transferência.", + "save": { + "title": "Salvar" + } + }, + "accessDenied": { + "documentTitle": "Acesso negado - Frigate", + "title": "Acesso negado", + "desc": "Você não tem permissão para visualizar esta página." + }, + "notFound": { + "documentTitle": "Não encontrado - Frigate", + "desc": "Página não encontrada", + "title": "404" + }, + "selectItem": "Selecionar {{item}}" +} diff --git a/web/public/locales/pt/components/auth.json b/web/public/locales/pt/components/auth.json new file mode 100644 index 000000000..5de4e07cb --- /dev/null +++ b/web/public/locales/pt/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "user": "Nome de usuário", + "login": "Login", + "errors": { + "usernameRequired": "Nome de usuário é obrigatório", + "passwordRequired": "Senha é necessária", + "rateLimit": "Limite de taxa excedido. Tente novamente mais tarde.", + "loginFailed": "Falha no login", + "unknownError": "Erro desconhecido. Verifique os logs.", + "webUnknownError": "Erro desconhecido. Verifique os logs do console." + }, + "password": "Senha" + } +} diff --git a/web/public/locales/pt/components/camera.json b/web/public/locales/pt/components/camera.json new file mode 100644 index 000000000..1272553a6 --- /dev/null +++ b/web/public/locales/pt/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "label": "Grupos de câmeras", + "add": "Adicionar grupo de câmeras", + "edit": "Editar grupo de câmeras", + "delete": { + "label": "Excluir grupo de câmeras", + "confirm": { + "title": "Confirmar exclusão", + "desc": "Tem certeza de que deseja excluir o grupo de câmeras {{name}}?" + } + }, + "name": { + "label": "Nome", + "placeholder": "Digite um nome…", + "errorMessage": { + "exists": "O nome do grupo de câmeras já existe.", + "nameMustNotPeriod": "O nome do grupo de câmeras não deve conter ponto.", + "mustLeastCharacters": "O nome do grupo de câmeras deve ter pelo menos 2 caracteres.", + "invalid": "Nome de grupo de câmeras inválido." + } + }, + "cameras": { + "desc": "Selecione câmeras para este grupo.", + "label": "Câmeras" + }, + "icon": "Ícone", + "success": "O grupo de câmeras ({{name}}) foi salvo.", + "camera": { + "setting": { + "audioIsAvailable": "O áudio está disponível para esta transmissão", + "audioIsUnavailable": "O áudio não está disponível para esta transmissão", + "audio": { + "tips": { + "document": "Leia a documentação ", + "title": "O áudio deve ser emitido pela sua câmera e configurado no go2rtc para esta transmissão." + } + }, + "streamMethod": { + "label": "Método de transmissão", + "method": { + "smartStreaming": { + "label": "Transmissão inteligente (recomendado)", + "desc": "A transmissão inteligente atualizará a imagem da sua câmera uma vez por minuto quando nenhuma atividade detectável estiver ocorrendo para conservar largura de banda e recursos. Quando a atividade é detectada, a imagem muda perfeitamente para uma transmissão ao vivo." + }, + "continuousStreaming": { + "label": "Transmissão contínua", + "desc": { + "warning": "A transmissão contínua pode causar alto uso de largura de banda e problemas de desempenho. Use com cautela.", + "title": "A imagem da câmera sempre será uma transmissão ao vivo quando visível no painel, mesmo que nenhuma atividade esteja sendo detectada." + } + }, + "noStreaming": { + "label": "Sem transmissão", + "desc": "As imagens da câmera serão atualizadas apenas uma vez por minuto e não haverá transmissão ao vivo." + } + } + }, + "compatibilityMode": { + "label": "Modo de compatibilidade", + "desc": "Habilite esta opção somente se a transmissão ao vivo da sua câmera estiver exibindo artefatos de cor e tiver uma linha diagonal no lado direito da imagem." + }, + "label": "Configurações de transmissão da câmera", + "desc": "Altere as opções de transmissão ao vivo para o painel deste grupo de câmeras. Essas configurações são específicas do dispositivo/navegador.", + "title": "{{cameraName}} configurações de transmissão" + } + } + }, + "debug": { + "options": { + "label": "Configurações", + "title": "Opções", + "hideOptions": "Ocultar opções", + "showOptions": "Mostrar opções" + }, + "boundingBox": "Caixa delimitadora", + "timestamp": "Carimbo de hora", + "zones": "Zonas", + "mask": "Máscara", + "motion": "Movimento", + "regions": "Regiões" + } +} diff --git a/web/public/locales/pt/components/dialog.json b/web/public/locales/pt/components/dialog.json new file mode 100644 index 000000000..c67cc8834 --- /dev/null +++ b/web/public/locales/pt/components/dialog.json @@ -0,0 +1,116 @@ +{ + "restart": { + "button": "Reiniciar", + "restarting": { + "title": "Frigate está reiniciando", + "content": "Esta página será recarregada em {{countdown}} segundos.", + "button": "Forçar atualização agora" + }, + "title": "Tem certeza de que deseja reiniciar o Frigate?" + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "Enviar para Frigate+", + "desc": "Objetos em locais que você quer evitar não são falsos positivos. Enviá-los como falsos positivos confundirá o modelo." + }, + "review": { + "true": { + "label": "Confirme esta etiqueta para Frigate Plus", + "true_one": "Este é um {{label}}", + "true_many": "Estes são muitos {{label}}", + "true_other": "Estão são {{label}}" + }, + "state": { + "submitted": "Enviado" + }, + "false": { + "label": "Não confirmar esta etiqueta para Frigate Plus", + "false_one": "Este não é um {{label}}", + "false_many": "Estes não são muitos {{label}}", + "false_other": "Estes não são {{label}}" + } + } + }, + "video": { + "viewInHistory": "Ver no histórico" + } + }, + "export": { + "time": { + "fromTimeline": "Selecione na linha do tempo", + "start": { + "title": "Hora de início", + "label": "Selecione a hora de início" + }, + "end": { + "title": "Hora de término", + "label": "Selecione a hora de término" + }, + "custom": "Personalizado", + "lastHour_one": "Última hora", + "lastHour_many": "Últimas {{count}} horas", + "lastHour_other": "Últimas {{count}} horas" + }, + "export": "Exportar", + "toast": { + "success": "Exportação iniciada com sucesso. Veja o arquivo na pasta /exports.", + "error": { + "failed": "Falha ao iniciar a exportação: {{error}}", + "endTimeMustAfterStartTime": "O horário de término deve ser posterior ao horário de início", + "noVaildTimeSelected": "Nenhum intervalo de tempo válido selecionado" + } + }, + "selectOrExport": "Selecionar ou Exportar", + "fromTimeline": { + "saveExport": "Salvar exportação", + "previewExport": "Visualizar exportação" + }, + "select": "Selecione", + "name": { + "placeholder": "Nomeie a exportação" + } + }, + "streaming": { + "showStats": { + "label": "Mostrar estatísticas de transmissão", + "desc": "Habilite esta opção para mostrar estatísticas de transmissão como uma sobreposição no feed da câmera." + }, + "restreaming": { + "desc": { + "title": "Configure o go2rtc para obter opções adicionais de visualização ao vivo e áudio para esta câmera.", + "readTheDocumentation": "Leia a documentação" + }, + "disabled": "A retransmissão não está habilitada para esta câmera." + }, + "label": "Transmissão", + "debugView": "Exibição de depuração" + }, + "search": { + "saveSearch": { + "label": "Salvar pesquisa", + "overwrite": "{{searchName}} já existe. Salvar substituirá o valor existente.", + "success": "A pesquisa ({{searchName}}) foi salva.", + "button": { + "save": { + "label": "Salvar esta pesquisa" + } + }, + "placeholder": "Digite um nome para sua pesquisa", + "desc": "Forneça um nome para esta pesquisa salva." + } + }, + "recording": { + "confirmDelete": { + "title": "Confirmar exclusão", + "desc": { + "selected": "Tem certeza de que deseja excluir todos os vídeos gravados associados a este item de revisão?

    Segure a tecla Shift para ignorar esta caixa de diálogo no futuro." + } + }, + "button": { + "export": "Exportar", + "markAsReviewed": "Marcar como revisado", + "deleteNow": "Excluir agora" + } + } +} diff --git a/web/public/locales/pt/components/filter.json b/web/public/locales/pt/components/filter.json new file mode 100644 index 000000000..e9a7e89a4 --- /dev/null +++ b/web/public/locales/pt/components/filter.json @@ -0,0 +1,104 @@ +{ + "labels": { + "label": "Etiquetas", + "all": { + "short": "Etiquetas", + "title": "Todas as etiquetas" + }, + "count": "{{count}} etiquetas", + "count_one": "{{count}} Etiqueta", + "count_other": "{{count}} Etiquetas" + }, + "filter": "Filtro", + "zones": { + "label": "Zonas", + "all": { + "title": "Todas as zonas", + "short": "Zonas" + } + }, + "dates": { + "all": { + "title": "Todas as datas", + "short": "Datas" + } + }, + "more": "Mais filtros", + "reset": { + "label": "Redefinir filtros para valores padrão" + }, + "subLabels": { + "label": "Sub etiquetas", + "all": "Todas sub etiquetas" + }, + "score": "Pontuação", + "features": { + "label": "Funcionalidades", + "hasSnapshot": "Tem um snapshot", + "hasVideoClip": "Tem um videoclipe", + "submittedToFrigatePlus": { + "label": "Enviado para Frigate+", + "tips": "Primeiro, você deve filtrar os objetos rastreados que têm um snapshot.

    Objetos rastreados sem um snapshot não podem ser enviados ao Frigate+." + } + }, + "sort": { + "label": "Organizar", + "dateAsc": "Data (Ascendente)", + "scoreAsc": "Pontuação do objeto (Crescente)", + "scoreDesc": "Pontuação do objeto (Decrescente)", + "speedDesc": "Velocidade estimada (Decrescente)", + "speedAsc": "Velocidade estimada (Crescente)", + "dateDesc": "Data (Decrescente)", + "relevance": "Relevância" + }, + "cameras": { + "label": "Filtro de câmeras", + "all": { + "short": "Câmeras", + "title": "Todas as câmeras" + } + }, + "review": { + "showReviewed": "Mostrar revisado" + }, + "motion": { + "showMotionOnly": "Mostrar apenas movimento" + }, + "explore": { + "settings": { + "title": "Configurações", + "defaultView": { + "title": "Exibição padrão", + "summary": "Sumário", + "unfilteredGrid": "Grade não filtrada", + "desc": "Quando nenhum filtro for selecionado, exiba um resumo dos objetos rastreados mais recentemente por etiqueta ou exiba uma grade não filtrada." + }, + "gridColumns": { + "title": "Colunas da grade", + "desc": "Selecione o número de colunas na visualização em grade." + }, + "searchSource": { + "label": "Pesquisar fonte", + "desc": "Escolha se deseja pesquisar nas miniaturas ou descrições dos seus objetos rastreados.", + "options": { + "thumbnailImage": "Imagem em miniatura", + "description": "Descrição" + } + } + }, + "date": { + "selectDateBy": { + "label": "Selecione uma data para filtrar" + } + } + }, + "logSettings": { + "label": "Nível de log do filtro", + "loading": { + "title": "Carregando" + }, + "filterBySeverity": "Filtrar logs por gravidade" + }, + "estimatedSpeed": "Velocidade estimada ({{unit}})", + "timeRange": "Intervalo de tempo" +} diff --git a/web/public/locales/pt/components/icons.json b/web/public/locales/pt/components/icons.json new file mode 100644 index 000000000..ddd38e84c --- /dev/null +++ b/web/public/locales/pt/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "Selecione um ícone", + "search": { + "placeholder": "Pesquisar por um ícone…" + } + } +} diff --git a/web/public/locales/pt/components/input.json b/web/public/locales/pt/components/input.json new file mode 100644 index 000000000..a78718405 --- /dev/null +++ b/web/public/locales/pt/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Baixar vídeo", + "toast": { + "success": "O vídeo do seu item de análise começou a ser baixado." + } + } + } +} diff --git a/web/public/locales/pt/components/player.json b/web/public/locales/pt/components/player.json new file mode 100644 index 000000000..851aa9547 --- /dev/null +++ b/web/public/locales/pt/components/player.json @@ -0,0 +1,51 @@ +{ + "noPreviewFound": "Nenhuma visualização encontrada", + "noPreviewFoundFor": "Nenhuma visualização encontrada para {{cameraName}}", + "submitFrigatePlus": { + "title": "Enviar este quadro para o Frigate+?", + "submit": "Enviar" + }, + "streamOffline": { + "title": "Transmissão offline", + "desc": "Nenhum quadro foi recebido na transmissão de detecção {{cameraName}}, verifique os logs de erro" + }, + "cameraDisabled": "A câmera está desativada", + "stats": { + "streamType": { + "title": "Tipo de transmissão:", + "short": "Tipo" + }, + "bandwidth": { + "title": "Largura de banda:", + "short": "Largura de banda" + }, + "latency": { + "value": "{{seconds}} segundos", + "short": { + "title": "Latência", + "value": "{{seconds}} seg" + }, + "title": "Latência:" + }, + "totalFrames": "Total de quadros:", + "droppedFrames": { + "title": "Quadros perdidos:", + "short": { + "title": "Perdido", + "value": "{{droppedFrames}} quadros" + } + }, + "decodedFrames": "Quadros decodificados:", + "droppedFrameRate": "Taxa de Quadros Perdidos:" + }, + "noRecordingsFoundForThisTime": "Nenhuma gravação encontrada para este momento", + "livePlayerRequiredIOSVersion": "iOS 17.1 ou superior é necessário para este tipo de transmissão ao vivo.", + "toast": { + "success": { + "submittedFrigatePlus": "Quadro enviado com sucesso para o Frigate+" + }, + "error": { + "submitFrigatePlusFailed": "Falha ao enviar o quadro para o Frigate+" + } + } +} diff --git a/web/public/locales/pt/objects.json b/web/public/locales/pt/objects.json new file mode 100644 index 000000000..b67725d94 --- /dev/null +++ b/web/public/locales/pt/objects.json @@ -0,0 +1,120 @@ +{ + "giraffe": "Girafa", + "cup": "Xicara", + "person": "Pessoa", + "stop_sign": "Sinal de Pare", + "sheep": "Ovelha", + "sandwich": "Lanche", + "carrot": "Cenoura", + "dining_table": "Mesa de jantar", + "motorcycle": "Motocicleta", + "bicycle": "Bicicleta", + "street_sign": "Sinal de rua", + "pizza": "Pizza", + "parking_meter": "Medidor de estacionamento", + "skateboard": "Skate", + "bottle": "Garrafa", + "car": "Carro", + "airplane": "Avião", + "bus": "Ônibus", + "train": "Trem", + "boat": "Barco", + "traffic_light": "Semaforo", + "fire_hydrant": "Hidratação de Fogo", + "bird": "Pássaro", + "cat": "Gato", + "bench": "Bench", + "elephant": "Elefante", + "hat": "Chapéu", + "backpack": "Mochila", + "shoe": "Sapato", + "handbag": "Bolsa de mão", + "tie": "Gravata", + "suitcase": "Mala de viagem", + "frisbee": "Frisbee", + "skis": "Esquis", + "kite": "Kite", + "baseball_bat": "Taco basebol", + "tennis_racket": "Raquete de Tenis", + "plate": "Placa", + "wine_glass": "Taça de vinho", + "fork": "Garfo", + "spoon": "Colher", + "bowl": "Tijela", + "banana": "Banana", + "apple": "Maça", + "hot_dog": "Cão quente", + "donut": "Donut", + "cake": "Bolo", + "chair": "Cadeira", + "potted_plant": "Planta em vaso", + "mirror": "Espelho", + "desk": "Mesa", + "toilet": "Banheiro", + "door": "Porta", + "baseball_glove": "Luva de beisebol", + "surfboard": "Prancha", + "broccoli": "Brócolis", + "snowboard": "Snowboard", + "dog": "Cão", + "bear": "Urso", + "eye_glasses": "Óculos", + "umbrella": "guarda-chuva", + "horse": "Cavalo", + "bed": "Cama", + "cow": "Vaca", + "zebra": "Zebra", + "sports_ball": "Bola", + "knife": "Faca", + "orange": "Laranja", + "window": "Janela", + "clock": "Relógio", + "keyboard": "Teclado", + "animal": "Animal", + "bark": "Latido", + "goat": "Bode", + "vehicle": "Veículo", + "scissors": "Tesoura", + "mouse": "Rato", + "teddy_bear": "Urso de pelúcia", + "hair_dryer": "Secador de cabelo", + "toothbrush": "Escova de dentes", + "hair_brush": "Escova de Cabelo", + "squirrel": "Esquilo", + "couch": "Sofá", + "tv": "TV", + "laptop": "Laptop", + "remote": "Remoto", + "cell_phone": "Celular", + "microwave": "Microondas", + "oven": "Forno", + "toaster": "Torradeira", + "sink": "Pia", + "refrigerator": "Refrigerador", + "blender": "Liquidificador", + "book": "Livro", + "vase": "Vaso", + "deer": "Veado", + "fox": "Raposa", + "rabbit": "Coelho", + "raccoon": "Guaxinim", + "robot_lawnmower": "Robô cortador de grama", + "waste_bin": "Lixeira", + "on_demand": "Sob demanda", + "face": "Rosto", + "license_plate": "Placa", + "package": "Pacote", + "bbq_grill": "Churrasqueira", + "amazon": "Amazonas", + "usps": "USPS", + "ups": "UPS", + "fedex": "FedEx", + "dhl": "DHL", + "an_post": "Uma postagem", + "purolator": "Purolator", + "postnl": "PostNL", + "nzpost": "NZPost", + "postnord": "PostNord", + "gls": "GLS", + "dpd": "DPD" +} diff --git a/web/public/locales/pt/views/configEditor.json b/web/public/locales/pt/views/configEditor.json new file mode 100644 index 000000000..1edf4a02f --- /dev/null +++ b/web/public/locales/pt/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "configEditor": "Editor de configuração", + "copyConfig": "Copiar configuração", + "saveAndRestart": "Salvar e reiniciar", + "saveOnly": "Somente salvar", + "toast": { + "success": { + "copyToClipboard": "Configuração copiada para a área de transferência." + }, + "error": { + "savingError": "Erro ao salvar configuração" + } + }, + "documentTitle": "Editor de configuração - Frigate" +} diff --git a/web/public/locales/pt/views/events.json b/web/public/locales/pt/views/events.json new file mode 100644 index 000000000..12303e5e9 --- /dev/null +++ b/web/public/locales/pt/views/events.json @@ -0,0 +1,35 @@ +{ + "detections": "Detecções", + "motion": { + "label": "Movimento", + "only": "Somente movimento" + }, + "allCameras": "Todas as câmeras", + "empty": { + "motion": "Nenhum dado de movimento encontrado", + "alert": "Não há alertas para revisar", + "detection": "Não há detecções para revisar" + }, + "timeline": "Linha do tempo", + "events": { + "aria": "Selecionar eventos", + "label": "Eventos", + "noFoundForTimePeriod": "Nenhum evento encontrado para este período." + }, + "timeline.aria": "Selecione a linha do tempo", + "alerts": "Alertas", + "documentTitle": "Análise - Frigate", + "recordings": { + "documentTitle": "Gravações - Frigate" + }, + "calendarFilter": { + "last24Hours": "Últimas 24 horas" + }, + "markAsReviewed": "Marcar como revisado", + "markTheseItemsAsReviewed": "Marque esses itens como revisados", + "newReviewItems": { + "label": "Ver novos itens de revisão", + "button": "Novos itens para revisar" + }, + "camera": "Câmera" +} diff --git a/web/public/locales/pt/views/explore.json b/web/public/locales/pt/views/explore.json new file mode 100644 index 000000000..b6635186a --- /dev/null +++ b/web/public/locales/pt/views/explore.json @@ -0,0 +1,175 @@ +{ + "generativeAI": "IA Generativa", + "exploreIsUnavailable": { + "embeddingsReindexing": { + "startingUp": "Iniciando…", + "estimatedTime": "Tempo restante estimado:", + "finishingShortly": "Terminando em breve", + "step": { + "thumbnailsEmbedded": "Miniaturas incorporadas: ", + "descriptionsEmbedded": "Descrições incorporadas: ", + "trackedObjectsProcessed": "Objetos rastreados processados: " + }, + "context": "O explorar pode ser usado depois que as incorporações de objetos rastreados terminarem de ser reindexadas." + }, + "downloadingModels": { + "setup": { + "visionModel": "Modelo de visão", + "textModel": "Modelo de texto", + "textTokenizer": "Tokenizador de texto", + "visionModelFeatureExtractor": "Extrator de características de modelo de visão" + }, + "context": "O Frigate está baixando os modelos de incorporação necessários para dar suporte a funcionalidade de pesquisa semântica. Isso pode levar vários minutos, dependendo da velocidade da sua conexão de rede.", + "tips": { + "context": "Talvez você queira reindexar as incorporações dos seus objetos rastreados depois que os modelos forem baixados.", + "documentation": "Leia a documentação" + }, + "error": "Ocorreu um erro. Verifique os logs do Frigate." + }, + "title": "Explorar não está disponível" + }, + "details": { + "timestamp": "Carimbo de hora", + "item": { + "title": "Revisar detalhes do item", + "desc": "Revisar detalhes do item", + "tips": { + "hasMissingObjects": "Ajuste sua configuração se você quiser que o Frigate salve os objetos rastreados para os seguintes rótulos: {{objects}}", + "mismatch_one": "{{count}} objeto indisponível foi detectado e incluído neste item de análise. Esses objetos não qualificaram como alerta ou detecção ou já foram limpos/excluídos.", + "mismatch_many": "{{count}} objetos indisponíveis foram detectados e incluídos neste item de análise. Esses objetos não qualificaram como alerta ou detecção ou já foram limpos/excluídos.", + "mismatch_other": "" + }, + "toast": { + "success": { + "regenerate": "Uma nova descrição foi solicitada pelo {{provider}}. Dependendo da velocidade do seu provedor, a nova descrição pode levar algum tempo para ser regenerada.", + "updatedSublabel": "Sub-rotulo atualizado com sucesso.", + "updatedLPR": "Placa de veículo atualizada com sucesso." + }, + "error": { + "regenerate": "Falha ao chamar {{provider}} para uma nova descrição: {{errorMessage}}", + "updatedSublabelFailed": "Falha ao atualizar o sub-rotulo: {{errorMessage}}", + "updatedLPRFailed": "Falha ao atualizar a placa de veículo: {{errorMessage}}" + } + }, + "button": { + "share": "Compartilhe este item para análise", + "viewInExplore": "Ver no Explorar" + } + }, + "zones": "Zonas", + "description": { + "label": "Descrição", + "aiTips": "O Frigate não solicitará uma descrição do seu provedor de IA Generativa até que o ciclo de vida do objeto rastreado tenha terminado.", + "placeholder": "Descrição do objeto rastreado" + }, + "camera": "Câmera", + "snapshotScore": { + "label": "Pontuação da captura" + }, + "topScore": { + "label": "Maior pontuação", + "info": "A maior pontuação é a maior pontuação mediana para o objeto rastreado, portanto, isso pode diferir da pontuação exibida na miniatura do resultado da pesquisa." + }, + "button": { + "findSimilar": "Encontrar similar", + "regenerate": { + "title": "Regenerar", + "label": "Regenerar descrição do objeto rastreado" + } + }, + "label": "Rótulo", + "editSubLabel": { + "title": "Editar sub-rotulo", + "desc": "Digite um novo sub-rotulo para este {{label}}", + "descNoLabel": "Digite um novo sub-rotulo para este objeto rastreado" + }, + "editLPR": { + "title": "Editar placa de veículo", + "desc": "Digite um novo valor de placa de veículo para este {{label}}", + "descNoLabel": "Digite um novo valor de placa de veículo para este objeto rastreado" + }, + "recognizedLicensePlate": "Placa de veículo reconhecida", + "estimatedSpeed": "Velocidade estimada", + "objects": "Objetos", + "expandRegenerationMenu": "Expandir menu de regeneração", + "regenerateFromSnapshot": "Regenerar a partir da captura", + "regenerateFromThumbnails": "Regenerar a partir das miniaturas", + "tips": { + "descriptionSaved": "Descrição salva com sucesso", + "saveDescriptionFailed": "Falha ao atualizar a descrição: {{errorMessage}}" + } + }, + "documentTitle": "Explorar - Frigate", + "trackedObjectDetails": "Detalhes do objeto rastreado", + "type": { + "details": "detalhes", + "video": "vídeo", + "object_lifecycle": "ciclo de vida do objeto", + "snapshot": "snapshot" + }, + "objectLifecycle": { + "title": "Ciclo de vida do objeto", + "lifecycleItemDesc": { + "attribute": { + "other": "{{label}} reconhecido como {{attribute}}", + "faceOrLicense_plate": "{{attribute}} detectado por {{label}}" + }, + "gone": "{{label}} saiu", + "heard": "{{label}} ouvido", + "visible": "{{label}} detectado", + "external": "{{label}} detectado", + "entered_zone": "{{label}} entrou em {{zones}}", + "active": "{{label}} se tornou ativo", + "stationary": "{{label}} se tornou estacionário" + }, + "annotationSettings": { + "title": "Configurações de anotação", + "offset": { + "documentation": "Leia a documentação ", + "desc": "Esses dados vêm do feed de detecção da sua câmera, mas são sobrepostos nas imagens do feed de gravação. É improvável que os dois streams estejam perfeitamente sincronizados. Como resultado, a caixa delimitadora e o vídeo não se alinharão perfeitamente. No entanto, o campo annotation_offset pode ser usado para ajustar isso.", + "tips": "DICA: Imagine que há um clipe de evento com uma pessoa andando da esquerda para a direita. Se a caixa delimitadora da linha do tempo do evento estiver consistentemente à esquerda da pessoa, o valor deve ser diminuído. Da mesma forma, se uma pessoa estiver andando da esquerda para a direita e a caixa delimitadora estiver consistentemente à frente da pessoa, o valor deve ser aumentado.", + "label": "Annotation Offset", + "millisecondsToOffset": "Milissegundos para deslocar as anotações de detecção. Padrão: 0" + }, + "showAllZones": { + "title": "Mostrar todas as zonas", + "desc": "Sempre mostrar zonas nos quadros onde os objetos entraram em uma zona." + } + }, + "carousel": { + "previous": "Slide anterior", + "next": "Próximo slide" + }, + "noImageFound": "Nenhuma imagem encontrada para este carimbo de data/hora.", + "createObjectMask": "Criar Máscara de Objeto", + "adjustAnnotationSettings": "Ajustar configurações de anotação", + "autoTrackingTips": "As posições da caixa delimitadora serão imprecisas para câmeras com rastreamento automático.", + "scrollViewTips": "Role para ver os momentos significativos do ciclo de vida deste objeto." + }, + "itemMenu": { + "downloadSnapshot": { + "aria": "Baixar captura", + "label": "Baixar captura" + }, + "viewObjectLifecycle": { + "label": "Ver ciclo de vida do objeto", + "aria": "Mostrar o ciclo de vida do objeto" + }, + "viewInHistory": { + "label": "Ver no Histórico", + "aria": "Ver no Histórico" + }, + "downloadVideo": { + "label": "Baixar vídeo", + "aria": "Baixar vídeo" + }, + "findSimilar": { + "label": "Encontrar similar", + "aria": "Encontrar objetos rastreados similares" + }, + "submitToPlus": { + "label": "Enviar para o Frigate+", + "aria": "Enviar para o Frigate Plus" + } + } +} diff --git a/web/public/locales/pt/views/exports.json b/web/public/locales/pt/views/exports.json new file mode 100644 index 000000000..8a2ad68cf --- /dev/null +++ b/web/public/locales/pt/views/exports.json @@ -0,0 +1,17 @@ +{ + "documentTitle": "Exportar - Frigate", + "search": "Pesquisar", + "noExports": "Nenhuma exportação encontrada", + "deleteExport": "Excluir exportação", + "editExport": { + "title": "Renomear exportação", + "desc": "Digite um novo nome para esta exportação.", + "saveExport": "Salvar exportação" + }, + "toast": { + "error": { + "renameExportFailed": "Falha ao renomear exportação: {{errorMessage}}" + } + }, + "deleteExport.desc": "Tem certeza de que deseja excluir {{exportName}}?" +} diff --git a/web/public/locales/pt/views/faceLibrary.json b/web/public/locales/pt/views/faceLibrary.json new file mode 100644 index 000000000..565d2423d --- /dev/null +++ b/web/public/locales/pt/views/faceLibrary.json @@ -0,0 +1,78 @@ +{ + "description": { + "placeholder": "Digite um nome para esta coleção", + "addFace": "Veja como adicionar uma nova coleção à biblioteca de rostos." + }, + "details": { + "person": "Pessoa", + "face": "Detalhes do rosto", + "faceDesc": "Detalhes do rosto e objeto associado", + "timestamp": "Carimbo de hora", + "confidence": "Confiança" + }, + "documentTitle": "Biblioteca de rostos - Frigate", + "uploadFaceImage": { + "title": "Carregar imagem do rosto", + "desc": "Carregue uma imagem para escanear rostos e incluir em {{pageToggle}}" + }, + "createFaceLibrary": { + "title": "Criar coleção", + "desc": "Criar uma nova coleção", + "new": "Criar novo rosto", + "nextSteps": "Para construir uma base sólida:
  • Use a aba Treinar para selecionar e treinar em imagens para cada pessoa detectada.
  • Concentre-se em imagens diretas para obter melhores resultados; evite imagens de treinamento que capturem rostos em ângulo.
  • " + }, + "train": { + "aria": "Selecionar treino", + "title": "Treinar" + }, + "selectItem": "Selecionar {{item}}", + "selectFace": "Selecionar rosto", + "deleteFaceLibrary": { + "title": "Excluir nome", + "desc": "Tem certeza de que deseja excluir a coleção {{name}}? Isso excluirá permanentemente todos os rostos associados." + }, + "button": { + "addFace": "Adicionar rosto", + "uploadImage": "Carregar imagem", + "deleteFaceAttempts": "Apagar tentativas de detecção facial", + "reprocessFace": "Reprocessar Rosto" + }, + "imageEntry": { + "validation": { + "selectImage": "Selecione um arquivo de imagem." + }, + "dropActive": "Solte a imagem aqui…", + "maxSize": "Tamanho máximo: {{size}}MB", + "dropInstructions": "Arraste e solte uma imagem aqui ou clique para selecionar" + }, + "trainFace": "Treinar rosto", + "toast": { + "success": { + "updatedFaceScore": "Pontuação facial atualizada com sucesso.", + "trainedFace": "Rosto treinado com sucesso.", + "deletedFace_one": "{{count}} rosto excluído com sucesso.", + "deletedFace_many": "{{count}} rostos excluídos com sucesso.", + "deletedFace_other": "{{count}} rostos excluídos com sucesso.", + "deletedName_one": "{{count}} rosto foi excluído com sucesso.", + "deletedName_many": "{{count}} rostos foram excluídos com sucesso.", + "deletedName_other": "{{count}} rostos foram excluídos com sucesso.", + "uploadedImage": "Imagem carregada com sucesso.", + "addFaceLibrary": "{{name}} foi adicionado com sucesso à biblioteca de rostos!" + }, + "error": { + "uploadingImageFailed": "Falha ao carregar a imagem: {{errorMessage}}", + "deleteFaceFailed": "Falha ao excluir: {{errorMessage}}", + "deleteNameFailed": "Falha ao excluir nome: {{errorMessage}}", + "addFaceLibraryFailed": "Falhou ao definir nome do rosto: {{errorMessage}}", + "trainFailed": "Falhou ao treinar: {{errorMessage}}", + "updateFaceScoreFailed": "Falhou ao atualizar pontuação da face: {{errorMessage}}" + } + }, + "readTheDocs": "Leia a documentação", + "trainFaceAs": "Treinar rosto como:", + "steps": { + "faceName": "Digite o Nome do Rosto", + "uploadFace": "Carregar imagem do rosto", + "nextSteps": "Próximos passos" + } +} diff --git a/web/public/locales/pt/views/live.json b/web/public/locales/pt/views/live.json new file mode 100644 index 000000000..12956f88a --- /dev/null +++ b/web/public/locales/pt/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "Ao vivo - Frigate", + "documentTitle.withCamera": "{{camera}} - Ao vivo - Frigate", + "twoWayTalk": { + "disable": "Desativar conversação bidirecional", + "enable": "Habilitar conversação bidirecional" + }, + "cameraAudio": { + "enable": "Habilitar áudio da câmera", + "disable": "Desativar áudio da câmera" + }, + "ptz": { + "move": { + "clickMove": { + "label": "Clique no quadro para centralizar a câmera", + "enable": "Habilitar clique para mover", + "disable": "Desativar clique para mover" + }, + "down": { + "label": "Mover a câmera PTZ para baixo" + }, + "up": { + "label": "Mover a câmera PTZ para cima" + }, + "left": { + "label": "Mover a câmera PTZ para a esquerda" + }, + "right": { + "label": "Mover a câmera PTZ para a direita" + } + }, + "zoom": { + "in": { + "label": "Aumentar zoom da câmera PTZ" + }, + "out": { + "label": "Diminuir zoom da câmera PTZ" + } + }, + "presets": "Predefinições de câmera PTZ", + "frame": { + "center": { + "label": "Clique no quadro para centralizar a câmera PTZ" + } + } + }, + "lowBandwidthMode": "Modo de baixa largura de banda", + "camera": { + "enable": "Habilitar câmera", + "disable": "Desativar câmera" + }, + "muteCameras": { + "disable": "Ativar áudio de todas as câmeras", + "enable": "Silenciar todas as câmeras" + }, + "detect": { + "enable": "Habilitar detecção", + "disable": "Desativar detecção" + }, + "snapshots": { + "enable": "Habilitar snapshots", + "disable": "Desativar snapshots" + }, + "audioDetect": { + "enable": "Habilitar detecção de áudio", + "disable": "Desativar detecção de áudio" + }, + "autotracking": { + "enable": "Habilitar rastreamento automático", + "disable": "Desativar rastreamento automático" + }, + "streamStats": { + "enable": "Mostrar estatísticas de transmissão", + "disable": "Ocultar estatísticas de transmissão" + }, + "manualRecording": { + "tips": "Inicie um evento manual com base nas configurações de retenção de gravação desta câmera.", + "playInBackground": { + "label": "Reproduzir em segundo plano", + "desc": "Habilite esta opção para continuar a transmissão quando o player estiver oculto." + }, + "showStats": { + "label": "Mostrar estatísticas", + "desc": "Habilite esta opção para mostrar estatísticas de transmissão como uma sobreposição no feed da câmera." + }, + "start": "Iniciar gravação sob demanda", + "recordDisabledTips": "Como a gravação está desabilitada ou restrita na configuração desta câmera, apenas um snapshot será salvo.", + "end": "Encerrar gravação sob demanda", + "ended": "Fim da gravação manual sob demanda.", + "failedToEnd": "Falha ao finalizar a gravação manual sob demanda.", + "failedToStart": "Falha ao iniciar a gravação manual sob demanda.", + "title": "Gravação sob demanda", + "started": "Iniciou a gravação manual sob demanda.", + "debugView": "Exibição de depuração" + }, + "streamingSettings": "Configurações de transmissão", + "notifications": "Notificações", + "suspend": { + "forTime": "Suspender por: " + }, + "stream": { + "title": "Transmissão", + "audio": { + "tips": { + "title": "O áudio deve ser emitido pela sua câmera e configurado no go2rtc para esta transmissão.", + "documentation": "Leia a documentação " + }, + "available": "O áudio está disponível para esta transmissão", + "unavailable": "O áudio não está disponível para esta transmissão" + }, + "twoWayTalk": { + "tips.documentation": "Leia a documentação ", + "unavailable": "Conversa bidirecional não está disponível para este fluxo", + "tips": "Seu dispositivo deve suportar o recurso e o WebRTC deve ser configurado para conversação bidirecional.", + "available": "Conversa bidirecional está disponível para esta transmissão" + }, + "lowBandwidth": { + "tips": "A visualização ao vivo está em modo de baixa largura de banda devido a erros de buffer ou transmissão.", + "resetStream": "Reiniciar transmissão" + }, + "playInBackground": { + "label": "Reproduzir em segundo plano", + "tips": "Habilite esta opção para continuar a transmissão quando o player estiver oculto." + } + }, + "cameraSettings": { + "title": "{{camera}} configurações", + "cameraEnabled": "Câmera habilitada", + "objectDetection": "Detecção de objeto", + "recording": "Gravando", + "audioDetection": "Detecção de áudio", + "autotracking": "Rastreamento automático", + "snapshots": "Snapshots" + }, + "effectiveRetainMode": { + "modes": { + "active_objects": "Objetos ativos", + "motion": "Movimento", + "all": "Todos" + }, + "notAllTips": "Sua configuração de retenção de gravação {{source}} está definida como modo: {{effectiveRetainMode}}, portanto, esta gravação sob demanda manterá apenas segmentos com {{effectiveRetainModeName}}." + }, + "editLayout": { + "label": "Editar layout", + "group": { + "label": "Editar grupo de câmeras" + }, + "exitEdit": "Sair da edição" + }, + "audio": "Áudio", + "recording": { + "enable": "Habilitar gravação", + "disable": "Desativar gravação" + }, + "history": { + "label": "Mostrar filmagens históricas" + } +} diff --git a/web/public/locales/pt/views/recording.json b/web/public/locales/pt/views/recording.json new file mode 100644 index 000000000..a8b6e390c --- /dev/null +++ b/web/public/locales/pt/views/recording.json @@ -0,0 +1,12 @@ +{ + "export": "Exportar", + "calendar": "Calendário", + "filter": "Filtro", + "filters": "Filtros", + "toast": { + "error": { + "endTimeMustAfterStartTime": "O horário de término deve ser posterior ao horário de início", + "noValidTimeSelected": "Nenhum intervalo de tempo válido selecionado" + } + } +} diff --git a/web/public/locales/pt/views/search.json b/web/public/locales/pt/views/search.json new file mode 100644 index 000000000..32b01148c --- /dev/null +++ b/web/public/locales/pt/views/search.json @@ -0,0 +1,67 @@ +{ + "search": "Pesquisar", + "savedSearches": "Pesquisas salvas", + "searchFor": "Pesquisar por {{inputValue}}", + "button": { + "save": "Salvar pesquisa", + "delete": "Excluir pesquisa salva", + "filterInformation": "Informação do filtro", + "filterActive": "Filtros ativos", + "clear": "Limpar pesquisa" + }, + "trackedObjectId": "ID do objeto rastreado", + "filter": { + "label": { + "sub_labels": "Sub etiquetas", + "zones": "Zonas", + "cameras": "Câmeras", + "labels": "Etiquetas", + "search_type": "Tipo de pesquisa", + "time_range": "Intervalo de tempo", + "before": "Antes", + "after": "Depois", + "min_score": "Pontuação mínima", + "max_score": "Pontuação máxima", + "min_speed": "Velocidade mínima", + "max_speed": "Velocidade máxima", + "recognized_license_plate": "Placa reconhecida", + "has_clip": "Tem Clipe", + "has_snapshot": "Tem Captura de Imagem" + }, + "searchType": { + "thumbnail": "Miniatura", + "description": "Descrição" + }, + "header": { + "noFilters": "Filtros", + "activeFilters": "Filtros ativos", + "currentFilterType": "Valores de filtro" + }, + "tips": { + "desc": { + "text": "Os filtros ajudam você a restringir os resultados da sua pesquisa. Veja como usá-los no campo de entrada:", + "example": "Exemplo: cameras:front_door label:person before:01012024 time_range:3:00PM-4:00PM ", + "step": "
    • Digite um nome de filtro seguido de dois pontos (ex: \"cameras:\").
    • Selecione um valor entre as sugestões ou digite o seu próprio.
    • Use múltiplos filtros adicionando-os um após o outro com um espaço entre eles.
    • Filtros de data (before: e after:) usam o formato {{DateFormat}}.
    • O filtro de intervalo de tempo usa o formato {{exampleTime}}.
    • Remova filtros clicando no 'x' ao lado deles.
    " + }, + "title": "Como usar filtros de texto" + }, + "toast": { + "error": { + "beforeDateBeLaterAfter": "A data 'antes' deve ser posterior à data 'depois'.", + "minScoreMustBeLessOrEqualMaxScore": "O 'min_score' deve ser inferior ou igual ao 'max_score'.", + "minSpeedMustBeLessOrEqualMaxSpeed": "O 'min_speed' deve ser inferior ou igual ao 'max_speed'.", + "afterDatebeEarlierBefore": "A data \"depois\" deve ser anterior à data \"antes\".", + "maxScoreMustBeGreaterOrEqualMinScore": "O 'max_score' deve ser maior ou igual ao 'min_score'.", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "O 'max_speed' deve ser maior ou igual ao 'min_speed'." + } + } + }, + "placeholder": { + "search": "Pesquisar…" + }, + "similaritySearch": { + "title": "Pesquisa de similaridade", + "active": "Busca de semelhança ativa", + "clear": "Pesquisa de semelhança clara" + } +} diff --git a/web/public/locales/pt/views/settings.json b/web/public/locales/pt/views/settings.json new file mode 100644 index 000000000..cdd0fc582 --- /dev/null +++ b/web/public/locales/pt/views/settings.json @@ -0,0 +1,383 @@ +{ + "documentTitle": { + "camera": "Configurações da câmera - Frigate", + "classification": "Configurações de classificação - Frigate", + "masksAndZones": "Editor de máscara e zona - Frigate", + "motionTuner": "Ajuste de movimento - Frigate", + "object": "Configurações do objeto - Frigate", + "authentication": "Configurações de autenticação - Frigate", + "general": "Configurações gerais - Frigate", + "frigatePlus": "Configurações do Frigate+ - Frigate", + "default": "Configurações - Frigate" + }, + "menu": { + "ui": "UI", + "masksAndZones": "Máscaras / Zonas", + "cameras": "Configurações da câmera", + "classification": "Classificação", + "motionTuner": "Ajuste de movimento", + "debug": "Depurar", + "users": "Usuários", + "notifications": "Notificações", + "frigateplus": "Frigate+" + }, + "dialog": { + "unsavedChanges": { + "title": "Você tem alterações não salvas.", + "desc": "Deseja salvar suas alterações antes de continuar?" + } + }, + "cameraSetting": { + "camera": "Câmera", + "noCamera": "Sem câmera" + }, + "general": { + "title": "Configurações gerais", + "liveDashboard": { + "title": "Painel ao vivo", + "automaticLiveView": { + "label": "Visualização ao vivo automática", + "desc": "Alternar automaticamente para a visualização ao vivo de uma câmera quando uma atividade for detectada. Desativar esta opção faz com que as imagens estáticas das câmeras no painel Ao Vivo sejam atualizadas apenas uma vez por minuto." + }, + "playAlertVideos": { + "label": "Reproduzir vídeos de alerta", + "desc": "Por padrão, alertas recentes no painel ao vivo são reproduzidos como vídeos curtos em loop. Desative esta opção para mostrar apenas uma imagem estática dos alertas recentes neste dispositivo/navegador." + } + }, + "calendar": { + "title": "Calendário", + "firstWeekday": { + "label": "Primeiro dia da semana", + "sunday": "Domingo", + "monday": "Segunda-feira", + "desc": "O dia em que as semanas do calendário de revisão começam." + } + }, + "storedLayouts": { + "title": "Layouts armazenados", + "desc": "O layout das câmeras em um grupo de câmeras pode ser arrastado/redimensionado. As posições são armazenadas no armazenamento local do seu navegador.", + "clearAll": "Limpar todos os layouts" + }, + "recordingsViewer": { + "defaultPlaybackRate": { + "label": "Taxa de reprodução padrão", + "desc": "Taxa de reprodução padrão para a reprodução das gravações." + }, + "title": "Visualizador de gravações" + }, + "cameraGroupStreaming": { + "desc": "As configurações de transmissão de cada grupo de câmeras são armazenadas no armazenamento local do seu navegador.", + "title": "Configurações de transmissão do grupo de câmeras", + "clearAll": "Limpar todas as configurações de transmissão" + }, + "toast": { + "success": { + "clearStreamingSettings": "Configurações de transmissão para todos os grupos de câmeras limpas.", + "clearStoredLayout": "Limpo layout armazenado para {{cameraName}}" + }, + "error": { + "clearStoredLayoutFailed": "Falha ao limpar o layout armazenado: {{errorMessage}}", + "clearStreamingSettingsFailed": "Falha ao limpar as configurações de transmissão: {{errorMessage}}" + } + } + }, + "classification": { + "faceRecognition": { + "modelSize": { + "label": "Tamanho do modelo", + "small": { + "title": "pequeno", + "desc": "Usar pequeno utiliza um modelo de incorporação facial FaceNet que é eficiente na maioria dos CPUs." + }, + "large": { + "title": "grande", + "desc": "Usar grande utiliza um modelo de incorporação facial ArcFace e será executado automaticamente na GPU, se aplicável." + }, + "desc": "O tamanho do modelo utilizado para o reconhecimento facial." + }, + "readTheDocumentation": "Leia a documentação", + "title": "Reconhecimento facial", + "desc": "O reconhecimento facial permite que pessoas sejam atribuídas a nomes e, quando o rosto delas for reconhecido, o Frigate atribuirá o nome da pessoa como um sub-rótulo. Essa informação é incluída na interface do usuário, filtros e também nas notificações." + }, + "licensePlateRecognition": { + "readTheDocumentation": "Leia a documentação", + "title": "Reconhecimento de placas de veículo", + "desc": "O Frigate pode reconhecer placas de veículos e adicionar automaticamente os caracteres detectados ao campo placa_de_veículo_reconhecida ou um nome conhecido como sub_rótulo para objetos do tipo carro. Um caso de uso comum pode ser ler as placas de veículos que entram em uma garagem ou os carros que passam por uma rua." + }, + "semanticSearch": { + "readTheDocumentation": "Leia a documentação", + "title": "Pesquisa semântica", + "reindexNow": { + "label": "Reindexar agora", + "desc": "A reindexação irá regenerar as incorporações de todos os objetos rastreados. Esse processo é executado em segundo plano e pode sobrecarregar seu CPU e levar um bom tempo, dependendo do número de objetos rastreados que você possui.", + "confirmTitle": "Confirmar reindexação", + "confirmDesc": "Você tem certeza de que deseja reindexar todos as incorporações dos objetos rastreados? Esse processo será executado em segundo plano, mas pode sobrecarregar seu CPU e levar um bom tempo. Você pode acompanhar o progresso na página Explorar.", + "confirmButton": "Reindexar", + "alreadyInProgress": "A reindexação já está em andamento.", + "error": "Falha ao iniciar a reindexação: {{errorMessage}}", + "success": "Reindexação iniciada com sucesso." + }, + "modelSize": { + "label": "Tamanho do modelo", + "desc": "O tamanho do modelo utilizado para as incorporações de pesquisa semântica.", + "small": { + "title": "pequeno", + "desc": "Usar pequeno utiliza uma versão quantizada do modelo, que usa menos RAM e executa mais rápido no CPU, com uma diferença insignificante na qualidade da incorporação." + }, + "large": { + "title": "grande", + "desc": "Usar grande utiliza o modelo completo do Jina e será executado automaticamente na GPU, se aplicável." + } + }, + "desc": "A Pesquisa Semântica no Frigate permite que você encontre objetos rastreados dentro dos itens de revisão usando a imagem em si, uma descrição de texto definida pelo usuário ou uma descrição gerada automaticamente." + }, + "title": "Configurações de classificação", + "toast": { + "success": "As configurações de classificação foram salvas. Reinicie o Frigate para aplicar as alterações.", + "error": "Falha ao salvar as alterações de configuração: {{errorMessage}}" + }, + "birdClassification": { + "title": "Classificação de Pássaros", + "desc": "A classificação de aves/pássaros identifica aves conhecidas usando um modelo Tensorflow quantizado. Quando uma ave/ pássaro conhecida(o) for reconhecida(o), o seu nome comum será adicionado como um sub_rótulo. Estas informações estão incluídas na interface do utilizador, nos filtros e também nas notificações." + } + }, + "notification": { + "globalSettings": { + "title": "Configurações globais", + "desc": "Suspenda temporariamente as notificações para câmaras específicas em todos os dispositivos registados." + }, + "notificationSettings": { + "documentation": "Leia a documentação", + "title": "Configurações de notificação", + "desc": "O Frigate pode enviar notificações push para o seu dispositivo quando está a ser executado no browser ou instalado como um PWA." + }, + "notificationUnavailable": { + "documentation": "Leia a documentação", + "title": "Notificações indisponíveis" + }, + "cameras": { + "title": "Câmeras", + "noCameras": "Nenhuma câmara disponível", + "desc": "Selecione para que câmaras as notificações serão ativadas." + }, + "deviceSpecific": "Configurações específicas do dispositivo", + "registerDevice": "Registe este dispositivo", + "email": { + "placeholder": "por exemplo: exemplo@email.com", + "desc": "É necessário um e-mail válido que será utilizado para o notificar caso haja algum problema com o serviço push.", + "title": "E-mail" + }, + "title": "Notificações" + }, + "frigatePlus": { + "snapshotConfig": { + "documentation": "Leia a documentação", + "table": { + "snapshots": "Snapshots", + "camera": "Câmera" + } + }, + "toast": { + "success": "As definições do Frigate+ foram guardadas. Reinicie o Frigate para aplicar as alterações.", + "error": "Falha ao guardar alterações de configuração: {{errorMessage}}" + } + }, + "masksAndZones": { + "motionMasks": { + "point_one": "{{count}} ponto", + "point_many": "{{count}} pontos", + "point_other": "{{count}} pontos", + "context": { + "documentation": "Leia a documentação" + }, + "polygonAreaTooLarge": { + "documentation": "Leia a documentação" + }, + "label": "Máscara de movimento", + "desc": { + "documentation": "Documentação" + }, + "clickDrawPolygon": "Clique para desenhar um polígono na imagem.", + "toast": { + "success": { + "noName": "O filtro de movimento foi guardado. Reinicie o Frigate para aplicar as alterações." + } + } + }, + "zones": { + "label": "Zonas", + "documentTitle": "Editar Zona - Frigate", + "desc": { + "documentation": "Documentação", + "title": "As zonas permitem definir uma área específica do quadro para que você possa determinar se um objeto está ou não dentro de uma área particular." + }, + "point_one": "{{count}} ponto", + "point_many": "{{count}} pontos", + "point_other": "{{count}} pontos", + "add": "Adicionar Zona", + "edit": "Editar Zona", + "clickDrawPolygon": "Clique para desenhar um polígono na imagem.", + "name": { + "title": "Nome", + "inputPlaceHolder": "Digite um nome…", + "tips": "O nome deve ter pelo menos 2 caracteres e não pode ser o nome de uma câmera ou de outra zona." + }, + "inertia": { + "title": "Inércia", + "desc": "Especifica quantos quadros um objeto deve estar em uma zona antes de ser considerado dentro da zona. Padrão: 3" + }, + "loiteringTime": { + "title": "Tempo de permanência", + "desc": "Define o tempo mínimo, em segundos, que o objeto deve permanecer na zona para que ela seja ativada. Padrão: 0" + }, + "objects": { + "title": "Objetos", + "desc": "Lista de objetos que se aplicam a esta zona." + }, + "allObjects": "Todos os objetos", + "speedEstimation": { + "title": "Estimativa de velocidade", + "desc": "Ativar estimativa de velocidade para objetos nesta zona. A zona deve ter exatamente 4 pontos." + }, + "speedThreshold": { + "title": "Limite de velocidade ({{unit}})", + "desc": "Especifica uma velocidade mínima para que os objetos sejam considerados nesta zona.", + "toast": { + "error": { + "pointLengthError": "A estimativa de velocidade foi desativada para esta zona. Zonas com estimativa de velocidade devem ter exatamente 4 pontos.", + "loiteringTimeError": "Zonas com tempos de permanência maiores que 0 não devem ser usadas com estimativa de velocidade." + } + } + }, + "toast": { + "success": "A zona ({{zoneName}}) foi salva. Reinicie o Frigate para aplicar as alterações." + } + }, + "filter": { + "all": "Todas as Máscaras e Zonas" + }, + "toast": { + "success": { + "copyCoordinates": "Coordenadas de {{polyName}} copiadas para a área de transferência." + }, + "error": { + "copyCoordinatesFailed": "Não foi possível copiar as coordenadas para a área de transferência." + } + }, + "form": { + "zoneName": { + "error": { + "mustBeAtLeastTwoCharacters": "O nome da zona deve ter pelo menos 2 caracteres.", + "mustNotContainPeriod": "O nome da zona não pode conter pontos.", + "hasIllegalCharacter": "O nome da zona contém caracteres ilegais.", + "mustNotBeSameWithCamera": "O nome da zona não pode ser o mesmo que o nome da câmera.", + "alreadyExists": "Já existe uma zona com esse nome para esta câmera." + } + }, + "distance": { + "error": { + "text": "A distância deve ser maior ou igual a 0,1.", + "mustBeFilled": "Todos os campos de distância devem ser preenchidos para usar a estimativa de velocidade." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "A inércia deve ser maior que 0." + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "O tempo de permanência deve ser maior ou igual a 0." + } + }, + "polygonDrawing": { + "removeLastPoint": "Remover o último ponto", + "reset": { + "label": "Limpar todos os pontos" + }, + "snapPoints": { + "true": "Fixar pontos", + "false": "Não fixar pontos" + }, + "delete": { + "title": "Confirmar exclusão", + "success": "{{name}} foi excluído.", + "desc": "Você tem certeza de que deseja excluir o {{type}} {{name}}?" + }, + "error": { + "mustBeFinished": "A criação do polígono deve ser concluída antes de salvar." + } + } + }, + "objectMasks": { + "label": "Máscaras de objetos", + "clickDrawPolygon": "Clique para desenhar um polígono na imagem.", + "desc": { + "documentation": "Documentação" + }, + "point_one": "{{count}} ponto", + "point_many": "{{count}} pontos", + "point_other": "{{count}} pontos", + "objects": { + "allObjectTypes": "Todos os tipos de objeto", + "title": "Objetos" + }, + "add": "Adicionar filtro para objecto", + "edit": "Editar filtro de objecto", + "documentTitle": "Editar filtro de movimento - Frigate" + }, + "restart_required": "É necessário reiniciar (máscaras/zonas alteradas)" + }, + "debug": { + "zones": { + "title": "Zonas" + }, + "timestamp": { + "title": "Carimbo de hora" + } + }, + "camera": { + "reviewClassification": { + "readTheDocumentation": "Leia a documentação", + "title": "Classificação de Revisão", + "noDefinedZones": "Nenhuma zona está definida para esta câmera.", + "objectAlertsTips": "Todos os objetos {{alertsLabels}} na câmera {{cameraName}} serão exibidos como Alertas.", + "zoneObjectDetectionsTips": { + "text": "Todos os objetos {{detectionsLabels}} não categorizados na zona {{zone}} na câmera {{cameraName}} serão exibidos como Detecções.", + "regardlessOfZoneObjectDetectionsTips": "Todos os objetos {{detectionsLabels}} não categorizados na câmera {{cameraName}} serão exibidos como Detecções, independentemente da zona em que se encontram.", + "notSelectDetections": "Todos os objetos {{detectionsLabels}} detectados na zona {{zone}} na câmera {{cameraName}} que não forem categorizados como Alertas serão exibidos como Detecções, independentemente da zona em que se encontram." + }, + "selectAlertsZones": "Selecionar zonas para Alertas", + "selectDetectionsZones": "Selecionar zonas para Detecções", + "limitDetections": "Limitar detecções a zonas específicas", + "desc": "O Frigate categoriza os itens de revisão como Alertas e Detecções. Por padrão, todos os objetos do tipo pessoa e carro são considerados Alertas. Você pode refinar a categorização dos seus itens de revisão configurando as zonas necessárias para eles.", + "objectDetectionsTips": "Todos os objetos {{detectionsLabels}} não categorizados na câmera {{cameraName}} serão exibidos como Detecções, independentemente da zona em que se encontram.", + "zoneObjectAlertsTips": "Todos os objetos {{alertsLabels}} detectados na zona {{zone}} na câmera {{cameraName}} serão exibidos como Alertas.", + "toast": { + "success": "A configuração de classificação de revisão foi salva. Reinicie o Frigate para aplicar as alterações." + } + }, + "title": "Configurações da câmera", + "streams": { + "title": "fluxos", + "desc": "Desativar uma câmera interrompe completamente o processamento dos fluxos dessa câmera pelo Frigate. Detecção, gravação e depuração ficarão indisponíveis.
    Observação: Isso não desativa as retransmissões do go2rtc." + }, + "review": { + "title": "Revisão", + "desc": "Ative ou desative alertas e detecções para esta câmera. Quando desativado, nenhum novo item de revisão será gerado.", + "alerts": "Alertas ", + "detections": "Detecções " + } + }, + "motionDetectionTuner": { + "contourArea": { + "title": "Área de contorno" + }, + "improveContrast": { + "title": "Melhorar o contraste" + }, + "Threshold": { + "title": "Limite" + } + } +} diff --git a/web/public/locales/pt/views/system.json b/web/public/locales/pt/views/system.json new file mode 100644 index 000000000..56bd3f97a --- /dev/null +++ b/web/public/locales/pt/views/system.json @@ -0,0 +1,157 @@ +{ + "documentTitle": { + "storage": "Estatísticas de armazenamento - Frigate", + "general": "Estatísticas gerais - Frigate", + "enrichments": "Estatísticas de enriquecimento - Frigate", + "logs": { + "frigate": "Logs do Frigate - Frigate", + "go2rtc": "Logs do Go2RTC - Frigate", + "nginx": "Logs do Nginx - Frigate" + }, + "cameras": "Estatísticas das câmeras - Frigate" + }, + "title": "Sistema", + "metrics": "Métricas do sistema", + "logs": { + "type": { + "label": "Tipo", + "timestamp": "Carimbo de hora", + "tag": "Tag", + "message": "Mensagem" + }, + "copy": { + "success": "Logs copiados para a área de transferência", + "label": "Copiar para a área de transferência", + "error": "Não foi possível copiar os logs para a área de transferência" + }, + "download": { + "label": "Baixar logs" + }, + "tips": "Os logs estão sendo transmitidos do servidor", + "toast": { + "error": { + "fetchingLogsFailed": "Erro ao buscar logs: {{errorMessage}}", + "whileStreamingLogs": "Erro ao transmitir logs: {{errorMessage}}" + } + } + }, + "storage": { + "cameraStorage": { + "camera": "Câmera", + "storageUsed": "Armazenamento", + "percentageOfTotalUsed": "Porcentagem do total", + "bandwidth": "Largura de banda", + "unused": { + "tips": "Este valor pode não representar com precisão o espaço livre disponível para o Frigate se você tiver outros arquivos armazenados em sua unidade além das gravações do Frigate. O Frigate não rastreia o uso de armazenamento fora de suas gravações.", + "title": "Não utilizado" + }, + "unusedStorageInformation": "Informações de armazenamento não utilizado", + "title": "Armazenamento da câmera" + }, + "title": "Armazenamento", + "overview": "Visão geral", + "recordings": { + "title": "Gravações", + "earliestRecording": "Primeira gravação disponível:", + "tips": "Esse valor representa o armazenamento total usado pelas gravações no banco de dados do Frigate. O Frigate não acompanha o uso de armazenamento de todos os arquivos no seu disco." + } + }, + "cameras": { + "title": "Câmeras", + "info": { + "video": "Vídeo:", + "unknown": "Desconhecido", + "error": "Erro: {{error}}", + "fetching": "Obtendo dados da câmera", + "resolution": "Resolução:", + "codec": "Codec:", + "fps": "FPS:", + "stream": "Transmissão {{idx}}", + "audio": "Áudio:", + "cameraProbeInfo": "{{camera}} Explorar informações da Camera", + "tips": { + "title": "Explorar informações da Camera" + }, + "streamDataFromFFPROBE": "Os dados de fluxo são obtidos com ffprobe." + }, + "framesAndDetections": "Quadros / Detecções", + "label": { + "camera": "câmera", + "detect": "detectar", + "capture": "capturar", + "skipped": "pulado", + "ffmpeg": "ffmpeg" + }, + "overview": "Visão geral", + "toast": { + "success": { + "copyToClipboard": "Dados de Exploração copiados para a área de transferência." + }, + "error": { + "unableToProbeCamera": "Não foi possível explorar a câmera: {{errorMessage}}" + } + } + }, + "lastRefreshed": "Última atualização: ", + "stats": { + "ffmpegHighCpuUsage": "{{camera}} tem alto uso de CPU FFMPEG ({{ffmpegAvg}}%)", + "detectHighCpuUsage": "{{camera}} tem alto uso de CPU de detecção ({{detectAvg}}%)", + "healthy": "O sistema está saudável", + "reindexingEmbeddings": "Reindexando incorporações ({{processed}}% completo)" + }, + "general": { + "title": "Geral", + "detector": { + "title": "Detectores", + "cpuUsage": "Uso da CPU do detector", + "memoryUsage": "Uso da memória do detector", + "inferenceSpeed": "Velocidade de Inferência do Detector" + }, + "hardwareInfo": { + "title": "Informações de hardware", + "gpuUsage": "Uso da GPU", + "gpuMemory": "Memória da GPU", + "gpuInfo": { + "nvidiaSMIOutput": { + "driver": "Driver: {{driver}}", + "vbios": "Informação VBios: {{vbios}}", + "name": "Nome: {{name}}", + "cudaComputerCapability": "Capacidade de computação CUDA: {{cuda_compute}}", + "title": "Saída Nvidia SMI" + }, + "copyInfo": { + "label": "Copiar informações da GPU" + }, + "closeInfo": { + "label": "Fechar informações da GPU" + }, + "toast": { + "success": "Informações da GPU copiadas para a área de transferência" + }, + "vainfoOutput": { + "title": "Saída do Vainfo", + "returnCode": "Código de retorno: {{code}}", + "processOutput": "Saída do processo:", + "processError": "Erro no processo:" + } + }, + "gpuEncoder": "Codificador de GPU", + "gpuDecoder": "Decodificador de GPU" + }, + "otherProcesses": { + "title": "Outros processos", + "processCpuUsage": "Uso de CPU do processo", + "processMemoryUsage": "Uso de memória do processo" + } + }, + "enrichments": { + "title": "Enriquecimentos", + "infPerSecond": "Inferências por segundo", + "embeddings": { + "image_embedding_speed": "Velocidade de incorporação de imagem", + "face_embedding_speed": "Velocidade de incorporação facial", + "plate_recognition_speed": "Velocidade de reconhecimento de placas", + "text_embedding_speed": "Velocidade de incorporação de texto" + } + } +} diff --git a/web/public/locales/ro/audio.json b/web/public/locales/ro/audio.json new file mode 100644 index 000000000..d49651c15 --- /dev/null +++ b/web/public/locales/ro/audio.json @@ -0,0 +1,34 @@ +{ + "gunshot": "Foc de arma", + "machine_gun": "Mitraliera", + "speech": "Vorbire", + "babbling": "Murmur", + "yell": "Striga", + "bellow": "Sub", + "dog": "Caine", + "horse": "Cal", + "bird": "Pasare", + "sheep": "Oaie", + "boat": "Barca", + "motorcycle": "Motocicleta", + "bus": "Autobuz", + "train": "Tren", + "skateboard": "Skateboard", + "camera": "Camera", + "bicycle": "Bicicleta", + "car": "Masina", + "cat": "Pisica", + "animal": "Animal", + "goat": "Capra", + "keyboard": "Tastatura", + "vehicle": "Vehicul", + "sink": "Chiuveta", + "scissors": "Foarfeca", + "hair_dryer": "Uscator de Par", + "door": "Usa", + "blender": "Blender", + "mouse": "Mouse", + "clock": "Ceas", + "toothbrush": "Periuta de Dinti", + "bark": "Latrat" +} diff --git a/web/public/locales/ro/common.json b/web/public/locales/ro/common.json new file mode 100644 index 000000000..26941ce3e --- /dev/null +++ b/web/public/locales/ro/common.json @@ -0,0 +1,8 @@ +{ + "time": { + "untilForTime": "Pana la {{time}}", + "untilForRestart": "Pana la repornirea Frigate.", + "untilRestart": "Pana la repornire", + "ago": "{{timeAgo}} in urma" + } +} diff --git a/web/public/locales/ro/components/auth.json b/web/public/locales/ro/components/auth.json new file mode 100644 index 000000000..918a0435b --- /dev/null +++ b/web/public/locales/ro/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "user": "Utilizator", + "password": "Parola", + "login": "Logare", + "errors": { + "passwordRequired": "Parola este necesara", + "rateLimit": "Limita a fost depasita. Reincearca mai tarziu.", + "loginFailed": "Logare esuata", + "webUnknownError": "Eroare necunoscuta. Verifica logurile din consola.", + "usernameRequired": "Utilizatorul este necesar", + "unknownError": "Eroare necunoscuta. Verifica logurile." + } + } +} diff --git a/web/public/locales/ro/components/camera.json b/web/public/locales/ro/components/camera.json new file mode 100644 index 000000000..a3fa10887 --- /dev/null +++ b/web/public/locales/ro/components/camera.json @@ -0,0 +1,43 @@ +{ + "group": { + "label": "Grupuri de Camere", + "add": "Adauga Grup de Camere", + "edit": "Editeaza Grupul de Camere", + "delete": { + "label": "Sterge Grupul de Camere", + "confirm": { + "title": "Confirma Stergerea", + "desc": "Esti sigur ca doresti sa stergi gruoul de camere {{name}}?" + } + }, + "name": { + "label": "Nume", + "placeholder": "Introdu un nume…", + "errorMessage": { + "mustLeastCharacters": "Numele grupului de cmere trebuie sa sontina minim 2 caractere.", + "exists": "Numele grupului de camere exista deja.", + "nameMustNotPeriod": "Numele grupului de camere nu trebuia sa contina punct.", + "invalid": "Nume invalid pentru grupul de camere." + } + }, + "cameras": { + "label": "Camere", + "desc": "Selecteaza camere pentru acest grup." + }, + "icon": "Pictograma", + "success": "Grupul de camere {{name}}) a fost salvat.", + "camera": { + "setting": { + "label": "Setarile de Stream ale Camerei", + "title": "{{cameraName}} Setari de Stream" + } + } + }, + "debug": { + "options": { + "label": "Setari", + "title": "Optiuni", + "showOptions": "Arata Optiuni" + } + } +} diff --git a/web/public/locales/ro/components/dialog.json b/web/public/locales/ro/components/dialog.json new file mode 100644 index 000000000..203cb5424 --- /dev/null +++ b/web/public/locales/ro/components/dialog.json @@ -0,0 +1,40 @@ +{ + "restart": { + "title": "Esti sigur ca doresti sa repornesti Frigate?", + "button": "Reporneste", + "restarting": { + "title": "Frigate Reporneste", + "content": "Aceasta pagina se va reincarca in {{countdown}} secunde.", + "button": "Forteaza Reincarcarea Acum" + } + }, + "explore": { + "plus": { + "review": { + "true": { + "label": "Confirma aceasta eticheta pentru Frigate Plus", + "true_one": "Asta e o {{label}}", + "true_few": "Astea sunt {{label}}", + "true_other": "Astea sunt {{label}}" + }, + "false": { + "label": "Nu confirma aceasta eticheta pentru Frigate Plus", + "false_one": "Asta nu este {{label}}", + "false_few": "Astea nu sunt {{label}}", + "false_other": "Astea nu sunt {{label}}" + }, + "state": { + "submitted": "Trimis" + } + }, + "submitToPlus": { + "label": "Trimite catre Frigate+" + } + } + }, + "recording": { + "button": { + "deleteNow": "Sterge Acum" + } + } +} diff --git a/web/public/locales/ro/components/filter.json b/web/public/locales/ro/components/filter.json new file mode 100644 index 000000000..785575a32 --- /dev/null +++ b/web/public/locales/ro/components/filter.json @@ -0,0 +1,10 @@ +{ + "filter": "Filtru", + "labels": { + "label": "Etichete", + "all": { + "title": "Toate etichetele", + "short": "Etichete" + } + } +} diff --git a/web/public/locales/ro/components/icons.json b/web/public/locales/ro/components/icons.json new file mode 100644 index 000000000..4019c8f66 --- /dev/null +++ b/web/public/locales/ro/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "Selecteaza o pictograma", + "search": { + "placeholder": "Cauta o pictograma…" + } + } +} diff --git a/web/public/locales/ro/components/input.json b/web/public/locales/ro/components/input.json new file mode 100644 index 000000000..8faa6219a --- /dev/null +++ b/web/public/locales/ro/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Descarca Video", + "toast": { + "success": "A inceput descarcarea clipului ce contine articolul revizuit." + } + } + } +} diff --git a/web/public/locales/ro/components/player.json b/web/public/locales/ro/components/player.json new file mode 100644 index 000000000..8a1bea151 --- /dev/null +++ b/web/public/locales/ro/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "Nu au fost gasite inregistrari in perioada de timp mentionata", + "noPreviewFound": "Nu a fost gasita o Previzualizare", + "noPreviewFoundFor": "Nu exista Previzualizari pentru {{cameraName}}", + "submitFrigatePlus": { + "title": "Trimiteti acest cadru catre Frigate+?", + "submit": "Trimite" + }, + "livePlayerRequiredIOSVersion": "iOS 17.1 sau mai recent este necesar pentru acest tip de stream live.", + "streamOffline": { + "title": "Stream Offline", + "desc": "Nici un cadru nu a fost receptionat de la streamul {{cameraName}} detect, verifica logurile de eroare" + }, + "cameraDisabled": "Camera este dezactivata", + "stats": { + "streamType": { + "title": "Tip Stream:", + "short": "Tip" + }, + "bandwidth": { + "title": "Latime de Banda:", + "short": "Latime de Banda" + }, + "latency": { + "title": "Latenta:", + "value": "{{seconds}} secunde", + "short": { + "title": "Latenta", + "value": "{{seconds}} sec" + } + }, + "totalFrames": "Total Cadre:", + "droppedFrames": { + "title": "Cadre Pierdute:", + "short": { + "title": "Pierdut", + "value": "{{droppedFrames}} cadre" + } + }, + "decodedFrames": "Cadre Decodate:", + "droppedFrameRate": "Rata de Cadre Pierdute:" + }, + "toast": { + "error": { + "submitFrigatePlusFailed": "Eraoare trimitere Cadru catre Frigate+" + }, + "success": { + "submittedFrigatePlus": "Cadru trimis cu Succes catre Frigate+" + } + } +} diff --git a/web/public/locales/ro/objects.json b/web/public/locales/ro/objects.json new file mode 100644 index 000000000..b934485d0 --- /dev/null +++ b/web/public/locales/ro/objects.json @@ -0,0 +1,120 @@ +{ + "person": "Persoana", + "bicycle": "Bicicleta", + "car": "Masina", + "airplane": "Avion", + "bus": "Autobuz", + "train": "Tren", + "boat": "Barca", + "fire_hydrant": "Hidrant", + "street_sign": "Semn de Circulatie", + "stop_sign": "Semn de Stop", + "parking_meter": "Automat de Parcare", + "bench": "Bancheta", + "bird": "Pasare", + "cat": "Pisica", + "dog": "Caine", + "horse": "Cal", + "cow": "Vaca", + "elephant": "Elefant", + "bear": "Urs", + "giraffe": "Girafa", + "hat": "Palarie", + "backpack": "Rucsac", + "umbrella": "Umbrela", + "shoe": "Pantof", + "eye_glasses": "Ochelari", + "tie": "Cravata", + "suitcase": "Servieta", + "frisbee": "Frisbee", + "skis": "Schiuri", + "snowboard": "Placa de Snowboard", + "sports_ball": "Minge pentru Sport", + "kite": "Zmeu", + "baseball_bat": "Bata de Baseball", + "baseball_glove": "Manusa de Baseball", + "skateboard": "Skateboard", + "surfboard": "Placa de Surf", + "tennis_racket": "Racheta de Tenis", + "bottle": "Sticla", + "plate": "Placa", + "wine_glass": "Pahar de Vin", + "cup": "Ceasca", + "fork": "Furculita", + "knife": "Cutit", + "spoon": "Lingura", + "bowl": "Castron", + "banana": "Banana", + "apple": "Mar", + "motorcycle": "Motocicleta", + "traffic_light": "Semafor", + "sheep": "Oaie", + "zebra": "Zebra", + "handbag": "Geanta de mana", + "sandwich": "Sandwich", + "gls": "GLS", + "dpd": "DPD", + "sink": "Chiuveta", + "raccoon": "Raton", + "orange": "Portocala", + "laptop": "Laptop", + "fox": "Vulpe", + "animal": "Animal", + "package": "Pachet", + "remote": "Telecomanda", + "toilet": "Toaleta", + "amazon": "Amazon", + "broccoli": "Broccoli", + "carrot": "Morcov", + "hot_dog": "Hot Dog", + "dining_table": "Masa", + "hair_dryer": "Uscator de Par", + "pizza": "Pizza", + "donut": "Gogoasa", + "teddy_bear": "Ursulet de Plus", + "waste_bin": "Tomberon", + "cake": "Tort", + "window": "Fereastra", + "chair": "Scaun", + "door": "Usa", + "on_demand": "La Cerere", + "usps": "USPS", + "couch": "Canapea", + "blender": "Blender", + "scissors": "Foarfeca", + "cell_phone": "Telefon Mobil", + "potted_plant": "Ghiveci de Plante", + "bed": "Pat", + "refrigerator": "Frigider", + "mirror": "Oglinda", + "desk": "Birou", + "tv": "TV", + "ups": "UPS", + "fedex": "FedEx", + "mouse": "Mouse", + "keyboard": "Tastatura", + "microwave": "Microunde", + "oven": "Cuptor", + "rabbit": "Iepure", + "robot_lawnmower": "Robot de Tuns Iarba", + "toaster": "Prajitor de Paine", + "book": "Carte", + "clock": "Ceas", + "vase": "Vaza", + "toothbrush": "Periuta de Dinti", + "hair_brush": "Perie de Par", + "vehicle": "Vehicul", + "squirrel": "Veverita", + "deer": "Caprioara", + "bark": "Latrat", + "goat": "Capra", + "bbq_grill": "Gratar", + "face": "Fata", + "purolator": "Purolator", + "license_plate": "Numar de Inmatriculare", + "dhl": "DHL", + "an_post": "An Post", + "postnl": "PostNL", + "nzpost": "NZPost", + "postnord": "PostNord" +} diff --git a/web/public/locales/ro/views/configEditor.json b/web/public/locales/ro/views/configEditor.json new file mode 100644 index 000000000..45f667989 --- /dev/null +++ b/web/public/locales/ro/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "documentTitle": "Editor Setari - Frigate", + "configEditor": "Editor Setari", + "copyConfig": "Copiaza Setarile", + "saveAndRestart": "Salveaza & Reporneste", + "saveOnly": "Doar Salveaza", + "toast": { + "success": { + "copyToClipboard": "Setari copiate in clipboard." + }, + "error": { + "savingError": "Eroare la salvarea setarilor" + } + } +} diff --git a/web/public/locales/ro/views/events.json b/web/public/locales/ro/views/events.json new file mode 100644 index 000000000..7d41a7d7b --- /dev/null +++ b/web/public/locales/ro/views/events.json @@ -0,0 +1,35 @@ +{ + "alerts": "Alerte", + "motion": { + "label": "Miscare", + "only": "Doar Miscare" + }, + "allCameras": "Toate Camerele", + "empty": { + "alert": "Nu sunt alerte de revizuit", + "detection": "Nu sunt detectii de revizuit", + "motion": "Nu au fost gasite date despre miscare" + }, + "timeline": "Cronologie", + "timeline.aria": "Selecteaza Cronologie", + "events": { + "aria": "Selecteaza Evenimente", + "noFoundForTimePeriod": "Niciun eveniment gasit pentru acest interval de timp.", + "label": "Evenimente" + }, + "documentTitle": "Revizuieste - Frigate", + "recordings": { + "documentTitle": "Inregistrari - frigate" + }, + "calendarFilter": { + "last24Hours": "Ultimele 24 de ore" + }, + "markAsReviewed": "Marcheaza ca Revizuit", + "markTheseItemsAsReviewed": "Marcheaza aceste articole ca revizuite", + "newReviewItems": { + "label": "Vezi articole noi de revizuit", + "button": "Articole Noi de Revizuit" + }, + "camera": "Camera", + "detections": "Detectii" +} diff --git a/web/public/locales/ro/views/explore.json b/web/public/locales/ro/views/explore.json new file mode 100644 index 000000000..e208948f3 --- /dev/null +++ b/web/public/locales/ro/views/explore.json @@ -0,0 +1,20 @@ +{ + "documentTitle": "Exploreaza - Frigate", + "generativeAI": "AI Generativ", + "exploreIsUnavailable": { + "title": "Explorarea este Indisponibila", + "embeddingsReindexing": { + "startingUp": "Porneste…", + "estimatedTime": "Timp ramas estimat:", + "finishingShortly": "Termina curand" + } + }, + "type": { + "details": "detalii" + }, + "objectLifecycle": { + "lifecycleItemDesc": { + "visible": "{{label}} detectata" + } + } +} diff --git a/web/public/locales/ro/views/exports.json b/web/public/locales/ro/views/exports.json new file mode 100644 index 000000000..acc8a9c79 --- /dev/null +++ b/web/public/locales/ro/views/exports.json @@ -0,0 +1,17 @@ +{ + "search": "Cauta", + "documentTitle": "Export - Frigate", + "noExports": "Nu au fost gasite exporturi", + "deleteExport": "Sterge Export", + "deleteExport.desc": "Esti sigur ca vrei sa stergi {{exportName}}?", + "editExport": { + "title": "Redenumeste Exportul", + "saveExport": "Salveaza Export", + "desc": "Introdu un nume nou pentru acest Export." + }, + "toast": { + "error": { + "renameExportFailed": "Eroare redenumire export: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/ro/views/faceLibrary.json b/web/public/locales/ro/views/faceLibrary.json new file mode 100644 index 000000000..9105a4ab0 --- /dev/null +++ b/web/public/locales/ro/views/faceLibrary.json @@ -0,0 +1,9 @@ +{ + "description": { + "addFace": "Parcurge adaugare unei colectii noi la Libraria de Fete.", + "placeholder": "Introduceti un nume pentru aceasta colectie" + }, + "details": { + "person": "Persoana" + } +} diff --git a/web/public/locales/ro/views/live.json b/web/public/locales/ro/views/live.json new file mode 100644 index 000000000..21ffaa8b8 --- /dev/null +++ b/web/public/locales/ro/views/live.json @@ -0,0 +1,5 @@ +{ + "documentTitle": "Live - Frigate", + "documentTitle.withCamera": "{{camera}} - Live - Frigate", + "lowBandwidthMode": "Mod Latime de Banda Limitata" +} diff --git a/web/public/locales/ro/views/recording.json b/web/public/locales/ro/views/recording.json new file mode 100644 index 000000000..1b96b7c42 --- /dev/null +++ b/web/public/locales/ro/views/recording.json @@ -0,0 +1,12 @@ +{ + "filter": "Filtru", + "export": "Exporta", + "calendar": "Calendar", + "filters": "Filtre", + "toast": { + "error": { + "endTimeMustAfterStartTime": "Timpul de sfarsit trebuie sa fie dupa cel de start", + "noValidTimeSelected": "Niciun interval de timp valid nu a fost selectat" + } + } +} diff --git a/web/public/locales/ro/views/search.json b/web/public/locales/ro/views/search.json new file mode 100644 index 000000000..e5131006f --- /dev/null +++ b/web/public/locales/ro/views/search.json @@ -0,0 +1,5 @@ +{ + "search": "Cauta", + "savedSearches": "Cautari Salvate", + "searchFor": "Cauta {{inputValue}}" +} diff --git a/web/public/locales/ro/views/settings.json b/web/public/locales/ro/views/settings.json new file mode 100644 index 000000000..9f9f7d1f5 --- /dev/null +++ b/web/public/locales/ro/views/settings.json @@ -0,0 +1,7 @@ +{ + "documentTitle": { + "authentication": "Setari de Autentificcare - Frigate", + "camera": "Setari Camera - Frigate", + "default": "Setari - Frigate" + } +} diff --git a/web/public/locales/ro/views/system.json b/web/public/locales/ro/views/system.json new file mode 100644 index 000000000..2c1f00c5a --- /dev/null +++ b/web/public/locales/ro/views/system.json @@ -0,0 +1,7 @@ +{ + "documentTitle": { + "storage": "Statistici Stocare - Frigate", + "cameras": "Statistici Camere - Frigate", + "general": "Statistici Generale - Frigate" + } +} diff --git a/web/public/locales/ru/audio.json b/web/public/locales/ru/audio.json new file mode 100644 index 000000000..9f5e58530 --- /dev/null +++ b/web/public/locales/ru/audio.json @@ -0,0 +1,429 @@ +{ + "grunt": "Хрюк", + "babbling": "Бормотание", + "laughter": "Смех", + "choir": "Хор", + "mantra": "Мантра", + "speech": "Речь", + "child_singing": "Детское пение", + "whistling": "Свист", + "breathing": "Дыхание", + "synthetic_singing": "Синтетическое пение", + "rapping": "Рэп", + "yell": "Крик", + "humming": "Гудение", + "groan": "Стон", + "bellow": "Рёв", + "whispering": "Шёпот", + "whoop": "Возглас", + "crying": "Плач", + "yodeling": "Йодль (пение)", + "snicker": "Смешок", + "sigh": "Сигнал", + "singing": "Пение", + "wheeze": "Хрип", + "snoring": "Храп", + "gasp": "Вздох", + "pant": "Пыхтение", + "snort": "Фырканье", + "sniff": "Нюхание", + "burping": "Отрыжка", + "cough": "Кашель", + "run": "Бег", + "throat_clearing": "Прочистка горла", + "sneeze": "Чихание", + "shuffle": "Шаркание", + "chewing": "Жевание", + "biting": "Кусание", + "gargling": "Полоскание горла", + "stomach_rumble": "Урчание живота", + "hiccup": "Икание", + "fart": "Пукание", + "footsteps": "Шаги", + "chant": "Песнопение", + "hands": "Руки", + "finger_snapping": "Щелкать пальцами", + "clapping": "Хлопать", + "moo": "Мычание", + "cowbell": "Коровий колокольчик", + "heart_murmur": "Сердечный шум", + "cheering": "Ликование", + "applause": "Аплодисменты", + "chatter": "Болтовня", + "crowd": "Толпа", + "children_playing": "Игра детей", + "animal": "Животное", + "pets": "Домашние животные", + "dog": "Собака", + "bark": "Лай", + "yip": "Тявканье", + "howl": "Вой", + "whimper_dog": "Собачий скулеж", + "cat": "Кошка", + "purr": "Мурлыканье", + "meow": "Мяуканье", + "hiss": "Шипение", + "growling": "Рычание", + "bow_wow": "Гавканье", + "heartbeat": "Сердцебиение", + "caterwaul": "Кошачий вой", + "horse": "Лошадь", + "clip_clop": "Цоканье", + "neigh": "Ржание", + "livestock": "Скот", + "cattle": "Крупный рогатый скот", + "pig": "Свинья", + "oink": "Хрюканье", + "bleat": "Блеяние", + "sheep": "Овца", + "fowl": "Домашняя птица", + "goat": "Коза", + "chicken": "Курица", + "cluck": "Кудахтанье", + "cock_a_doodle_doo": "Кукареканье", + "turkey": "Индейка", + "gobble": "Бормотание индейки", + "duck": "Утка", + "quack": "Кряканье", + "goose": "Гусь", + "honk": "Гоготание", + "wild_animals": "Дикие животные", + "roaring_cats": "Рычащие кошки", + "roar": "Рык", + "chirp": "Чириканье", + "squawk": "Птичий крик", + "pigeon": "Голубь", + "coo": "Воркование", + "crow": "Ворона", + "caw": "Карканье", + "owl": "Сова", + "hoot": "Уханье", + "flapping_wings": "Хлопание крыльев", + "dogs": "Собаки", + "rats": "Крысы", + "mouse": "Мышь", + "insect": "Насекомое", + "cricket": "Сверчок", + "mosquito": "Комар", + "fly": "Муха", + "buzz": "Жужжание", + "frog": "Лягушка", + "croak": "Кваканье", + "snake": "Змея", + "rattle": "Треск", + "music": "Музыка", + "musical_instrument": "Музыкальный инструмент", + "whale_vocalization": "Пение кита", + "plucked_string_instrument": "Щипковый струнный инструмент", + "guitar": "Гитара", + "patter": "Шорох", + "bass_guitar": "Бас-гитара", + "steel_guitar": "Стальная гитара", + "tapping": "Постукивание", + "car": "Автомобиль", + "motorcycle": "Мотоцикл", + "bicycle": "Велосипед", + "bird": "Птица", + "electric_guitar": "Электрогитара", + "acoustic_guitar": "Акустическая гитара", + "scream": "Крик", + "strum": "Звук струн", + "banjo": "Банджо", + "zither": "Цитра", + "ukulele": "Укулеле", + "keyboard": "Клавиатура", + "electric_piano": "Электропианино", + "organ": "Орган", + "electronic_organ": "Электроорган", + "synthesizer": "Синтезатор", + "hammond_organ": "Орган Хаммонда", + "sampler": "Сэмплер", + "harpsichord": "Клавесин", + "percussion": "Ударные инструменты", + "drum_kit": "Ударная установка", + "drum_machine": "Драммашина", + "drum": "Барабан", + "snare_drum": "Малый барабан", + "rimshot": "Обод барабана", + "drum_roll": "Барабанная дробь", + "bass_drum": "Бас-барабан", + "timpani": "Литавры", + "tabla": "Табла", + "cymbal": "Тарелка", + "hi_hat": "Хай-хэт", + "wood_block": "Вуд-блок", + "tambourine": "Бубен", + "maraca": "Маракас", + "gong": "Гонг", + "tubular_bells": "Трубчатые колокола", + "mallet_percussion": "Маллет-перкуссия", + "marimba": "Маримба", + "glockenspiel": "Колокольчики", + "vibraphone": "Вибрафон", + "steelpan": "Стальной барабан", + "orchestra": "Оркестр", + "brass_instrument": "Медный духовой инструмент", + "french_horn": "Валторна", + "trumpet": "Труба", + "trombone": "Тромбон", + "bowed_string_instrument": "Смычковый струнный инструмент", + "string_section": "Струнная секция", + "mandolin": "Мандолина", + "piano": "Пианино", + "sitar": "Ситар", + "violin": "Скрипка", + "pizzicato": "Пиццикато", + "cello": "Виолончель", + "double_bass": "Контрабас", + "wind_instrument": "Духовой инструмент", + "flute": "Флейта", + "saxophone": "Саксофон", + "clarinet": "Кларнет", + "harp": "Арфа", + "bell": "Колокол", + "church_bell": "Церковный колокол", + "jingle_bell": "Бубенчик", + "bicycle_bell": "Велосипедный звонок", + "tuning_fork": "Камертон", + "chime": "Колокольчик", + "wind_chime": "Музыка ветра", + "harmonica": "Губная гармошка", + "accordion": "Аккордеон", + "bagpipes": "Волынка", + "didgeridoo": "Диджериду", + "theremin": "Терменвокс", + "singing_bowl": "Поющая чаша", + "scratching": "Скрэтчинг", + "pop_music": "Поп-музыка", + "hip_hop_music": "Хип-хоп", + "beatboxing": "Битбоксинг", + "rock_music": "Рок-музыка", + "heavy_metal": "Хеви-метал", + "punk_rock": "Панк-рок", + "grunge": "Гранж", + "progressive_rock": "Прогрессив-рок", + "rock_and_roll": "Рок-н-ролл", + "psychedelic_rock": "Психоделический рок", + "rhythm_and_blues": "Ритм-н-блюз", + "soul_music": "Соул", + "bluegrass": "Блюграсс", + "funk": "Фанк", + "middle_eastern_music": "Ближневосточная музыка", + "jazz": "Джаз", + "disco": "Диско", + "classical_music": "Классическая музыка", + "opera": "Опера", + "house_music": "Хаус", + "techno": "Техно", + "dubstep": "Дабстеп", + "drum_and_bass": "Драм-н-бейс", + "electronica": "Электроника", + "electronic_dance_music": "Электронная танцевальная музыка", + "ambient_music": "Эмбиент", + "music_of_latin_america": "Латиноамериканская музыка", + "salsa_music": "Сальса", + "flamenco": "Фламенко", + "blues": "Блюз", + "music_for_children": "Детская музыка", + "new-age_music": "Нью-эйдж", + "a_capella": "А капелла", + "music_of_africa": "Африканская музыка", + "afrobeat": "Афробит", + "christian_music": "Христианская музыка", + "gospel_music": "Госпел", + "music_of_asia": "Азиатская музыка", + "carnatic_music": "Карнатическая музыка", + "music_of_bollywood": "Музыка Болливуда", + "ska": "Ска", + "traditional_music": "Традиционная музыка", + "independent_music": "Инди", + "song": "Песня", + "background_music": "Фоновая музыка", + "theme_music": "Тематическая музыка", + "jingle": "Джингл", + "soundtrack_music": "Саундтрек", + "lullaby": "Колыбельная", + "video_game_music": "Музыка из видеоигр", + "christmas_music": "Рождественская музыка", + "dance_music": "Танцевальная музыка", + "wedding_music": "Свадебная музыка", + "happy_music": "Весёлая музыка", + "sad_music": "Грустная музыка", + "tender_music": "Нежная музыка", + "exciting_music": "Энергичная музыка", + "angry_music": "Агрессивная музыка", + "scary_music": "Жуткая музыка", + "wind": "Ветер", + "rustling_leaves": "Шуршание листьев", + "wind_noise": "Шум ветра", + "thunderstorm": "Гроза", + "thunder": "Гром", + "water": "Вода", + "rain": "Дождь", + "raindrop": "Капли дождя", + "rain_on_surface": "Дождь на поверхности", + "stream": "Поток", + "waterfall": "Водопад", + "gurgling": "Журчание", + "fire": "Огонь", + "crackle": "Потрескивание", + "vehicle": "Транспорт", + "boat": "Лодка", + "sailboat": "Парусник", + "rowboat": "Вёсельная лодка", + "motorboat": "Моторная лодка", + "ship": "Корабль", + "motor_vehicle": "Моторный транспорт", + "power_windows": "Электростеклоподъемники", + "skidding": "Занос", + "tire_squeal": "Визг шин", + "car_passing_by": "Проезжающая машина", + "race_car": "Гоночный автомобиль", + "truck": "Грузовик", + "air_brake": "Пневматический тормоз", + "air_horn": "Пневматический гудок", + "reversing_beeps": "Сигнал заднего хода", + "ice_cream_truck": "Грузовик с мороженым", + "bus": "Автобус", + "emergency_vehicle": "Транспорт экстренных служб", + "police_car": "Полицейский автомобиль", + "fire_engine": "Пожарная машина", + "rail_transport": "Рельсовый транспорт", + "train": "Поезд", + "train_whistle": "Свисток поезда", + "train_horn": "Гудок поезда", + "railroad_car": "Железнодорожный вагон", + "train_wheels_squealing": "Визг колес поезда", + "subway": "Метро", + "aircraft": "Воздушное судно", + "aircraft_engine": "Двигатель воздушного судна", + "jet_engine": "Реактивный двигатель", + "propeller": "Пропеллер", + "fixed-wing_aircraft": "Самолет с неподвижным крылом", + "skateboard": "Скейтборд", + "engine": "Двигатель", + "light_engine": "Легкий двигатель", + "dental_drill's_drill": "Стоматологическая бормашина", + "medium_engine": "Средний двигатель", + "heavy_engine": "Тяжёлый двигатель", + "engine_knocking": "Детонация двигателя", + "engine_starting": "Запуск двигателя", + "idling": "Холостой ход", + "accelerating": "Ускорение", + "ding-dong": "Дин-дон", + "sliding_door": "Раздвижная дверь", + "slam": "Хлопок", + "knock": "Стук", + "tap": "Небольшой стук", + "squeak": "Скрип", + "cupboard_open_or_close": "Открытие или закрытие шкафа", + "drawer_open_or_close": "Открытие или закрытие ящика", + "dishes": "Тарелки", + "cutlery": "Столовые приборы", + "chopping": "Нарезание", + "frying": "Жарка", + "microwave_oven": "Микроволновка", + "blender": "Блендер", + "water_tap": "Водопроводный кран", + "sink": "Раковина", + "bathtub": "Ванна", + "hair_dryer": "Фен", + "toilet_flush": "Слив унитаза", + "toothbrush": "Зубная щетка", + "zipper": "Молния на одежде", + "keys_jangling": "Бряканье ключей", + "coin": "Монета", + "scissors": "Ножницы", + "electric_shaver": "Электробритва", + "shuffling_cards": "Тасование карт", + "typing": "Печатание", + "typewriter": "Печатная машинка", + "computer_keyboard": "Компьютерная клавиатура", + "writing": "Письмо", + "alarm": "Сигнализация", + "telephone": "Телефон", + "telephone_bell_ringing": "Звонок телефона", + "ringtone": "Рингтон", + "telephone_dialing": "Набор телефонного номера", + "dial_tone": "Телефонный гудок", + "busy_signal": "Сигнал занято", + "alarm_clock": "Будильник", + "siren": "Сирена", + "civil_defense_siren": "Сирена гражданской обороны", + "foghorn": "Туманный горн", + "whistle": "Свисток", + "steam_whistle": "Паровой свисток", + "mechanisms": "Механизмы", + "clock": "Часы", + "tick": "Тик", + "tick-tock": "Тик-так", + "gears": "Шестерни", + "pulleys": "Шкивы", + "sewing_machine": "Швейная машинка", + "mechanical_fan": "Механический вентилятор", + "printer": "Принтер", + "camera": "Камера", + "single-lens_reflex_camera": "Зеркальная камера", + "tools": "Инструменты", + "sawing": "Распиловка", + "filing": "Звук напильника", + "sanding": "Шлифовка", + "power_tool": "Электроинструмент", + "drill": "Дрель", + "explosion": "Взрыв", + "gunshot": "Выстрел", + "machine_gun": "Автомат", + "fusillade": "Оружейная очередь", + "artillery_fire": "Артиллерийский огонь", + "burst": "Очередь выстрелов", + "eruption": "Извержение", + "boom": "Бум", + "wood": "Дерево", + "chop": "Рубка", + "splinter": "Щепка", + "glass": "Стекло", + "crack": "Трещина", + "chink": "Звон", + "shatter": "Разбитие", + "silence": "Тишина", + "sound_effect": "Звуковой эффект", + "environmental_noise": "Шум окружающей среды", + "static": "Статический шум", + "field_recording": "Полевая запись", + "country": "Кантри", + "vocal_music": "Вокальная музыка", + "electronic_music": "Электронная музыка", + "folk_music": "Фолк-музыка", + "trance_music": "Транс", + "swing_music": "Свинг", + "reggae": "Регги", + "waves": "Волны", + "ambulance": "Скорая помощь", + "helicopter": "Вертолет", + "radio": "Радио", + "lawn_mower": "Газонокосилка", + "electric_toothbrush": "Электрическая зубная щетка", + "air_conditioning": "Кондиционер", + "toot": "Гудок", + "traffic_noise": "Дорожный шум", + "ocean": "Океан", + "steam": "Пар", + "car_alarm": "Автомобильная сигнализация", + "buzzer": "Зуммер", + "chainsaw": "Цепная пила", + "door": "Дверь", + "doorbell": "Дверной звонок", + "smoke_detector": "Датчик дыма", + "white_noise": "Белый шум", + "cash_register": "Касса", + "vacuum_cleaner": "Пылесос", + "fire_alarm": "Пожарная сигнализация", + "ratchet": "Трещотка", + "cap_gun": "Игрушечный пистолет", + "fireworks": "Фейерверк", + "jackhammer": "Отбойный молоток", + "pink_noise": "Розовый шум", + "hammer": "Молоток", + "firecracker": "Петарда", + "television": "Телевидение" +} diff --git a/web/public/locales/ru/common.json b/web/public/locales/ru/common.json new file mode 100644 index 000000000..45c497c6d --- /dev/null +++ b/web/public/locales/ru/common.json @@ -0,0 +1,265 @@ +{ + "time": { + "untilForTime": "До {{time}}", + "untilForRestart": "До перезапуска Frigate.", + "untilRestart": "До перезапуска", + "ago": "{{timeAgo}} назад", + "justNow": "Только что", + "today": "Сегодня", + "yesterday": "Вчера", + "thisWeek": "На этой неделе", + "last14": "Последние 14 дней", + "last30": "Последние 30 дней", + "last7": "Последние 7 дней", + "thisMonth": "В этом месяце", + "5minutes": "5 минут", + "30minutes": "30 минут", + "1hour": "1 час", + "12hours": "12 часов", + "24hours": "24 часа", + "pm": "pm", + "am": "am", + "yr": "{{time}}л", + "year_one": "{{time}} год", + "year_few": "{{time}} года", + "year_many": "{{time}} лет", + "mo": "{{time}}мес", + "month_one": "{{time}} месяц", + "month_few": "{{time}} месяца", + "month_many": "{{time}} месяцев", + "d": "{{time}}д", + "h": "{{time}}ч", + "hour_one": "{{time}} час", + "hour_few": "{{time}} часа", + "hour_many": "{{time}} часов", + "m": "{{time}}мин", + "minute_one": "{{time}} минута", + "minute_few": "{{time}} минуты", + "minute_many": "{{time}} минут", + "day_one": "{{time}} день", + "day_few": "{{time}} дня", + "day_many": "{{time}} дней", + "lastWeek": "На прошлой неделе", + "lastMonth": "В прошлом месяце", + "10minutes": "10 минут", + "s": "{{time}}с", + "second_one": "{{time}} секунда", + "second_few": "{{time}} секунды", + "second_many": "{{time}} секунд", + "formattedTimestampExcludeSeconds": { + "24hour": "%b %-d, %H:%M", + "12hour": "%b %-d, %I:%M %p" + }, + "formattedTimestampWithYear": { + "24hour": "%b %-d %Y, %H:%M", + "12hour": "%b %-d %Y, %I:%M %p" + }, + "formattedTimestamp2": { + "24hour": "d MMM HH:mm:ss", + "12hour": "MM/dd h:mm:ssa" + }, + "formattedTimestamp": { + "12hour": "MMM d, h:mm:ss aaa", + "24hour": "MMM d, HH:mm:ss" + }, + "formattedTimestampOnlyMonthAndDay": "%b %-d", + "formattedTimestampHourMinuteSecond": { + "12hour": "h:mm:ss aaa", + "24hour": "HH:mm:ss" + }, + "formattedTimestampFilename": { + "24hour": "MM-dd-yy-HH-mm-ss", + "12hour": "MM-dd-yy-h-mm-ss-a" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "MMM d, h:mm aaa", + "24hour": "MMM d, HH:mm" + }, + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "MMM d yyyy, h:mm aaa", + "24hour": "MMM d yyyy, HH:mm" + }, + "formattedTimestampMonthDay": "MMM d", + "formattedTimestampHourMinute": { + "12hour": "h:mm aaa", + "24hour": "HH:mm" + } + }, + "selectItem": "Выбор {{item}}", + "button": { + "apply": "Применить", + "done": "Готово", + "enabled": "Включено", + "enable": "Включить", + "save": "Сохранить", + "saving": "Сохранение…", + "fullscreen": "Полноэкранный режим", + "pictureInPicture": "Картинка в картинке", + "twoWayTalk": "Двусторонняя связь", + "cameraAudio": "Аудио с камеры", + "on": "Вкл", + "edit": "Редактировать", + "copyCoordinates": "Скопировать координаты", + "delete": "Удалить", + "yes": "Да", + "no": "Нет", + "download": "Загрузить", + "info": "Информация", + "suspended": "Приостановлено", + "cancel": "Отменить", + "disable": "Отключить", + "reset": "Сбросить", + "disabled": "Отключено", + "close": "Закрыть", + "copy": "Скопировать", + "back": "Назад", + "history": "История", + "off": "Выкл", + "exitFullscreen": "Выйти из полноэкранного режима", + "unsuspended": "Возобновить", + "play": "Воспроизвести", + "unselect": "Снять выбор", + "export": "Экспортировать", + "deleteNow": "Удалить сейчас", + "next": "Следующий" + }, + "label": { + "back": "Вернуться" + }, + "unit": { + "speed": { + "kph": "км/ч", + "mph": "миль/ч" + } + }, + "menu": { + "configuration": "Конфигурация", + "systemLogs": "Логи системы", + "settings": "Настройки", + "configurationEditor": "Редактор конфигурации", + "system": "Система", + "systemMetrics": "Метрики системы", + "languages": "Языки", + "language": { + "en": "English (Английский)", + "zhCN": "简体中文 (Упрощённый китайский)", + "es": "Español (Испанский)", + "hi": "हिन्दी (Хинди)", + "fr": "Français (Французский)", + "ar": "العربية (Арабский)", + "pt": "Português (Португальский)", + "ru": "Русский", + "tr": "Türkçe (Турецкий)", + "nl": "Nederlands (Нидерландский)", + "cs": "Čeština (Чешский)", + "nb": "Norsk Bokmål (Норвежский (букмол))", + "vi": "Tiếng Việt (Вьетнамский)", + "fa": "فارسی (Фарси)", + "pl": "Polski (Польский)", + "uk": "Українська (Украинский)", + "el": "Ελληνικά (Греческий)", + "da": "Dansk (Датский)", + "sk": "Slovenčina (Словацкий)", + "sv": "Svenska (Шведский)", + "hu": "Magyar (Венгерский)", + "fi": "Suomi (Финский)", + "ro": "Română (Румынский)", + "ja": "日本語 (Японский)", + "it": "Italiano (Итальянский)", + "de": "Deutsch (Немецкий)", + "ko": "한국어 (Корейский)", + "he": "עברית (Иврит)", + "withSystem": { + "label": "Использовать системные настройки языка" + }, + "yue": "粵語 (Кантонский)" + }, + "darkMode": { + "withSystem": { + "label": "Использовать системные настройки светлой/тёмной темы" + }, + "label": "Тёмный режим", + "light": "Светлый", + "dark": "Тёмный" + }, + "withSystem": "Системный", + "theme": { + "label": "Тема", + "blue": "Синяя", + "default": "По умолчанию", + "green": "Зелёная", + "nord": "Северная", + "red": "Красная", + "contrast": "Высокий контраст", + "highcontrast": "Контрастная" + }, + "help": "Помощь", + "documentation": { + "title": "Документация", + "label": "Документация по Frigate" + }, + "explore": "Поиск событий", + "restart": "Перезапуск Frigate", + "live": { + "title": "Прямой эфир", + "allCameras": "Все камеры", + "cameras": { + "count_one": "{{count}} камера", + "count_few": "{{count}} камеры", + "count_many": "{{count}} камер", + "title": "Камеры" + } + }, + "review": "Обзор событий", + "export": "Экспортировать", + "uiPlayground": "Среда тестирования интерфейсов", + "faceLibrary": "Библиотека лиц", + "user": { + "title": "Пользователь", + "account": "Аккаунт", + "current": "Текущий пользователь: {{user}}", + "anonymous": "anonymous", + "logout": "Выход", + "setPassword": "Установить пароль" + }, + "appearance": "Внешний вид" + }, + "pagination": { + "label": "пагинация", + "previous": { + "title": "Предыдущая", + "label": "Переход на предыдущую страницу" + }, + "next": { + "title": "Следующая", + "label": "Переход на следующую страницу" + }, + "more": "Больше страниц" + }, + "accessDenied": { + "desc": "У вас нет разрешения на просмотр этой страницы.", + "documentTitle": "Доступ запрещён - Frigate", + "title": "Доступ запрещён" + }, + "notFound": { + "desc": "Страница не найдена", + "documentTitle": "Не найдена - Frigate", + "title": "404" + }, + "toast": { + "copyUrlToClipboard": "URL скопирован в буфер обмена.", + "save": { + "error": { + "noMessage": "Не удалось сохранить изменения конфигурации", + "title": "Не удалось сохранить изменения конфигурации: {{errorMessage}}" + }, + "title": "Сохранить" + } + }, + "role": { + "title": "Роль", + "admin": "Администратор", + "viewer": "Наблюдатель", + "desc": "Администраторы имеют полный доступ ко всем функциям в интерфейсе Frigate. Наблюдатели ограничены просмотром камер, элементов просмотра и архивных записей." + } +} diff --git a/web/public/locales/ru/components/auth.json b/web/public/locales/ru/components/auth.json new file mode 100644 index 000000000..b227af835 --- /dev/null +++ b/web/public/locales/ru/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "user": "Имя пользователя", + "password": "Пароль", + "login": "Логин", + "errors": { + "usernameRequired": "Необходимо ввести имя пользователя", + "passwordRequired": "Необходимо ввести пароль", + "rateLimit": "Превышение числа попыток. Попробуй еще раз позже.", + "loginFailed": "Ошибка входа", + "unknownError": "Неизвестная ошибка. Проверьте логи.", + "webUnknownError": "Неизвестная ошибка. Проверьте логи консоли." + } + } +} diff --git a/web/public/locales/ru/components/camera.json b/web/public/locales/ru/components/camera.json new file mode 100644 index 000000000..95f9efe85 --- /dev/null +++ b/web/public/locales/ru/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "label": "Группы камер", + "add": "Добавить группу камер", + "edit": "Редактирование группы камер", + "delete": { + "label": "Удалить группу камер", + "confirm": { + "title": "Подтвердить удаление", + "desc": "Вы уверены, что хотите удалить группу камер {{name}}?" + } + }, + "name": { + "label": "Название", + "placeholder": "Введите название…", + "errorMessage": { + "exists": "Такое название группы камер уже существует.", + "nameMustNotPeriod": "Название группы камер не должно содержать точки.", + "invalid": "Неверное название группы камер.", + "mustLeastCharacters": "Название группы камер должно содержать не менее 2 символов." + } + }, + "cameras": { + "label": "Камеры", + "desc": "Выберите камеры для этой группы." + }, + "icon": "Иконка", + "success": "Группа камер {{name}} сохранена.", + "camera": { + "setting": { + "label": "Настройки видеопотока", + "desc": "Изменение параметров прямой трансляции для панели этой группы камер. Эти настройки зависят от устройства/браузера.", + "audioIsAvailable": "Для этого потока доступен звук", + "audioIsUnavailable": "Для этого потока звук недоступен", + "audio": { + "tips": { + "title": "Аудио должно выводиться с вашей камеры и быть настроено в go2rtc для этого потока.", + "document": "Читать документацию " + } + }, + "streamMethod": { + "label": "Метод стриминга", + "method": { + "noStreaming": { + "label": "Нет потока", + "desc": "Кадры с камеры обновляются раз в минуту, без прямой трансляции." + }, + "smartStreaming": { + "label": "Умный поток (рекомендуется)", + "desc": "Для экономии ресурсов поток обновляется раз в минуту. При обнаружении активности автоматически активируется прямая трансляция." + }, + "continuousStreaming": { + "label": "Непрерывный поток", + "desc": { + "warning": "Непрерывная потоковая передача может привести к высокому потреблению трафика и проблемам с производительностью. Используйте с осторожностью.", + "title": "Когда изображение выводится на панель, оно всегда обновляется в режиме реального времени, вне зависимости от обнаружения активности." + } + } + } + }, + "compatibilityMode": { + "label": "Режим совместимости", + "desc": "Активируйте эту настройку только при появлении цветовых искажений или диагональной полосы с правого края в прямой трансляции." + }, + "title": "Настройки видеопотока {{cameraName}}" + } + } + }, + "debug": { + "options": { + "label": "Настройки", + "title": "Опции", + "hideOptions": "Скрыть опции", + "showOptions": "Показать опции" + }, + "boundingBox": "Ограничивающая рамка", + "timestamp": "Метка времени", + "zones": "Зоны", + "mask": "Маска", + "motion": "Движение", + "regions": "Регионы" + } +} diff --git a/web/public/locales/ru/components/dialog.json b/web/public/locales/ru/components/dialog.json new file mode 100644 index 000000000..768c7977f --- /dev/null +++ b/web/public/locales/ru/components/dialog.json @@ -0,0 +1,122 @@ +{ + "restart": { + "title": "Вы уверены, что хотите перезапустить Frigate?", + "button": "Перезапуск", + "restarting": { + "title": "Frigate перезапускается", + "content": "Эта страница перезагрузится через {{countdown}} сек.", + "button": "Принудительная перезагрузка" + } + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "Отправить в Frigate+", + "desc": "Объекты в местах, которых вы хотите избежать, не являются ложными срабатываниями. Отправка их как ложных срабатываний запутает модель." + }, + "review": { + "true": { + "label": "Подтвердите метку для Frigate Plus", + "true_one": "Это {{label}}", + "true_few": "Это {{label}}", + "true_many": "Это {{label}}" + }, + "false": { + "label": "Не подтверждать эту метку для Frigate Plus", + "false_one": "Это не {{label}}", + "false_few": "Это не {{label}}", + "false_many": "Это не {{label}}" + }, + "state": { + "submitted": "Отправлено" + }, + "question": { + "ask_an": "Это объект — {{label}} ?", + "label": "Подтвердить эту метку для Frigate Plus", + "ask_a": "Это объект — {{label}}?", + "ask_full": "Это объект — {{untranslatedLabel}} ({{translatedLabel}})?" + } + } + }, + "video": { + "viewInHistory": "Посмотреть в истории" + } + }, + "export": { + "time": { + "fromTimeline": "Выбрать на таймлайне", + "custom": "Пользовательский", + "start": { + "title": "Время начала", + "label": "Выберите время начала" + }, + "end": { + "title": "Время окончания", + "label": "Выберите время окончания" + }, + "lastHour_one": "Последний час", + "lastHour_few": "Последние {{count}} часа", + "lastHour_many": "Последние {{count}} часов" + }, + "name": { + "placeholder": "Введите название для экспорта" + }, + "select": "Выбрать", + "export": "Экспорт", + "selectOrExport": "Выбрать или экспортировать", + "toast": { + "success": "Экспорт успешно запущен. Файл доступен в папке /exports.", + "error": { + "failed": "Не удалось запустить экспорт: {{error}}", + "noVaildTimeSelected": "Не выбран допустимый временной диапазон", + "endTimeMustAfterStartTime": "Время окончания должно быть после времени начала" + } + }, + "fromTimeline": { + "saveExport": "Сохранить экспорт", + "previewExport": "Предпросмотр экспорта" + } + }, + "streaming": { + "label": "Поток", + "restreaming": { + "disabled": "Рестриминг не включён для этой камеры.", + "desc": { + "title": "Настройте go2rtc для дополнительных вариантов просмотра в реальном времени и аудио для этой камеры.", + "readTheDocumentation": "Читать документацию" + } + }, + "debugView": "Режим отладки", + "showStats": { + "label": "Отображение статистики потока", + "desc": "Включите эту опцию, чтобы отображать статистику потока в виде наложения на изображение с камеры." + } + }, + "search": { + "saveSearch": { + "label": "Сохранить поиск", + "placeholder": "Введите название для вашего поиска", + "overwrite": "{{searchName}} уже существует. Сохранение перезапишет существующее значение.", + "success": "Поиск {{searchName}} был сохранен.", + "button": { + "save": { + "label": "Сохранить этот поиск" + } + }, + "desc": "Укажите название этого сохранённого поиска." + } + }, + "recording": { + "confirmDelete": { + "title": "Подтвердить удаление", + "desc": { + "selected": "Вы уверены, что хотите удалить все записанное видео, связанное с этим элементом просмотра?

    Удерживайте клавишу Shift, чтобы пропустить это окно в будущем." + } + }, + "button": { + "export": "Экспорт", + "markAsReviewed": "Пометить как просмотренное", + "deleteNow": "Удалить сейчас" + } + } +} diff --git a/web/public/locales/ru/components/filter.json b/web/public/locales/ru/components/filter.json new file mode 100644 index 000000000..e1bc2904f --- /dev/null +++ b/web/public/locales/ru/components/filter.json @@ -0,0 +1,126 @@ +{ + "filter": "Фильтр", + "labels": { + "label": "Метки", + "all": { + "title": "Все метки", + "short": "Метки" + }, + "count": "{{count}} меток", + "count_one": "{{count}} Метка", + "count_other": "{{count}} меток" + }, + "zones": { + "all": { + "title": "Все зоны", + "short": "Зоны" + }, + "label": "Зоны" + }, + "dates": { + "all": { + "title": "Все даты", + "short": "Даты" + } + }, + "timeRange": "Временной диапазон", + "subLabels": { + "label": "Вторичные метки", + "all": "Все вторичные метки" + }, + "score": "Оценка", + "estimatedSpeed": "Расчетная скорость ({{unit}})", + "more": "Больше фильтров", + "reset": { + "label": "Сброс фильтров к значениям по умолчанию" + }, + "features": { + "hasSnapshot": "Есть снимок", + "hasVideoClip": "Есть видеоклип", + "submittedToFrigatePlus": { + "label": "Отправлено в Frigate+", + "tips": "Сначала необходимо отфильтровать отслеживаемые объекты, у которых есть снимок.

    Отслеживаемые объекты без снимка нельзя отправить в Frigate+." + }, + "label": "Функции" + }, + "sort": { + "speedAsc": "Расчетная скорость (по возрастанию)", + "speedDesc": "Расчетная скорость (по убыванию)", + "label": "Сортировка", + "dateAsc": "Дата (по возрастанию)", + "dateDesc": "Дата (по убыванию)", + "scoreAsc": "Оценка объекта (по возрастанию)", + "scoreDesc": "Оценка объекта (по убыванию)", + "relevance": "Релевантность" + }, + "cameras": { + "label": "Фильтр камер", + "all": { + "title": "Все камеры", + "short": "Камеры" + } + }, + "explore": { + "settings": { + "defaultView": { + "unfilteredGrid": "Нефильтрованная сетка", + "summary": "Сводка", + "title": "Вид по умолчанию", + "desc": "При отсутствии выбранных фильтров отображать сводку последних отслеживаемых объектов для каждой метки или показывать нефильтрованную сетку." + }, + "gridColumns": { + "title": "Столбцы сетки", + "desc": "Выберите количество столбцов сетки." + }, + "searchSource": { + "label": "Источник поиска", + "desc": "Выберите, выполнять поиск по миниатюрам или описаниям отслеживаемых объектов.", + "options": { + "thumbnailImage": "Изображение миниатюры", + "description": "Описание" + } + }, + "title": "Настройки" + }, + "date": { + "selectDateBy": { + "label": "Выберите дату для фильтрации" + } + } + }, + "logSettings": { + "filterBySeverity": "Фильтровать логи по уровню важности", + "loading": { + "title": "Загрузка", + "desc": "При прокрутке панели логов в самый низ новые записи автоматически отображаются по мере их добавления." + }, + "label": "Уровень детализации логов", + "allLogs": "Все логи", + "disableLogStreaming": "Отключить потоковую передачу логов" + }, + "trackedObjectDelete": { + "title": "Подтвердить удаление", + "toast": { + "error": "Не удалось удалить отслеживаемые объекты: {{errorMessage}}", + "success": "Отслеживаемые объекты успешно удалены." + }, + "desc": "Удаление этих {{objectLength}} отслеживаемых объектов приведёт к удалению их снимков, сохранённых эмбеддингов и записей жизненного цикла. НО сами записи в разделе «История» останутся.

    Вы уверены, что хотите продолжить?

    Удерживайте Shift, чтобы пропустить это окно в будущем." + }, + "zoneMask": { + "filterBy": "Фильтр по маске зоны" + }, + "recognizedLicensePlates": { + "noLicensePlatesFound": "Номерных знаков не найдено.", + "placeholder": "Введите номер для поиска знака…", + "title": "Распознанные номерные знаки", + "loadFailed": "Не удалось загрузить распознанные номерные знаки.", + "loading": "Загрузка распознанных номерных знаков…", + "selectPlatesFromList": "Выберите один или более знаков из списка." + }, + "review": { + "showReviewed": "Показать просмотренные" + }, + "motion": { + "showMotionOnly": "Показывать только движение" + } +} diff --git a/web/public/locales/ru/components/icons.json b/web/public/locales/ru/components/icons.json new file mode 100644 index 000000000..2d0f3ccd7 --- /dev/null +++ b/web/public/locales/ru/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "Выберите иконку", + "search": { + "placeholder": "Поиск иконки…" + } + } +} diff --git a/web/public/locales/ru/components/input.json b/web/public/locales/ru/components/input.json new file mode 100644 index 000000000..149b56d0a --- /dev/null +++ b/web/public/locales/ru/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Скачать видео", + "toast": { + "success": "Загрузка видео начата." + } + } + } +} diff --git a/web/public/locales/ru/components/player.json b/web/public/locales/ru/components/player.json new file mode 100644 index 000000000..f0a44efcd --- /dev/null +++ b/web/public/locales/ru/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "Не найдено ни одной записи", + "noPreviewFound": "Предпросмотр не найден", + "submitFrigatePlus": { + "title": "Отправить этот кадр в Frigate+?", + "submit": "Отправить" + }, + "noPreviewFoundFor": "Не найдено предпросмотра для {{cameraName}}", + "livePlayerRequiredIOSVersion": "iOS 17.1 или выше требуется для этого типа стрима.", + "streamOffline": { + "title": "Поток оффлайн", + "desc": "С потока detect камеры {{cameraName}} не получено кадров, проверьте логи ошибок" + }, + "cameraDisabled": "Камера отключена", + "stats": { + "streamType": { + "title": "Тип потока:", + "short": "Тип" + }, + "bandwidth": { + "title": "Пропускная способность:", + "short": "Пропускная способность" + }, + "latency": { + "title": "Задержка:", + "value": "{{seconds}} сек", + "short": { + "title": "Задержка", + "value": "{{seconds}} сек" + } + }, + "totalFrames": "Всего кадров:", + "droppedFrames": { + "title": "Пропущено кадров:", + "short": { + "title": "Пропущено", + "value": "{{droppedFrames}} кадров" + } + }, + "decodedFrames": "Декодированные кадры:", + "droppedFrameRate": "Частота пропущенных кадров:" + }, + "toast": { + "error": { + "submitFrigatePlusFailed": "Не удалось отправить кадр в Frigate+" + }, + "success": { + "submittedFrigatePlus": "Кадр успешно загружен в Frigate+" + } + } +} diff --git a/web/public/locales/ru/objects.json b/web/public/locales/ru/objects.json new file mode 100644 index 000000000..c8cdac48d --- /dev/null +++ b/web/public/locales/ru/objects.json @@ -0,0 +1,120 @@ +{ + "dog": "Собака", + "cat": "Кошка", + "animal": "Животное", + "bark": "Лай", + "person": "Человек", + "bicycle": "Велосипед", + "car": "Автомобиль", + "motorcycle": "Мотоцикл", + "bird": "Птица", + "horse": "Лошадь", + "sheep": "Овца", + "mouse": "Мышь", + "goat": "Коза", + "airplane": "Самолет", + "keyboard": "Клавиатура", + "boat": "Лодка", + "bus": "Автобус", + "train": "Поезд", + "skateboard": "Скейтборд", + "door": "Дверь", + "blender": "Блендер", + "sink": "Раковина", + "clock": "Часы", + "vehicle": "Транспорт", + "hair_dryer": "Фен", + "toothbrush": "Зубная щетка", + "scissors": "Ножницы", + "traffic_light": "Светофор", + "fire_hydrant": "Пожарный гидрант", + "street_sign": "Дорожный знак", + "stop_sign": "Знак Стоп", + "parking_meter": "Парковочный счётчик", + "bench": "Скамейка", + "cow": "Корова", + "elephant": "Слон", + "bear": "Медведь", + "zebra": "Зебра", + "giraffe": "Жираф", + "hat": "Шляпа", + "backpack": "Рюкзак", + "umbrella": "Зонтик", + "shoe": "Обувь", + "eye_glasses": "Очки", + "tie": "Галстук", + "suitcase": "Чемодан", + "handbag": "Сумочка", + "frisbee": "Фрисби", + "skis": "Лыжи", + "snowboard": "Сноуборд", + "kite": "Воздушный змей", + "baseball_bat": "Бейсбольная бита", + "baseball_glove": "Бейсбольная перчатка", + "sports_ball": "Спортивный мяч", + "surfboard": "Доска для серфинга", + "tennis_racket": "Теннисная ракетка", + "bottle": "Бутылка", + "plate": "Тарелка", + "wine_glass": "Винный бокал", + "cup": "Чашка", + "fork": "Вилка", + "spoon": "Ложка", + "bowl": "Миска", + "banana": "Банан", + "apple": "Яблоко", + "orange": "Апельсин", + "broccoli": "Брокколи", + "sandwich": "Сэндвич", + "carrot": "Морковь", + "hot_dog": "Хот-дог", + "pizza": "Пицца", + "donut": "Пончик", + "cake": "Торт", + "chair": "Стул", + "couch": "Диван", + "potted_plant": "Комнатное растение", + "bed": "Кровать", + "mirror": "Зеркало", + "dining_table": "Обеденный стол", + "window": "Окно", + "desk": "Стол", + "toilet": "Туалет", + "tv": "Телевизор", + "laptop": "Ноутбук", + "remote": "Пульт дистанционного управления", + "cell_phone": "Мобильный телефон", + "microwave": "Микроволновка", + "oven": "Духовка", + "toaster": "Тостер", + "refrigerator": "Холодильник", + "book": "Книга", + "vase": "Ваза", + "teddy_bear": "Плюшевый мишка", + "hair_brush": "Расчёска", + "squirrel": "Белка", + "deer": "Олень", + "fox": "Лиса", + "rabbit": "Кролик", + "raccoon": "Енот", + "robot_lawnmower": "Роботизированная газонокосилка", + "waste_bin": "Мусорное ведро", + "on_demand": "По требованию", + "face": "Лицо", + "license_plate": "Номерной знак", + "package": "Посылка", + "bbq_grill": "Гриль и барбекю", + "amazon": "Amazon", + "usps": "USPS", + "ups": "UPS", + "fedex": "FedEx", + "dhl": "DHL", + "an_post": "An Post", + "purolator": "Purolator", + "knife": "Нож", + "postnl": "PostNL", + "nzpost": "NZPost", + "postnord": "PostNord", + "gls": "GLS", + "dpd": "DPD" +} diff --git a/web/public/locales/ru/views/configEditor.json b/web/public/locales/ru/views/configEditor.json new file mode 100644 index 000000000..af3d00745 --- /dev/null +++ b/web/public/locales/ru/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "configEditor": "Редактор конфигурации", + "copyConfig": "Скопировать конфигурацию", + "saveAndRestart": "Сохранить и перезапустить", + "saveOnly": "Только сохранить", + "documentTitle": "Редактор конфигурации - Frigate", + "toast": { + "success": { + "copyToClipboard": "Конфигурация скопирована в буфер обмена." + }, + "error": { + "savingError": "Ошибка сохранения конфигурации" + } + } +} diff --git a/web/public/locales/ru/views/events.json b/web/public/locales/ru/views/events.json new file mode 100644 index 000000000..d6c5d6b71 --- /dev/null +++ b/web/public/locales/ru/views/events.json @@ -0,0 +1,38 @@ +{ + "alerts": "Тревоги", + "detections": "Обнаружения", + "motion": { + "label": "Движение", + "only": "Только движение" + }, + "allCameras": "Все камеры", + "camera": "Камера", + "empty": { + "alert": "Отсутствуют тревоги для просмотра", + "detection": "Отсутствуют обнаружения для просмотра", + "motion": "Не найдено данных о движении" + }, + "timeline": "Таймлайн", + "timeline.aria": "Выбор таймлайна", + "events": { + "label": "События", + "aria": "Выбор событий", + "noFoundForTimePeriod": "Для этого периода времени не найдено ни одного события." + }, + "documentTitle": "Обзор событий - Frigate", + "recordings": { + "documentTitle": "Записи - Frigate" + }, + "calendarFilter": { + "last24Hours": "Последние 24 часа" + }, + "markAsReviewed": "Пометить как просмотренное", + "newReviewItems": { + "label": "Посмотреть новые элементы для просмотра", + "button": "Новые элементы для просмотра" + }, + "markTheseItemsAsReviewed": "Пометить эти элементы как просмотренные", + "selected": "{{count}} выбрано", + "selected_one": "{{count}} выбрано", + "selected_other": "{{count}} выбрано" +} diff --git a/web/public/locales/ru/views/explore.json b/web/public/locales/ru/views/explore.json new file mode 100644 index 000000000..1ef96769b --- /dev/null +++ b/web/public/locales/ru/views/explore.json @@ -0,0 +1,202 @@ +{ + "exploreIsUnavailable": { + "embeddingsReindexing": { + "context": "Поиск станет доступен после завершения переиндексации эмбеддингов отслеживаемых объектов.", + "startingUp": "Запуск…", + "estimatedTime": "Оставшееся время:", + "finishingShortly": "Скоро завершится", + "step": { + "descriptionsEmbedded": "Встроенные описания: ", + "trackedObjectsProcessed": "Обработанные отслеживаемые объекты: ", + "thumbnailsEmbedded": "Встроенные миниатюры: " + } + }, + "title": "Поиск событий недоступен", + "downloadingModels": { + "setup": { + "visionModel": "Модель компьютерного зрения", + "visionModelFeatureExtractor": "Экстрактор признаков модели компьютерного зрения", + "textModel": "Текстовая модель", + "textTokenizer": "Текстовый токенизатор" + }, + "tips": { + "context": "Возможно, вы захотите переиндексировать эмбеддинги отслеживаемых объектов после загрузки моделей.", + "documentation": "Читать документацию" + }, + "context": "Frigate загружает необходимые модели эмбеддингов для поддержки функции семантического поиска. Это может занять несколько минут в зависимости от скорости вашего интернет-соединения.", + "error": "Произошла ошибка. Проверьте логи Frigate." + } + }, + "generativeAI": "Генеративный ИИ", + "documentTitle": "Поиск событий - Frigate", + "details": { + "timestamp": "Метка времени", + "item": { + "title": "Детали элемента просмотра", + "desc": "Детали элемента просмотра", + "button": { + "share": "Поделиться этим элементом просмотра", + "viewInExplore": "Смотреть в Поиске событий" + }, + "tips": { + "hasMissingObjects": "Настройте конфигурацию, если хотите, чтобы Frigate сохранял отслеживаемые объекты для следующих меток: {{objects}}", + "mismatch_one": "{{count}} недоступный объект обнаружен и включен в этот элемент просмотра. Эти объекты либо не соответствовали критериям тревоги/детекции, либо уже были удалены.", + "mismatch_few": "{{count}} недоступных объекта обнаружено и включено в этот элемент просмотра. Эти объекты либо не соответствовали критериям тревоги/детекции, либо уже были удалены.", + "mismatch_many": "{{count}} недоступных объектов обнаружено и включено в этот элемент просмотра. Эти объекты либо не соответствовали критериям тревоги/детекции, либо уже были удалены." + }, + "toast": { + "success": { + "updatedSublabel": "Успешно обновлена вторичная метка.", + "updatedLPR": "Номерной знак успешно обновлён.", + "regenerate": "Новое описание запрошено у {{provider}}. В зависимости от скорости работы вашего провайдера, генерация нового описания может занять некоторое время." + }, + "error": { + "updatedSublabelFailed": "Не удалось обновить вторичную метку: {{errorMessage}}", + "updatedLPRFailed": "Не удалось обновить номерной знак: {{errorMessage}}", + "regenerate": "Не удалось запросить новое описание у {{provider}}: {{errorMessage}}" + } + } + }, + "editSubLabel": { + "descNoLabel": "Введите новую вторичную метку для этого отслеживаемого объекта", + "title": "Редактирование вторичной метки", + "desc": "Введите новую вторичную метку для {{label}}" + }, + "topScore": { + "label": "Лучшая оценка", + "info": "Лучшая оценка — это наивысшая медианная оценка для отслеживаемого объекта, поэтому она может отличаться от оценки, показанной на превью в результатах поиска." + }, + "estimatedSpeed": "Расчётная скорость", + "tips": { + "saveDescriptionFailed": "Не удалось обновить описание: {{errorMessage}}", + "descriptionSaved": "Описание успешно сохранено" + }, + "label": "Метка", + "editLPR": { + "title": "Редактирование номерного знака", + "descNoLabel": "Введите новое значение номерного знака для этого отслеживаемого объекта", + "desc": "Введите новое значение номерного знака для {{label}}" + }, + "recognizedLicensePlate": "Распознанный номерной знак", + "objects": "Объекты", + "camera": "Камера", + "zones": "Зоны", + "button": { + "findSimilar": "Найти похожее", + "regenerate": { + "title": "Перегенерировать", + "label": "Перегенерировать описание отслеживаемого объекта" + } + }, + "description": { + "label": "Описание", + "aiTips": "Frigate не будет запрашивать описание у вашего генеративного ИИ-провайдера, пока жизненный цикл отслеживаемого объекта не завершится.", + "placeholder": "Описание отслеживаемого объекта" + }, + "expandRegenerationMenu": "Развернуть меню перегенерации", + "regenerateFromSnapshot": "Перегенерировать из снимка", + "regenerateFromThumbnails": "Перегенерировать из миниатюры", + "snapshotScore": { + "label": "Оценка снимка" + } + }, + "trackedObjectDetails": "Детали отслеживаемого объекта", + "type": { + "details": "детали", + "snapshot": "снимок", + "video": "видео", + "object_lifecycle": "жизненный цикл объекта" + }, + "objectLifecycle": { + "title": "Жизненный цикл объекта", + "noImageFound": "Для этой метки времени изображение не найдено.", + "createObjectMask": "Создать маску объекта", + "adjustAnnotationSettings": "Изменить настройки аннотаций", + "scrollViewTips": "Прокрутите, чтобы просмотреть ключевые моменты жизненного цикла этого объекта.", + "autoTrackingTips": "Позиции ограничивающих рамок будут неточными для камер с автотрекингом.", + "lifecycleItemDesc": { + "visible": "Обнаружен(а) {{label}}", + "entered_zone": "{{label}} зафиксирован(а) в {{zones}}", + "active": "{{label}} активировался(ась)", + "stationary": "{{label}} перестал(а) двигаться", + "attribute": { + "faceOrLicense_plate": "{{attribute}} обнаружен для {{label}}", + "other": "{{label}} распознан(а) как {{attribute}}" + }, + "gone": "{{label}} покинул(а) зону", + "heard": "Обнаружен звук {{label}}", + "external": "Обнаружен(а) {{label}}", + "header": { + "zones": "Зоны", + "ratio": "Соотношение", + "area": "Область" + } + }, + "annotationSettings": { + "title": "Настройки аннотаций", + "showAllZones": { + "title": "Показать все зоны", + "desc": "Всегда показывать зоны на кадрах, где объекты вошли в зону." + }, + "offset": { + "label": "Сдвиг аннотаций", + "desc": "Эти данные поступают из потока детекции вашей камеры, но накладываются на изображения из потока записи. Потоки вряд ли идеально синхронизированы, поэтому ограничивающая рамка и видео могут не совпадать. Для корректировки используйте поле annotation_offset.", + "millisecondsToOffset": "Смещение аннотаций детекции в миллисекундах. По умолчанию: 0", + "documentation": "Читать документацию ", + "tips": "СОВЕТ: Представьте, у вас клип события, где человек идёт слева направо. Если рамка на таймлайне постоянно смещена влево от человека — уменьшите значение. Если рамка опережает движение — увеличьте значение." + } + }, + "carousel": { + "previous": "Предыдущий слайд", + "next": "Следующий слайд" + } + }, + "itemMenu": { + "downloadVideo": { + "label": "Скачать видео", + "aria": "Скачать видео" + }, + "downloadSnapshot": { + "label": "Скачать снимок", + "aria": "Скачать снимок" + }, + "viewObjectLifecycle": { + "label": "Просмотр жизненного цикла объекта", + "aria": "Показать жизненный цикл объекта" + }, + "findSimilar": { + "label": "Найти похожее", + "aria": "Найти похожие отслеживаемые объекты" + }, + "submitToPlus": { + "label": "Отправить в Frigate+", + "aria": "Отправить в Frigate Plus" + }, + "viewInHistory": { + "label": "Посмотреть в Истории", + "aria": "Посмотреть в Истории" + }, + "deleteTrackedObject": { + "label": "Удалить этот отслеживаемый объект" + } + }, + "dialog": { + "confirmDelete": { + "title": "Подтвердить удаление", + "desc": "Удаление этого отслеживаемого объекта приведёт к удалению его снимка, всех сохранённых эмбеддингов и записей жизненного цикла. Сами записи в разделе История НЕ будут удалены.

    Вы уверены, что хотите продолжить?" + } + }, + "noTrackedObjects": "Не найдено отслеживаемых объектов", + "fetchingTrackedObjectsFailed": "При получении списка отслеживаемых объектов произошла ошибка: {{errorMessage}}", + "trackedObjectsCount_one": "{{count}} отслеживаемый объект ", + "trackedObjectsCount_few": "{{count}} отслеживаемых объекта ", + "trackedObjectsCount_many": "{{count}} отслеживаемых объектов ", + "searchResult": { + "deleteTrackedObject": { + "toast": { + "success": "Отслеживаемый объект успешно удалён.", + "error": "Не удалось удалить отслеживаемый объект: {{errorMessage}}" + } + } + } +} diff --git a/web/public/locales/ru/views/exports.json b/web/public/locales/ru/views/exports.json new file mode 100644 index 000000000..f48fb3e71 --- /dev/null +++ b/web/public/locales/ru/views/exports.json @@ -0,0 +1,17 @@ +{ + "documentTitle": "Экспорт - Frigate", + "search": "Поиск", + "noExports": "Не найдено файлов экспорта", + "deleteExport": "Удалить экспорт", + "deleteExport.desc": "Вы уверены, что хотите удалить {{exportName}}?", + "editExport": { + "title": "Переименовать экспорт", + "desc": "Введите новое имя для этого экспорта.", + "saveExport": "Сохранить экспорт" + }, + "toast": { + "error": { + "renameExportFailed": "Не удалось переименовать экспорт: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/ru/views/faceLibrary.json b/web/public/locales/ru/views/faceLibrary.json new file mode 100644 index 000000000..5f2365acf --- /dev/null +++ b/web/public/locales/ru/views/faceLibrary.json @@ -0,0 +1,86 @@ +{ + "details": { + "person": "Человек", + "timestamp": "Метка времени", + "face": "Подробности о лице", + "faceDesc": "Подробности о лице и связанном объекте", + "confidence": "Достоверность" + }, + "documentTitle": "Библиотека лиц - Frigate", + "description": { + "placeholder": "Введите название коллекции", + "addFace": "Пошаговое добавление новой коллекции в Библиотеку лиц." + }, + "createFaceLibrary": { + "desc": "Создание новой коллекции", + "nextSteps": "Для создания надежной базы:
  • Используйте вкладку Обучение, чтобы выбрать изображения и обучить систему для каждого обнаруженного человека.
  • Используйте фронтальные изображения для лучшего результата; избегайте изображений с лицами, снятыми под углом.
  • ", + "title": "Создать коллекцию", + "new": "Создать новое лицо" + }, + "selectFace": "Выбор лица", + "uploadFaceImage": { + "desc": "Загрузите изображение для поиска лиц и связывания с {{pageToggle}}", + "title": "Загрузка изображения с лицом" + }, + "selectItem": "Выбор {{item}}", + "train": { + "aria": "Выбор обучения", + "title": "Обучение" + }, + "toast": { + "success": { + "deletedFace_one": "Успешно удалено {{count}} лицо.", + "deletedFace_few": "Успешно удалено {{count}} лица.", + "deletedFace_many": "Успешно удалено {{count}} лиц.", + "deletedName_one": "{{count}} лицо успешно удалено.", + "deletedName_few": "{{count}} лица успешно удалено.", + "deletedName_many": "{{count}} лиц успешно удалено.", + "uploadedImage": "Изображение успешно загружено.", + "trainedFace": "Лицо успешно запомнено.", + "addFaceLibrary": "{{name}} успешно добавлен(а) в Библиотеку лиц!", + "updatedFaceScore": "Оценка лица успешно обновлена.", + "renamedFace": "Лицо успешно переименовано в {{name}}" + }, + "error": { + "deleteFaceFailed": "Не удалось удалить: {{errorMessage}}", + "uploadingImageFailed": "Не удалось загрузить изображение: {{errorMessage}}", + "trainFailed": "Не удалось запомнить: {{errorMessage}}", + "updateFaceScoreFailed": "Не удалось обновить оценку лица: {{errorMessage}}", + "addFaceLibraryFailed": "Не удалось установить имя для лица: {{errorMessage}}", + "deleteNameFailed": "Не удалось удалить имя: {{errorMessage}}", + "renameFaceFailed": "Не удалось переименовать лицо: {{errorMessage}}" + } + }, + "deleteFaceLibrary": { + "title": "Удалить имя", + "desc": "Вы уверены, что хотите удалить коллекцию «{{name}}»? Это действие безвозвратно удалит все лица в коллекции." + }, + "imageEntry": { + "dropActive": "Перетащите изображение сюда…", + "dropInstructions": "Перетащите изображение сюда или нажмите для выбора", + "maxSize": "Макс. размер: {{size}}Мб", + "validation": { + "selectImage": "Пожалуйста, выберите файл изображения." + } + }, + "readTheDocs": "Читать документацию", + "trainFaceAs": "Запомнить лицо как:", + "button": { + "uploadImage": "Загрузить изображение", + "deleteFaceAttempts": "Удалить попытки распознавания лиц", + "addFace": "Добавить лицо", + "reprocessFace": "Обработать лицо повторно", + "renameFace": "Переименовать лицо", + "deleteFace": "Удалить лицо" + }, + "trainFace": "Запомнить лицо", + "steps": { + "faceName": "Введите имя лица", + "nextSteps": "Следующие шаги", + "uploadFace": "Загрузить изображение лица" + }, + "renameFace": { + "desc": "Введите новое имя для {{name}}", + "title": "Переименовать лицо" + } +} diff --git a/web/public/locales/ru/views/live.json b/web/public/locales/ru/views/live.json new file mode 100644 index 000000000..e7960d58f --- /dev/null +++ b/web/public/locales/ru/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "Прямой эфир - Frigate", + "documentTitle.withCamera": "{{camera}} - Прямой эфир - Frigate", + "lowBandwidthMode": "Экономичный режим", + "twoWayTalk": { + "enable": "Включить двустороннюю связь", + "disable": "Отключить двустороннюю связь" + }, + "cameraAudio": { + "enable": "Включить звук с камеры", + "disable": "Отключить звук с камеры" + }, + "ptz": { + "move": { + "clickMove": { + "label": "Кликните в кадре для центрирования камеры", + "enable": "Включить перемещение по клику", + "disable": "Отключить перемещение по клику" + }, + "left": { + "label": "Переместить PTZ-камеру влево" + }, + "down": { + "label": "Переместить PTZ-камеру вниз" + }, + "up": { + "label": "Переместить PTZ-камеру вверх" + }, + "right": { + "label": "Переместить PTZ-камеру вправо" + } + }, + "zoom": { + "in": { + "label": "Приблизить PTZ-камеру" + }, + "out": { + "label": "Отдалить PTZ-камеру" + } + }, + "frame": { + "center": { + "label": "Кликните в кадре для центрирования PTZ-камеры" + } + }, + "presets": "Предустановки PTZ-камеры" + }, + "camera": { + "enable": "Включить камеру", + "disable": "Отключить камеру" + }, + "muteCameras": { + "enable": "Отключить звук на всех камерах", + "disable": "Включить звук на всех камерах" + }, + "detect": { + "enable": "Включить детекцию", + "disable": "Отключить детекцию" + }, + "recording": { + "enable": "Включить запись", + "disable": "Отключить запись" + }, + "snapshots": { + "enable": "Включить снимки", + "disable": "Отключить снимки" + }, + "audioDetect": { + "enable": "Включить детекцию аудио", + "disable": "Отключить детекцию аудио" + }, + "autotracking": { + "enable": "Включить автотрекинг", + "disable": "Отключить автотрекинг" + }, + "streamStats": { + "enable": "Показать статистику потока", + "disable": "Скрыть статистику потока" + }, + "manualRecording": { + "title": "Запись по требованию", + "tips": "Создать ручное событие на основе настроек хранения записей этой камеры.", + "playInBackground": { + "label": "Воспроизведение в фоне", + "desc": "Включите эту опцию, чтобы продолжать трансляцию при скрытом плеере." + }, + "showStats": { + "label": "Показать статистику", + "desc": "Включите эту опцию, чтобы отображать статистику потока в виде наложения на изображение с камеры." + }, + "debugView": "Режим отладки", + "start": "Запустить запись по запросу", + "started": "Запущена запись по запросу.", + "failedToStart": "Не удалось запустить запись по требованию.", + "recordDisabledTips": "Поскольку запись отключена или ограничена в конфигурации для этой камеры, будет сохранён только снимок.", + "end": "Завершить запись по требованию", + "ended": "Запись по требованию остановлена.", + "failedToEnd": "Не удалось остановить запись по требованию." + }, + "streamingSettings": "Настройки потока", + "suspend": { + "forTime": "Приостановить на: " + }, + "stream": { + "audio": { + "tips": { + "documentation": "Читать документацию ", + "title": "Аудио должно выводиться с вашей камеры и быть настроено в go2rtc для этого потока." + }, + "available": "Для этого потока доступен звук", + "unavailable": "Аудио недоступно для этого потока" + }, + "title": "Поток", + "twoWayTalk": { + "tips": "Ваше устройство должно поддерживать эту функцию, а WebRTC должен быть настроен для двусторонней связи.", + "tips.documentation": "Читать документацию ", + "available": "Двусторонняя связь доступна для этого потока", + "unavailable": "Двусторонняя связь недоступна для этого потока" + }, + "lowBandwidth": { + "tips": "Режим просмотра в реальном времени переведён в экономичный режим из-за буферизации или ошибок потока.", + "resetStream": "Сброс потока" + }, + "playInBackground": { + "label": "Воспроизвести в фоне", + "tips": "Включите эту опцию, чтобы продолжать трансляцию при скрытом плеере." + } + }, + "cameraSettings": { + "title": "Настройки {{camera}}", + "objectDetection": "Обнаружение объектов", + "recording": "Запись", + "audioDetection": "Детекция аудио", + "snapshots": "Снимки", + "autotracking": "Автотрекинг", + "cameraEnabled": "Камера активирована" + }, + "history": { + "label": "Отобразить архивные записи" + }, + "effectiveRetainMode": { + "modes": { + "all": "Все", + "motion": "Движение", + "active_objects": "Активные объекты" + }, + "notAllTips": "Ваша конфигурация хранения записей {{source}} установлена в mode: {{effectiveRetainMode}}, поэтому эта запись по запросу будет сохранять только сегменты с {{effectiveRetainModeName}}." + }, + "editLayout": { + "label": "Редактировать макет", + "group": { + "label": "Редактирование группы камер" + }, + "exitEdit": "Выход из редактирования" + }, + "audio": "Аудио", + "notifications": "Уведомления" +} diff --git a/web/public/locales/ru/views/recording.json b/web/public/locales/ru/views/recording.json new file mode 100644 index 000000000..24d34f580 --- /dev/null +++ b/web/public/locales/ru/views/recording.json @@ -0,0 +1,12 @@ +{ + "filter": "Фильтр", + "export": "Экспорт", + "calendar": "Календарь", + "filters": "Фильтры", + "toast": { + "error": { + "endTimeMustAfterStartTime": "Конечное время должно быть позже начального", + "noValidTimeSelected": "Выбран недопустимый временной диапазон" + } + } +} diff --git a/web/public/locales/ru/views/search.json b/web/public/locales/ru/views/search.json new file mode 100644 index 000000000..efed09673 --- /dev/null +++ b/web/public/locales/ru/views/search.json @@ -0,0 +1,74 @@ +{ + "savedSearches": "Сохраненные поиски", + "button": { + "clear": "Очистить поиск", + "save": "Сохранить поиск", + "delete": "Удалить сохранённый поиск", + "filterActive": "Активные фильтры", + "filterInformation": "Информация о фильтре" + }, + "search": "Поиск", + "searchFor": "Поиск {{inputValue}}", + "trackedObjectId": "ID отслеживаемого объекта", + "filter": { + "label": { + "cameras": "Камеры", + "zones": "Зоны", + "sub_labels": "Вторичные метки", + "search_type": "Тип поиска", + "time_range": "Временной диапазон", + "before": "До", + "after": "После", + "min_score": "Мин. оценка", + "max_score": "Макс. оценка", + "min_speed": "Мин. скорость", + "recognized_license_plate": "Распознанный номерной знак", + "max_speed": "Макс. скорость", + "has_clip": "Есть клип", + "has_snapshot": "Есть снимок", + "labels": "Метки" + }, + "searchType": { + "thumbnail": "Миниатюра", + "description": "Описание" + }, + "toast": { + "error": { + "beforeDateBeLaterAfter": "Дата 'до' должна быть позже, чем дата 'после'.", + "afterDatebeEarlierBefore": "Дата 'после' должна быть раньше, чем дата 'до'.", + "minScoreMustBeLessOrEqualMaxScore": "Значение 'min_score' должно быть меньше или равно значению 'max_score'.", + "maxScoreMustBeGreaterOrEqualMinScore": "Значение 'max_score' должно быть больше или равно значению 'min_score'.", + "minSpeedMustBeLessOrEqualMaxSpeed": "Значение 'min_speed' должно быть меньше или равно значению 'max_speed'.", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "Значение 'max_speed' должно быть больше или равно значению 'min_speed'." + } + }, + "tips": { + "title": "Как использовать текстовые фильтры", + "desc": { + "text": "Фильтры помогают уточнить результаты поиска. Вот как их использовать в поле ввода:", + "step": "
    • Введите название фильтра, затем двоеточие (например, \"камеры:\").
    • Выберите значение из подсказок или введите своё.
    • Используйте несколько фильтров, добавляя их через пробел.
    • Фильтры даты (before:/after:) используют формат {{DateFormat}}.
    • Временной диапазон — в формате {{exampleTime}}.
    • Удаляйте фильтры нажатием на «×» рядом с ними.
    ", + "example": "Пример: cameras:front_door label:person before:01012024 time_range:3:00PM-4:00PM ", + "step1": "Введите имя ключа фильтра с двоеточием (например, \"камеры:\").", + "step5": "Фильтр временного диапазона использует формат {{exampleTime}}.", + "exampleLabel": "Пример:", + "step2": "Выберите значение из предложенных или введите свое собственное.", + "step3": "Вы можете применять несколько фильтров, указывая их подряд через пробел.", + "step6": "Удаляйте фильтры, нажав на значок \"x\" рядом с ними.", + "step4": "Фильтры по дате (до: и после:) используют формат {{DateFormat}}." + } + }, + "header": { + "currentFilterType": "Значения фильтров", + "noFilters": "Фильтры", + "activeFilters": "Активные фильтры" + } + }, + "similaritySearch": { + "title": "Поиск похожего", + "active": "Активен поиск похожего", + "clear": "Очистить поиск похожего" + }, + "placeholder": { + "search": "Поиск…" + } +} diff --git a/web/public/locales/ru/views/settings.json b/web/public/locales/ru/views/settings.json new file mode 100644 index 000000000..3c24dfa0d --- /dev/null +++ b/web/public/locales/ru/views/settings.json @@ -0,0 +1,600 @@ +{ + "documentTitle": { + "default": "Настройки - Frigate", + "camera": "Настройки камеры - Frigate", + "masksAndZones": "Маски и Зоны - Frigate", + "motionTuner": "Детекции движения - Frigate", + "general": "Общие настройки - Frigate", + "frigatePlus": "Настройки Frigate+ - Frigate", + "authentication": "Настройки аутентификации - Frigate", + "classification": "Настройки распознавания - Frigate", + "object": "Отладка - Frigate", + "notifications": "Настройки уведомлений - Frigate" + }, + "menu": { + "cameras": "Настройки камеры", + "masksAndZones": "Маски / Зоны", + "motionTuner": "Детекции движения", + "debug": "Отладка", + "users": "Пользователи", + "notifications": "Уведомления", + "frigateplus": "Frigate+", + "ui": "Интерфейс", + "classification": "Распознавание" + }, + "dialog": { + "unsavedChanges": { + "title": "У вас есть несохраненные изменения.", + "desc": "Хотите сохранить изменения перед продолжением?" + } + }, + "cameraSetting": { + "camera": "Камера", + "noCamera": "Нет камеры" + }, + "general": { + "title": "Общие настройки", + "liveDashboard": { + "title": "Панель мониторинга", + "automaticLiveView": { + "desc": "Автоматически переключаться на просмотр камеры в реальном времени при обнаружении активности. Если отключить эту опцию, статичные изображения камер на панели мониторинга будут обновляться только раз в минуту.", + "label": "Автоматический просмотр в реальном времени" + }, + "playAlertVideos": { + "label": "Воспроизводить видео с тревогами", + "desc": "По умолчанию последние тревоги на панели мониторинга воспроизводятся как короткие зацикленные видео. Отключите эту опцию, чтобы показывать только статичное изображение последних оповещений на этом устройстве/браузере." + } + }, + "calendar": { + "title": "Календарь", + "firstWeekday": { + "sunday": "Воскресенье", + "monday": "Понедельник", + "label": "Первый день недели", + "desc": "День, с которого начинаются недели в календаре обзора событий." + } + }, + "recordingsViewer": { + "title": "Просмотр записей", + "defaultPlaybackRate": { + "label": "Скорость воспроизведения по умолчанию", + "desc": "Скорость воспроизведения записей по умолчанию." + } + }, + "storedLayouts": { + "clearAll": "Сбросить все макеты", + "desc": "Расположение камер в группе можно настраивать перетаскиванием и изменением размера. Позиции сохраняются в локальном хранилище браузера.", + "title": "Сохранённые макеты" + }, + "cameraGroupStreaming": { + "title": "Настройки трансляции группы камер", + "desc": "Настройки трансляции для каждой группы камер хранятся локально в вашем браузере.", + "clearAll": "Очистить все настройки трансляции" + }, + "toast": { + "success": { + "clearStoredLayout": "Сохранённый макет для {{cameraName}} удалён", + "clearStreamingSettings": "Настройки потоков для всех групп камер сброшены." + }, + "error": { + "clearStoredLayoutFailed": "Не удалось удалить макет: {{errorMessage}}", + "clearStreamingSettingsFailed": "Не удалось очистить настройки потока: {{errorMessage}}" + } + } + }, + "classification": { + "semanticSearch": { + "title": "Семантический поиск", + "readTheDocumentation": "Читать документацию", + "reindexNow": { + "label": "Переиндексировать сейчас", + "confirmButton": "Переиндексировать", + "alreadyInProgress": "Переиндексация уже выполняется.", + "desc": "Переиндексация заново сгенерирует векторные представления для всех отслеживаемых объектов. Этот процесс выполняется в фоновом режиме и может максимально загрузить ваш процессор, а также занять значительное время в зависимости от количества отслеживаемых объектов.", + "confirmTitle": "Подтвердить переиндексацию", + "success": "Реиндексация запущена успешно.", + "error": "Не удалось начать реиндексацию: {{errorMessage}}", + "confirmDesc": "Вы уверены, что хотите переиндексировать все векторные представления отслеживаемых объектов? Этот процесс будет выполняться в фоновом режиме, но может максимально загрузить ваш процессор и занять довольно много времени. Вы можете следить за ходом выполнения на странице «Поиск событий»." + }, + "desc": "Семантический поиск во Frigate позволяет находить отслеживаемые объекты в записях с помощью самого изображения, пользовательского текстового описания или автоматически сгенерированного описания.", + "modelSize": { + "label": "Размер модели", + "desc": "Размер модели, используемой для эмбеддингов семантического поиска.", + "small": { + "title": "малый", + "desc": "Использование малой модели задействует квантованную версию модели, которая потребляет меньше оперативной памяти и работает быстрее на CPU с очень незначительной разницей в качестве эмбеддингов." + }, + "large": { + "title": "большой", + "desc": "Использование большой модели задействует полную модель Jina и автоматически запускается на GPU, если это возможно." + } + } + }, + "faceRecognition": { + "desc": "Функция распознавания лиц позволяет присваивать людям имена, и когда их лицо будет распознано, Frigate присвоит имя человека в качестве дополнительной метки. Эта информация содержится в пользовательском интерфейсе, фильтрах, а также в уведомлениях.", + "title": "Распознавание лиц", + "readTheDocumentation": "Читать документацию", + "modelSize": { + "label": "Размер модели", + "desc": "Размер модели, используемой для распознавания лиц.", + "small": { + "title": "малый", + "desc": "Использование малой модели задействует модель FaceNet для эмбеддингов лиц, которая эффективно работает на большинстве CPU." + }, + "large": { + "title": "большой", + "desc": "При выборе большой модели используется модель векторизации лиц ArcFace, которая автоматически задействует GPU (если он доступен)." + } + } + }, + "licensePlateRecognition": { + "title": "Распознавание номерных знаков", + "readTheDocumentation": "Читать документацию", + "desc": "Frigate способен распознавать автомобильные номера и автоматически добавлять обнаруженные символы в поле recognized_license_plate или известное имя в качестве sub_label для объектов типа 'car'. Типичный пример использования — чтение номеров автомобилей, заезжающих на подъездную дорожку или проезжающих по улице." + }, + "toast": { + "success": "Настройки классификации сохранены. Перезапустите Frigate, чтобы применить внесенные изменения.", + "error": "Не удалось сохранить изменения конфигурации: {{errorMessage}}" + }, + "title": "Настройки классификации", + "birdClassification": { + "title": "Классификация птиц", + "desc": "Классификация птиц определяет известные виды с помощью квантованной модели TensorFlow. При распознавании птицы её общепринятое название добавляется как sub_label. Эти данные отображаются в интерфейсе, фильтрах и уведомлениях." + }, + "restart_required": "Требуется перезапуск (изменены настройки классификации)" + }, + "users": { + "dialog": { + "passwordSetting": { + "updatePassword": "Обновить пароль для {{username}}", + "setPassword": "Установить пароль", + "desc": "Создайте надежный пароль для защиты аккаунта." + }, + "deleteUser": { + "warn": "Вы уверены, что хотите удалить пользователя {{username}}?", + "title": "Удалить пользователя", + "desc": "Это действие необратимо. Учётная запись пользователя и все связанные с ней данные будут удалены без возможности восстановления." + }, + "changeRole": { + "title": "Изменить роль пользователя", + "desc": "Обновить права доступа для {{username}}", + "roleInfo": { + "intro": "Выберите подходящую роль для этого пользователя:", + "viewer": "Наблюдатель", + "viewerDesc": "Доступны только панель мониторинга, обзор событий, поиск и экспорт данных.", + "admin": "Администратор", + "adminDesc": "Полный доступ ко всем функциям." + } + }, + "form": { + "user": { + "placeholder": "Введите имя пользователя", + "desc": "Допустимо использовать только буквы, цифры, точки и подчёркивания.", + "title": "Имя пользователя" + }, + "password": { + "title": "Пароль", + "placeholder": "Введите пароль", + "confirm": { + "title": "Подтвердите пароль", + "placeholder": "Подтвердите пароль" + }, + "strength": { + "title": "Сложность пароля: ", + "weak": "Слабый", + "medium": "Средний", + "strong": "Сложный", + "veryStrong": "Очень сложный" + }, + "match": "Пароли совпадают", + "notMatch": "Пароли не совпадают" + }, + "newPassword": { + "title": "Новый пароль", + "confirm": { + "placeholder": "Повторно введите новый пароль" + }, + "placeholder": "Введите новый пароль" + }, + "usernameIsRequired": "Необходимо ввести имя пользователя" + }, + "createUser": { + "title": "Создать нового пользователя", + "usernameOnlyInclude": "Имя пользователя может включать только буквы, цифры, . или _", + "desc": "Добавить новую учетную запись пользователя и определить роль для доступа к разделам интерфейса Frigate." + } + }, + "title": "Пользователи", + "toast": { + "success": { + "roleUpdated": "Обновлена роль для {{user}}", + "createUser": "Пользователь {{user}} успешно создан", + "deleteUser": "Пользователь {{user}} успешно удалён", + "updatePassword": "Пароль успешно обновлён." + }, + "error": { + "setPasswordFailed": "Не удалось сохранить пароль: {{errorMessage}}", + "createUserFailed": "Не удалось создать пользователя: {{errorMessage}}", + "deleteUserFailed": "Не удалось удалить пользователя: {{errorMessage}}", + "roleUpdateFailed": "Не удалось обновить роль: {{errorMessage}}" + } + }, + "table": { + "username": "Имя пользователя", + "actions": "Действия", + "password": "Пароль", + "noUsers": "Пользователей не найдено.", + "changeRole": "Изменить роль пользователя", + "role": "Роль", + "deleteUser": "Удалить пользователя" + }, + "management": { + "title": "Управление пользователями", + "desc": "Управление учетными записями пользователей Frigate." + }, + "updatePassword": "Обновить пароль", + "addUser": "Добавить пользователя" + }, + "notification": { + "title": "Уведомления", + "notificationSettings": { + "documentation": "Читать документацию", + "title": "Настройки уведомлений", + "desc": "Frigate может отправлять push-уведомления на ваше устройство, когда приложение открыто в браузере или установлено как PWA." + }, + "notificationUnavailable": { + "documentation": "Читать документацию", + "title": "Уведомления недоступны", + "desc": "Веб-уведомления требуют защищённого контекста (https://…). Это ограничение браузера. Получите безопасный доступ к Frigate, чтобы использовать уведомления." + }, + "email": { + "title": "Email", + "desc": "Для уведомлений о проблемах с push-сервисом требуется указать действующий адрес электронной почты.", + "placeholder": "например, example@email.com" + }, + "globalSettings": { + "title": "Глобальные настройки", + "desc": "Временно приостановить уведомления для определённых камер на всех зарегистрированных устройствах." + }, + "cameras": { + "title": "Камеры", + "noCameras": "Нет доступных камер", + "desc": "Выберите камеры для активации уведомлений." + }, + "deviceSpecific": "Настройки для конкретного устройства", + "registerDevice": "Зарегистрировать это устройство", + "unregisterDevice": "Отменить регистрацию этого устройства", + "suspended": "Уведомления приостановлены {{time}}", + "sendTestNotification": "Отправить тестовое уведомление", + "active": "Уведомления активны", + "suspendTime": { + "30minutes": "Приостановить на 30 минут", + "1hour": "Приостановить на 1 час", + "12hours": "Приостановить на 12 часов", + "24hours": "Приостановить на 24 часа", + "untilRestart": "Приостановить до перезапуска", + "5minutes": "Приостановить на 5 минут", + "10minutes": "Приостановить на 10 минут", + "suspend": "Приостановить" + }, + "toast": { + "success": { + "settingSaved": "Настройки уведомлений сохранены.", + "registered": "Регистрация для уведомлений успешно завершена. Перезапуск Frigate необходим перед отправкой любых уведомлений (включая тестовое уведомление)." + }, + "error": { + "registerFailed": "Не удалось сохранить регистрацию уведомлений." + } + }, + "cancelSuspension": "Отменить приостановку" + }, + "camera": { + "review": { + "alerts": "Тревоги ", + "desc": "Включить или отключить тревоги и обнаружения для этой камеры. В отключенном состоянии новые события не будут записываться.", + "detections": "Обнаружения ", + "title": "Обзор событий" + }, + "reviewClassification": { + "objectAlertsTips": "Все объекты {{alertsLabels}} на камере {{cameraName}} будут отображаться как тревоги.", + "desc": "Frigate разделяет записи для проверки на два типа как «Тревоги» и «Обнаружения». По умолчанию все объекты person и car считаются Тревогами. Вы можете уточнить эту классификацию, настроив для них требуемые зоны.", + "selectAlertsZones": "Выберите зоны для тревог", + "zoneObjectDetectionsTips": { + "notSelectDetections": "Все объекты {{detectionsLabels}}, обнаруженные в {{zone}} на камере {{cameraName}}, которые не отнесены к тревогам, будут отображаться как обнаружения, независимо от того, в какой зоне они находятся.", + "text": "Все объекты {{detectionsLabels}}, не отнесённые к категории в {{zone}} на камере {{cameraName}}, будут отображаться как обнаружения.", + "regardlessOfZoneObjectDetectionsTips": "Все объекты {{detectionsLabels}}, не отнесённые к категории на камере {{cameraName}}, будут отображаться как обнаружения, независимо от того, в какой зоне они находятся." + }, + "zoneObjectAlertsTips": "Все объекты {{alertsLabels}}, обнаруженные в {{zone}} на камере {{cameraName}}, будут отображаться как тревоги.", + "selectDetectionsZones": "Выберите зоны для обнаружения", + "noDefinedZones": "Для этой камеры не определено ни одной зоны.", + "objectDetectionsTips": "Все объекты {{detectionsLabels}}, не отнесённые к категории на камере {{cameraName}}, будут отображаться как обнаружения, независимо от того, в какой зоне они находятся.", + "title": "Классификация событий", + "readTheDocumentation": "Читать документацию", + "limitDetections": "Ограничение обнаружения отдельными зонами", + "toast": { + "success": "Конфигурация классификации событий была сохранена. Перезапустите Frigate для применения изменений." + } + }, + "title": "Настройки камеры", + "streams": { + "title": "Потоки", + "desc": "Отключение камеры полностью останавливает обработку Frigate потоков с этой камеры. Обнаружение, запись и отладка будут недоступны.
    Примечание: Это не отключает рестриминг go2rtc." + } + }, + "masksAndZones": { + "zones": { + "objects": { + "title": "Объекты", + "desc": "Список объектов, применяемых к этой зоне." + }, + "speedEstimation": { + "desc": "Включить оценку скорости объектов в этой зоне. Зона должна состоять ровно из 4 точек.", + "title": "Расчёт скорости" + }, + "label": "Зоны", + "documentTitle": "Редактирование зоны - Frigate", + "desc": { + "title": "Зоны позволяют определить конкретную область кадра, чтобы можно было определить, находится ли объект в заданной области.", + "documentation": "Документация" + }, + "add": "Добавить зону", + "edit": "Редактировать зону", + "point_one": "{{count}} точка", + "point_few": "{{count}} точки", + "point_many": "{{count}} точек", + "clickDrawPolygon": "Кликните, чтобы нарисовать полигон на изображении.", + "name": { + "title": "Название", + "inputPlaceHolder": "Введите название…", + "tips": "Название должно содержать не менее 2 символов и не совпадать с названием камеры или другой зоны." + }, + "inertia": { + "title": "Инерция", + "desc": "Указывает, сколько кадров объект должен находиться в зоне, прежде чем он будет считаться находящимся в ней. Значение по умолчанию: 3" + }, + "loiteringTime": { + "title": "Время присутствия", + "desc": "Устанавливает минимальное время в секундах, которое объект должен находиться в зоне для её активации. Значение по умолчанию: 0" + }, + "allObjects": "Все объекты", + "speedThreshold": { + "title": "Предел скорости ({{unit}})", + "toast": { + "error": { + "loiteringTimeError": "Зоны с установленным временем присутствия более 0 не должны использоваться для вычисления скорости.", + "pointLengthError": "Расчёт скорости отключён для этой зоны. Зоны с расчётом скорости должны содержать ровно 4 точки." + } + }, + "desc": "Задаёт минимальную скорость объектов для учёта в этой зоне." + }, + "toast": { + "success": "Зона ({{zoneName}}) сохранена. Перезапустите Frigate для применения изменений." + } + }, + "motionMasks": { + "desc": { + "documentation": "Документация", + "title": "Маски движения используются, чтобы предотвратить срабатывание обнаружений на нежелательные типы движения. Чрезмерная маскировка усложняет отслеживание объектов." + }, + "add": "Новая маска движения", + "edit": "Редактировать маску движения", + "context": { + "documentation": "Читать документацию", + "title": "Маски движения используются, чтобы предотвратить срабатывание обнаружений на нежелательные типы движения (например, ветки деревьев, метки времени на камере). При этом маски движения нужно использовать очень умеренно: чрезмерное применение масок затруднит отслеживание объектов." + }, + "clickDrawPolygon": "Нажмите, чтобы нарисовать полигон на изображении.", + "polygonAreaTooLarge": { + "documentation": "Читать документацию", + "title": "Маска движения покрывает {{polygonArea}}% кадра. Большие маски движения не рекомендуются.", + "tips": "Маски движения не предотвращают обнаружение объектов. Вместо этого следует использовать обязательную зону." + }, + "point_one": "{{count}} точка", + "point_few": "{{count}} точки", + "point_many": "{{count}} точек", + "label": "Маска движения", + "documentTitle": "Редактирование маски движения - Frigate", + "toast": { + "success": { + "title": "{{polygonName}} сохранена. Перезапустите Frigate для применения изменений.", + "noName": "Маска движения сохранена. Перезапустите Frigate для применения изменений." + } + } + }, + "filter": { + "all": "Все маски и зоны" + }, + "form": { + "zoneName": { + "error": { + "mustBeAtLeastTwoCharacters": "Имя зоны должно содержать не менее 2 символов.", + "mustNotBeSameWithCamera": "Имя зоны не должно совпадать с именем камеры.", + "hasIllegalCharacter": "Имя зоны содержит недопустимые символы.", + "alreadyExists": "Зона с таким именем уже существует для этой камеры.", + "mustNotContainPeriod": "Имя зоны не должно содержать точки." + } + }, + "distance": { + "error": { + "text": "Расстояние должно быть больше или равно 0.1.", + "mustBeFilled": "Все поля расстояния должны быть заполнены для расчёта скорости." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "Инерция должна быть больше 0." + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "Время присутствия должно быть больше или равно 0." + } + }, + "polygonDrawing": { + "removeLastPoint": "Удалить последнюю точку", + "error": { + "mustBeFinished": "Рисование полигона должно быть завершено перед сохранением." + }, + "delete": { + "success": "{{name}} удалён.", + "title": "Подтвердить удаление", + "desc": "Вы уверены, что хотите удалить {{type}} {{name}}?" + }, + "snapPoints": { + "false": "Не привязывать к точкам", + "true": "Привязать точки" + }, + "reset": { + "label": "Удалить все точки" + } + } + }, + "toast": { + "error": { + "copyCoordinatesFailed": "Не удалось скопировать координаты в буфер обмена." + }, + "success": { + "copyCoordinates": "Координаты {{polyName}} скопированы в буфер обмена." + } + }, + "objectMasks": { + "label": "Маски объектов", + "desc": { + "documentation": "Документация", + "title": "Маски фильтра объектов используются для исключения ложных срабатываний определённого типа объектов в зависимости от местоположения." + }, + "documentTitle": "Редактирование маски объектов - Frigate", + "add": "Добавить маску объектов", + "clickDrawPolygon": "Кликните, чтобы нарисовать полигон на изображении.", + "edit": "Редактирование маски объектов", + "context": "Маски фильтра объектов используются для исключения ложных срабатываний определённого типа объектов в зависимости от местоположения.", + "point_one": "{{count}} точка", + "point_few": "{{count}} точки", + "point_many": "{{count}} точек", + "objects": { + "allObjectTypes": "Все типы объектов", + "title": "Объекты", + "desc": "Тип объекта, к которому применяется эта маска." + }, + "toast": { + "success": { + "title": "{{polygonName}} сохранена. Перезапустите Frigate для применения изменений.", + "noName": "Маска объектов сохранена. Перезапустите Frigate для применения изменений." + } + } + }, + "restart_required": "Требуется перезапуск (изменены маски/зоны)" + }, + "motionDetectionTuner": { + "desc": { + "documentation": "Читать руководство по настройке детекции движения", + "title": "Frigate использует детекцию движения как первичную проверку, чтобы определить, есть ли в кадре что-то, что стоит анализировать с помощью детекции объектов." + }, + "title": "Настройка детекции движения", + "contourArea": { + "title": "Площадь контура", + "desc": "Параметр площади контура определяет, какие группы изменённых пикселей считаются движением. По умолчанию: 10" + }, + "improveContrast": { + "title": "Улучшить контрастность", + "desc": "Улучшение контрастности в тёмных сценах. По умолчанию: ВКЛ" + }, + "Threshold": { + "title": "Порог", + "desc": "Пороговое значение определяет, насколько должна измениться яркость пикселя, чтобы считаться движением. По умолчанию: 30" + }, + "toast": { + "success": "Настройки движения сохранены." + } + }, + "debug": { + "objectShapeFilterDrawing": { + "document": "Читать документацию ", + "title": "Отрисовка фильтра формы объекта", + "desc": "Отображает прямоугольник на изображении, чтобы видеть данные о площади и соотношении сторон", + "tips": "Включите эту опцию, чтобы нарисовать прямоугольник на изображении с камеры для отображения его площади и соотношения сторон. Эти значения можно затем использовать для настройки параметров фильтра формы объектов в вашем конфигурационном файле.", + "area": "Площадь", + "ratio": "Соотношение", + "score": "Оценка" + }, + "detectorDesc": "Frigate использует ваши детекторы ({{detectors}}) для обнаружения объектов в видеопотоке с камер.", + "desc": "Режим отладки отображает отслеживаемые объекты и их статистику в реальном времени. Список объектов показывает отложенную по времени сводку обнаруженных объектов.", + "debugging": "Отладка", + "title": "Отладка", + "boundingBoxes": { + "colors": { + "label": "Цвета ограничивающих рамок объектов", + "info": "
  • При запуске каждой метке объекта назначается уникальный цвет
  • Тонкая синяя линия: объект в данный момент не обнаружен
  • Тонкая серая линия: объект помечен как статичный
  • Толстая линия: объект под автотрекингом (если включено)
  • " + }, + "title": "Ограничивающие рамки", + "desc": "Показывать ограничивающие рамки вокруг отслеживаемых объектов" + }, + "objectList": "Список объектов", + "noObjects": "Нет объектов", + "timestamp": { + "title": "Метка времени", + "desc": "Наложить временную метку на изображение" + }, + "zones": { + "title": "Зоны", + "desc": "Показать контур всех определённых зон" + }, + "mask": { + "title": "Маски движения", + "desc": "Показать полигоны маски движения" + }, + "motion": { + "title": "Области движения", + "desc": "Показать рамки вокруг областей, в которых определяется движение", + "tips": "

    Области движения


    Красные рамки будут наложены на участки кадра, где в данный момент обнаружено движение

    " + }, + "regions": { + "title": "Регионы", + "desc": "Показать рамку области интереса, отправленной детектору объектов", + "tips": "

    Рамки областей интереса


    Ярко-зелёные рамки будут наложены на области интереса в кадре, которые отправляются детектору объектов.

    " + } + }, + "frigatePlus": { + "snapshotConfig": { + "documentation": "Прочитать документацию", + "title": "Настройки снимков", + "cleanCopyWarning": "У некоторых камер включены снимки (snapshots), но отключена опция чистой копии (clean copy). Чтобы иметь возможность отправлять изображения с этих камер в Frigate+, необходимо включить параметр clean_copy в конфигурации снимков.", + "table": { + "cleanCopySnapshots": "Снимки clean_copy", + "camera": "Камера", + "snapshots": "Снимки" + }, + "desc": "Отправка в Frigate+ требует, чтобы в вашей конфигурации были включены как снимки (snapshots), так и снимки clean_copy." + }, + "title": "Настройки Frigate+", + "apiKey": { + "title": "Ключ API Frigate+", + "validated": "Ключ API Frigate+ найден и проверен", + "notValidated": "Ключ API Frigate+ не найден или не проверен", + "desc": "Ключ API Frigate+ включает интеграцию с сервисом Frigate+.", + "plusLink": "Подробнее про Frigate+" + }, + "modelInfo": { + "title": "Информация о модели", + "modelType": "Тип модели", + "trainDate": "Дата обучения", + "error": "Не удалось загрузить информацию о модели", + "availableModels": "Доступные модели", + "loadingAvailableModels": "Загрузка доступных моделей…", + "modelSelect": "Здесь можно выбрать ваши доступные модели на Frigate+. Обратите внимание, что могут быть выбраны только модели, совместимые с текущей конфигурацией детектора.", + "baseModel": "Базовая модель", + "supportedDetectors": "Поддерживаемые детекторы", + "dimensions": "Размеры", + "loading": "Загрузка информации о модели…", + "cameras": "Камеры", + "plusModelType": { + "baseModel": "Базовая модель", + "userModel": "Дообученная" + } + }, + "toast": { + "success": "Настройки Frigate+ были сохранены. Перезапустите Frigate, чтобы применить изменения.", + "error": "Не удалось сохранить изменения конфигурации: {{errorMessage}}" + }, + "restart_required": "Требуется перезапуск (изменена модель Frigate+)" + } +} diff --git a/web/public/locales/ru/views/system.json b/web/public/locales/ru/views/system.json new file mode 100644 index 000000000..328cd6536 --- /dev/null +++ b/web/public/locales/ru/views/system.json @@ -0,0 +1,179 @@ +{ + "documentTitle": { + "cameras": "Статистика камер - Frigate", + "storage": "Статистика хранилища - Frigate", + "general": "Общая статистика - Frigate", + "enrichments": "Статистика улучшений - Frigate", + "logs": { + "frigate": "Логи Frigate - Frigate", + "go2rtc": "Логи Go2RTC - Frigate", + "nginx": "Логи Nginx - Frigate" + } + }, + "title": "Система", + "metrics": "Показатели системы", + "logs": { + "download": { + "label": "Загрузить логи" + }, + "copy": { + "label": "Копировать в буфер", + "success": "Логи скопированы в буфер", + "error": "Не удалось скопировать логи в буфер обмена" + }, + "type": { + "label": "Тип", + "timestamp": "Метка времени", + "tag": "Тег", + "message": "Сообщение" + }, + "tips": "Логи передаются с сервера в потоковом режиме", + "toast": { + "error": { + "fetchingLogsFailed": "Ошибка получения логов: {{errorMessage}}", + "whileStreamingLogs": "Ошибка при потоковой передаче логов: {{errorMessage}}" + } + } + }, + "general": { + "title": "Общие", + "detector": { + "title": "Детекторы", + "inferenceSpeed": "Скорость вывода детектора", + "cpuUsage": "Использование CPU детектором", + "memoryUsage": "Использование памяти детектором", + "temperature": "Температура детектора" + }, + "hardwareInfo": { + "title": "Информация об оборудовании", + "gpuUsage": "Использование GPU", + "gpuMemory": "Память GPU", + "gpuEncoder": "GPU-кодировщик", + "gpuDecoder": "GPU-декодер", + "gpuInfo": { + "vainfoOutput": { + "title": "Вывод Vainfo", + "returnCode": "Код возврата: {{code}}", + "processOutput": "Вывод процесса:", + "processError": "Ошибка процесса:" + }, + "nvidiaSMIOutput": { + "title": "Вывод Nvidia SMI", + "name": "Название: {{name}}", + "driver": "Драйвер: {{driver}}", + "cudaComputerCapability": "Вычислительная способность CUDA: {{cuda_compute}}", + "vbios": "Информация VBios: {{vbios}}" + }, + "closeInfo": { + "label": "Закрыть информацию GPU" + }, + "copyInfo": { + "label": "Скопировать информацию о GPU" + }, + "toast": { + "success": "Информация о GPU скопирована в буфер обмена" + } + }, + "npuMemory": "Память NPU", + "npuUsage": "Использование NPU" + }, + "otherProcesses": { + "title": "Другие процессы", + "processCpuUsage": "Использование CPU процессом", + "processMemoryUsage": "Использование памяти процессом" + } + }, + "storage": { + "title": "Хранилище", + "overview": "Обзор", + "recordings": { + "title": "Записи", + "tips": "Это значение показывает, сколько места в хранилище занимают записи из базы данных Frigate. Frigate не учитывает другие файлы на диске.", + "earliestRecording": "Первая запись:" + }, + "cameraStorage": { + "title": "Хранилище камеры", + "camera": "Камера", + "unusedStorageInformation": "Информация о неиспользованном хранилище", + "storageUsed": "Хранилище", + "percentageOfTotalUsed": "Доля (%)", + "bandwidth": "Пропускная способность", + "unused": { + "title": "Не используется", + "tips": "Это значение может неточно отражать свободное место, доступное Frigate, если на вашем диске есть другие файлы помимо записей Frigate. Frigate не отслеживает использование хранилища за пределами своих записей." + } + } + }, + "cameras": { + "title": "Камеры", + "overview": "Обзор", + "info": { + "cameraProbeInfo": "Информация о проверке камеры {{camera}}", + "streamDataFromFFPROBE": "Данные о потоке получены от ffprobe.", + "fetching": "Получение данных камеры", + "stream": "Поток {{idx}}", + "video": "Видео:", + "codec": "Кодек:", + "resolution": "Разрешение:", + "fps": "FPS:", + "unknown": "Неизвестно", + "audio": "Аудио:", + "error": "Ошибка: {{error}}", + "tips": { + "title": "Информация о тестировании камеры" + } + }, + "framesAndDetections": "Кадры/детекции", + "label": { + "ffmpeg": "FFmpeg", + "camera": "камера", + "capture": "захват", + "skipped": "пропущено", + "detect": "детекция", + "cameraDetectionsPerSecond": "{{camName}} обнаружений в секунду", + "cameraSkippedDetectionsPerSecond": "{{camName}} пропущенных обнаружений в секунду", + "cameraFramesPerSecond": "{{camName}} кадров в секунду", + "overallFramesPerSecond": "общее количество кадров в секунду", + "overallDetectionsPerSecond": "общее количество обнаружений в секунду", + "overallSkippedDetectionsPerSecond": "общее количество пропущенных обнаружений в секунду", + "cameraFfmpeg": "{{camName}} FFmpeg", + "cameraCapture": "{{camName}} захват", + "cameraDetect": "{{camName}} обнаружения" + }, + "toast": { + "success": { + "copyToClipboard": "Данные тестирования скопированы в буфер обмена." + }, + "error": { + "unableToProbeCamera": "Не удалось протестировать камеру: {{errorMessage}}" + } + } + }, + "lastRefreshed": "Обновлено: ", + "stats": { + "ffmpegHighCpuUsage": "Камера {{camera}} использует чрезмерно много ресурсов CPU в FFmpeg ({{ffmpegAvg}}%)", + "detectHighCpuUsage": "Камера {{camera}} использует слишком много ресурсов CPU для детекции ({{detectAvg}}%)", + "healthy": "Система в порядке", + "reindexingEmbeddings": "Переиндексация эмбеддингов (выполнено {{processed}} %)", + "cameraIsOffline": "{{camera}} отключена", + "detectIsVerySlow": "{{detect}} идёт очень медленно ({{speed}} мс)", + "detectIsSlow": "{{detect}} идёт медленно ({{speed}} мс)" + }, + "enrichments": { + "title": "Обогащение данных", + "infPerSecond": "Выводов в секунду", + "embeddings": { + "image_embedding_speed": "Скорость векторизации изображений", + "plate_recognition_speed": "Скорость распознавания номеров", + "text_embedding_speed": "Скорость векторизации текста", + "face_embedding_speed": "Скорость векторизации лиц", + "face_recognition_speed": "Скорость распознавания лиц", + "text_embedding": "Векторизация текста", + "yolov9_plate_detection_speed": "Скорость обнаружения номеров YOLOv9", + "yolov9_plate_detection": "Обнаружение номеров YOLOv9", + "face_recognition": "Распознавание лиц", + "plate_recognition": "Распознавание номеров", + "image_embedding": "Векторизация изображений" + } + } +} diff --git a/web/public/locales/sl/audio.json b/web/public/locales/sl/audio.json new file mode 100644 index 000000000..e9f6fb7b6 --- /dev/null +++ b/web/public/locales/sl/audio.json @@ -0,0 +1,36 @@ +{ + "speech": "Govor", + "babbling": "Blebetanje", + "yell": "Kričanje", + "whispering": "Šepetanje", + "laughter": "Smejanje", + "crying": "Jokanje", + "sigh": "Vzdih", + "singing": "Petje", + "yodeling": "Jodlanje", + "rapping": "Rapanje", + "run": "Tek", + "whistling": "Žvižganje", + "breathing": "Dihanje", + "snoring": "Smrčanje", + "cough": "Kašelj", + "animal": "Žival", + "pets": "Ljubljenčki", + "dog": "Pes", + "cat": "Maček", + "meow": "Mijav", + "horse": "Konj", + "moo": "Mu", + "cowbell": "Kravji zvonec", + "pig": "Pujs", + "goat": "Koza", + "sheep": "Ovca", + "chicken": "Kokoš", + "turkey": "Puran", + "duck": "Raca", + "goose": "Gos", + "bird": "Ptič", + "radio": "Radio", + "television": "Televizija", + "footsteps": "Stopinje" +} diff --git a/web/public/locales/sl/common.json b/web/public/locales/sl/common.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/common.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/components/auth.json b/web/public/locales/sl/components/auth.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/components/auth.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/components/camera.json b/web/public/locales/sl/components/camera.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/components/camera.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/components/dialog.json b/web/public/locales/sl/components/dialog.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/components/dialog.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/components/filter.json b/web/public/locales/sl/components/filter.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/components/filter.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/components/icons.json b/web/public/locales/sl/components/icons.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/components/icons.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/components/input.json b/web/public/locales/sl/components/input.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/components/input.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/components/player.json b/web/public/locales/sl/components/player.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/components/player.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/objects.json b/web/public/locales/sl/objects.json new file mode 100644 index 000000000..4d8668eff --- /dev/null +++ b/web/public/locales/sl/objects.json @@ -0,0 +1,9 @@ +{ + "cat": "Maček", + "sheep": "Ovca", + "bird": "Ptič", + "animal": "Žival", + "goat": "Koza", + "horse": "Konj", + "dog": "Pes" +} diff --git a/web/public/locales/sl/views/configEditor.json b/web/public/locales/sl/views/configEditor.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/views/configEditor.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/views/events.json b/web/public/locales/sl/views/events.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/views/events.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/views/explore.json b/web/public/locales/sl/views/explore.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/views/explore.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/views/exports.json b/web/public/locales/sl/views/exports.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/views/exports.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/views/faceLibrary.json b/web/public/locales/sl/views/faceLibrary.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/views/faceLibrary.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/views/live.json b/web/public/locales/sl/views/live.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/views/live.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/views/recording.json b/web/public/locales/sl/views/recording.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/views/recording.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/views/search.json b/web/public/locales/sl/views/search.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/views/search.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/views/settings.json b/web/public/locales/sl/views/settings.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/views/settings.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sl/views/system.json b/web/public/locales/sl/views/system.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/sl/views/system.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/sv/audio.json b/web/public/locales/sv/audio.json new file mode 100644 index 000000000..3e1b88b8f --- /dev/null +++ b/web/public/locales/sv/audio.json @@ -0,0 +1,146 @@ +{ + "yell": "Skrik", + "bicycle": "Cykel", + "speech": "Tal", + "car": "Bil", + "bellow": "Under", + "motorcycle": "Motorcykel", + "whispering": "Viskning", + "bus": "Buss", + "babbling": "Babblande", + "whoop": "Skrika", + "camera": "Kamera", + "laughter": "Skratt", + "snicker": "Fnittra", + "crying": "Gråt", + "choir": "Kör", + "singing": "Sjunger", + "yodeling": "Joddling", + "chant": "Sång", + "mantra": "Mantra", + "synthetic_singing": "Syntetisk sång", + "rapping": "Rappar", + "groan": "Stöna", + "grunt": "Grymta", + "whistling": "Visslar", + "breathing": "Andas", + "snoring": "Snarkning", + "gasp": "Flämtning", + "pant": "Flämta", + "cough": "Hosta", + "throat_clearing": "Halsrensning", + "sneeze": "Nysa", + "run": "Spring", + "shuffle": "Blanda", + "footsteps": "Fotsteg", + "chewing": "Tugga", + "biting": "Biter", + "gargling": "Gurgling", + "stomach_rumble": "Magljud", + "burping": "Rapning", + "hiccup": "Hicka", + "fart": "Fis", + "hands": "Händer", + "finger_snapping": "Knäppning med fingrar", + "clapping": "Klappar", + "heartbeat": "Hjärtslag", + "heart_murmur": "Blåsljud i hjärtat", + "cheering": "Glädjande", + "applause": "Applåder", + "chatter": "Prat", + "crowd": "Folkmassa", + "animal": "Djur", + "yip": "Japp", + "howl": "Tjut", + "bow_wow": "Bow Wow", + "growling": "Morrande", + "whimper_dog": "Hund gnäll", + "cat": "Katt", + "meow": "Mjau", + "hiss": "Väsa", + "caterwaul": "Kattgräl", + "livestock": "Boskap", + "horse": "Häst", + "clip_clop": "Klipp Clop", + "neigh": "Gnägga", + "cattle": "Boskap", + "oink": "Oink", + "goat": "Get", + "bleat": "Bräka", + "fowl": "Fjäderfä", + "cluck": "Kluck", + "cock_a_doodle_doo": "kukilikuk", + "turkey": "kalkon", + "gobble": "Gobble", + "duck": "Anka", + "quack": "Quack", + "goose": "Gås", + "honk": "Tuta", + "wild_animals": "Vilda djur", + "roaring_cats": "Rytande katter", + "roar": "Rytande", + "bird": "Fågel", + "chirp": "Kvittra", + "squawk": "Skriande", + "pigeon": "Duva", + "caw": "Kraxa", + "owl": "Uggla", + "hoot": "Tuta", + "dogs": "Hundar", + "rats": "Råttor", + "mouse": "Älg", + "music": "Musik", + "sigh": "Suck", + "child_singing": "Barnsång", + "sheep": "Får", + "wheeze": "Väsande", + "dog": "Hund", + "sniff": "Sniffa", + "humming": "Hummar", + "pets": "Husdjur", + "coo": "Kuttra", + "snort": "Fnysa", + "children_playing": "Barn som leker", + "bark": "Skall", + "purr": "Spinna", + "moo": "Muu", + "cowbell": "Koskälla", + "pig": "Gris", + "chicken": "Kyckling", + "crow": "Kråka", + "frog": "Groda", + "patter": "Droppar", + "insect": "Insekt", + "cricket": "Syrsa", + "fly": "Fluga", + "buzz": "Surr", + "croak": "Kvack", + "rattle": "Skallra", + "musical_instrument": "Musikinstrument", + "plucked_string_instrument": "Stränginstrument", + "guitar": "Gitarr", + "electric_guitar": "Elektrisk Gitarr", + "bass_guitar": "Basgitarr", + "steel_guitar": "Stålgitarr", + "tapping": "Knackning", + "snake": "Orm", + "acoustic_guitar": "Aukustisk gitarr", + "mosquito": "Mygga", + "flapping_wings": "Vingslag", + "whale_vocalization": "Val-ljud", + "bass_drum": "Bastrumma", + "timpani": "Pukor", + "tabla": "Tabla", + "hi_hat": "Hi-Hat", + "wood_block": "Träblock", + "tambourine": "Tamburin", + "maraca": "Maracas", + "drum_roll": "Trumvirvel", + "rimshot": "Kantslag", + "snare_drum": "Virveltrumma", + "cymbal": "Cymbal", + "mandolin": "Mandolin", + "boat": "Båt", + "train": "Tåg", + "bowed_string_instrument": "stråkinstrument" +} diff --git a/web/public/locales/sv/common.json b/web/public/locales/sv/common.json new file mode 100644 index 000000000..f68414929 --- /dev/null +++ b/web/public/locales/sv/common.json @@ -0,0 +1,36 @@ +{ + "time": { + "untilForTime": "Till {{time}}", + "untilForRestart": "Tills Frigate startar om.", + "untilRestart": "Tills omstart", + "ago": "{{timeAgo}} sedan", + "justNow": "Just nu", + "today": "Idag", + "yesterday": "Igår", + "last14": "Senaste 14 dagarna", + "thisMonth": "Denna månad", + "lastMonth": "Förra månaden", + "30minutes": "30 minuter", + "1hour": "1 timma", + "12hours": "12 timmar", + "pm": "pm", + "am": "am", + "yr": "{{time}}år", + "mo": "{{time}} mån", + "month_one": "{{time}} månad", + "month_other": "{{time}} månader", + "d": "{{time}}dag", + "last7": "Senaste 7 dagarna", + "5minutes": "5 minuter", + "last30": "Senaste 30 dagarna", + "thisWeek": "Denna vecka", + "lastWeek": "Förra veckan", + "10minutes": "10 minuter", + "24hours": "24 timmar", + "year_one": "{{time}} år", + "year_other": "{{time}} år" + }, + "button": { + "save": "Spara" + } +} diff --git a/web/public/locales/sv/components/auth.json b/web/public/locales/sv/components/auth.json new file mode 100644 index 000000000..8581ffe94 --- /dev/null +++ b/web/public/locales/sv/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "password": "Lösenord", + "user": "Användarnamn", + "login": "Logga in", + "errors": { + "usernameRequired": "Användarnamn är obligatoriskt", + "passwordRequired": "Lösenord är obligatoriskt", + "loginFailed": "Inloggning misslyckades", + "unknownError": "Okänt fel. Kontrollera loggarna.", + "webUnknownError": "Okänt fel. Kontrollera konsol loggarna.", + "rateLimit": "Överskriden anropsgräns. Försök igen senare." + } + } +} diff --git a/web/public/locales/sv/components/camera.json b/web/public/locales/sv/components/camera.json new file mode 100644 index 000000000..55e195e84 --- /dev/null +++ b/web/public/locales/sv/components/camera.json @@ -0,0 +1,13 @@ +{ + "group": { + "label": "Kameragrupper", + "add": "Lägg till Kameragrupp", + "edit": "Ändra Kameragrupp", + "delete": { + "label": "Radera kameragrupp", + "confirm": { + "title": "Bekräfta borttagning" + } + } + } +} diff --git a/web/public/locales/sv/components/dialog.json b/web/public/locales/sv/components/dialog.json new file mode 100644 index 000000000..8e5db043d --- /dev/null +++ b/web/public/locales/sv/components/dialog.json @@ -0,0 +1,18 @@ +{ + "restart": { + "button": "Starta om", + "restarting": { + "title": "Frigate startar om", + "content": "Sidan uppdateras om {{countdown}} seconds.", + "button": "Tvinga uppdatering nu" + }, + "title": "Är du säker på att du vill starta om Frigate?" + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "Skicka till Frigate+" + } + } + } +} diff --git a/web/public/locales/sv/components/filter.json b/web/public/locales/sv/components/filter.json new file mode 100644 index 000000000..da7cd7fe4 --- /dev/null +++ b/web/public/locales/sv/components/filter.json @@ -0,0 +1,71 @@ +{ + "labels": { + "all": { + "title": "Alla Etiketter", + "short": "Etiketter" + }, + "label": "Etiketter", + "count": "{{count}} Etiketter" + }, + "filter": "Filter", + "zones": { + "label": "Zoner", + "all": { + "title": "Alla zoner" + } + }, + "features": { + "hasSnapshot": "Har ögonblicksbild" + }, + "sort": { + "dateAsc": "Datum (Stigande)", + "label": "Sortera", + "scoreAsc": "Objektpoäng (Stigande)", + "speedDesc": "Uppskattad Hastighet (Fallande)", + "relevance": "Relevans", + "dateDesc": "Datum (Fallande)", + "scoreDesc": "Objektpoäng (Fallande)", + "speedAsc": "Uppskattad Hastighet (Stigande)" + }, + "cameras": { + "all": { + "short": "Kameror", + "title": "Alla Kameror" + }, + "label": "Kamerafilter" + }, + "explore": { + "settings": { + "title": "Inställningar", + "defaultView": { + "title": "Standard Vy" + }, + "searchSource": { + "options": { + "description": "Beskrivning" + } + } + }, + "date": { + "selectDateBy": { + "label": "Välj datum att filtrera efter" + } + } + }, + "review": { + "showReviewed": "Visa Kontrollerade" + }, + "motion": { + "showMotionOnly": "Visa Endast Rörelse" + }, + "score": "Poäng", + "dates": { + "all": { + "short": "Datum" + } + }, + "recognizedLicensePlates": { + "noLicensePlatesFound": "Inga registreringsplåtar hittade.", + "selectPlatesFromList": "Välj en eller flera registreringsplåtar från listan." + } +} diff --git a/web/public/locales/sv/components/icons.json b/web/public/locales/sv/components/icons.json new file mode 100644 index 000000000..e15428582 --- /dev/null +++ b/web/public/locales/sv/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "search": { + "placeholder": "Sök efter ikon…" + }, + "selectIcon": "Välj en ikon" + } +} diff --git a/web/public/locales/sv/components/input.json b/web/public/locales/sv/components/input.json new file mode 100644 index 000000000..b3081bd54 --- /dev/null +++ b/web/public/locales/sv/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Ladda ner Video", + "toast": { + "success": "Din video laddas ner." + } + } + } +} diff --git a/web/public/locales/sv/components/player.json b/web/public/locales/sv/components/player.json new file mode 100644 index 000000000..59a46ad74 --- /dev/null +++ b/web/public/locales/sv/components/player.json @@ -0,0 +1,29 @@ +{ + "noPreviewFound": "Ingen Förhandsvisning Hittad", + "noRecordingsFoundForThisTime": "Inga inspelningar hittade för denna tid", + "noPreviewFoundFor": "Ingen förhandsvisning hittad för {{cameraName}}", + "submitFrigatePlus": { + "title": "Skicka denna bild till Frigate+?", + "submit": "Skicka" + }, + "livePlayerRequiredIOSVersion": "iOS 17.1 eller senare krävs för den här typen av livestream.", + "streamOffline": { + "title": "Ström ej tillgänglig" + }, + "stats": { + "streamType": { + "short": "Typ" + }, + "bandwidth": { + "title": "Bandbredd:", + "short": "Bandbredd" + }, + "latency": { + "title": "Latens:", + "short": { + "title": "Latens" + } + } + }, + "cameraDisabled": "Kameran är disablead" +} diff --git a/web/public/locales/sv/objects.json b/web/public/locales/sv/objects.json new file mode 100644 index 000000000..130d0f828 --- /dev/null +++ b/web/public/locales/sv/objects.json @@ -0,0 +1,47 @@ +{ + "car": "Bil", + "person": "Person", + "bicycle": "Cykel", + "motorcycle": "Motorcykel", + "airplane": "Flygplan", + "bus": "Buss", + "horse": "Häst", + "sheep": "Får", + "mouse": "Älg", + "bark": "Skall", + "goat": "Get", + "animal": "Djur", + "dog": "Hund", + "cat": "Katt", + "bird": "Fågel", + "train": "Tåg", + "traffic_light": "Trafiklyse", + "stop_sign": "Stoppskylt", + "cow": "Ko", + "elephant": "Elefant", + "bear": "Björn", + "hat": "Hatt", + "boat": "Båt", + "street_sign": "Gatuskylt", + "shoe": "Sko", + "giraffe": "Giraff", + "fire_hydrant": "Brandpost", + "zebra": "Zebra", + "backpack": "Ryggsäck", + "umbrella": "Paraply", + "bench": "Bänk", + "wine_glass": "vinglas", + "bottle": "Flaska", + "spoon": "Sked", + "orange": "Apelsin", + "carrot": "Morot", + "hot_dog": "Varmkorv", + "broccoli": "Broccoli", + "fork": "Gaffel", + "banana": "Banan", + "apple": "Äpple", + "knife": "Kniv", + "bowl": "Skål", + "cup": "Kopp", + "sandwich": "Smörgås" +} diff --git a/web/public/locales/sv/views/configEditor.json b/web/public/locales/sv/views/configEditor.json new file mode 100644 index 000000000..8d86a9a49 --- /dev/null +++ b/web/public/locales/sv/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "copyConfig": "Kopiera konfiguration", + "saveAndRestart": "Spara & Starta om", + "saveOnly": "Spara", + "toast": { + "success": { + "copyToClipboard": "Konfiguration kopierad till urklipp." + }, + "error": { + "savingError": "Problem att spara konfiguration" + } + }, + "documentTitle": "Ändra konfiguration - Frigate", + "configEditor": "Ändra konfiguration" +} diff --git a/web/public/locales/sv/views/events.json b/web/public/locales/sv/views/events.json new file mode 100644 index 000000000..1e33fd3fc --- /dev/null +++ b/web/public/locales/sv/views/events.json @@ -0,0 +1,35 @@ +{ + "detections": "Detektioner", + "alerts": "Varningar", + "motion": { + "label": "Rörelse", + "only": "Endast rörelse" + }, + "allCameras": "Alla kameror", + "empty": { + "alert": "Det finns inga varningar att granska", + "detection": "Det finns inga detekteringar att granska", + "motion": "Ingen rörelsedata hittad" + }, + "documentTitle": "Granska - Frigate", + "timeline": "Tidslinje", + "events": { + "noFoundForTimePeriod": "Inga hädelser hittade för denna tidsperiod.", + "aria": "Välj händelse", + "label": "Händelse" + }, + "recordings": { + "documentTitle": "Inspelningar - Frigate" + }, + "newReviewItems": { + "label": "Visa nya objekt att granska", + "button": "Nya objekt att granska" + }, + "markAsReviewed": "Markera som granskad", + "calendarFilter": { + "last24Hours": "Senaste 24 timmarna" + }, + "timeline.aria": "Välj tidslinje", + "camera": "Kamera", + "markTheseItemsAsReviewed": "Markera dessa objekt som granskade" +} diff --git a/web/public/locales/sv/views/explore.json b/web/public/locales/sv/views/explore.json new file mode 100644 index 000000000..32a06c179 --- /dev/null +++ b/web/public/locales/sv/views/explore.json @@ -0,0 +1,15 @@ +{ + "generativeAI": "Generativ AI", + "documentTitle": "Utforska - Frigate", + "exploreIsUnavailable": { + "embeddingsReindexing": { + "startingUp": "Startar upp…", + "estimatedTime": "Beräknad återstående tid:", + "finishingShortly": "Snart klar" + }, + "title": "Utforska är inte tillgänglig" + }, + "details": { + "timestamp": "tidsstämpel" + } +} diff --git a/web/public/locales/sv/views/exports.json b/web/public/locales/sv/views/exports.json new file mode 100644 index 000000000..f5b8f37b5 --- /dev/null +++ b/web/public/locales/sv/views/exports.json @@ -0,0 +1,17 @@ +{ + "search": "Sök", + "documentTitle": "Export - Frigate", + "noExports": "Inga exporter hittade", + "deleteExport": "Radera export", + "deleteExport.desc": "Är du säker att du vill radera {{exportName}}?", + "editExport": { + "desc": "Ange ett nytt namn för denna export.", + "title": "Byt namn på Export", + "saveExport": "Spara Export" + }, + "toast": { + "error": { + "renameExportFailed": "Misslyckades att byta namn på export: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/sv/views/faceLibrary.json b/web/public/locales/sv/views/faceLibrary.json new file mode 100644 index 000000000..7e533000a --- /dev/null +++ b/web/public/locales/sv/views/faceLibrary.json @@ -0,0 +1,32 @@ +{ + "details": { + "person": "Person", + "confidence": "Säkerhet", + "face": "Ansiktsdetaljer", + "timestamp": "tidsstämpel", + "faceDesc": "Detaljer för ansiktet och tillhörande objekt" + }, + "description": { + "placeholder": "Ange ett namn för denna samling", + "addFace": "Gå genom för att lägga till nya ansikte till biblioteket." + }, + "documentTitle": "Ansiktsbibliotek - Frigate", + "steps": { + "faceName": "Ange namn", + "uploadFace": "Ladda upp bild på ansikte", + "nextSteps": "Nästa steg" + }, + "createFaceLibrary": { + "title": "Skapa samling", + "desc": "Skapa ny samling", + "nextSteps": "För att bygga en stark grund:
  • Använd fliken Träna för att välja och träna på bilder för varje upptäckt person.
  • Fokusera på raka bilder för bästa resultat; undvik träningsbilder som fångar ansikten i vinkel.
  • ", + "new": "Skapa nytt ansikte" + }, + "train": { + "title": "Träna" + }, + "uploadFaceImage": { + "title": "Ladda upp ansiktsbild", + "desc": "Ladda upp en bild för att skanna efter ansikte och inkludera {{pageToggle}}" + } +} diff --git a/web/public/locales/sv/views/live.json b/web/public/locales/sv/views/live.json new file mode 100644 index 000000000..9c00e9683 --- /dev/null +++ b/web/public/locales/sv/views/live.json @@ -0,0 +1,48 @@ +{ + "documentTitle": "Live - Frigate", + "documentTitle.withCamera": "{{camera}} - Live - Frigate", + "twoWayTalk": { + "enable": "Aktivera Two Way Talk", + "disable": "Avaktivera Two Way Talk" + }, + "cameraAudio": { + "disable": "Inaktivera kameraljud", + "enable": "Aktivera kameraljud" + }, + "ptz": { + "zoom": { + "in": { + "label": "Zooma in PTZ kamera" + }, + "out": { + "label": "Zooma ut PTZ kamera" + } + } + }, + "streamStats": { + "enable": "Visa videostatistik", + "disable": "Dölj videostatistik" + }, + "detect": { + "enable": "Aktivera detektering", + "disable": "Avaktivera detektering" + }, + "recording": { + "enable": "Aktivera inspelning", + "disable": "Avaktivera inspelning" + }, + "snapshots": { + "enable": "Aktivera ögonblicksbilder", + "disable": "Avaktivera ögonblicksbilder" + }, + "audioDetect": { + "enable": "Aktivera ljudaktivering", + "disable": "Avaktivera ljudaktivering" + }, + "autotracking": { + "enable": "Aktivera automatisk panorering", + "disable": "Avaktivera automatisk panorering" + }, + "notifications": "Notifikationer", + "audio": "Ljud" +} diff --git a/web/public/locales/sv/views/recording.json b/web/public/locales/sv/views/recording.json new file mode 100644 index 000000000..6e9e231a3 --- /dev/null +++ b/web/public/locales/sv/views/recording.json @@ -0,0 +1,12 @@ +{ + "export": "Export", + "filter": "Filter", + "calendar": "Kalender", + "filters": "Filter", + "toast": { + "error": { + "noValidTimeSelected": "Inget giltigt tidsintervall valt", + "endTimeMustAfterStartTime": "Sluttid måste vara efter starttid" + } + } +} diff --git a/web/public/locales/sv/views/search.json b/web/public/locales/sv/views/search.json new file mode 100644 index 000000000..87ca6ed23 --- /dev/null +++ b/web/public/locales/sv/views/search.json @@ -0,0 +1,9 @@ +{ + "savedSearches": "Sparade Sökningar", + "searchFor": "Sök efter {{inputValue}}", + "search": "Sök", + "button": { + "clear": "Radera sökning", + "save": "Spara sökning" + } +} diff --git a/web/public/locales/sv/views/settings.json b/web/public/locales/sv/views/settings.json new file mode 100644 index 000000000..631800c5d --- /dev/null +++ b/web/public/locales/sv/views/settings.json @@ -0,0 +1,8 @@ +{ + "documentTitle": { + "camera": "Kamerainställningar - Frigate", + "default": "Inställningar - Frigate", + "general": "Allmäna inställningar - Frigate", + "authentication": "Autentiseringsinställningar - Frigate" + } +} diff --git a/web/public/locales/sv/views/system.json b/web/public/locales/sv/views/system.json new file mode 100644 index 000000000..dc3a35dea --- /dev/null +++ b/web/public/locales/sv/views/system.json @@ -0,0 +1,10 @@ +{ + "documentTitle": { + "storage": "Lagringsstatistik - Frigate", + "general": "Allmän statistik - Frigate", + "cameras": "Kamerastatistik - Frigate", + "logs": { + "frigate": "Frigate loggar - Frigate" + } + } +} diff --git a/web/public/locales/tr/audio.json b/web/public/locales/tr/audio.json new file mode 100644 index 000000000..95452fa4b --- /dev/null +++ b/web/public/locales/tr/audio.json @@ -0,0 +1,429 @@ +{ + "mantra": "mantra", + "breathing": "nefes alma", + "snoring": "horlama", + "animal": "hayvan", + "dog": "köpek", + "laughter": "kahkaha", + "yell": "bağırma", + "cat": "kedi", + "whispering": "fısıldama", + "crying": "ağlama", + "bark": "havlama", + "speech": "konuşma", + "bicycle": "bisiklet", + "horse": "at", + "goat": "keçi", + "mouse": "fare", + "keyboard": "klavye", + "vehicle": "araç", + "boat": "bot", + "car": "araba", + "bus": "otobüs", + "motorcycle": "motosiklet", + "skateboard": "kaykay", + "door": "kapı", + "blender": "mikser", + "sink": "lavabo", + "toothbrush": "diş fırçası", + "clock": "saat", + "scissors": "makas", + "bird": "kuş", + "sheep": "koyun", + "train": "tren", + "hair_dryer": "saç kurutma makinesi", + "babbling": "aguşlama", + "snicker": "kıkırdama", + "sigh": "iç çekme", + "bellow": "haykırma", + "whoop": "nara", + "singing": "şarkı söyleme", + "choir": "koro", + "yodeling": "gırtlak naresi", + "grunt": "homurdanma", + "whistling": "ıslık", + "wheeze": "hırıltı", + "gasp": "kesik nefes", + "pant": "soluma", + "cough": "öksürük", + "throat_clearing": "boğaz temizleme", + "chatter": "gevezelik", + "crowd": "kalabalık", + "children_playing": "oynayan çocuklar", + "pets": "evcil hayvan", + "meow": "miyavlama", + "hiss": "tıslama", + "moo": "böğürme", + "cowbell": "inek çanı", + "fowl": "kümes hayvanı", + "chicken": "tavuk", + "cluck": "gıdaklama", + "quack": "vakvaklama", + "coo": "kumru sesi", + "crow": "karga", + "insect": "böcek", + "plucked_string_instrument": "çekmeli telli çalgı", + "guitar": "gitar", + "electric_guitar": "elektro gitar", + "strum": "pena vuruşu", + "organ": "org", + "electronic_organ": "elektronik org", + "hammond_organ": "hammond org", + "percussion": "vurmalı çalgı", + "drum_kit": "bateri", + "drum": "davul", + "gong": "gong", + "tubular_bells": "boru çanlar", + "mallet_percussion": "tokmaklı vurmalılar", + "brass_instrument": "bakır nefesli", + "flute": "flüt", + "church_bell": "kilise çanı", + "didgeridoo": "didgeridoo", + "theremin": "teremin", + "heavy_metal": "heavy metal", + "punk_rock": "punk rock", + "grunge": "grunge", + "reggae": "reggae", + "country": "country müzik", + "middle_eastern_music": "orta doğu müziği", + "jazz": "caz", + "trance_music": "trance müzik", + "music_of_latin_america": "latin amerika müziği", + "music_of_africa": "afrika müziği", + "afrobeat": "afrobeat", + "christian_music": "hristiyan müziği", + "gospel_music": "gospel", + "independent_music": "bağımsız müzik", + "wedding_music": "düğün müziği", + "happy_music": "mutlu müzik", + "scary_music": "korkutucu müzik", + "wind": "rüzgar", + "thunder": "gök gürültüsü", + "water": "su", + "rain": "yağmur", + "ocean": "okyanus", + "waves": "dalgalar", + "steam": "buhar", + "gurgling": "şırıltı", + "fire": "ateş", + "sailboat": "yelkenli", + "rowboat": "sandal", + "motorboat": "motorbot", + "toot": "korna sesi", + "race_car": "yarış arabası", + "ambulance": "ambulans", + "train_horn": "tren kornası", + "jet_engine": "jet motoru", + "accelerating": "hızlanma", + "doorbell": "kapı zili", + "ding-dong": "ding dong", + "cupboard_open_or_close": "dolap açma/kapama", + "drawer_open_or_close": "çekmece açma/kapama", + "dishes": "bulaşık", + "toilet_flush": "sifon çekme", + "zipper": "fermuar", + "shuffling_cards": "kart karıştırma", + "ringtone": "zil sesi", + "telephone_dialing": "numara çevirme", + "dial_tone": "çevir sesi", + "buzzer": "buzzer", + "mechanisms": "mekanizma", + "ratchet": "cırcır", + "tick": "tik", + "filing": "törpüleme", + "burst": "patlama", + "eruption": "püskürme", + "silence": "sessizlik", + "chant": "tezahürat", + "child_singing": "çocuk şarkısı", + "synthetic_singing": "sentetik şarkı", + "rapping": "rap", + "humming": "mırıldanma", + "groan": "inleme", + "snort": "burnundan soluma", + "sneeze": "hapşırma", + "sniff": "burun çekme", + "run": "koşma", + "shuffle": "ayak sürtme", + "footsteps": "adım sesleri", + "chewing": "çiğneme", + "biting": "ısırma", + "gargling": "gargara", + "stomach_rumble": "mide gurultusu", + "burping": "geğirme", + "hiccup": "hıçkırık", + "fart": "gaz çıkarma", + "hands": "el sesi", + "finger_snapping": "parmak şıklatma", + "clapping": "alkışlama", + "heartbeat": "kalp atışı", + "heart_murmur": "kalp üfürümü", + "cheering": "tezahürat", + "applause": "alkış", + "yip": "ince havlama", + "howl": "uluma", + "bow_wow": "havlama", + "growling": "hırlama", + "whimper_dog": "köpek sızlanması", + "purr": "mırlama", + "caterwaul": "kedi çığlığı", + "livestock": "çiftlik hayvanı", + "clip_clop": "nal sesi", + "neigh": "kişneme", + "cattle": "büyükbaş hayvan", + "pig": "domuz", + "oink": "domuz sesi", + "bleat": "meleme", + "cock_a_doodle_doo": "horoz ötüşü", + "turkey": "hindi", + "gobble": "hindi sesi", + "duck": "ördek", + "goose": "kaz", + "honk": "kaz sesi", + "wild_animals": "vahşi hayvan", + "roaring_cats": "kükreyen kedi", + "roar": "kükreme", + "chirp": "cıvıltı", + "squawk": "kuş çığlığı", + "pigeon": "güvercin", + "caw": "karga sesi", + "owl": "baykuş", + "hoot": "baykuş ötüşü", + "flapping_wings": "kanat çırpma", + "dogs": "köpekler", + "rats": "sıçanlar", + "patter": "tıkırtı", + "cricket": "cırcır böceği", + "mosquito": "sivrisinek", + "fly": "sinek", + "frog": "kurbağa", + "croak": "vraklama", + "snake": "yılan", + "rattle": "çıngırak", + "buzz": "vızıltı", + "whale_vocalization": "balina sesi", + "music": "müzik", + "musical_instrument": "müzik aleti", + "bass_guitar": "bas gitar", + "acoustic_guitar": "akustik gitar", + "steel_guitar": "steel gitar", + "tapping": "tıklatma", + "ukulele": "ukulele", + "banjo": "banjo", + "sitar": "sitar", + "mandolin": "mandolin", + "zither": "ziter", + "piano": "piyano", + "electric_piano": "elektro piyano", + "synthesizer": "sentezleyici", + "sampler": "örnekleyici", + "drum_machine": "davul makinesi", + "harpsichord": "klavsen", + "snare_drum": "trampet", + "rimshot": "rimşat", + "drum_roll": "davul geçişi", + "bass_drum": "bas davul", + "timpani": "timpani", + "maraca": "marakas", + "tabla": "tabla", + "cymbal": "zil", + "hi_hat": "hi-hat", + "wood_block": "tahta blok", + "tambourine": "tef", + "marimba": "marimba", + "glockenspiel": "glockenspiel", + "vibraphone": "vibrafon", + "steelpan": "steelpan", + "orchestra": "orkestra", + "french_horn": "korno", + "trumpet": "trompet", + "trombone": "trombon", + "bowed_string_instrument": "yaylı telli çalgı", + "string_section": "yaylılar", + "violin": "keman", + "pizzicato": "pizzicato", + "cello": "viyolonsel", + "double_bass": "kontrbas", + "wind_instrument": "nefesli çalgı", + "saxophone": "saksafon", + "clarinet": "klarnet", + "harp": "arp", + "bell": "çan", + "singing_bowl": "tibet çanağı", + "scratching": "tırmalama", + "pop_music": "pop müzik", + "bicycle_bell": "bisiklet zili", + "tuning_fork": "diyapazon", + "chime": "çan sesi", + "wind_chime": "rüzgar çanı", + "harmonica": "mızıka", + "accordion": "akordeon", + "bagpipes": "gayda", + "hip_hop_music": "hip hop müzik", + "beatboxing": "beatbox", + "rock_music": "rock müzik", + "progressive_rock": "progressive rock", + "rock_and_roll": "rock and roll", + "psychedelic_rock": "psychedelic rock", + "rhythm_and_blues": "rhythm and blues", + "soul_music": "soul müzik", + "swing_music": "swing müzik", + "bluegrass": "bluegrass", + "funk": "funk", + "folk_music": "halk müziği", + "disco": "disko", + "classical_music": "klasik müzik", + "opera": "opera", + "electronic_music": "elektronik müzik", + "house_music": "house müzik", + "techno": "tekno", + "dubstep": "dubstep", + "drum_and_bass": "drum and bass", + "electronica": "electronica", + "electronic_dance_music": "elektronik dans müziği", + "ambient_music": "ambient müzik", + "salsa_music": "salsa müziği", + "flamenco": "flamenko", + "blues": "blues", + "music_for_children": "çocuk müziği", + "new-age_music": "new age müzik", + "vocal_music": "vokal müzik", + "a_capella": "akapella", + "music_of_asia": "asya müziği", + "carnatic_music": "karnatik müzik", + "music_of_bollywood": "bollywood müziği", + "ska": "ska", + "traditional_music": "geleneksel müzik", + "song": "şarkı", + "background_music": "arka plan müziği", + "theme_music": "tema müziği", + "jingle": "jingle", + "soundtrack_music": "film müziği", + "lullaby": "ninni", + "video_game_music": "video oyunu müziği", + "christmas_music": "noel müziği", + "dance_music": "dans müziği", + "sad_music": "hüzünlü müzik", + "tender_music": "yumuşak müzik", + "exciting_music": "heyecanlı müzik", + "angry_music": "öfkeli müzik", + "rustling_leaves": "yaprak hışırtısı", + "wind_noise": "rüzgar gürültüsü", + "thunderstorm": "gök gürültülü fırtına", + "raindrop": "yağmur damlası", + "rain_on_surface": "yüzeye düşen yağmur", + "stream": "dere", + "waterfall": "şelale", + "crackle": "çıtırtı", + "ship": "gemi", + "motor_vehicle": "motorlu taşıt", + "car_alarm": "araç alarmı", + "power_windows": "otomatik cam", + "skidding": "kayma", + "tire_squeal": "lastik gıcırtısı", + "car_passing_by": "geçen araba", + "truck": "kamyon", + "air_brake": "havalı fren", + "air_horn": "havalı korna", + "reversing_beeps": "geri vites bip sesi", + "ice_cream_truck": "dondurma kamyonu", + "emergency_vehicle": "acil durum aracı", + "police_car": "polis arabası", + "fire_engine": "itfaiye aracı", + "traffic_noise": "trafik gürültüsü", + "rail_transport": "raylı ulaşım", + "train_whistle": "tren düdüğü", + "railroad_car": "vagon", + "fixed-wing_aircraft": "sabit kanatlı uçak", + "train_wheels_squealing": "tren tekeri gıcırtısı", + "subway": "metro", + "aircraft": "hava aracı", + "aircraft_engine": "uçak motoru", + "propeller": "pervane", + "helicopter": "helikopter", + "engine": "motor", + "light_engine": "hafif motor", + "dental_drill's_drill": "dişçi matkabı", + "lawn_mower": "çim biçme makinesi", + "chainsaw": "motorlu testere", + "medium_engine": "orta motor", + "heavy_engine": "ağır motor", + "engine_knocking": "motor vuruntusu", + "engine_starting": "motor çalıştırma", + "idling": "rölanti", + "sliding_door": "sürgülü kapı", + "slam": "kapı çarpma", + "knock": "kapı çalma", + "tap": "tıklatma", + "squeak": "gıcırtı", + "cutlery": "çatal bıçak", + "chopping": "doğrama", + "frying": "kızartma", + "microwave_oven": "mikrodalga fırın", + "water_tap": "musluk", + "bathtub": "küvet", + "electric_toothbrush": "elektrikli diş fırçası", + "vacuum_cleaner": "elektrik süpürgesi", + "keys_jangling": "anahtar şıngırtısı", + "coin": "madeni para", + "electric_shaver": "tıraş makinesi", + "typing": "klavyede yazma", + "typewriter": "daktilo", + "computer_keyboard": "bilgisayar klavyesi", + "writing": "yazma", + "alarm": "alarm", + "telephone": "telefon", + "telephone_bell_ringing": "telefon çalması", + "busy_signal": "meşgul sinyali", + "alarm_clock": "çalar saat", + "siren": "siren", + "civil_defense_siren": "sivil savunma sireni", + "smoke_detector": "duman dedektörü", + "fire_alarm": "yangın alarmı", + "foghorn": "sis düdüğü", + "whistle": "düdük", + "steam_whistle": "buhar düdüğü", + "tick-tock": "tik tak", + "gears": "dişliler", + "pulleys": "makaralar", + "sewing_machine": "dikiş makinesi", + "mechanical_fan": "mekanik vantilatör", + "air_conditioning": "klima", + "cash_register": "yazar kasa", + "printer": "yazıcı", + "camera": "kamera", + "single-lens_reflex_camera": "slr kamera", + "tools": "aletler", + "hammer": "çekiç", + "jackhammer": "hilti", + "sawing": "testere ile kesme", + "sanding": "zımparalama", + "power_tool": "elektrikli alet", + "drill": "matkap", + "explosion": "patlama", + "gunshot": "silah sesi", + "machine_gun": "makineli tüfek", + "fusillade": "yaylım ateşi", + "artillery_fire": "topçu ateşi", + "cap_gun": "mantar tabancası", + "fireworks": "havai fişek", + "firecracker": "torpil", + "boom": "gümbürtü", + "wood": "ahşap", + "chop": "kesme", + "splinter": "parçalanma", + "crack": "çatlama", + "glass": "cam", + "chink": "şıngırtı", + "shatter": "kırılma", + "sound_effect": "ses efekti", + "environmental_noise": "çevre gürültüsü", + "static": "parazit", + "white_noise": "beyaz gürültü", + "pink_noise": "pembe gürültü", + "television": "televizyon", + "radio": "radyo", + "field_recording": "alan kaydı", + "scream": "çığlık", + "jingle_bell": "küçük çan" +} diff --git a/web/public/locales/tr/common.json b/web/public/locales/tr/common.json new file mode 100644 index 000000000..a738ba068 --- /dev/null +++ b/web/public/locales/tr/common.json @@ -0,0 +1,256 @@ +{ + "time": { + "lastWeek": "Geçen Hafta", + "thisWeek": "Bu Hafta", + "lastMonth": "Geçen Ay", + "untilForRestart": "Frigate yeniden başlatılana kadar.", + "untilRestart": "Yeniden başlatmaya kadar", + "ago": "{{timeAgo}} önce", + "justNow": "Az önce", + "today": "Bugün", + "yesterday": "Dün", + "last7": "Son 7 gün", + "last30": "Son 30 gün", + "thisMonth": "Bu Ay", + "5minutes": "5 dakika", + "10minutes": "10 dakika", + "30minutes": "30 dakika", + "1hour": "1 saat", + "12hours": "12 saat", + "last14": "Son 14 gün", + "24hours": "24 saat", + "formattedTimestamp": { + "24hour": "d MMM, HH:mm:ss", + "12hour": "d MMM, h:mm:ss aaa" + }, + "formattedTimestamp2": { + "24hour": "d MMM HH:mm:ss", + "12hour": "dd/MM h:mm:ssa" + }, + "second_one": "{{time}} saniye", + "second_other": "{{time}} saniye", + "year_one": "{{time}} yıl", + "year_other": "{{time}} yıl", + "hour_one": "{{time}} saat", + "hour_other": "{{time}} saat", + "h": "{{time}} s", + "yr": "{{time}} yıl", + "mo": "{{time}} ay", + "untilForTime": "{{time}}'a kadar", + "pm": "ÖS", + "am": "ÖÖ", + "d": "{{time}} gün", + "day_one": "{{time}} gün", + "day_other": "{{time}} gün", + "m": "{{time}}d", + "minute_one": "{{time}} dakika", + "minute_other": "{{time}} dakika", + "formattedTimestampWithYear": { + "12hour": "%-d %b %Y, %I:%M %p", + "24hour": "%-d %b %Y, %H:%M" + }, + "formattedTimestampOnlyMonthAndDay": "%-d %b", + "formattedTimestampExcludeSeconds": { + "12hour": "%-d %b, %I:%M %p", + "24hour": "%-d %b, %H:%M" + }, + "s": "{{time}}sn", + "month_one": "{{time}} ay", + "month_other": "{{time}} ay", + "formattedTimestampHourMinute": { + "12hour": "h:mm aaa", + "24hour": "HH:mm" + }, + "formattedTimestampHourMinuteSecond": { + "12hour": "h:mm:ss aaa", + "24hour": "HH:mm:ss" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "d MMM, h:mm aaa", + "24hour": "d MMM, HH:mm" + }, + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "d MMM yyyy, h:mm aaa", + "24hour": "d MMM yyyy, HH:mm" + }, + "formattedTimestampMonthDay": "d MMM", + "formattedTimestampFilename": { + "12hour": "dd-MM-yy-h-mm-ss-a", + "24hour": "dd-MM-yy-HH-mm-ss" + } + }, + "button": { + "off": "KAPALI", + "next": "Sonraki", + "saving": "Kaydediliyor…", + "back": "Geri", + "unselect": "Seçimi kaldır", + "info": "Bilgi", + "enable": "Aç", + "disabled": "Kapalı", + "disable": "Kapat", + "history": "Geçmiş", + "cameraAudio": "Kamera Sesi", + "on": "AÇIK", + "suspended": "Askıya alınmış", + "unsuspended": "Askıdan çıkart", + "export": "Dışa aktar", + "download": "İndir", + "edit": "Düzenle", + "fullscreen": "Tam ekran", + "deleteNow": "Şimdi Sil", + "apply": "Uygula", + "reset": "Sıfırla", + "done": "Bitti", + "enabled": "Açık", + "save": "Kaydet", + "exitFullscreen": "Tam ekrandan çık", + "pictureInPicture": "Pencere içinde pencere", + "copyCoordinates": "Koordinatları kopyala", + "yes": "Evet", + "play": "Oynat", + "no": "Hayır", + "copy": "Kopyala", + "cancel": "İptal", + "twoWayTalk": "Çift Yönlü Ses", + "close": "Kapat", + "delete": "Sil" + }, + "menu": { + "systemLogs": "Sistem günlükleri", + "user": { + "anonymous": "anonim", + "account": "Hesap", + "current": "Mevcut kullanıcı: {{user}}", + "setPassword": "Parola Belirle", + "logout": "Oturumu Kapat", + "title": "Kullanıcı" + }, + "configuration": "Yapılandırma", + "languages": "Diller", + "language": { + "en": "İngilizce", + "zhCN": "简体中文 (Basitleştirilmiş Çince)", + "withSystem": { + "label": "Dil için sistem tercihini kullan" + }, + "hi": "हिन्दी (Hintçe)", + "fr": "Français (Fransızca)", + "pt": "Português (Portekizce)", + "de": "Deutsch (Almanca)", + "ja": "日本語 (Japonca)", + "tr": "Türkçe (Türkçe)", + "it": "Italiano (İtalyanca)", + "nl": "Nederlands (Felemenkçe)", + "sv": "Svenska (İsveççe)", + "cs": "Čeština (Çekçe)", + "nb": "Norsk Bokmål (Bokmål Norveç Dili)", + "ko": "한국어 (Korece)", + "vi": "Tiếng Việt (Vietnamca)", + "pl": "Polski (Lehçe)", + "uk": "Українська (Ukraynaca)", + "he": "עברית (İbranice)", + "el": "Ελληνικά (Yunanca)", + "ro": "Română (Rumence)", + "hu": "Magyar (Macarca)", + "fi": "Suomi (Fince)", + "da": "Dansk (Danimarka Dili)", + "sk": "Slovenčina (Slovakça)", + "fa": "فارسی (Farsça)", + "es": "Español (İspanyolca)", + "ar": "العربية (Arapça)", + "ru": "Русский (Rusça)" + }, + "withSystem": "Sistem", + "theme": { + "label": "Tema", + "blue": "Mavi", + "contrast": "Yüksek Karşıtlık", + "green": "Yeşil", + "red": "Kırmızı", + "default": "Varsayılan", + "nord": "Kuzey" + }, + "restart": "Frigate'i yeniden başlat", + "live": { + "title": "Canlı", + "allCameras": "Tüm Kameralar", + "cameras": { + "title": "Kameralar", + "count_one": "{{count}} Kamera", + "count_other": "{{count}} Kamera" + } + }, + "review": "İncele", + "explore": "Keşfet", + "system": "Sistem", + "documentation": { + "title": "Dökümantasyon", + "label": "Frigate dökümantasyonu" + }, + "settings": "Ayarlar", + "appearance": "Görünüm", + "darkMode": { + "label": "Karanlık Mod", + "withSystem": { + "label": "Karanlık tema için sistem tercihini kullan" + }, + "light": "Açık", + "dark": "Koyu" + }, + "export": "Dışa Aktar", + "configurationEditor": "Yapılandırma düzenleyicisi", + "help": "Yardım", + "faceLibrary": "Yüz Veritabanı", + "systemMetrics": "Sistem metrikleri", + "uiPlayground": "UI Deneme Alanı" + }, + "label": { + "back": "Geri" + }, + "notFound": { + "documentTitle": "Bulunamadı - Frigate", + "desc": "Sayfa bulunamadı", + "title": "404" + }, + "unit": { + "speed": { + "mph": "mph", + "kph": "km/s" + } + }, + "pagination": { + "next": { + "title": "Sonraki", + "label": "Sonraki sayfaya git" + }, + "previous": { + "label": "Önceki sayfaya git", + "title": "Önceki" + }, + "label": "sayfalandırma", + "more": "Daha fazla" + }, + "accessDenied": { + "title": "Erişim Reddedildi", + "desc": "Bu sayfayı görüntüleme yetkiniz yok.", + "documentTitle": "Erişim Reddedildi - Frigate" + }, + "toast": { + "copyUrlToClipboard": "URL panoya kopyalandı.", + "save": { + "title": "Kaydet", + "error": { + "noMessage": "Yapılandırma değişiklikleri kaydedilemedi", + "title": "Yapılandırma değişiklikleri kaydedilemedi: {{errorMessage}}" + } + } + }, + "selectItem": "{{item}} seçin", + "role": { + "title": "Rol", + "viewer": "Görüntüleyici", + "admin": "Yönetici", + "desc": "Yöneticiler Frigate arayüzündeki bütün özelliklere tam erişim sahibidir. Görüntüleyiciler ise yalnızca kameraları, eski görüntüleri ve inceleme öğelerini görüntülemekle sınırlıdır." + } +} diff --git a/web/public/locales/tr/components/auth.json b/web/public/locales/tr/components/auth.json new file mode 100644 index 000000000..dbc444b05 --- /dev/null +++ b/web/public/locales/tr/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "password": "Parola", + "login": "Oturum Aç", + "errors": { + "webUnknownError": "Bilinmeyen hata. Konsol günlüklerini kontrol edin.", + "usernameRequired": "Kullanıcı adı gereklidir", + "loginFailed": "Oturum açma başarısız", + "passwordRequired": "Parola gereklidir", + "rateLimit": "İstek sınırı aşıldı. Daha sonra tekrar deneyin.", + "unknownError": "Bilinmeyen hata. Günlükleri kontrol edin." + }, + "user": "Kullanıcı Adı" + } +} diff --git a/web/public/locales/tr/components/camera.json b/web/public/locales/tr/components/camera.json new file mode 100644 index 000000000..a8620b3fe --- /dev/null +++ b/web/public/locales/tr/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "name": { + "placeholder": "Bir isim girin…", + "label": "İsim", + "errorMessage": { + "nameMustNotPeriod": "Kamera grubu ismi nokta içeremez.", + "invalid": "Geçersiz kamera grubu ismi.", + "mustLeastCharacters": "Kamera grubu ismi en az iki karakterden oluşmalıdır.", + "exists": "Bu isimle bir kamera grubu zaten var." + } + }, + "success": "{{name}} adlı kamera grubu kaydedildi.", + "camera": { + "setting": { + "title": "{{cameraName}} Yayın Ayarları", + "audio": { + "tips": { + "document": "Dökümantasyonu oku ", + "title": "Bu yayın için kameranızın yayın çıkışında ses olması ve go2rtc'de ayarlanmış olması gerekmektedir." + } + }, + "label": "Kamera Yayın Ayarları", + "desc": "Bu kamera grubunun kontrol paneli için canlı yayın seçeneklerini değiştirin. Bu ayarlar cihaz/tarayıcı özelindedir.", + "audioIsUnavailable": "Bu yayında ses yok", + "audioIsAvailable": "Bu yayında ses kullanılabilir", + "streamMethod": { + "label": "Yayın Yöntemi", + "method": { + "noStreaming": { + "label": "Yayın Yok", + "desc": "Kamera görüntüsü dakikda bir güncellenecektir ve canlı yayın yapılmayacaktır." + }, + "continuousStreaming": { + "desc": { + "title": "Kamera görüntüsü panelde görüldüğü sürece, kamerada aktivite olmasa bile, canlı yayın şeklinde olacaktır.", + "warning": "Sürekli yayın yüksek internet kullanımına ve performans sorunlarına yol açabilir. Dikkatli kullanın." + }, + "label": "Sürekli Yayın" + }, + "smartStreaming": { + "label": "Akıllı yayın (önerilir)", + "desc": "Akıllı yayın özelliği, internet ve diğer kaynaklardan tasarruf için aktivite yokken yayının yerine dakikada bir güncellenen sabit resim gösterir. Kamerada aktivite tespit edildiğinde görüntü sabit resimden canlı yayına geçer." + } + } + }, + "compatibilityMode": { + "label": "Uyumluluk modu", + "desc": "Bu özelliği sadece kamera akışında renkli mozaiklenme yahut resmin sağ tarafında çizgi görüyorsanız etkinleştirin." + } + } + }, + "icon": "Simge", + "add": "Kamera Grubu Ekle", + "label": "Kamera Grupları", + "delete": { + "confirm": { + "desc": "{{name}} isimli kamera grubunu silmek istediğinizden emin misiniz?", + "title": "Silmeyi Onayla" + }, + "label": "Kamera Grubunu Sil" + }, + "edit": "Kamera Grubunu Düzenle", + "cameras": { + "desc": "Bu gruba dahil olacak kameraları seçin.", + "label": "Kameralar" + } + }, + "debug": { + "options": { + "label": "Ayarlar", + "title": "Seçenekler", + "hideOptions": "Seçenekleri Gizle", + "showOptions": "Seçenekleri Göster" + }, + "boundingBox": "Çerçeve", + "timestamp": "Zaman Damgası", + "zones": "Alanlar", + "mask": "Maske", + "motion": "Hareket", + "regions": "Tespit Bölgeleri" + } +} diff --git a/web/public/locales/tr/components/dialog.json b/web/public/locales/tr/components/dialog.json new file mode 100644 index 000000000..02c348bd2 --- /dev/null +++ b/web/public/locales/tr/components/dialog.json @@ -0,0 +1,119 @@ +{ + "restart": { + "title": "Frigate'i yeniden başlatmak istediğinize emin misiniz?", + "button": "Yeniden Başlat", + "restarting": { + "content": "Bu sayfa {{countdown}} saniye sonra yeniden yüklenecektir.", + "title": "Frigate Yeniden Başlatılıyor", + "button": "Şimdi Yeniden Yükle" + } + }, + "explore": { + "plus": { + "review": { + "state": { + "submitted": "Gönderildi" + }, + "true": { + "true_one": "Bu bir {{label}}", + "true_other": "Bu bir {{label}}", + "label": "Frigate+ için bu etiketi onaylayın" + }, + "false": { + "label": "Bu etiketi Frigate+ için onaylamaktan vazgeç", + "false_one": "Bu bir {{label}} değil", + "false_other": "Bu bir {{label}} değil" + }, + "question": { + "ask_an": "Bu nesne bir {{label}} mi?", + "label": "Bu etikeri Frigate+ için onaylayın", + "ask_a": "Bu nesne bir {{label}} mi?", + "ask_full": "Bu nesne bir {{untranslatedLabel}} ({{translatedLabel}}) mi?" + } + }, + "submitToPlus": { + "label": "Frigate+'ya Gönder", + "desc": "Görülmesini istemediğiniz yerlerdeki nesneler yanlış pozitif değildir. Bunları yanlış pozitif olarak göndermek modeli yanıltacaktır." + } + }, + "video": { + "viewInHistory": "Geçmiş Görünümünde Görüntüle" + } + }, + "export": { + "time": { + "end": { + "label": "Bitiş Zamanını Seç", + "title": "Bitiş Zamanı" + }, + "lastHour_one": "Son 1 Saat", + "lastHour_other": "Son {{count}} Saat", + "start": { + "title": "Başlangıç Zamanı", + "label": "Başlangıç Zamanını Seç" + }, + "fromTimeline": "Zaman Şeridinde Seç", + "custom": "Özel" + }, + "select": "Seç", + "export": "Dışa Aktar", + "selectOrExport": "Seç veya Dışa Aktar", + "toast": { + "success": "Dışa aktarım başladı. Dosyaya /exports klasöründe veya Dışa Aktar sekmesinden ulaşabilirsiniz.", + "error": { + "failed": "Dışa aktarım başlatılamadı: {{error}}", + "endTimeMustAfterStartTime": "Bitiş zamanı başlangıç zamanından sonra olmalıdır", + "noVaildTimeSelected": "Geçerli bir zaman aralığı seçilmedi" + } + }, + "fromTimeline": { + "saveExport": "Dışa Aktarımı Kaydet", + "previewExport": "Dışa Aktarımı Önizle" + }, + "name": { + "placeholder": "Dışa Aktarımı Adlandırın" + } + }, + "streaming": { + "label": "Akış", + "restreaming": { + "disabled": "Bu kamera için Yeniden Akış devre dışı.", + "desc": { + "readTheDocumentation": "Dökümantasyonu oku", + "title": "Bu kameradan ek canlı gösterim seçenekleri ve sesli yayın almak için go2rtc'yi yapılandırın." + } + }, + "showStats": { + "label": "Akış istatistiklerini göster", + "desc": "Kamera akışının üzerinde akış istastistiklerini görmek için bu seçeneği aktifleştirin." + }, + "debugView": "Hata Ayıklama Görünümü" + }, + "search": { + "saveSearch": { + "desc": "Kayıtlı aramaya bir isim verin.", + "placeholder": "Aramanız için bir isim girin", + "overwrite": "{{searchName}} zaten var. Bu isimle kaydetmek mevcut olanın üzerine yazacaktır.", + "label": "Aramayı Kaydet", + "button": { + "save": { + "label": "Bu aramayı kaydet" + } + }, + "success": "Arama ({{searchName}}) kaydedildi." + } + }, + "recording": { + "confirmDelete": { + "title": "Silmeyi Onayla", + "desc": { + "selected": "Bu inceleme öğesiyle ilişkili tüm kaydedilmiş videoları silmek istediğinizden emin misiniz?

    Gelecekte bu diyaloğu pas geçmek için Shift tuşuna basılı tutarak tıklayın." + } + }, + "button": { + "export": "Dışa Aktar", + "markAsReviewed": "İncelendi olarak işaretle", + "deleteNow": "Şimdi Sil" + } + } +} diff --git a/web/public/locales/tr/components/filter.json b/web/public/locales/tr/components/filter.json new file mode 100644 index 000000000..393f996ed --- /dev/null +++ b/web/public/locales/tr/components/filter.json @@ -0,0 +1,126 @@ +{ + "labels": { + "label": "Etiketler", + "all": { + "title": "Bütün Etiketler", + "short": "Etiketler" + }, + "count": "{{count}} Etiket", + "count_one": "{{count}} Etiket", + "count_other": "{{count}} Etiket" + }, + "dates": { + "all": { + "title": "Tüm Tarihler", + "short": "Tarihler" + } + }, + "sort": { + "label": "Sırala", + "dateAsc": "Tarih (Artan)", + "dateDesc": "Tarih (Azalan)", + "scoreAsc": "Nesne Skoru (Artan)", + "scoreDesc": "Nesne Skoru (Azalan)", + "speedAsc": "Tahmini Hız (Artan)", + "relevance": "Alaka", + "speedDesc": "Tahmini Hız (Azalan)" + }, + "filter": "Filtre", + "zones": { + "all": { + "short": "Alanlar", + "title": "Bütün Alanlar" + }, + "label": "Alanlar" + }, + "reset": { + "label": "Filtreleri varsayılanlara sıfırla" + }, + "features": { + "submittedToFrigatePlus": { + "tips": "Öncelikle izlenen nesneler içinde fotoğrafı olanlar için filtre uygulamalısınız.

    Fotoğrafı olmayan nesneler Frigate+’a gönderilemez.", + "label": "Frigate+'a Gönderildi" + }, + "hasVideoClip": "Video klibi var", + "hasSnapshot": "Fotoğrafı var", + "label": "Özellikler" + }, + "score": "Skor", + "estimatedSpeed": "Tahmini Hız ({{unit}})", + "timeRange": "Zaman Aralığı", + "subLabels": { + "all": "Tüm Alt Etiketler", + "label": "Alt Etiketler" + }, + "more": "Daha Fazla Filtre", + "cameras": { + "all": { + "short": "Kameralar", + "title": "Tüm Kameralar" + }, + "label": "Kameraları Filtrele" + }, + "review": { + "showReviewed": "İncelenenleri de Göster" + }, + "explore": { + "settings": { + "defaultView": { + "summary": "Özet", + "title": "Varsayılan Görünüm", + "unfilteredGrid": "Filtresiz Izgara", + "desc": "Filtre seçilmediğinde, her etiket için en son izlenen nesnelerin özeti ya da filtresiz ızgara görünümü gösterilir." + }, + "gridColumns": { + "title": "Izgara Sütun Sayısı", + "desc": "Izgara görünümüde gösterilecek sütun sayısı." + }, + "title": "Ayarlar", + "searchSource": { + "options": { + "thumbnailImage": "Küçük Resim", + "description": "Metin Açıklaması" + }, + "label": "Arama kaynağı", + "desc": "Aramanızda küçük resimleri mi yoksa açıklamaları mı kullanacağınızı seçin." + } + }, + "date": { + "selectDateBy": { + "label": "Filtrelemek için tarih seçin" + } + } + }, + "logSettings": { + "filterBySeverity": "Önceliğe göre günlükleri filtrele", + "disableLogStreaming": "Günlük akışını devre dışı bırak", + "allLogs": "Tüm günlükler", + "loading": { + "title": "Günlük Akışı", + "desc": "Günlükler sayfası en aşağıya kaydırıldığında yeni günlük satırları geldikçe aşağıya eklenir." + }, + "label": "Düzeye göre günlükleri filtrele" + }, + "trackedObjectDelete": { + "toast": { + "success": "Takip edilen nesneler başarıyla silindi.", + "error": "Takip edilen nesneler silinemedi: {{errorMessage}}" + }, + "title": "Silmeyi onayla", + "desc": "Bu {{objectLength}} adet izlenen nesneyi sildiğinizde ilgili tüm fotoğraflar, kaydedilmiş tüm gömüler ve ilişkili tüm Nesne Geçmişi kayıtları kaldırılır. Bu izlenen nesnelere ait Geçmiş görünümündeki kayıtlı görüntüler SİLİNMEYECEKTİR.

    Devam etmek istediğinize emin misiniz?

    Gelecekte bu diyaloğu pas geçmek için Shift tuşuna basılı tutarak tıklayın." + }, + "recognizedLicensePlates": { + "selectPlatesFromList": "Listeden bir veya birden fazla plaka seçin.", + "placeholder": "Plaka ara…", + "loading": "Tanınan plakalar yükleniyor…", + "title": "Tanınan Plakalar", + "noLicensePlatesFound": "Plaka bulunamadı.", + "loadFailed": "Tanınan plakalar yüklenemedi." + }, + "motion": { + "showMotionOnly": "Yalnızca Hareket Olanları Göster" + }, + "zoneMask": { + "filterBy": "Alana göre filtrele" + } +} diff --git a/web/public/locales/tr/components/icons.json b/web/public/locales/tr/components/icons.json new file mode 100644 index 000000000..30c0e1d44 --- /dev/null +++ b/web/public/locales/tr/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "search": { + "placeholder": "Bir simge arayın…" + }, + "selectIcon": "Bir simge belirleyin" + } +} diff --git a/web/public/locales/tr/components/input.json b/web/public/locales/tr/components/input.json new file mode 100644 index 000000000..bbaa987f4 --- /dev/null +++ b/web/public/locales/tr/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Videoyu İndir", + "toast": { + "success": "İncele öğesinin videosu indirilmeye başlandı." + } + } + } +} diff --git a/web/public/locales/tr/components/player.json b/web/public/locales/tr/components/player.json new file mode 100644 index 000000000..6a7950369 --- /dev/null +++ b/web/public/locales/tr/components/player.json @@ -0,0 +1,51 @@ +{ + "streamOffline": { + "title": "Yayın Çevrimdışı", + "desc": "{{cameraName}} isimli kameranın tespit akışından hiç bir görüntü alınamadı, hata günlüklerini kontrol edin" + }, + "stats": { + "streamType": { + "title": "Yayın Türü:", + "short": "Tür" + }, + "latency": { + "value": "{{seconds}} saniye", + "short": { + "title": "Gecikme", + "value": "{{seconds}} sn" + }, + "title": "Gecikme:" + }, + "bandwidth": { + "title": "Bant genişliği:", + "short": "Bant genişliği" + }, + "decodedFrames": "Çözülen kareler:", + "droppedFrameRate": "Atlanan Kare Oranı:", + "totalFrames": "Toplam Kareler:", + "droppedFrames": { + "short": { + "title": "Atlanan", + "value": "{{droppedFrames}} kare" + }, + "title": "Atlanan Kareler:" + } + }, + "noPreviewFound": "Önizleme Bulunamadı", + "toast": { + "success": { + "submittedFrigatePlus": "Kare başarıyla Frigate+'a gönderildi" + }, + "error": { + "submitFrigatePlusFailed": "Kare Frigate+'a gönderilemedi" + } + }, + "noRecordingsFoundForThisTime": "Bu zaman aralığı için kayıt bulunamadı", + "cameraDisabled": "Kamera devre dışı bırakıldı", + "noPreviewFoundFor": "{{cameraName}} için Önizleme Bulunamadı", + "livePlayerRequiredIOSVersion": "Bu canlı yayın türü için iOS 17.1 veya daha yeni sürüm gereklidir.", + "submitFrigatePlus": { + "title": "Bu kare Frigate+'ya gönderilsin mi?", + "submit": "Gönder" + } +} diff --git a/web/public/locales/tr/objects.json b/web/public/locales/tr/objects.json new file mode 100644 index 000000000..fb07a0965 --- /dev/null +++ b/web/public/locales/tr/objects.json @@ -0,0 +1,120 @@ +{ + "dog": "köpek", + "cat": "kedi", + "animal": "hayvan", + "bark": "havlama", + "blender": "mikser", + "mouse": "fare", + "door": "kapı", + "sink": "lavabo", + "boat": "bot", + "skateboard": "kaykay", + "sheep": "koyun", + "bicycle": "bisiklet", + "motorcycle": "motosiklet", + "bird": "kuş", + "car": "araba", + "bus": "otobüs", + "goat": "keçi", + "hair_dryer": "saç kurutma makinesi", + "clock": "saat", + "scissors": "makas", + "vehicle": "araç", + "keyboard": "klavye", + "toothbrush": "diş fırçası", + "horse": "at", + "train": "tren", + "handbag": "El Çantası", + "umbrella": "Şemsiye", + "shoe": "Ayakkabı", + "eye_glasses": "Gözlük", + "desk": "Masa", + "remote": "Uzaktan Kumanda", + "refrigerator": "Buzdolabı", + "book": "Kitap", + "hair_brush": "Saç Fırçası", + "squirrel": "Sincap", + "waste_bin": "Çöp Kutusu", + "face": "Yüz", + "license_plate": "Araç Plakası", + "an_post": "An Post", + "sandwich": "Sandviç", + "couch": "Koltuk", + "baseball_glove": "Beyzbol Eldiveni", + "donut": "Donut", + "bed": "Yatak", + "backpack": "Sırt Çantası", + "parking_meter": "Parkmetre", + "stop_sign": "Dur Tabelası", + "person": "İnsan", + "bear": "Ayı", + "hat": "Şapka", + "orange": "Portakal", + "dining_table": "Yemek Masası", + "traffic_light": "Trafik Lambası", + "giraffe": "Zürafa", + "fire_hydrant": "Yangın Musluğu", + "street_sign": "Sokak Tabelası", + "mirror": "Ayna", + "banana": "Muz", + "carrot": "Havuç", + "pizza": "Pizza", + "vase": "Vazo", + "nzpost": "NZPost", + "bench": "Bank", + "elephant": "Fil", + "spoon": "Kaşık", + "laptop": "Dizüstü Bilgisayar", + "frisbee": "Frizbi", + "skis": "Kayak", + "kite": "Uçurtma", + "bottle": "Şişe", + "cup": "Fincan", + "knife": "Bıçak", + "bowl": "Kase", + "package": "Paket", + "airplane": "Uçak", + "snowboard": "Kar Kayağı", + "usps": "USPS", + "ups": "UPS", + "cow": "İnek", + "zebra": "Zebra", + "suitcase": "Bavul", + "sports_ball": "Spor Topu", + "baseball_bat": "Beyzbol Sopası", + "surfboard": "Sörf Tahtası", + "plate": "Plaka", + "broccoli": "Brokoli", + "tv": "Televizyon", + "cell_phone": "Cep Telefonu", + "teddy_bear": "Ayıcık", + "deer": "Geyik", + "fox": "Tilki", + "purolator": "Purolator", + "fork": "Çatal", + "toilet": "Tuvalet", + "window": "Pencere", + "microwave": "Mikrodalga Fırın", + "hot_dog": "Sosisli Sandviç", + "wine_glass": "Şarap Bardağı", + "cake": "Kek", + "potted_plant": "Saksı Bitkisi", + "bbq_grill": "Izgara", + "tennis_racket": "Tenis Raketi", + "dhl": "DHL", + "raccoon": "Rakun", + "robot_lawnmower": "Robot Çim Biçme Makinesi", + "toaster": "Tost Makinesi", + "apple": "Elma", + "amazon": "Amazon", + "rabbit": "Tavşan", + "chair": "Sandalye", + "postnl": "PostNL", + "oven": "Fırın", + "fedex": "FedEx", + "on_demand": "İstenildiğinde", + "tie": "Kravat", + "dpd": "DPD", + "gls": "GLS", + "postnord": "PostNord" +} diff --git a/web/public/locales/tr/views/configEditor.json b/web/public/locales/tr/views/configEditor.json new file mode 100644 index 000000000..5a3133c7c --- /dev/null +++ b/web/public/locales/tr/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "saveOnly": "Sadece Kaydet", + "toast": { + "error": { + "savingError": "Yapılandırma kaydedilirken hata" + }, + "success": { + "copyToClipboard": "Yapılandırma panoya kopyalandı." + } + }, + "copyConfig": "Yapılandırmayı Kopyala", + "configEditor": "Yapılandırma Düzenleyicisi", + "documentTitle": "Yapılandırma Düzenleyicisi - Frigate", + "saveAndRestart": "Kaydet & Yeniden Başlat" +} diff --git a/web/public/locales/tr/views/events.json b/web/public/locales/tr/views/events.json new file mode 100644 index 000000000..2358dd7b5 --- /dev/null +++ b/web/public/locales/tr/views/events.json @@ -0,0 +1,37 @@ +{ + "camera": "kamera", + "alerts": "Alarmlar", + "detections": "Tespitler", + "empty": { + "detection": "İncelenecek tespit öğesi yok", + "alert": "İncelenecek alarm öğesi yok", + "motion": "Hareket verisi bulunamadı" + }, + "timeline": "Zaman şeridi", + "events": { + "aria": "Olayları seçin", + "noFoundForTimePeriod": "Seçili zaman aralığında olay bulunamadı.", + "label": "Olaylar" + }, + "recordings": { + "documentTitle": "Kayıtlar - Frigate" + }, + "calendarFilter": { + "last24Hours": "Son 24 Saat" + }, + "markAsReviewed": "İncelendi Olarak İşaretle", + "newReviewItems": { + "button": "Yeni İncelenecek Öğeler Var", + "label": "Yeni inceleme öğelerini göster" + }, + "documentTitle": "İncele - Frigate", + "motion": { + "label": "Hareket", + "only": "Yalnızca hareket" + }, + "timeline.aria": "Zaman şeridi seçin", + "markTheseItemsAsReviewed": "Bunları incelendi olarak işaretle", + "allCameras": "Tüm Kameralar", + "selected_one": "{{count}} seçildi", + "selected_other": "{{count}} seçildi" +} diff --git a/web/public/locales/tr/views/explore.json b/web/public/locales/tr/views/explore.json new file mode 100644 index 000000000..73b7031ee --- /dev/null +++ b/web/public/locales/tr/views/explore.json @@ -0,0 +1,200 @@ +{ + "documentTitle": "Keşfet - Frigate", + "details": { + "timestamp": "Zaman Damgası", + "item": { + "title": "Nesne Detaylarını İncele", + "desc": "Nesne detaylarıın incele", + "button": { + "share": "Bu incele öğesini paylaş", + "viewInExplore": "Keşfet'te Görüntüle" + }, + "tips": { + "hasMissingObjects": "Eğer Frigate'in {{objects}} etiketine sahip nesneleri kaydetmesini istiyorsanız yapılandırmanızı buna göre ayarlayın.", + "mismatch_one": "Tespit edilmiş olan bir nesne bu İncele öğesine dahil edildi. Bu nesne Alarm veya Tespit olarak derecelendirilemedi veya çoktan silindi/temizlendi.", + "mismatch_other": "Tespit edilmiş olan {{count}} adet nesne bu İncele öğesine dahil edildi. Bu nesneler Alarm veya Tespit olarak derecelendirilemedi veya çoktan silindi/temizlendi." + }, + "toast": { + "success": { + "updatedSublabel": "Alt etiket başarıyla gücellendi.", + "regenerate": "Yeni bir açıklama {{provider}} sağlayıcısından talep edildi. Sağlayıcının hızına bağlı olarak yeni açıklamanın oluşturulması biraz zaman alabilir.", + "updatedLPR": "Plaka başarıyla güncellendi." + }, + "error": { + "updatedSublabelFailed": "Alt etiket güncellenemedi: {{errorMessage}}", + "regenerate": "{{provider}} sağlayıcısından yeni açıklama talep edilemedi: {{errorMessage}}", + "updatedLPRFailed": "Plaka güncellenemedi: {{errorMessage}}" + } + } + }, + "label": "Etiket", + "editSubLabel": { + "desc": "Bu {{label}} için yeni bir alt etiket girin", + "descNoLabel": "Bu takip edilmiş nesne için yeni bir alt etiket girin", + "title": "Alt etiketi gücelle" + }, + "estimatedSpeed": "Tahmini Hız", + "camera": "Kamera", + "zones": "Alanlar", + "description": { + "label": "Açıklama", + "aiTips": "Frigate, Nesne Geçmişi tamamlanana kadar Üretken Yapay Zeka sağlayıcısından bir resim açıklaması talep etmeyecektir.", + "placeholder": "Takip edilen nesnenin açıklaması" + }, + "expandRegenerationMenu": "Yeniden Üret menüsünü genişlet", + "regenerateFromSnapshot": "Fotoğraftan Üret", + "regenerateFromThumbnails": "Küçük Resimden Üret", + "tips": { + "descriptionSaved": "Açıklama başarıyla kaydedildi", + "saveDescriptionFailed": "Açıklama güncellenemedi: {{errorMessage}}" + }, + "button": { + "regenerate": { + "label": "Nesne açıklaması yeniden üretildi", + "title": "Yeniden Üret" + }, + "findSimilar": "Benzerini Bul" + }, + "topScore": { + "info": "Tepe skor, bir takip edilen nesne için en yüksek ortalama puandır ve arama sonucundaki küçük resimde gösterilen puandan farklı olabilir.", + "label": "Tepe Skor" + }, + "objects": "Nesneler", + "editLPR": { + "title": "Plakayı düzenle", + "desc": "Bu {{label}} için yeni bir plaka değeri girin", + "descNoLabel": "Bu nesne için yeni bir plaka değeri girin" + }, + "recognizedLicensePlate": "Tanınan Plaka", + "snapshotScore": { + "label": "Fotoğraf Skoru" + } + }, + "generativeAI": "Üretken Yapay Zeka", + "exploreIsUnavailable": { + "title": "Keşfet şu anda kullanılamıyor", + "embeddingsReindexing": { + "startingUp": "Başlatılıyor…", + "estimatedTime": "Tahmini kalan süre:", + "step": { + "thumbnailsEmbedded": "Gömü eklenen küçük resimler: ", + "descriptionsEmbedded": "Gömü eklenen açıklamalar: ", + "trackedObjectsProcessed": "İşlenen takip edilen nesneler: " + }, + "finishingShortly": "Birazdan tamamlanacak", + "context": "Keşfet sayfası nesnelerin gömülerinin yeniden dizinlemesi tamamlandığında kullanılabilecektir." + }, + "downloadingModels": { + "setup": { + "visionModel": "Görüş modeli", + "visionModelFeatureExtractor": "Görüş modeli özellik çıkarmcısı", + "textModel": "Metin modeli", + "textTokenizer": "Metin tokenizeri" + }, + "error": "Bir hata oluştu. Frigate günlüklerini kontrol edin.", + "tips": { + "documentation": "Dökümantasyonu oku", + "context": "Model indirildikten sonra takip edilmiş nesnelerinizin gömüleri tekrar dizinlemeyi tercih edebilirsiniz." + }, + "context": "Frigate, Anlamsal Arama özelliği için gerekli olan gömü modellerini indiriyor. Ağ bağlantınızın hızına göre bu işlem bir kaç dakika sürebilir." + } + }, + "trackedObjectDetails": "Takip Edilen Nesne Detayları", + "type": { + "details": "detaylar", + "object_lifecycle": "nesne geçmişi", + "snapshot": "fotoğraf", + "video": "video" + }, + "objectLifecycle": { + "title": "Nesne Geçmişi", + "noImageFound": "Bu zaman damgası için bir resim bulunamadı.", + "createObjectMask": "Nesne Maskesi Oluştur", + "adjustAnnotationSettings": "Belirteç ayarları", + "lifecycleItemDesc": { + "visible": "{{label}} tespit edildi", + "entered_zone": "{{label}} {{zones}} alanına girdi", + "active": "{{label}} inaktif oldu", + "heard": "{{label}} duyuldu", + "external": "{{label}} tespit edildi", + "stationary": "{{label}} sabit durdu", + "attribute": { + "other": "{{label}} {{attribute}} olarak tespit edildi", + "faceOrLicense_plate": "{{label}} için {{attribute}} tespit edildi" + }, + "gone": "{{label}} ayrıldı", + "header": { + "zones": "Alanlar", + "ratio": "Oran", + "area": "Alan" + } + }, + "annotationSettings": { + "offset": { + "label": "Belirteç telafisi", + "documentation": "Dökümantasyonu oku ", + "millisecondsToOffset": "Belirteç gecikmesi. Varsayılan: 0", + "desc": "Tespit belirteç verisi kameranızın tespit yayınından gelir fakat kameranızın kayıt yayını üzerine çizilir. Bu iki yayın zaman zaman senkrondan kayar. Bunun sonucu olarak görüntü ve belirteç karelerinin zaman uyumu kayabilir. Bunu telafi etmek için annotation_offset alanı kullanılarak gecikmeyi ayarlanabilir.", + "tips": "İPUCU: Videoda bir kişinin soldan sağa doğru yürüdüğünü hayal edin. Eğer belirteç sürekli olarak kişinin solunda/arkasında ise bu değer daha küçük veya negatif olarak ayarlanmalıdır. Benzer şekilde, eğer kişi sağdan sola doğru yürürken belirteç karesi sürekli olarak kişinin önünde/sağında kalıyorsa bu değer daha büyük veya pozitif olarak ayarlanmalıdır." + }, + "title": "Belirteç Ayarları", + "showAllZones": { + "title": "Tüm Alanları Göster", + "desc": "Nesnelerin bir alana girdiği karelerde her zaman alanları göster." + } + }, + "carousel": { + "next": "Sonraki sayfa", + "previous": "Önceki sayfa" + }, + "scrollViewTips": "Bu nesnenin geçmişindeki önemli noktaları görmek için kaydırın.", + "autoTrackingTips": "Otomatik takip yapılan kameralarda gösterilen çerçeveler hatalı olacaktır." + }, + "itemMenu": { + "downloadVideo": { + "label": "Videoyu indir", + "aria": "Videoyu indir" + }, + "findSimilar": { + "aria": "Benzer takip edilen nesneleri bul", + "label": "Benzerini bul" + }, + "submitToPlus": { + "label": "Frigate+'a gönder", + "aria": "Frigate+'a gönder" + }, + "viewInHistory": { + "label": "Geçmiş görünümünde görüntüle", + "aria": "Geçmiş görünümünde görüntüle" + }, + "deleteTrackedObject": { + "label": "Bu takip edilen nesneyi sil" + }, + "viewObjectLifecycle": { + "aria": "Nesne yaşam döngüsünü göster", + "label": "Nesne yaşam döngüsünü göster" + }, + "downloadSnapshot": { + "aria": "Fotoğrafı indir", + "label": "Fotoğrafı indir" + } + }, + "noTrackedObjects": "Takip Edilen Nesne Bulunamadı", + "fetchingTrackedObjectsFailed": "Takip edilen nesneler getirilirken hata: {{errorMessage}}", + "searchResult": { + "deleteTrackedObject": { + "toast": { + "error": "Takip edilen nesne silinemedi: {{errorMessage}}", + "success": "Takip edilen nesne başarıyla silindi." + } + } + }, + "dialog": { + "confirmDelete": { + "desc": "Bu takip edilen nesneyi silmek nesne fotoğrafını, ilişkili gömüyü ve ilişkili yaşam döngüsü kayıtlarını siler. Video kayıt görüntüleri geçmiş görünümünden SİLİNMEYECEKTİR.

    Devam etmek istediğinize emin misiniz?", + "title": "Silmeyi onayla" + } + }, + "trackedObjectsCount_one": "{{count}} adet takip edilen nesne ", + "trackedObjectsCount_other": "{{count}} adet takip edilen nesne " +} diff --git a/web/public/locales/tr/views/exports.json b/web/public/locales/tr/views/exports.json new file mode 100644 index 000000000..3a1d19512 --- /dev/null +++ b/web/public/locales/tr/views/exports.json @@ -0,0 +1,17 @@ +{ + "search": "Arama", + "documentTitle": "Dışa Aktar - Frigate", + "deleteExport": "Dışa Aktarımı Sil", + "deleteExport.desc": "{{exportName}} adlı dışa aktarımı silmek istediğinize emin misiniz?", + "editExport": { + "saveExport": "Dışa Aktarımı Kaydet", + "desc": "Bu dışa aktarım için yeni bir isim girin.", + "title": "Dışa Aktarımı Yeniden Adlandır" + }, + "toast": { + "error": { + "renameExportFailed": "Dışa aktarım adlandırılamadı: {{errorMessage}}" + } + }, + "noExports": "Dışa aktarım bulunamadı" +} diff --git a/web/public/locales/tr/views/faceLibrary.json b/web/public/locales/tr/views/faceLibrary.json new file mode 100644 index 000000000..29668ac3b --- /dev/null +++ b/web/public/locales/tr/views/faceLibrary.json @@ -0,0 +1,84 @@ +{ + "selectItem": "{{item}} seçin", + "description": { + "placeholder": "Bu koleksiyona bir isim verin", + "addFace": "Yüz Kütüphanesi’ne yeni bir koleksiyon ekleme adımlarını takip edin." + }, + "details": { + "person": "İnsan", + "faceDesc": "Yüz ve ilişkili nesneye ait detaylar", + "confidence": "Kesinlik", + "timestamp": "Zaman Damgası", + "face": "Yüz Detayları" + }, + "documentTitle": "Yüz Kütüphanesi - Frigate", + "uploadFaceImage": { + "title": "Yüz Resmi Yükle", + "desc": "Yüzleri taramak ve {{pageToggle}} için dahil etmek üzere bir resim yükleyin" + }, + "createFaceLibrary": { + "desc": "Yeni bir yüz koleksiyonu oluşturun", + "new": "Yeni Yüz Oluştur", + "title": "Koleksiyon Oluştur", + "nextSteps": "Sağlam bir temel oluşturmak için:
  • Her tespit edilen kişi için 'Eğit' sekmesinden resimler seçip eğitin.
  • En iyi sonuçlar için doğrudan karşıdan çekilmiş yüz resimlerine odaklanın; açılı yüz resimlerinden kaçının.
  • " + }, + "train": { + "title": "Eğit", + "aria": "Eğitimi seç" + }, + "deleteFaceLibrary": { + "title": "İsmi Sil", + "desc": "{{name}} koleksiyonunu silmek istediğinizden emin misiniz? Bu işlem, ilişkili tüm yüzleri kalıcı olarak silecektir." + }, + "button": { + "deleteFaceAttempts": "Yüz Denemelerini Sil", + "addFace": "Yüz Ekle", + "reprocessFace": "Yüzü Yeniden İşle", + "uploadImage": "Resim Yükle", + "renameFace": "Yüzü Yeniden Adlandır", + "deleteFace": "Yüzü Sil" + }, + "imageEntry": { + "dropActive": "Resmi buraya bırakın…", + "maxSize": "Maksimum boyut: {{size}} MB", + "validation": { + "selectImage": "Lütfen bir resim dosyası seçin." + }, + "dropInstructions": "Bir resmi buraya sürükleyip bırakın ya da tıklayarak seçin" + }, + "trainFaceAs": "Yüzü şu olarak eğit:", + "toast": { + "success": { + "deletedFace_one": "{{count}} yüz başarıyla silindi.", + "deletedFace_other": "{{count}} yüz başarıyla silindi.", + "deletedName_one": "{{count}} yüz başarıyla silindi.", + "deletedName_other": "{{count}} yüz başarıyla silindi.", + "addFaceLibrary": "{{name}} başarıyla Yüz Kütüphanesi’ne eklendi!", + "trainedFace": "Yüz başarıyla eğitildi.", + "uploadedImage": "Resim başarıyla yüklendi.", + "updatedFaceScore": "Yüz skoru başarıyla güncellendi.", + "renamedFace": "Yüz başarıyla {{name}} olarak adlandırıldı" + }, + "error": { + "uploadingImageFailed": "Resim yüklenemedi: {{errorMessage}}", + "addFaceLibraryFailed": "Yüz ismi ayarlanamadı: {{errorMessage}}", + "updateFaceScoreFailed": "Yüz skoru güncellenemedi: {{errorMessage}}", + "trainFailed": "Eğitme işlemi başarısız oldu: {{errorMessage}}", + "deleteFaceFailed": "Silme işlemi başarısız: {{errorMessage}}", + "deleteNameFailed": "İsim silinemedi: {{errorMessage}}", + "renameFaceFailed": "Yüz yeniden adlandırılamadı: {{errorMessage}}" + } + }, + "readTheDocs": "Dokümantasyonu oku", + "selectFace": "Yüz Seçin", + "trainFace": "Yüzü Eğit", + "steps": { + "faceName": "Yüze İsim Verin", + "uploadFace": "Yüz Resmi Yükle", + "nextSteps": "Sonraki Adımlar" + }, + "renameFace": { + "title": "Yüzü Yeniden Adlandır", + "desc": "{{name}} için yeni bir isim girin" + } +} diff --git a/web/public/locales/tr/views/live.json b/web/public/locales/tr/views/live.json new file mode 100644 index 000000000..88f040856 --- /dev/null +++ b/web/public/locales/tr/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "Canlı - Frigate", + "documentTitle.withCamera": "{{camera}} - Canlı - Frigate", + "muteCameras": { + "disable": "Tüm Kameraların Sesini Aç", + "enable": "Tüm Kameraları Sustur" + }, + "autotracking": { + "disable": "Otomatik Takibi Kapat", + "enable": "Otomatik Takibi Aç" + }, + "manualRecording": { + "start": "Talep üzerine kaydı başlat", + "failedToEnd": "Manuel talep üzerine kayıt bitirilemedi.", + "recordDisabledTips": "Kamera konfigürasyonunda kayıtlar devre dışı bırakıldığı veya kısıtlandığı için yalnızca bir fotoğraf kaydedilcektir.", + "showStats": { + "desc": "Yayın istatistiklerini göstermek için bu seçeneği açın.", + "label": "İstatistikleri Göster" + }, + "started": "Manuel talep üzerine kayıt başlatıldı.", + "failedToStart": "Manuel talep üzerine kayıt başlatılamadı.", + "title": "İsteğe Bağlı Kayıt", + "end": "Talep üzerine kaydı bitir", + "debugView": "Hata Ayıklama Görünümü", + "ended": "Manuel talep üzerine kayıt bitirildi.", + "tips": "Bu kameranın kayıt tutma ayarları kapsamında manuel olarak bir olay başlatın.", + "playInBackground": { + "label": "Arka planda oynat", + "desc": "Yayını oynatıcı arkadayken de devam ettirmek için bu seçeneği açın." + } + }, + "stream": { + "audio": { + "tips": { + "documentation": "Dökümantasyonu oku ", + "title": "Bu yayın için kameranızın yayın çıkışında ses olması ve go2rtc'de ayarlanmış olması gerekmektedir." + }, + "unavailable": "Bu yayında ses yok", + "available": "Bu yayında ses var" + }, + "twoWayTalk": { + "tips": "Çift yönlü ses için cihazınızın ve kameranızın bu özelliği desteklemesi ve WebRTC'nin ayarlanmış olması gereklidir.", + "tips.documentation": "Dökümantasyonu oku ", + "available": "Bu yayında çift yönlü ses var", + "unavailable": "Bu yayında çift yönlü ses yok" + }, + "lowBandwidth": { + "tips": "Canlı görünüm, yayında donmalar veya yayın hataları sebebiyle düşük bant genişliği moduna geçti.", + "resetStream": "Yayını sıfırla" + }, + "playInBackground": { + "label": "Arka planda oynat", + "tips": "Yayını oynatıcı arkadayken de devam ettirmek için bu seçeneği açın." + }, + "title": "Yayın" + }, + "cameraSettings": { + "recording": "Kayıt", + "snapshots": "Fotoğraflar", + "title": "{{camera}} Ayarları", + "autotracking": "Otomatik Takip", + "cameraEnabled": "Kamera Açık", + "objectDetection": "Nesne Algılama", + "audioDetection": "Ses Algılama" + }, + "effectiveRetainMode": { + "modes": { + "active_objects": "Aktif nesneler", + "all": "Tümü", + "motion": "Hareket" + }, + "notAllTips": "İlgili {{source}} kaynağındaki kayıt saklama politikanız şu moda ayarlı: {{effectiveRetainMode}}. Dolayısıyla şu anda gerçekleştirdiğiniz manuel talep üzerine kayıtta yalnızca {{effectiveRetainModeName}} içeren bölümler yer alacaktır." + }, + "editLayout": { + "label": "Düzeni düzenle", + "group": { + "label": "Kamera Grubunu Düzenle" + }, + "exitEdit": "Düzenlemeden Çık" + }, + "cameraAudio": { + "enable": "Kamera sesini aç", + "disable": "Kamera sesini kapat" + }, + "ptz": { + "move": { + "clickMove": { + "enable": "Tıklamayla gezintiyi aç", + "disable": "Tıklamayla gezintiyi kapat", + "label": "Kamerayı ortalamak için görüntüye tıklatın" + }, + "down": { + "label": "PTZ kamerayı aşağı çevir" + }, + "right": { + "label": "PTZ kamerayı sağa çevir" + }, + "left": { + "label": "PTZ kameryı sağa çevir" + }, + "up": { + "label": "PTZ kamerayı yukarı çevir" + } + }, + "zoom": { + "out": { + "label": "PTZ kamerayı uzaklaştır" + }, + "in": { + "label": "PTZ kamerayı yakınlaştır" + } + }, + "presets": "PTZ kamera ön ayarları", + "frame": { + "center": { + "label": "PTZ kamerayı ortalamak için görüntüye tıklatın" + } + } + }, + "history": { + "label": "Geçmiş görüntüleri göster" + }, + "camera": { + "enable": "Kamerayı aç", + "disable": "Kamerayı kapat" + }, + "suspend": { + "forTime": "Askıya alınma süresi: " + }, + "twoWayTalk": { + "disable": "Çift yönli sesi kapat", + "enable": "Çift yönli sesi aç" + }, + "snapshots": { + "enable": "Resimleri Aç", + "disable": "Resimleri Kapat" + }, + "audioDetect": { + "enable": "Ses Tespitini Aç", + "disable": "Ses Tespitini Kapat" + }, + "streamStats": { + "disable": "Yayın İstatistiklerini Gizel", + "enable": "Yayın İstatistiklerini Göster" + }, + "lowBandwidthMode": "Düşük bant genişliği modu", + "streamingSettings": "Yayın ayarları", + "audio": "Ses", + "recording": { + "enable": "Kaydı Aç", + "disable": "Kaydı Kapat" + }, + "notifications": "Bildirimler", + "detect": { + "disable": "Tespiti Kapat", + "enable": "Tespiti Aç" + } +} diff --git a/web/public/locales/tr/views/recording.json b/web/public/locales/tr/views/recording.json new file mode 100644 index 000000000..c113d368f --- /dev/null +++ b/web/public/locales/tr/views/recording.json @@ -0,0 +1,12 @@ +{ + "filter": "Filtre", + "export": "Dışa Aktar", + "filters": "Filtreler", + "toast": { + "error": { + "noValidTimeSelected": "Geçerli bir zaman aralığı seçilmedi", + "endTimeMustAfterStartTime": "Bitiş zamanı başlangıç zamanında sonra olmalıdır" + } + }, + "calendar": "Takvim" +} diff --git a/web/public/locales/tr/views/search.json b/web/public/locales/tr/views/search.json new file mode 100644 index 000000000..059023308 --- /dev/null +++ b/web/public/locales/tr/views/search.json @@ -0,0 +1,74 @@ +{ + "button": { + "save": "Aramayı kaydet", + "filterActive": "Fitreler açık", + "filterInformation": "Filtrele", + "clear": "Aramayı temizle", + "delete": "Kayıtlı aramayı sil" + }, + "trackedObjectId": "Takip Edilen Nesne ID", + "filter": { + "label": { + "min_score": "Min. Skor", + "recognized_license_plate": "Tanınan Plaka", + "search_type": "Arama Türü", + "has_snapshot": "Fotoğrafı var", + "cameras": "Kameralar", + "max_score": "Maks. Skor", + "labels": "Etiketler", + "time_range": "Zaman Aralığı", + "before": "Önce", + "zones": "Alanlar", + "after": "Sonras", + "has_clip": "Klibi var", + "min_speed": "Min. Hız", + "sub_labels": "Alt Etiketler", + "max_speed": "Maks. Hız" + }, + "searchType": { + "description": "Açıklama", + "thumbnail": "Küçük resim" + }, + "tips": { + "title": "Metin filtreleri nasıl kullanılır", + "desc": { + "text": "Filtreler arama sonuçlarınızı daraltmanıza yardımcı olur. Giriş alanındaki kullanımları şöyledir:", + "step": "
    • Bir filtre adı yazın ve iki nokta üst üste (:) ile bitirin (örn. \"kameralar:\").
    • Önerilerden bir değer seçin veya kendiniz yazın.
    • Birden fazla filtreyi aralarına boşluk koyarak art arda ekleyip kullanın.
    • Tarih filtreleri (before: ve after:) {{DateFormat}} biçimini kullanır.
    • Zaman aralığı filtresi {{exampleTime}} biçimini kullanır.
    • Filtreleri kaldırmak için yanlarındaki 'x'e tıklayın.
    ", + "example": "Örnek(anahtar kelimeler ingilizce olmalıdır): cameras:front_door label:person before:01012024 time_range:3:00PM-4:00PM ", + "exampleLabel": "Örnek:", + "step1": "Bir filtre anahtarını iki nokta üst üste ile beraber yazın (örn. belli kameraları seçmek için \"cameras:\").", + "step2": "Önerilen bir değer seçin veya kendiniz girin.", + "step3": "Birden fazla filtreyi aralarında boşluk bırakarak kullanabilirsiniz.", + "step4": "Tarih filtreleri (before: ve after:) {{DateFormat}} formatını kullanır.", + "step5": "Zaman aralığı filtreleri {{exampleTime}} formatını kullanır.", + "step6": "Filtreleri kaldırmak için yanlarındaki çarpıya basın." + } + }, + "toast": { + "error": { + "beforeDateBeLaterAfter": "'Önce' tarihi 'sonra' tarihinden sonra olmalıdır.", + "maxScoreMustBeGreaterOrEqualMinScore": "Maksimum skor, minimum skora eşit veya daha fazla olmalıdır.", + "minScoreMustBeLessOrEqualMaxScore": "Minimum skor, maksimum skora eşit veya daha az olmalıdır.", + "afterDatebeEarlierBefore": "'Sonra' tarihi 'Önce' tarihinden önce olmalıdır.", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "Maksimum hız, minimum hıza eşit veya daha fazla olmalıdır.", + "minSpeedMustBeLessOrEqualMaxSpeed": "Minimum hız, maksimum hıza eşit veya daha az olmalıdır." + } + }, + "header": { + "noFilters": "Filtreler", + "activeFilters": "Aktif Filtreler", + "currentFilterType": "Değerleri Filtrele" + } + }, + "placeholder": { + "search": "Ara…" + }, + "similaritySearch": { + "active": "Benzerlik araması aktif", + "title": "Benzerlik Araması", + "clear": "Benzerlik aramasını temizle" + }, + "searchFor": "{{inputValue}} için Arat", + "search": "Arama", + "savedSearches": "Kayıtlı Aramalar" +} diff --git a/web/public/locales/tr/views/settings.json b/web/public/locales/tr/views/settings.json new file mode 100644 index 000000000..d7cac3d2b --- /dev/null +++ b/web/public/locales/tr/views/settings.json @@ -0,0 +1,595 @@ +{ + "documentTitle": { + "default": "Ayarlar - Frigate", + "classification": "Sınıflandırma Ayarları - Frigate", + "camera": "Kamera Ayarları - Frigate", + "masksAndZones": "Maske ve Alan Düzenleyici - Frigate", + "authentication": "Kimlik Doğrulama Ayarları - Frigate", + "motionTuner": "Hareket Algılama Ayarları - Frigate", + "frigatePlus": "Frigate+ Ayarları - Frigate", + "object": "Nesne Ayarları - Frigate", + "general": "Genel Ayarlar - Frigate" + }, + "menu": { + "masksAndZones": "Maskeler / Alanlar", + "users": "Kullanıcılar", + "frigateplus": "Frigate+", + "ui": "Arayüz", + "notifications": "Bildirimler", + "motionTuner": "Hareket Algılama", + "classification": "Sınıflandırma", + "debug": "Hata Ayıklama", + "cameras": "Kamera Ayarları" + }, + "general": { + "title": "Genel Ayarlar", + "liveDashboard": { + "automaticLiveView": { + "label": "Otomatik Canlı Görünüm", + "desc": "Aktivite tespit edildiğinde otomatik olarak kameranın canlı akışına geç. Bu seçeneği devre dışı bırakmak canlı görüntü panelinde dakikada bir güncellenen sabit resim gösterilmesine sebep olur." + }, + "playAlertVideos": { + "label": "Alarm Videolarını Oynat", + "desc": "Varsayılan olarak canlı görüntü panelinde gösterilen son alarmlar ufak videolar olarak oynatılır. Bu tarayıcı/cihazda video yerine sabit resim göstermek için bu seçeneği kapatın." + }, + "title": "Canlı Görüntü Paneli" + }, + "storedLayouts": { + "desc": "Kamera grubundaki kameraların düzenini kameraları sürükleyerek ve büyüterek/küçülterek değiştirebilirsiniz. Düzen bilgisi tarayıcınızda depolanır.", + "clearAll": "Tüm Düzenleri Temizle", + "title": "Kayıtlı Düzenler" + }, + "cameraGroupStreaming": { + "title": "Kamera Grubu Yayın Ayarları", + "desc": "Kamera gruplarının ilgili yayın ayarları tarayıcınızda depolanır.", + "clearAll": "Tüm Yayın Ayarlarını Temizle" + }, + "recordingsViewer": { + "defaultPlaybackRate": { + "label": "Varsayılan Oynatma Hızı", + "desc": "Kayıt oynatılırken kullanılan varsayılan oynatma hızı." + }, + "title": "Kayıt Görüntüleyicisi" + }, + "calendar": { + "firstWeekday": { + "sunday": "Pazar", + "desc": "Arayüzdeki takvimde gösterilecek haftanın ilk günü.", + "label": "Haftanın ilk günü", + "monday": "Pazartesi" + }, + "title": "Takvim" + }, + "toast": { + "success": { + "clearStreamingSettings": "Tüm kamera grupları için yayın ayarları temizlendi.", + "clearStoredLayout": "{{cameraName}} için kayıtlı düzenler temizlendi" + }, + "error": { + "clearStreamingSettingsFailed": "Yayın ayarları temizlenemedi: {{errorMessage}}", + "clearStoredLayoutFailed": "Kayıtlı düzen temizlenemedi: {{errorMessage}}" + } + } + }, + "classification": { + "title": "Sınıflandırma Ayarları", + "semanticSearch": { + "title": "Anlamsal Arama", + "readTheDocumentation": "Dökümantasyonu Oku", + "reindexNow": { + "confirmButton": "Yeniden Dizinle", + "label": "Şimdi Yeniden Dizinle", + "desc": "Yeniden dizinleme bütün takip edilen nesneler için gömüleri tekrar oluşturur. Bu işlem arka planda çalışacak olsa da nesne sayısına göre işlemcinizi tamamen kullanabilir ve tamamlanması biraz zaman alabilir.", + "alreadyInProgress": "Yeniden dizinleme zaten devam ediyor.", + "confirmTitle": "Yenden Dizinlemeyi onayla", + "success": "Yeniden dizinleme başladı.", + "confirmDesc": "Takip edilen bütün objelerin gömülerini yeniden dizinlemek istediğinze emin misiniz? Bu işlem arka planda çalışacak fakat işlemcinizi tamamen kullanabilir ve tamamlanması biraz zaman alabilir. İlerlemeyi Keşfet sayfasından takip edebilirsiniz.", + "error": "Yeniden dizinlemeye başlanamadı: {{errorMessage}}" + }, + "modelSize": { + "label": "Model boyutu", + "large": { + "title": "büyük", + "desc": "Büyük modeli kullandığınızda tam boyutlu Jina modeli kullanılacaktır ve uygunsa otomatik olarak grafik işlemcisinde çalıştırılacaktır." + }, + "small": { + "desc": "Küçük modeli kullandığınızda modelin kuantize edilmiş bir sürümü kullanılır. Bu model daha az RAM kullanır, işlemcilerde daha hızlı çalışır ve gömü kalitesinde neredeyse hiç kalite farkı yoktur.", + "title": "küçük" + }, + "desc": "Anlamsal arama için kullanılan dil modelinin büyüklüğü." + }, + "desc": "Frigate'daki Anlamsal Arama özelliği inceleme öğelerinizde takip edilen nesneleri bizzat nesnenin resmi ile aratarak ya da otomatik olarak veya kullanıcı tarafından yazılmış bir metin açıklaması içinde aratarak bulmanıza imkan sağlar." + }, + "faceRecognition": { + "modelSize": { + "large": { + "desc": "Büyük modeli kullandığınızda tam boyutlu ArcFace yüz gömü modeli kullanılacaktır ve uygunsa otomatik olarak grafik işlemcisinde çalıştırılacaktır.", + "title": "büyük" + }, + "small": { + "title": "küçük", + "desc": "Küçük modeli kullandığınızda çoğu işlemcide verimli bir şekilde çalışan bir FaceNet yüz gömme modeli kullanılır." + }, + "label": "Model Boyutu", + "desc": "Yüz tanıma için kullanılan modelin boyutu." + }, + "title": "Yüz Tanıma", + "desc": "Yüz tanıma, tanınan insanlara isim vermenize olanak tanır ve bu yüzler tanındığında Frigate, kişinin adını alt etiket olarak ekler. Bu bilgi; kullanıcı arayüzü, filtreler ve bildirimlerde gösterilir.", + "readTheDocumentation": "Dökümantasyonu Oku" + }, + "toast": { + "error": "Yapılandırma değişiklikleri kaydedilemedi: {{errorMessage}}", + "success": "Sınıflandırma ayarları kaydedildi. Değişikliklerinizi uygulamak için Frigate'i yeniden başlatın." + }, + "licensePlateRecognition": { + "desc": "Frigate araç plakalarını tanıyabilir ve algılanan karakterleri otomatik olarak recognized_license_plate alanına veya belirli bir plaka için tanımladığınız bir takma ismi alt etiket olarak ilgili aracın tanımlanan nesnesine ekleyebilir. Bu sistem, garajınıza giren veya caddeden geçen araçların plakalarını okumak için kullanılabilir.", + "title": "Plaka Tanıma", + "readTheDocumentation": "Dökümantasyonu Oku" + }, + "birdClassification": { + "title": "Kuş Sınıflandırma", + "desc": "Kuş Sınıflandırma özelliği, bilinen kuş türlerini kuantize edilmiş bir Tensorflow modeli kullanarak teşhis etmenizi sağlar. Model bir kuş türünü teşhis ettiğinde, Frigate, bu türün adını alt etiket olarak ekler. Bu bilgi; kullanıcı arayüzü, filtreler ve bildirimlerde gösterilir." + }, + "restart_required": "Yeniden Başlatma Gerekli (Sınıflandırma ayarları değiştirildi)" + }, + "cameraSetting": { + "camera": "Kamera", + "noCamera": "Kamera Yok" + }, + "dialog": { + "unsavedChanges": { + "title": "Kaydedilmemiş değişiklikleriniz var.", + "desc": "Devam etmeden önce değişiklikleri kaydetmek ister misiniz?" + } + }, + "camera": { + "title": "Kamera Ayarları", + "review": { + "title": "İncele", + "alerts": "Alarmlar ", + "detections": "Tespitler ", + "desc": "Bu kamera için uyarıları ve algılamaları etkinleştirin/devre dışı bırakın. Devre dışı bırakıldığında, yeni inceleme öğeleri oluşturulmaz." + }, + "reviewClassification": { + "readTheDocumentation": "Dökümantasyonu Oku", + "selectAlertsZones": "Alarmlar için alanları seçin", + "zoneObjectDetectionsTips": { + "regardlessOfZoneObjectDetectionsTips": "{{cameraName}} kamerasındaki kategorize edilmemiş bütün {{detectionsLabels}} nesneleri hangi alanda olduklarına bakılmaksızın Algılama olarak sınıflandırılacaktır.", + "notSelectDetections": "{{cameraName}} kamerasındaki {{zone}} alanı içinde algılanan ve Alarm olarak kategorize edilmeyen bütün {{detectionsLabels}} nesneleri hangi alanda olduklarına bakılmaksızın Algılama olarak sınıflandırılacaktır.", + "text": "{{cameraName}} kamerasındaki {{zone}} alanındaki kategorize edilmemiş bütün {{detectionsLabels}} nesneleri Algılama olarak sınıflandırılacaktır." + }, + "zoneObjectAlertsTips": "{{cameraName}} kamerasındaki {{zone}} alanında algılanan bütün {{alertsLabels}} nesneleri Alarm olarak sınıflandırılacaktır.", + "desc": "Frigate tespit edilen İnceleme öğelerini Alarmlar ve Tespitler olarak kategorize eder. Varsayılan olarak bütün kişi ve araba nesneleri Alarm olarak sınıflandırılır. İnceleme öğelerinizin sınıflandırmasını tespit sınırlandırma sayfasında gerekli alanlar seçerek sınırlandırabilirsiniz.", + "objectDetectionsTips": "{{cameraName}} kamerasında kategorize edilmemiş bütün {{detectionsLabels}} nesneleri, hangi alanda olduklarına bakılmaksızın Algılama olarak sınıflandırılacaktır.", + "selectDetectionsZones": "Algılamalar için alanları seçin", + "title": "Tespit Sınıflandırmaları", + "noDefinedZones": "Bu kamera için tanımlanmış alan yok.", + "objectAlertsTips": "{{cameraName}} kamerasındaki bütün {{alertsLabels}} nesneleri Alarm olarak sınıflandırılacaktır.", + "limitDetections": "Algılamaları belirli alanlara sınırla", + "toast": { + "success": "İnceleme sınıflandırma ayarları kaydedildi. Değişiklikleri uygulamak için Frigate'i yeniden başlatın." + } + }, + "streams": { + "desc": "Bir kameranın devre dışı bırakılması, Frigate'in bu kamerayı işlemesini tamamen durdurur. Algılama, kayıt ve hata ayıklama özellikleri kullanılamaz.
    Not: Bu eylem, go2rtc'deki yeniden akışları devre dışı bırakmaz.", + "title": "Akışlar" + } + }, + "masksAndZones": { + "filter": { + "all": "Bütün Maskeler ve Alanlar" + }, + "toast": { + "success": { + "copyCoordinates": "{{polyName}} için koordinatlar panoya kopyalandı." + }, + "error": { + "copyCoordinatesFailed": "Koordinatlar panoya kopyalanamadı." + } + }, + "form": { + "zoneName": { + "error": { + "mustBeAtLeastTwoCharacters": "Alan adı en az 2 karakter olmalıdır.", + "hasIllegalCharacter": "Alan adı geçersiz karakterler içeriyor.", + "mustNotBeSameWithCamera": "Alan adı kamera adıyla aynı olmamalıdır.", + "alreadyExists": "Bu kamera için bu ada sahip bir alan zaten mevcut.", + "mustNotContainPeriod": "Alan adı nokta içermemelidir." + } + }, + "distance": { + "error": { + "text": "Mesafe 0.1'den büyük veya eşit olmalıdır.", + "mustBeFilled": "Hız tahmini özelliğini kullanabilmek için bütün mesafe alanları doldurulmalıdır." + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "Oyalanma süresi 0'dan büyük veya eşit olmalıdır." + } + }, + "polygonDrawing": { + "snapPoints": { + "false": "Noktaları hizalama", + "true": "Noktaları hizala" + }, + "removeLastPoint": "Son noktayı kaldır", + "reset": { + "label": "Bütün noktaları temizle" + }, + "delete": { + "desc": "{{type}} {{name}}'i silmek istediğinizden emin misiniz?", + "title": "Silmeyi Onayla", + "success": "{{name}} silindi." + }, + "error": { + "mustBeFinished": "Kaydetmeden önce çokgen çizimi bitirilmelidir." + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "Eylemsizlik sıfırın üzerinde olmalıdır." + } + } + }, + "zones": { + "label": "Alanlar", + "documentTitle": "Alanı Düzenle - Frigate", + "desc": { + "documentation": "Dökümantasyon", + "title": "Alanlar, görüntüde belirli bir alanını tanımlamanıza olanak tanır. Böylece bir nesnenin belirli bir alanda olup olmadığını tespit edebilirsiniz." + }, + "add": "Alan Ekle", + "point_one": "{{count}} nokta", + "point_other": "{{count}} nokta", + "name": { + "inputPlaceHolder": "Bir isim girin…", + "title": "İsim", + "tips": "Ad en az 2 karakter olmalı ve bir kamera veya başka bir bölgenin adı olmamalıdır." + }, + "inertia": { + "title": "Eylemsizlik", + "desc": "Bir nesnenin alanda kabul edilmesi için kaç kare boyunca alanda kalması gerektiğini belirtir. Varsayılan: 3" + }, + "objects": { + "title": "Nesneler", + "desc": "Bu alana uygulanan nesnelerin listesi." + }, + "speedEstimation": { + "title": "Hız Tahmini", + "desc": "Bu alandaki nesneler için hız tahminini etkinleştirin. Alan tam olarak 4 noktaya belirlenmiş olmalıdır." + }, + "clickDrawPolygon": "Görüntü üzerinde bir çokgen çizmek için tıklayın.", + "edit": "Alanı Düzenle", + "loiteringTime": { + "title": "Oyalanma Süresi", + "desc": "Nesnenin etkinleşmesi için alanda kalması gereken minimum süreyi saniye cinsinden ayarlar. Varsayılan: 0" + }, + "speedThreshold": { + "desc": "Nesnelerin bu alanda kabul edilmesi için minimum hızı belirtir.", + "toast": { + "error": { + "pointLengthError": "Bu alan için hız tahmini devre dışı bırakıldı. Hız tahmini olan alanlar tam olarak 4 noktaya sahip olmak zorundadır.", + "loiteringTimeError": "Oyalanma süreleri 0'dan büyük olan alanlar hız tahmini ile birlikte kullanılmamalıdır." + } + }, + "title": "Hız Alt Sınırı ({{unit}})" + }, + "toast": { + "success": "Alan ({{zoneName}}) kaydedildi. Değişiklikleri uygulamak için Frigate'i yeniden başlatın." + }, + "allObjects": "Bütün Nesneler" + }, + "motionMasks": { + "add": "Yeni Hareket Maskesi", + "context": { + "documentation": "Dökümantasyonu okuyun", + "title": "Hareket maskeleri, istenmeyen hareketli nesnelerin (örneğin: ağaç dalları, kamera yayınına gömülü tarih saat, vb.) algılamayı tetiklemesini önlemek için kullanılır. Hareket maskeleri çok dikkatli kullanılmalıdır, zira gereğinden fazla maskeleme nesnelerin tespitini zorlaştıracaktır." + }, + "point_one": "{{count}} nokta", + "point_other": "{{count}} nokta", + "clickDrawPolygon": "Görüntü üzerinde bir çokgen çizmek için tıklayın.", + "polygonAreaTooLarge": { + "title": "Bu hareket maskesi, kamera görüntüsünün %{{polygonArea}}'sını kaplıyor. Büyük hareket maskeleri kullanmanız önerilmez.", + "documentation": "Dökümantasyonu oku", + "tips": "Hareket maskeleri nesnelerin algılanmasını kesin olarak engellemez. Bunun yerine tespit sınıflandırma sayfasında gerekli alan kısıtlaması ayarlamalısınız." + }, + "toast": { + "success": { + "title": "{{polygonName}} kaydedildi. Değişiklikleri uygulamak için Frigate'i yeniden başlatın.", + "noName": "Hareket Maskesi kaydedildi. Değişiklikleri uygulamak için Frigate'i yeniden başlatın." + } + }, + "desc": { + "title": "Hareket maskeleri, istenmeyen hareketlerin algılamayı tetiklemesini önlemek için kullanılır. Gereğinden fazla maskeleme nesnelerin tespitini zorlaştıracaktır.", + "documentation": "Dökümantasyon" + }, + "label": "Hareket Maskesi", + "edit": "Hareket Maskesini Düzenle", + "documentTitle": "Hareket Maskesini Düzenle - Frigate" + }, + "objectMasks": { + "desc": { + "documentation": "Dökümantasyon", + "title": "Nesne filtresi maskeleri, belirli bir nesne türü için konum bazında yanlış pozitifleri filtrelemek için kullanılır." + }, + "point_one": "{{count}} nokta", + "point_other": "{{count}} nokta", + "context": "Nesne filtresi maskeleri, belirli bir nesne türü için konum bazında yanlış pozitifleri filtrelemek için kullanılır.", + "objects": { + "allObjectTypes": "Bütün nesne türleri", + "desc": "Bu nesne maskesinin geçerli olacağı nesne türü.", + "title": "Nesneler" + }, + "add": "Nesne Maskesi Ekle", + "edit": "Nesne Maskesini Düzenle", + "toast": { + "success": { + "noName": "Nesne Maskesi kaydedildi. Değişiklikleri uygulamak için Frigate'i yeniden başlatın.", + "title": "{{polygonName}} kaydedildi. Değişiklikleri uygulamak için Frigate'i yeniden başlatın." + } + }, + "documentTitle": "Nesne Maskesini Düzenle - Frigate", + "label": "Nesne Maskeleri", + "clickDrawPolygon": "Görüntü üzerinde bir çokgen çizmek için tıklayın." + }, + "restart_required": "Yeniden Başlatma Gerekli (maskeler/alanlar değiştirildi)" + }, + "motionDetectionTuner": { + "title": "Hareket Algılama Ayarlayıcı", + "Threshold": { + "desc": "Eşik değeri, bir pikselin parlaklığındaki ne kadar değişikliğin hareket olarak kabul edileceğini belirler. Varsayılan: 30", + "title": "Eşik" + }, + "contourArea": { + "desc": "Kontur alanı değeri, hangi değişen piksel gruplarının hareket olarak nitelendirileceğine karar vermek için kullanılır. Varsayılan: 10", + "title": "Kontur Alanı" + }, + "toast": { + "success": "Hareket ayarları kaydedildi." + }, + "desc": { + "title": "Frigate, kamera görüntüsünde nesne tespiti ile kontrol etmeye değer bir şey olup olmadığını görmek için ilk olarak hareket algılamayı kullanır.", + "documentation": "Hareket Algılama İnce Ayar Kılavuzunu Okuyun" + }, + "improveContrast": { + "desc": "Daha karanlık sahneler için kontrastı iyileştirin. Varsayılan: AÇIK", + "title": "Kontrastı İyileştir" + } + }, + "debug": { + "title": "Hata Ayıklama", + "boundingBoxes": { + "colors": { + "label": "Nesne Çerçeve Renkleri", + "info": "
  • Başlangıçta, her nesne etiketi için farklı renkler atanacaktır
  • Koyu mavi ince bir çizgi, nesnenin şu anda algılanamadığını gösterir
  • Gri ince bir çizgi, nesnenin sabit olduğunun algılandığını gösterir
  • Kalın bir çizgi, nesnenin otomatik izlemeye (eğer açıksa) tabi olduğunu gösterir
  • " + }, + "title": "Çerçeveler", + "desc": "İzlenen nesnelerin etrafında çerçeve göster" + }, + "timestamp": { + "title": "Zaman Damgası", + "desc": "Görüntüye bir zaman damgası ekle" + }, + "motion": { + "title": "Hareket kutuları", + "desc": "Hareketin algılandığı alanların etrafında çerçeve göster", + "tips": "

    Hareket Kutuları


    Hareketin algılandığı alanlar kırmızı çerçeve ile gösterilecektir.

    " + }, + "regions": { + "title": "Tespit Bölgeleri", + "desc": "Nesne algılayıcıya gönderilen tespit alanlarını göster", + "tips": "

    Bölge Kutuları


    Görüntüdeki nesne dedektörüne gönderilen tespit alanları parlak yeşil renk çerçeve ile gösterilir.

    " + }, + "objectShapeFilterDrawing": { + "title": "Nesne Şekil Filtresi Çizimi", + "desc": "Alan ve oran ayrıntılarını görüntülemek için görüntü üzerinde bir dikdörtgen çizin", + "score": "Puan", + "ratio": "Oran", + "area": "Alan", + "document": "Dökümantasyonu oku ", + "tips": "Alanını ve oranını göstermek için kamera görüntüsü üzerinde bir dikdörtgen çizmek için bu seçeneği etkinleştirin. Bu değerler daha sonra yapılandırmanızda nesne şekil filtresi parametrelerini ayarlamak için kullanılabilir." + }, + "debugging": "Hata Ayıklama", + "detectorDesc": "Frigate, kamera video akışınızdaki nesneleri algılamak için algılayıcılar ({{detectors}}) kullanır.", + "noObjects": "Nesne Yok", + "mask": { + "title": "Hareket maskeleri", + "desc": "Tanımlanmış hareket maskelerinin sınırlarını göster" + }, + "zones": { + "title": "Alanlar", + "desc": "Tanımlanmış alanların sınırlarını göster" + }, + "objectList": "Nesne Listesi", + "desc": "Hata ayıklama görünümü, izlenen nesnelerin ve istatistiklerinin gerçek zamanlı bir görünümünü gösterir. Nesne listesi algılanan nesnelerin zaman gecikmeli bir özetini gösterir." + }, + "users": { + "title": "Kullanıcılar", + "management": { + "title": "Kullanıcı Yönetimi", + "desc": "Bu Frigate kurulumundaki kullanıcı hesaplarını yönetin." + }, + "addUser": "Kullanıcı Ekle", + "toast": { + "success": { + "deleteUser": "{{user}} kullanıcısı başarıyla silindi", + "roleUpdated": "{{user}} için rol güncellendi", + "createUser": "{{user}} kullanıcısı başarıyla oluşturuldu", + "updatePassword": "Parola başarıyla güncellendi." + }, + "error": { + "setPasswordFailed": "Parola kaydedilemedi: {{errorMessage}}", + "createUserFailed": "Kullanıcı oluşturulamadı: {{errorMessage}}", + "deleteUserFailed": "Kullanıcı silinemedi: {{errorMessage}}", + "roleUpdateFailed": "Rol güncellenemedi: {{errorMessage}}" + } + }, + "table": { + "username": "Kullanıcı Adı", + "actions": "Eylemler", + "noUsers": "Kullanıcı bulunamadı.", + "changeRole": "Kullanıcı rolünü değiştir", + "deleteUser": "Kullanıcıyı sil", + "role": "Rol", + "password": "Parola" + }, + "dialog": { + "form": { + "user": { + "placeholder": "Kullanıcı adı girin", + "title": "Kullanıcı Adı", + "desc": "Yalnızca harfler, sayılar, noktalar ve alt çizgiler kullanabilirsiniz." + }, + "password": { + "title": "Parola", + "placeholder": "Parola girin", + "confirm": { + "title": "Parolayı Onayla", + "placeholder": "Parolayı Onayla" + }, + "strength": { + "title": "Parola kuvveti: ", + "weak": "Zayıf", + "medium": "Orta", + "strong": "Güçlü", + "veryStrong": "Çok Güçlü" + }, + "notMatch": "Parolalar eşleşmiyor", + "match": "Parolalar eşleşiyor" + }, + "newPassword": { + "placeholder": "Yeni parola girin", + "confirm": { + "placeholder": "Yeni parolayı tekrar girin" + }, + "title": "Yeni Parola" + }, + "usernameIsRequired": "Kullanıcı adı gereklidir" + }, + "createUser": { + "title": "Yeni Kullanıcı Oluştur", + "desc": "Yeni bir kullanıcı hesabı ekleyin ve Frigate'deki erişim düzeylerini sınırlandırmak için bir rol belirtin.", + "usernameOnlyInclude": "Kullanıcı adı yalnızca harfler, sayılar, nokta veya alt çizgi (_) içerebilir" + }, + "deleteUser": { + "title": "Kullanıcıyı Sil", + "warn": "{{username}}'i silmek istediğinizden emin misiniz?", + "desc": "Bu işlem geri alınamaz. Bu, kullanıcı hesabını kalıcı olarak silecek ve tüm ilişkili verileri kaldıracaktır." + }, + "passwordSetting": { + "updatePassword": "{{username}} için Parola Belirle", + "setPassword": "Parola Belirle", + "desc": "Bu hesabı güvenli hale getirmek güçlü bir parola belirleyin." + }, + "changeRole": { + "title": "Kullanıcı Rolünü Değiştir", + "desc": "{{username}} için izinleri güncelle", + "roleInfo": { + "adminDesc": "Tüm özelliklere tam erişim.", + "intro": "Bu kullanıcı için bir rol seçin:", + "admin": "Yönetici", + "viewer": "Görüntüleyici", + "viewerDesc": "Yalnızca Canlı, İncele, Keşfet ve Dışa Aktar'a girebilir." + } + } + }, + "updatePassword": "Parola Belirle" + }, + "notification": { + "title": "Bildirimler", + "notificationSettings": { + "title": "Bildirim Ayarları", + "documentation": "Dökümantasyonu Oku", + "desc": "Frigate, tarayıcıdan veya web uygulaması (PWA) olarak kullanıyor olmanız fark etmeksizin, tarayıcınızın bildirimler özelliği aracılığıyla bildirimler gönderebilir." + }, + "notificationUnavailable": { + "title": "Bildirimler Kullanılamıyor", + "documentation": "Dökümantasyonu Oku", + "desc": "Web push bildirimleri güvenli bağlantı (https://…) gerektirir. Bu tarayıcınızın bir sınırlandırmasıdır. Bildirimleri kullanmak için Frigate arayüzüne HTTPS ile erişin." + }, + "globalSettings": { + "title": "Genel Ayarlar", + "desc": "Kayıtlı tüm cihazlarda belirli kameralar için bildirimleri geçici olarak askıya alın." + }, + "email": { + "title": "E-posta", + "desc": "Geçerli bir e-posta adresi gereklidir ve push hizmetiyle ilgili herhangi bir sorun olması durumunda sizi bilgilendirmek için kullanılacaktır.", + "placeholder": "örn. ornek@eposta.com" + }, + "cameras": { + "desc": "Bildirimlerin etkinleştirileceği kameraları seçin.", + "title": "Kameralar", + "noCameras": "Kullanılabilir kamera yok" + }, + "deviceSpecific": "Cihaza Özel Ayarlar", + "suspended": "Bildirimler askıya alındı {{time}}", + "suspendTime": { + "1hour": "1 saat süreyle askıya al", + "12hours": "12 saat süreyle askıya al", + "24hours": "24 saat süreyle askıya al", + "30minutes": "30 dakika süreyle askıya al", + "untilRestart": "Yeniden başlatılana kadar askıya al", + "10minutes": "10 dakika süreyle askıya al", + "5minutes": "5 dakika süreyle askıya al" + }, + "toast": { + "success": { + "registered": "Bildirimlere başarıyla kaydolundu. Herhangi bir bildirimin (test bildirimi dahil) gönderilebilmesi için Frigate'in yeniden başlatılması gereklidir.", + "settingSaved": "Bildirim ayarları kaydedildi." + }, + "error": { + "registerFailed": "Bildirimlere kaydolunurken hata oluştu." + } + }, + "registerDevice": "Bu Cihazı Kaydet", + "sendTestNotification": "Bir test bildirimi gönder", + "cancelSuspension": "Askıya Almayı İptal Et", + "unregisterDevice": "Bu Cihazın Kaydını Sil", + "active": "Bildirimler Aktif" + }, + "frigatePlus": { + "title": "Frigate+ Ayarları", + "apiKey": { + "title": "Frigate+ API Anahtarı", + "validated": "Frigate+ API anahtarınız doğrulandı", + "plusLink": "Frigate+ hakkında daha fazla bilgi edinin", + "notValidated": "Frigate+ API anahtarı bulunamadı veya doğrulanamadı", + "desc": "Frigate+ API anahtarı, Frigate+ hizmetiyle entegrasyonu sağlar." + }, + "snapshotConfig": { + "title": "Fotoğraf Yapılandırması", + "documentation": "Dökümantasyonu oku", + "table": { + "camera": "Kamera", + "snapshots": "Fotoğraflar", + "cleanCopySnapshots": "clean_copy Fotoğraflar" + }, + "desc": "Frigate+'a göndermek için yapılandırmanızda hem fotoğrafların hem de clean_copy fotoğraflarının etkinleştirilmesi gerekir.", + "cleanCopyWarning": "Bazı kameralarda fotoğraflar etkin ancak temiz kopya özelliği devre dışı. Bu kameralardan Frigate+'a görüntü gönderebilmek için fotoğraf(snapshots) yapılandırmanızda clean_copy'yi etkinleştirmeniz gerekiyor." + }, + "modelInfo": { + "error": "Model bilgileri yüklenemedi", + "loadingAvailableModels": "Kullanılabilir modeller yükleniyor…", + "loading": "Model bilgileri yükleniyor…", + "modelType": "Model Türü", + "dimensions": "Boyutlar", + "availableModels": "Kullanılabilir Modeller", + "modelSelect": "Frigate+'daki kullanılabilir modelleriniz buradan seçilebilir. Yalnızca mevcut algılayıcı yapılandırmanızla uyumlu modellerin seçilebileceğini unutmayın.", + "baseModel": "Temel Model", + "title": "Model Bilgileri", + "trainDate": "Eğitim Tarihi", + "supportedDetectors": "Desteklenen Algılayıcılar", + "cameras": "Kameralar", + "plusModelType": { + "userModel": "İnce Ayarlı", + "baseModel": "Baz Model" + } + }, + "toast": { + "success": "Frigate+ ayarları kaydedildi. Değişiklikleri uygulamak için Frigate'i yeniden başlatın.", + "error": "Yapılandırma değişiklikleri kaydedilemedi: {{errorMessage}}" + }, + "restart_required": "Yeniden Başlatma Gerekli (Frigate+ modeli değiştirildi)" + } +} diff --git a/web/public/locales/tr/views/system.json b/web/public/locales/tr/views/system.json new file mode 100644 index 000000000..47b756975 --- /dev/null +++ b/web/public/locales/tr/views/system.json @@ -0,0 +1,169 @@ +{ + "documentTitle": { + "logs": { + "frigate": "Frigate Günlükleri - Frigate", + "go2rtc": "Go2RTC Günlükleri - Frigate", + "nginx": "Nginx Günlükleri - Frigate" + }, + "general": "Genel İstatistikler - Frigate", + "storage": "Depolama İstatistikleri - Frigate", + "cameras": "Kamera İstatistikleri - Frigate", + "enrichments": "Zenginleştirme İstatistikleri - Frigate" + }, + "metrics": "Sistem metrikleri", + "general": { + "hardwareInfo": { + "gpuDecoder": "GPU Kod Çözücü", + "gpuInfo": { + "nvidiaSMIOutput": { + "name": "İsim: {{name}}", + "driver": "Sürücü: {{driver}}", + "cudaComputerCapability": "CUDA Hesaplama Yeteneği: {{cuda_compute}}", + "vbios": "VBios Bilgisi: {{vbios}}", + "title": "Nvidia SMI Çıktısı" + }, + "toast": { + "success": "GPU bilgisi panoya kopyalandı" + }, + "vainfoOutput": { + "processError": "İşlem Hatası:", + "returnCode": "Dönüt Kodu: {{code}}", + "processOutput": "İşlem Çıktısı:", + "title": "Vainfo çıktısı" + }, + "closeInfo": { + "label": "GPU bilgisini kapat" + }, + "copyInfo": { + "label": "GPU bilgisini kopyala" + } + }, + "gpuUsage": "GPU Kullanımı", + "gpuMemory": "GPU Belleği", + "gpuEncoder": "GPU Kodlayıcı", + "title": "Donanım Bilgisi", + "npuUsage": "NPU Kullanımı", + "npuMemory": "NPU Bellek Kullanımı" + }, + "otherProcesses": { + "title": "Diğer İşlemler", + "processCpuUsage": "İşlem CPU Kullanımı", + "processMemoryUsage": "İşlem Bellek Kullanımı" + }, + "detector": { + "title": "Algılayıcılar", + "inferenceSpeed": "Algılayıcı Çıkarım Hızı", + "memoryUsage": "Algılayıcı Bellek Kullanımı", + "cpuUsage": "Algılayıcı İşlemci Kullanımı" + }, + "title": "Genel" + }, + "storage": { + "title": "Depolama", + "overview": "Genel", + "recordings": { + "title": "Kayıtlar", + "earliestRecording": "Mevcut en erken kayıt:", + "tips": "Burada gösterilen değer, Frigate’in veritabanına göre kayıtların diskinizde kullandığı toplam alanı ifade eder. Frigate, diskinizdeki tüm dosyaların alan kullanımını takip etmez." + }, + "cameraStorage": { + "title": "Kamera Depolaması", + "camera": "Kamera", + "unused": { + "tips": "Eğer diskinizde Frigate'in kayıtları dışında dosyalar varsa bu değer diskinizdeki boş alanı doğru olarak göstermeyebilir. Frigate kendi kayıtları dışındaki dosyaların disk kullanımını takip etmez.", + "title": "Kullanılmayan" + }, + "percentageOfTotalUsed": "Toplam Yüzde", + "storageUsed": "Depolama", + "bandwidth": "Saatlik Veri Kullanımı", + "unusedStorageInformation": "Kullanılmayan Depolama Bilgisi" + } + }, + "cameras": { + "info": { + "streamDataFromFFPROBE": "Yayın bilgisi ffprobe ile edinilmiştir.", + "video": "Video:", + "codec": "Kodlama:", + "fps": "Kare Hızı:", + "resolution": "Çözünürlük:", + "unknown": "Bilinmeyen", + "stream": "Yayın {{idx}}", + "tips": { + "title": "Kamera Detayları" + }, + "fetching": "Kamera Bilgileri Alınıyor", + "cameraProbeInfo": "{{camera}} Kamera Detayları", + "error": "Hata: {{error}}", + "audio": "Ses:" + }, + "framesAndDetections": "Kare / Tespit", + "label": { + "camera": "kamera", + "detect": "tespit", + "ffmpeg": "ffmpeg", + "capture": "kayıt", + "skipped": "atlanan" + }, + "toast": { + "success": { + "copyToClipboard": "Detaylar panoya kopyalandı." + }, + "error": { + "unableToProbeCamera": "Kamera detayları alınamadı: {{errorMessage}}" + } + }, + "title": "Kameralar", + "overview": "Genel" + }, + "lastRefreshed": "Son güncelleme: ", + "stats": { + "ffmpegHighCpuUsage": "{{camera}} FFMPEG'te yüksek miktarda CPU kullanıyor (%{{ffmpegAvg}})", + "reindexingEmbeddings": "Gömüler yeniden dizinleniyor (%{{processed}} tamamlandı)", + "detectHighCpuUsage": "{{camera}} tespitte yüksek miktarda CPU kullanıyor (%{{detectAvg}})", + "healthy": "Sistem sağlıklı", + "detectIsVerySlow": "{{detect}} çok yavaş çalışıyor ({{speed}} ms)", + "cameraIsOffline": "{{camera}} çevrimdışı", + "detectIsSlow": "{{detect}} yavaş çalışıyor ({{speed}} ms)" + }, + "enrichments": { + "embeddings": { + "image_embedding_speed": "Resim Gömü Hızı", + "text_embedding_speed": "Metin Gömü Hızı", + "plate_recognition_speed": "Plaka Tanıma Hızı", + "face_embedding_speed": "Yüz Gömü Hızı", + "image_embedding": "Resim Gömüleme", + "text_embedding": "Metin Gömülüeme", + "face_recognition": "Yüz Tanıma", + "plate_recognition": "Plaka Tanıma", + "face_recognition_speed": "Yüz Tanıma Hızı", + "yolov9_plate_detection_speed": "YOLOv9 Plaka Tanıma Hızı", + "yolov9_plate_detection": "YOLOv9 Plaka Tanıma" + }, + "infPerSecond": "Saniye Başına Çıkarım", + "title": "Zenginleştirmeler" + }, + "logs": { + "download": { + "label": "Günlükleri İndir" + }, + "type": { + "message": "Mesaj", + "tag": "Etiket", + "timestamp": "Zaman Damgası", + "label": "Tür" + }, + "copy": { + "error": "Günlükler panoya kopyalanamadı", + "label": "Panoya Kopyala", + "success": "Günlükler panoya kopyalandı" + }, + "tips": "Günlükler sunucudan yansıtılıyor", + "toast": { + "error": { + "whileStreamingLogs": "Günlükler yansıtılırken hata: {{errorMessage}}", + "fetchingLogsFailed": "Günlükler alınırken hata: {{errorMessage}}" + } + } + }, + "title": "Sistem" +} diff --git a/web/public/locales/uk/audio.json b/web/public/locales/uk/audio.json new file mode 100644 index 000000000..b5035e11c --- /dev/null +++ b/web/public/locales/uk/audio.json @@ -0,0 +1,429 @@ +{ + "child_singing": "Дитячий спів", + "breathing": "Дихання", + "cough": "Кашель", + "throat_clearing": "Прозорий очищення", + "mantra": "Мантра", + "synthetic_singing": "Синтетичний спів", + "whimper_dog": "Собаче скиглення", + "cat": "Кіт", + "cowbell": "Коров'ячий здвіночок", + "whispering": "Шепіт", + "run": "Біг", + "choir": "Хор", + "chewing": "Жування", + "pets": "Домашні улюбленці", + "dog": "Собака", + "bark": "Лай", + "meow": "Котяче нявчання", + "horse": "Кінь", + "moo": "Мичання", + "goat": "Коза", + "sheep": "Вівця", + "chicken": "Курка", + "speech": "Мо́влення", + "idling": "Холостий хід", + "railroad_car": "Залізничний вагон", + "alarm": "Сигналізація", + "fire_alarm": "Пожежна сигналізація", + "flute": "Флейта", + "musical_instrument": "Музичний інструмент", + "buzz": "Дзижчання", + "fly": "Муха", + "vocal_music": "Вокальна музика", + "motorcycle": "Мотоцикл", + "rustling_leaves": "Шелест листя", + "crackle": "Потріскування", + "thunder": "Грім", + "rock_and_roll": "Рок-н-рол", + "theme_music": "Тематична музика", + "exciting_music": "Енергійна музика", + "water": "Вода", + "violin": "Скрипка", + "tubular_bells": "Трубчасті дзвони", + "christmas_music": "Різдвяна музика", + "house_music": "Хауз", + "fire": "Вогонь", + "tapping": "Постукування", + "scratching": "Скретчінг", + "drum_kit": "Ударна установка", + "engine": "Двигун", + "light_engine": "Легкий двигун", + "swing_music": "Свінг", + "opera": "Опера", + "electronic_dance_music": "Електронна танцювальна музика", + "dance_music": "Танцювальна музика", + "thunderstorm": "Гроза", + "waves": "Хвилі", + "trombone": "Тромбон", + "music_of_asia": "Азіатська музика", + "tools": "Iнструменти", + "wind_chime": "Музика вітру", + "singing_bowl": "Співоча чаша", + "boat": "Човен", + "sailboat": "Вітрильник", + "rowboat": "Весловий човен", + "power_windows": "Електросклопідйомники", + "cutlery": "Столові прибори", + "mechanical_fan": "Механічний вентилятор", + "traffic_noise": "Дорожній шум", + "aircraft_engine": "Двигун повітряного судна", + "dental_drill's_drill": "Стоматологічна бормашина", + "door": "Двері", + "accelerating": "Прискорення", + "siren": "Сирена", + "typewriter": "Друкарська машинка", + "computer_keyboard": "Комп'ютерна клавіатура", + "smoke_detector": "Датчик диму", + "hammer": "Молот", + "gunshot": "Постріл", + "machine_gun": "Автомат", + "fireworks": "Феєрверки", + "firecracker": "Петарда", + "heartbeat": "Серцебиття", + "heart_murmur": "Серцевий шум", + "footsteps": "Кроки", + "burping": "Відрижка", + "hiccup": "Ікання", + "fart": "Пукання", + "finger_snapping": "Клацати пальцями", + "applause": "Оплески", + "chatter": "Балаканина", + "animal": "Тварина", + "yip": "Гавкання", + "babbling": "Бурмотіння", + "yell": "Кричати", + "bow_wow": "Гав гав", + "growling": "Ревіння", + "purr": "Муркотіти", + "hiss": "Шипіння", + "clip_clop": "Цокання", + "neigh": "іржання", + "oink": "Рохкання", + "bleat": "Мекання", + "cluck": "Кудкудакання", + "cock_a_doodle_doo": "Кукурікання", + "honk": "Гелготання", + "roar": "Гуркіт", + "bird": "Птах", + "chirp": "Цвірінькання", + "pigeon": "Голуб", + "coo": "Воркування", + "crow": "Ворона", + "caw": "Каркання", + "owl": "Сова", + "hoot": "Ухання", + "flapping_wings": "Ляскання крил", + "dogs": "Собаки", + "rats": "Щури", + "mouse": "Миш", + "patter": "Шерех", + "insect": "Комара", + "cricket": "Цвіркун", + "mosquito": "Комар", + "frog": "Жаба", + "croak": "Квакання", + "snake": "Змія", + "rattle": "Тріск", + "whale_vocalization": "Співання кита", + "music": "Музика", + "guitar": "Гітара", + "electric_guitar": "Електрогітара", + "bass_guitar": "Бас-гітара", + "acoustic_guitar": "Акустична гітара", + "strum": "Звук струн", + "keyboard": "Клавіатура", + "piano": "Піаніно", + "electric_piano": "Електропіаніно", + "organ": "Орган", + "electronic_organ": "Електроорган", + "synthesizer": "Синтезатор", + "percussion": "Ударні інструменти", + "drum": "Барабан", + "snare_drum": "Малий барабан", + "drum_roll": "Барабанний дріб", + "bass_drum": "Бас-барабан", + "tambourine": "Бубон", + "gong": "Гонг", + "glockenspiel": "Дзвіночки", + "orchestra": "Оркестр", + "double_bass": "Контрабас", + "wind_instrument": "Духовий інструмент", + "saxophone": "Саксофон", + "clarinet": "Кларнет", + "harp": "Арфа", + "bell": "Дзвін", + "church_bell": "Церковний дзвін", + "jingle_bell": "Бубонець", + "bicycle_bell": "Велосипедний дзвінок", + "tuning_fork": "Камертон", + "chime": "Дзвіночок", + "harmonica": "Губна гармоніка", + "accordion": "Акордеон", + "bagpipes": "Волинка", + "theremin": "Терменвокс", + "pop_music": "Поп-музика", + "hip_hop_music": "Хіп-хоп музика", + "beatboxing": "Бітбоксинг", + "rock_music": "Рок-музика", + "punk_rock": "Панк-рок", + "psychedelic_rock": "Психоделічний рок", + "rhythm_and_blues": "Ритм-н-блюз", + "country": "Кантрі", + "funk": "Фанк", + "folk_music": "Фолк-музика", + "jazz": "Джаз", + "disco": "Диско", + "classical_music": "Класична музика", + "electronic_music": "Електронна музика", + "techno": "Техно", + "dubstep": "Дабстеп", + "drum_and_bass": "Драм-н-бейс", + "electronica": "Електроніка", + "ambient_music": "Ембієнт", + "trance_music": "Транс музика", + "music_of_latin_america": "Латиноамериканська музика", + "flamenco": "Фламенко", + "blues": "Блюз", + "music_for_children": "Дитяча музика", + "a_capella": "А капела", + "music_of_africa": "Африканська музика", + "afrobeat": "Афробіт", + "christian_music": "Християнська музика", + "gospel_music": "Госпел", + "carnatic_music": "Карнатична музика", + "ska": "Ска-музика", + "traditional_music": "Традиційна музика", + "independent_music": "Iнді музика", + "song": "Пісня", + "background_music": "Фонова музика", + "jingle": "Джингл", + "soundtrack_music": "Саундтрек", + "lullaby": "Колискова", + "video_game_music": "Музика з відеоігор", + "wedding_music": "Весільна музика", + "happy_music": "Весела музика", + "sad_music": "Сумна музика", + "tender_music": "Ніжна музика", + "angry_music": "Сердита музика", + "scary_music": "Моторошна музика", + "wind": "Вітер", + "wind_noise": "Шум вітру", + "rain": "Дощ", + "raindrop": "Краплі дощу", + "rain_on_surface": "Дощ на поверхні", + "stream": "Потік", + "waterfall": "Водоспад", + "ocean": "Океан", + "steam": "Пар", + "gurgling": "Дзюрчання", + "vehicle": "Транспорт", + "motorboat": "Моторний човен", + "ship": "Корабель", + "motor_vehicle": "Моторний транспорт", + "car": "Автомобіль", + "toot": "Гудок", + "car_alarm": "Автосигналізація", + "skidding": "Занос", + "tire_squeal": "Вереск шін", + "car_passing_by": "Проїжджаюча машина", + "race_car": "Гоночний автомобіль", + "truck": "Вантажівка", + "air_brake": "Пневматичне гальмо", + "air_horn": "Пневматичні гудок", + "reversing_beeps": "Сигнал заднього ходу", + "ice_cream_truck": "Вантажівки з морозивом", + "bus": "Автобус", + "emergency_vehicle": "Транспорт екстрених служб", + "police_car": "Поліцейський автомобіль", + "ambulance": "Швидка допомога", + "fire_engine": "Пожежна машина", + "rail_transport": "Рейковий транспорт", + "train": "Поїзд", + "train_whistle": "Свист поїзда", + "train_horn": "Гудок поїзда", + "train_wheels_squealing": "Вереск колес поїзда", + "subway": "Метро", + "aircraft": "Повітряне судно", + "jet_engine": "Реактивний двигун", + "propeller": "Пропелер", + "helicopter": "Вертоліт", + "fixed-wing_aircraft": "Літак з нерухомим крилом", + "bicycle": "Велосипед", + "skateboard": "Скейтборд", + "lawn_mower": "Газонокосарка", + "chainsaw": "Ланцюгова пила", + "medium_engine": "Середні двигун", + "heavy_engine": "Важкий двигун", + "engine_knocking": "Детонація у двигуні", + "engine_starting": "Запуск двигуна", + "doorbell": "Дверний дзвінок", + "ding-dong": "Дін-дон", + "sliding_door": "Розсувні двері", + "slam": "Бавовна", + "knock": "Стукіт", + "tap": "Невеличкий стук", + "squeak": "Скрип", + "cupboard_open_or_close": "Відкриття або закриття шафи", + "drawer_open_or_close": "Відкриття або закриття коробки", + "dishes": "Тарілки", + "chopping": "Нарізування", + "frying": "Смаження", + "microwave_oven": "Мікрохвильова піч", + "blender": "Блендер", + "water_tap": "Водопровідний кран", + "sink": "Раковина", + "bathtub": "Ванна", + "hair_dryer": "Фен", + "toilet_flush": "Злив унітазу", + "toothbrush": "Зубна щітка", + "electric_toothbrush": "Електрична зубна щітка", + "vacuum_cleaner": "Пилосос", + "zipper": "Блискавки на одязі", + "keys_jangling": "Брязкання ключів", + "coin": "Монета", + "scissors": "Ножиці", + "electric_shaver": "Електробритва", + "shuffling_cards": "Тасуванні карт", + "typing": "Друкування", + "writing": "Написання", + "telephone": "Телефон", + "telephone_bell_ringing": "Телефонний дзвінок", + "ringtone": "Рінгтон", + "telephone_dialing": "Набір телефонного номеру", + "dial_tone": "Телефонний гудок", + "busy_signal": "Сигнал зайнято", + "alarm_clock": "Будильник", + "civil_defense_siren": "Сирени громадянської оборони", + "buzzer": "Зумер", + "foghorn": "Туманний горн", + "whistle": "Свисток", + "steam_whistle": "Парової свисток", + "mechanisms": "Механізми", + "ratchet": "Тріскачка", + "clock": "Годинник", + "tick": "Тік", + "tick-tock": "Тік-так", + "gears": "Шестерні", + "pulleys": "Шківи", + "sewing_machine": "Швейна машинка", + "air_conditioning": "Кондиціонер", + "cash_register": "Каса", + "printer": "Принтер", + "camera": "Камера", + "single-lens_reflex_camera": "Дзеркальна камера", + "jackhammer": "Відбійний молоток", + "sawing": "Розпилювання", + "filing": "Звучання напилку", + "sanding": "Шліфування", + "power_tool": "Електроінструмент", + "drill": "Дриль", + "explosion": "Вибух", + "fusillade": "Збройна черга", + "artillery_fire": "Артилерійський вогонь", + "cap_gun": "Iграшковий пістолет", + "burst": "Черга пострілів", + "eruption": "Виверження", + "boom": "Бум", + "wood": "Деревина", + "chop": "Рубання", + "splinter": "Тріска", + "crack": "Тріщина", + "glass": "Скло", + "chink": "Дзенькіт", + "shatter": "Розбиття", + "silence": "Тиша", + "sound_effect": "Звуковий ефект", + "environmental_noise": "Шум навколишнього середовища", + "static": "Статичний шум", + "white_noise": "Білий шум", + "pink_noise": "Рожевий шум", + "television": "Телебачення", + "radio": "Радіо", + "field_recording": "Польова запись", + "scream": "Крик", + "laughter": "сміх", + "bellow": "Рев", + "singing": "спів", + "whoop": "Вигук", + "snicker": "хіхікання", + "crying": "плач", + "sigh": "Зітхання", + "yodeling": "Співати йодлем", + "chant": "Скандування", + "grunt": "Гарчання", + "wheeze": "Хрипіти", + "gasp": "Aхнути", + "snort": "Пирхання", + "sniff": "Понюхати", + "shuffle": "Перетасувати", + "biting": "Кусання", + "gargling": "Полоскання", + "stomach_rumble": "Шлунок бурчати", + "hands": "Руки", + "clapping": "Плескання", + "cheering": "Аплодувати", + "crowd": "Натовп", + "children_playing": "Діти граються", + "howl": "Виття", + "rapping": "Стукiт", + "humming": "Гудіння", + "caterwaul": "Нявкання", + "livestock": "Тваринництво", + "cattle": "Велика рогата худоба", + "pig": "Свиня", + "fowl": "Птиця", + "turkey": "Iндичка", + "gobble": "Гелґотіння", + "duck": "Качка", + "quack": "Крякання", + "goose": "Гусак", + "wild_animals": "Дикі тварини", + "roaring_cats": "Ревіння котів", + "squawk": "Пташиний крик", + "plucked_string_instrument": "Щипковий струнний інструмент", + "steel_guitar": "Слайд-гітара", + "banjo": "Банджо", + "sitar": "Ситара", + "mandolin": "Мандоліна", + "zither": "Цитра", + "ukulele": "Укулеле", + "hammond_organ": "Орган Хаммонда", + "sampler": "Семплер", + "harpsichord": "Клавесин", + "drum_machine": "Драм-машина", + "rimshot": "Удар по ободу", + "timpani": "Тимпані", + "tabla": "Табла", + "cymbal": "Тарілка", + "hi_hat": "Хай-хет", + "wood_block": "Дерев'яний брусок", + "maraca": "Маракас", + "mallet_percussion": "Малет-перкусія", + "marimba": "Маримба", + "vibraphone": "Вібрафон", + "steelpan": "Стілпен", + "brass_instrument": "Мідний духовий інструмент", + "french_horn": "Валторна", + "trumpet": "Труба", + "bowed_string_instrument": "Струнно-смичкови інструмент", + "string_section": "Струнна секція", + "pizzicato": "Піцикато", + "cello": "Віолончель", + "didgeridoo": "Діджеріду", + "heavy_metal": "Хеві-метал", + "grunge": "Гранж", + "progressive_rock": "Прогресивний рок", + "soul_music": "Соул", + "reggae": "Реггі", + "bluegrass": "Блюграс", + "middle_eastern_music": "Близькосхідна музика", + "salsa_music": "Музика сальси", + "new-age_music": "Музика нью-ейдж", + "music_of_bollywood": "Музика Боллівуду", + "groan": "стогнати", + "whistling": "свист", + "snoring": "хропіння", + "pant": "задихатися", + "sneeze": "чхати" +} diff --git a/web/public/locales/uk/common.json b/web/public/locales/uk/common.json new file mode 100644 index 000000000..79c01da24 --- /dev/null +++ b/web/public/locales/uk/common.json @@ -0,0 +1,253 @@ +{ + "time": { + "year_one": "{{time}}рік", + "year_few": "{{time}}роки", + "year_many": "{{time}}років", + "month_one": "{{time}}місяць", + "month_few": "{{time}}місяця", + "month_many": "{{time}} місяців", + "justNow": "Зараз", + "today": "Сьогодні", + "last7": "Останні 7 днів", + "last14": "Останній 14 днів", + "last30": "Останній 30 днів", + "thisWeek": "Цей тиждень", + "lastWeek": "Останній тиждень", + "thisMonth": "У цьому місяці", + "lastMonth": "Останній місяць", + "5minutes": "5 хвилин", + "10minutes": "10 хвилин", + "30minutes": "30 хвилин", + "1hour": "1 година", + "12hours": "12 годин", + "24hours": "24 години", + "pm": "вечора", + "am": "ранку", + "yr": "{{time}} рік", + "hour_one": "{{time}} година", + "hour_few": "{{time}} години", + "hour_many": "{{time}} годин", + "minute_one": "{{time}} хвилина", + "minute_few": "{{time}} хвилини", + "minute_many": "{{time}} хвилин", + "day_one": "{{time}} день", + "day_few": "{{time}} дні", + "day_many": "{{time}} днів", + "second_one": "{{time}}секунда", + "second_few": "{{time}}секунди", + "second_many": "{{time}}секунд", + "ago": "{{timeAgo}} тому", + "yesterday": "Учора", + "mo": "{{time}}місяць", + "d": "{{time}}д", + "h": "{{time}}г", + "m": "{{time}}хв", + "s": "{{time}}сек", + "untilForTime": "До {{time}}", + "untilForRestart": "Доки Frigate не перезавантажиться.", + "untilRestart": "До перезавантаження", + "formattedTimestamp": { + "12hour": "MMM d, h:mm:ss aaa", + "24hour": "MMM d, HH:mm:ss" + }, + "formattedTimestampHourMinute": { + "12hour": "h:mm aaa", + "24hour": "HH:mm" + }, + "formattedTimestampHourMinuteSecond": { + "12hour": "h:mm:ss aaa", + "24hour": "HH:mm:ss" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "MMM d, h:mm aaa", + "24hour": "MMM d, HH:mm" + }, + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "MMM d yyyy, h:mm aaa", + "24hour": "MMM d yyyy, HH:mm" + }, + "formattedTimestampMonthDay": "MMM d", + "formattedTimestampFilename": { + "12hour": "MM-dd-yy-h-mm-ss-a", + "24hour": "MM-dd-yy-HH-mm-ss" + }, + "formattedTimestamp2": { + "12hour": "MM/dd h:mm:ssa", + "24hour": "d MMM HH:mm:ss" + } + }, + "button": { + "exitFullscreen": "Вийти з повноекранного режиму", + "on": "ВКЛ", + "yes": "Так", + "copy": "Копіювати", + "close": "Закрити", + "saving": "Збереження…", + "history": "Історія", + "cancel": "Відмінити", + "fullscreen": "Повноекранний режим", + "back": "Назад", + "pictureInPicture": "Картинка в картинці", + "cameraAudio": "Аудіо камери", + "copyCoordinates": "Копіювати координати", + "edit": "Редагувати", + "no": "Ні", + "twoWayTalk": "Двосторонній зв'язок", + "off": "ВИКЛ", + "delete": "Видалити", + "apply": "Застосувати", + "reset": "Скинути", + "done": "Готово", + "enabled": "Увімкнено", + "enable": "Увімкнути", + "disabled": "Вимкнено", + "disable": "Вимкнути", + "save": "Зберегти", + "download": "Завантажити", + "info": "Інфо", + "suspended": "Призупинено", + "play": "Грати", + "unselect": "Прибрати виділення", + "export": "Експортувати", + "deleteNow": "Видалити негайно", + "next": "Наступне", + "unsuspended": "Відновити дію" + }, + "menu": { + "language": { + "da": "Датська", + "uk": "Українська", + "ro": "Румунська", + "es": "Іспанська", + "zhCN": "Спрощена китайська", + "hi": "Хінді", + "fr": "Французька", + "ar": "Арабська", + "pt": "Португальська", + "de": "Німецька", + "ja": "Японська", + "tr": "Турецька", + "ru": "російська", + "it": "Італійська", + "nl": "Голландська", + "sv": "Швецька", + "cs": "Чешська", + "nb": "Норвежский букмол", + "ko": "Корейська", + "vi": "В'єтнамська", + "fa": "Персидська", + "pl": "Польська", + "he": "Иврит", + "el": "Грецька", + "hu": "Венгерська", + "fi": "Фінська", + "sk": "Словацька", + "withSystem": { + "label": "Використовувати системну мову" + }, + "en": "Англійська", + "yue": "粵語 (Кантонська)" + }, + "system": "Система", + "systemMetrics": "Системна метріка", + "configuration": "Конфігурація", + "systemLogs": "Системні логи", + "settings": "Налаштування", + "configurationEditor": "Редактор конфігурації", + "languages": "Мови", + "theme": { + "nord": "Північ", + "red": "Червоний", + "contrast": "Висока контрастність", + "default": "Типовий", + "label": "Тема", + "blue": "Синій", + "green": "Зелений", + "highcontrast": "Висока контрастність" + }, + "help": "Допомогти", + "documentation": { + "title": "Документація", + "label": "Frigate документація" + }, + "restart": "Перезапустити Frigate", + "live": { + "title": "Живи", + "allCameras": "Всi камери", + "cameras": { + "title": "Камери" + } + }, + "review": "Перегляд", + "explore": "Вивчити", + "export": "Експорт", + "uiPlayground": "UI iгровий майданчик", + "faceLibrary": "Бібліотека обличчя", + "user": { + "title": "Користувач", + "account": "Акаунт", + "current": "Поточний користувач: {{user}}", + "anonymous": "анонімний", + "logout": "Вихід", + "setPassword": "Встановити пароль" + }, + "darkMode": { + "label": "Темний режим", + "light": "Світло", + "dark": "Темний", + "withSystem": { + "label": "Використовуйте налаштування системи для світлого або темного режиму" + } + }, + "appearance": "Поява", + "withSystem": "Система" + }, + "unit": { + "speed": { + "mph": "миль/г", + "kph": "км/г" + } + }, + "label": { + "back": "Повернутись" + }, + "toast": { + "save": { + "title": "Зберегти", + "error": { + "title": "Не вдалося зберегти зміни конфігурації: {{errorMessage}}", + "noMessage": "Не вдалося зберегти зміни налаштування" + } + }, + "copyUrlToClipboard": "Скопійовано URL до буфера обміну." + }, + "role": { + "title": "Роль", + "desc": "Адміністратори мають повний доступ до всіх функцій інтерфейсу Fregate. Глядачі обмежуються переглядом камер, оглядовими елементами та історичними кадрами в інтерфейсі користувача.", + "admin": "Адміністратор", + "viewer": "Глядач" + }, + "pagination": { + "previous": { + "title": "Попередній", + "label": "Повернутись до попередньої сторінки" + }, + "next": { + "title": "Наступний", + "label": "Перехід до наступної сторінки" + }, + "more": "Більше сторінок", + "label": "Пагінація" + }, + "accessDenied": { + "documentTitle": "Доступ заборонений - Frigate", + "title": "Доступ заборонений", + "desc": "У вас немає дозволу на перегляд цієї сторінки." + }, + "notFound": { + "documentTitle": "Не знайдено - Frigate", + "desc": "Сторінка не знайдена", + "title": "404" + }, + "selectItem": "Вибрати {{item}}" +} diff --git a/web/public/locales/uk/components/auth.json b/web/public/locales/uk/components/auth.json new file mode 100644 index 000000000..07eaca4e3 --- /dev/null +++ b/web/public/locales/uk/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "errors": { + "webUnknownError": "Невідома помилка. Перевірте журнали консолi.", + "usernameRequired": "Ви повинні ввести ім'я користувача", + "passwordRequired": "Необхідно ввести пароль", + "rateLimit": "Перевищення кількості спроб. Спробуйте пізніше.", + "loginFailed": "Спроба входу зазнала невдачі", + "unknownError": "Невідома помилка. Перевірте журнали." + }, + "user": "Iм'я користувача", + "password": "Пароль", + "login": "Логiн" + } +} diff --git a/web/public/locales/uk/components/camera.json b/web/public/locales/uk/components/camera.json new file mode 100644 index 000000000..26fd97db4 --- /dev/null +++ b/web/public/locales/uk/components/camera.json @@ -0,0 +1,13 @@ +{ + "group": { + "name": { + "placeholder": "Введіть назву…" + } + }, + "debug": { + "zones": "Зони", + "mask": "Маска", + "motion": "Рух", + "regions": "Регiони" + } +} diff --git a/web/public/locales/uk/components/dialog.json b/web/public/locales/uk/components/dialog.json new file mode 100644 index 000000000..60c921b34 --- /dev/null +++ b/web/public/locales/uk/components/dialog.json @@ -0,0 +1,107 @@ +{ + "explore": { + "plus": { + "review": { + "question": { + "ask_a": "Чи є цей об'єкт {{label}}?", + "ask_full": "Чи є цей об'єкт {{untranslatedLabel}}{{translatedLabel}}?", + "label": "Підтвердіть цей ярлик для Frigate Plus", + "ask_an": "Це об'єкт – {{label}}?" + }, + "state": { + "submitted": "Поданi" + } + }, + "submitToPlus": { + "label": "Надіслати да Frigate+", + "desc": "Об'єкти в місцях, які ви хочете уникнути, не є помилковими спрацьовуваннями. Подання їх як помилкових спрацьовувань заплутає модель." + } + }, + "video": { + "viewInHistory": "Перегляд у історії" + } + }, + "streaming": { + "label": "Потік", + "restreaming": { + "desc": { + "readTheDocumentation": "Прочитати документацію", + "title": "Налаштуйте go2rtc для додаткових параметрів перегляду в реальному часі та аудіо для цієї камери." + }, + "disabled": "Перезавантаження не ввімкнено для цієї камери." + }, + "showStats": { + "label": "Показати статистику потоку", + "desc": "Позначте цей пункт, щоб показувати статистику потоку як накладання на канал камери." + }, + "debugView": "Режим зневаджування" + }, + "search": { + "saveSearch": { + "label": "Зберегти пошук", + "button": { + "save": { + "label": "Зберегти цей пошук" + } + }, + "desc": "Вкажіть назву для цього збереженого пошуку.", + "placeholder": "Введіть назву для пошуку", + "overwrite": "{{searchName}} вже існує. Збереження перезапише існуюче значення.", + "success": "Пошук ({{searchName}}) збережено." + } + }, + "export": { + "toast": { + "error": { + "failed": "Не вдалося розпочати експорт: {{error}}", + "endTimeMustAfterStartTime": "Час закінчення повинен бути після часу початку", + "noVaildTimeSelected": "Не вибрано допустимий діапазон часу" + }, + "success": "Експорт успішно запущено. Файл доступний у теці /exports." + }, + "fromTimeline": { + "saveExport": "Зберегти експорт", + "previewExport": "Попередній перегляд експорту" + }, + "time": { + "fromTimeline": "Вибір шкали часу", + "custom": "Користувацький", + "start": { + "title": "Час початку", + "label": "Виберіть час початку" + }, + "end": { + "title": "Час закінчення", + "label": "Вибрати час закінчення" + } + }, + "name": { + "placeholder": "Введіть назву для експорту" + }, + "select": "Вибрати", + "export": "Експорт", + "selectOrExport": "Выбiр або експорт" + }, + "recording": { + "button": { + "export": "Експорт", + "markAsReviewed": "Позначити як переглянуте", + "deleteNow": "Вилучити зараз" + }, + "confirmDelete": { + "title": "Підтвердити вилучення", + "desc": { + "selected": "Ви впевнені, що хочете видалити все записане відео, пов'язане з цим пунктом огляду?

    Утримуйте клавішу Shift, щоб обійти це діалогове вікно в майбутньому." + } + } + }, + "restart": { + "title": "Ви впевнені, що хочете перезапустити Frigate?", + "button": "Перезавантажувати", + "restarting": { + "title": "Frigate перезапускається", + "content": "Цю сторінку буде перезавантажено за {{countdown}} секунд.", + "button": "Примусово перезавантажити" + } + } +} diff --git a/web/public/locales/uk/components/filter.json b/web/public/locales/uk/components/filter.json new file mode 100644 index 000000000..26ad630c6 --- /dev/null +++ b/web/public/locales/uk/components/filter.json @@ -0,0 +1,125 @@ +{ + "filter": "Фiльтр", + "explore": { + "settings": { + "defaultView": { + "desc": "Якщо фільтри не вибрано, відобразити резюме останніх відстежуваних об'єктів за міткою, або показати нефільтровану сітку.", + "title": "Вид за замовчуванням", + "summary": "Підсумок", + "unfilteredGrid": "Нефільтровані сiтка" + }, + "searchSource": { + "desc": "Виберіть, чи слід шукати мініатюри або описи відстежуваних об'єктів.", + "label": "Пошук джерела", + "options": { + "thumbnailImage": "Зображення мініатюри", + "description": "Опис" + } + }, + "title": "Налаштування", + "gridColumns": { + "title": "Колонки сітки", + "desc": "Виберіть кількість стовпчиків у вигляді сітки." + } + }, + "date": { + "selectDateBy": { + "label": "Виберіть дату для фільтрування" + } + } + }, + "labels": { + "count_one": "{{count}} Етикетка", + "all": { + "title": "Всi етикетки", + "short": "Етикетки" + }, + "label": "Етикетки", + "count_other": "{{count}} Етикетки" + }, + "cameras": { + "all": { + "short": "Камери", + "title": "Всi камери" + }, + "label": "Фільтр камери" + }, + "timeRange": "Часовий діапазон", + "features": { + "hasSnapshot": "Має своє уявлення", + "hasVideoClip": "Має відеокліп", + "label": "Особливості", + "submittedToFrigatePlus": { + "label": "Подані до Frigate+", + "tips": "Спочатку потрібно відфільтрувати об'єкти, які відслідковуються.

    Відстежувані об'єкти без знімка не можуть бути передані Frigate+." + } + }, + "sort": { + "dateAsc": "Дата (за зростанням)", + "dateDesc": "Дата (по спадаючій)", + "label": "Сортування", + "scoreAsc": "Оцiнка об'єкту (За зростанням)", + "scoreDesc": "Оцiнка об'єкту (За спаданням)", + "speedAsc": "Розрахункова швидкість (За зростанням)", + "speedDesc": "Розрахункова швидкість (За спаданням)", + "relevance": "Актуальність" + }, + "trackedObjectDelete": { + "desc": "Видалення цих {{objectLength}} відстежуваних об'єктів видаляє знімок, будь-які збережені вкладення та пов'язані з ними записи життєвого циклу об'єкта. Записані кадри цих відстежуваних об'єктів у перегляді історії НЕ будуть видалені.

    Ви впевнені, що хочете продовжити?

    Утримуйте клавішу Shift, щоб обійти це діалогове вікно в майбутньому.", + "title": "Підтвердіть видалення", + "toast": { + "success": "Відстежені об'єкти успішно видалені.", + "error": "Не вдалося видалити відстежувані об'єкти: {{errorMessage}}" + } + }, + "zones": { + "label": "Зони", + "all": { + "title": "Всi зони", + "short": "Зони" + } + }, + "dates": { + "all": { + "title": "Всi дати", + "short": "Дати" + } + }, + "more": "Кілька фільтрів", + "reset": { + "label": "Відновити типові значення фільтрів" + }, + "subLabels": { + "label": "Суб-мiтка", + "all": "Всi суб-мiтки" + }, + "score": "Рахунок", + "estimatedSpeed": "Розрахункова швидкість ({{unit}})", + "review": { + "showReviewed": "Показати переглянув" + }, + "motion": { + "showMotionOnly": "Показати тiльки рух" + }, + "logSettings": { + "label": "Фільтр рівня журналу", + "filterBySeverity": "Фільтрувати журнали за ступенем тяжкості", + "loading": { + "title": "Завантаження", + "desc": "Коли панель журналу прокручується внизу, нові журнали автоматично транслюються після додавання." + }, + "disableLogStreaming": "Вимикати журнал стрімінгу", + "allLogs": "Всi журнали" + }, + "zoneMask": { + "filterBy": "Фільтрувати за маскою зони" + }, + "recognizedLicensePlates": { + "title": "Розпізнано номерні знаки", + "loadFailed": "Не вдалося завантажити розпізнані номерні знаки.", + "loading": "Завантаження визнаних номерів…", + "placeholder": "Введіть для пошуку номерні знаки…", + "noLicensePlatesFound": "Номерних знаків не знайдено.", + "selectPlatesFromList": "Виберіть одну або кілька пластин зі списку." + } +} diff --git a/web/public/locales/uk/components/icons.json b/web/public/locales/uk/components/icons.json new file mode 100644 index 000000000..65d0cd681 --- /dev/null +++ b/web/public/locales/uk/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "Оберіть іконку", + "search": { + "placeholder": "Пошук iконки…" + } + } +} diff --git a/web/public/locales/uk/components/input.json b/web/public/locales/uk/components/input.json new file mode 100644 index 000000000..e7b818db7 --- /dev/null +++ b/web/public/locales/uk/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "Завантажити відео", + "toast": { + "success": "Розпочата завантаження відео." + } + } + } +} diff --git a/web/public/locales/uk/components/player.json b/web/public/locales/uk/components/player.json new file mode 100644 index 000000000..746eba6c1 --- /dev/null +++ b/web/public/locales/uk/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "Не знайдено жодного запису", + "noPreviewFoundFor": "Попередній перегляд для {{cameraName}} не знайдені", + "livePlayerRequiredIOSVersion": "Для цього типу потокового передавання потрібна iOS 17.1 або пізніша версія.", + "stats": { + "droppedFrames": { + "short": { + "title": "Пропущене", + "value": "{{droppedFrames}} кадрiв" + }, + "title": "Пропущене кадрiв:" + }, + "droppedFrameRate": "Частота пропущенив кадрiв:", + "streamType": { + "short": "Тип", + "title": "Тип потоку:" + }, + "bandwidth": { + "title": "Пропускна здатність:", + "short": "Пропускна здатність" + }, + "latency": { + "title": "Затримка:", + "short": { + "title": "Затримка", + "value": "{{seconds}} сек" + }, + "value": "{{seconds}} секунд" + }, + "totalFrames": "Всього кадрiв:", + "decodedFrames": "Декодовані кадри:" + }, + "noPreviewFound": "Попередній перегляд не знайдені", + "submitFrigatePlus": { + "title": "Відправити це зображення Frigate+?", + "submit": "Посилати" + }, + "streamOffline": { + "title": "Струм офлайн", + "desc": "Потік detect камера {{cameraName}} не отримувала ніяких кадрів, перевіряйте журнали помилок" + }, + "cameraDisabled": "Камера вимкнена", + "toast": { + "success": { + "submittedFrigatePlus": "Зображення успішно завантажено до Frigate+" + }, + "error": { + "submitFrigatePlusFailed": "Не вдалося надіслати фрейм Frigate+" + } + } +} diff --git a/web/public/locales/uk/objects.json b/web/public/locales/uk/objects.json new file mode 100644 index 000000000..6047ee633 --- /dev/null +++ b/web/public/locales/uk/objects.json @@ -0,0 +1,120 @@ +{ + "dog": "Собака", + "cat": "Кіт", + "horse": "Кінь", + "sheep": "Вівця", + "bark": "Лай", + "goat": "Коза", + "mouse": "Миш", + "skateboard": "Скейтборд", + "bird": "Птах", + "boat": "Човен", + "car": "Автомобіль", + "bus": "Автобус", + "motorcycle": "Мотоцикл", + "train": "Поїзд", + "bicycle": "Велосипед", + "keyboard": "Клавіатура", + "door": "Двері", + "sink": "Раковина", + "animal": "Тварина", + "vehicle": "Транспорт", + "blender": "Блендер", + "hair_dryer": "Фен", + "toothbrush": "Зубна щітка", + "scissors": "Ножиці", + "clock": "Годинник", + "toilet": "Вбиральня", + "spoon": "Ложка", + "tennis_racket": "Тенісна ракетка", + "potted_plant": "Кімнатна рослина", + "bbq_grill": "Гриль та барбекю", + "person": "Людина", + "airplane": "Літак", + "traffic_light": "Світлофор", + "fire_hydrant": "Пожежний гідрант", + "parking_meter": "Паркоматів", + "bench": "Лавка", + "cow": "Корова", + "elephant": "Слон", + "bear": "Ведмідь", + "zebra": "Зебра", + "giraffe": "Жираф", + "hat": "Шапка", + "backpack": "Рюкзак", + "street_sign": "Дорожній знак", + "stop_sign": "Знак зупинки", + "umbrella": "Парасолька", + "shoe": "Взуття", + "eye_glasses": "Окуляри", + "handbag": "Гаманець", + "tie": "Краватка", + "suitcase": "Валiза", + "frisbee": "Фрiсбi", + "skis": "Лижи", + "snowboard": "Сноуборд", + "sports_ball": "Спортивні м'яч", + "kite": "Повітряний змій", + "baseball_bat": "Бейсбольна біта", + "baseball_glove": "Рукавичка ловця", + "surfboard": "Дошка для серфінгу", + "bottle": "Пляшка", + "plate": "Тарiлка", + "wine_glass": "Винний келих", + "cup": "Чашка", + "fork": "Виделка", + "knife": "Нiж", + "bowl": "Миска", + "banana": "Банан", + "apple": "Яблуко", + "sandwich": "Сендвіч", + "orange": "Апельсин", + "broccoli": "Броколі", + "carrot": "Морква", + "hot_dog": "Хот-дог", + "pizza": "Пiца", + "donut": "Пампушка", + "cake": "Торт", + "chair": "Стілець", + "couch": "Диван", + "bed": "Лiжко", + "mirror": "Люстерко", + "dining_table": "Обідній стіл", + "window": "Вiкно", + "desk": "Стiл", + "tv": "Телевізор", + "laptop": "Лептоп", + "remote": "Пульт дистанційного керування", + "cell_phone": "Мобільний телефон", + "microwave": "Мікрохвильовка", + "oven": "Пiч", + "toaster": "Тостер", + "refrigerator": "Холодильник", + "book": "Книжка", + "vase": "Ваза", + "teddy_bear": "Плюшевий ведмедик", + "hair_brush": "Гребінець", + "squirrel": "Білка", + "deer": "Олень", + "fox": "Лисиця", + "rabbit": "Кролик", + "raccoon": "Єнот", + "robot_lawnmower": "Роботизована газонокосарка", + "waste_bin": "Відро для сміття", + "on_demand": "На вимогу", + "face": "Обличчя", + "license_plate": "Номерний знак", + "package": "Посилка", + "amazon": "Amazon", + "usps": "USPS", + "ups": "UPS", + "fedex": "FedEx", + "dhl": "DHL", + "an_post": "An Post", + "purolator": "Purolator", + "postnl": "PostNL", + "nzpost": "NZPost", + "postnord": "PostNord", + "gls": "GLS", + "dpd": "DPD" +} diff --git a/web/public/locales/uk/views/configEditor.json b/web/public/locales/uk/views/configEditor.json new file mode 100644 index 000000000..1dc4bb6d8 --- /dev/null +++ b/web/public/locales/uk/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "saveAndRestart": "Зберегти та перезавантажити", + "toast": { + "error": { + "savingError": "Помилка збереження конфігурації" + }, + "success": { + "copyToClipboard": "Налаштування було скопійовано до буфера обміну даними." + } + }, + "documentTitle": "Редактар конфігурації - Frigate", + "copyConfig": "Скопіювати конфігурацію", + "saveOnly": "Тільки зберегти", + "configEditor": "Налаштування редактора" +} diff --git a/web/public/locales/uk/views/events.json b/web/public/locales/uk/views/events.json new file mode 100644 index 000000000..f78ac8501 --- /dev/null +++ b/web/public/locales/uk/views/events.json @@ -0,0 +1,37 @@ +{ + "camera": "Камера", + "selected_one": "{{count}} відібраний", + "selected_other": "{{count}} відібраний", + "alerts": "Оповіщення", + "detections": "Виявлень", + "motion": { + "label": "Рух", + "only": "Тiльки рух" + }, + "allCameras": "Всi камери", + "empty": { + "alert": "Немає попереджень для перегляду", + "detection": "Немає ніяких ознак", + "motion": "Даних про рух не знайдено" + }, + "timeline": "Хронологія", + "timeline.aria": "Вибрати хронiку", + "events": { + "label": "Події", + "aria": "Выбрати події", + "noFoundForTimePeriod": "За цей період подій не знайдено." + }, + "documentTitle": "Перегляд подiй - Frigate", + "recordings": { + "documentTitle": "Записи - Frigate" + }, + "calendarFilter": { + "last24Hours": "Останні 24 години" + }, + "markAsReviewed": "Прибрати позначку про необхідність огляду", + "markTheseItemsAsReviewed": "Позначити ці елементи як переглянуті", + "newReviewItems": { + "label": "Переглянути нові елементи огляду", + "button": "Нові матеріали для перегляду" + } +} diff --git a/web/public/locales/uk/views/explore.json b/web/public/locales/uk/views/explore.json new file mode 100644 index 000000000..f87a2c3a2 --- /dev/null +++ b/web/public/locales/uk/views/explore.json @@ -0,0 +1,10 @@ +{ + "exploreIsUnavailable": { + "downloadingModels": { + "tips": { + "documentation": "Прочитати документацію" + } + } + }, + "documentTitle": "Пошук подій - Frigate" +} diff --git a/web/public/locales/uk/views/exports.json b/web/public/locales/uk/views/exports.json new file mode 100644 index 000000000..788851804 --- /dev/null +++ b/web/public/locales/uk/views/exports.json @@ -0,0 +1,17 @@ +{ + "documentTitle": "Експорт - Frigate", + "search": "Пошук", + "noExports": "Не знайдено експортованих файлів", + "deleteExport": "Видалити експортування", + "deleteExport.desc": "Ви справді бажаєте вилучити {{exportName}}?", + "editExport": { + "title": "Перейменувати експорт", + "desc": "Введіть нову назву для цього експорту.", + "saveExport": "Зберегти експорт" + }, + "toast": { + "error": { + "renameExportFailed": "Не вдалося перейменувати експорт: {{errorMessage}}" + } + } +} diff --git a/web/public/locales/uk/views/faceLibrary.json b/web/public/locales/uk/views/faceLibrary.json new file mode 100644 index 000000000..de1229a8f --- /dev/null +++ b/web/public/locales/uk/views/faceLibrary.json @@ -0,0 +1,5 @@ +{ + "selectItem": "Вибрати {{item}}", + "documentTitle": "Бібліотека облич - Frigate", + "readTheDocs": "Прочитати документацію" +} diff --git a/web/public/locales/uk/views/live.json b/web/public/locales/uk/views/live.json new file mode 100644 index 000000000..e56c821ed --- /dev/null +++ b/web/public/locales/uk/views/live.json @@ -0,0 +1,156 @@ +{ + "manualRecording": { + "started": "Почав ручний запис на вимогу.", + "showStats": { + "desc": "Позначте цей пункт, щоб показувати статистику потоку як накладання на канал камери.", + "label": "Показати статистику" + }, + "failedToEnd": "Не вдалося завершити запис вручну на вимогу.", + "playInBackground": { + "label": "Грати у фоновому режимі", + "desc": "Увімкніть цей параметр, щоб продовжувати потокове передавання, коли програвач приховано." + }, + "tips": "Запустіть ручну подію на основі параметрів збереження запису цієї камери.", + "title": "Запис на вимогу", + "debugView": "Режим зневаджування", + "start": "Почати запис за запитом", + "failedToStart": "Не вдалося запустити ручний запис на вимогу.", + "end": "Завершення запису на вимогу", + "ended": "Запис на вимогу припинився." + }, + "snapshots": { + "enable": "Увімкнути знімки", + "disable": "Вимкнути знімки" + }, + "stream": { + "twoWayTalk": { + "tips": "Ваш пристрій повинен підтримувати функцію, а WebRTC повинен бути налаштований для двосторонньої розмови.", + "tips.documentation": "Прочитати документацію ", + "available": "Двостороння розмова доступна для цього потоку", + "unavailable": "Двостороння розмова недоступна для цього потоку" + }, + "playInBackground": { + "tips": "Увімкніть цей параметр, щоб продовжувати потокове передавання, коли програвач приховано.", + "label": "Грати у фоновому режимі" + }, + "title": "Потiк", + "audio": { + "tips": { + "documentation": "Прочитати документацію ", + "title": "Звук повинен бути виведений з камери і налаштований в go2rtc для цього потоку." + }, + "available": "Звук доступний для цього потоку", + "unavailable": "Аудіо недоступне для цього потоку" + }, + "lowBandwidth": { + "resetStream": "Скинути потік", + "tips": "Режим перегляду в реальному часі перемикається в економічний режим через помилки буферизації або потоку." + } + }, + "muteCameras": { + "disable": "Увімкнути звук на всі камери", + "enable": "Вимкнути всі камери" + }, + "ptz": { + "move": { + "clickMove": { + "label": "Клацніть у кадрі, щоб відцентрувати камеру", + "enable": "Увімкнути клацання для переміщення", + "disable": "Вимкнути клацання для переміщення" + }, + "up": { + "label": "Перемістити PTZ камеру вгору" + }, + "left": { + "label": "Переміщення камери PTZ вліво" + }, + "down": { + "label": "Переміщення PTZ камери вниз" + }, + "right": { + "label": "Переміщення PTZ камери вправо" + } + }, + "zoom": { + "in": { + "label": "Наближати PTZ камеру" + }, + "out": { + "label": "Зменшити PTZ камеру" + } + }, + "presets": "Попередни установки PTZ камери", + "frame": { + "center": { + "label": "Клацніть у кадрі, щоб відцентрувати камеру PTZ" + } + } + }, + "editLayout": { + "exitEdit": "Вийти з редагування", + "label": "Редагувати макет", + "group": { + "label": "Редагувати групу камер" + } + }, + "documentTitle": "Пряма трансляція - Frigate", + "documentTitle.withCamera": "{{camera}} - Пряма трансляція - Frigate", + "lowBandwidthMode": "Економічний режим", + "twoWayTalk": { + "enable": "Увімкнути двосторонню розмову", + "disable": "Вимкнути двосторонню розмову" + }, + "cameraAudio": { + "enable": "Увімкнути звук камери", + "disable": "Вимкнути звук камери" + }, + "camera": { + "enable": "Увімкнути камеру", + "disable": "Вимкнути камеру" + }, + "detect": { + "enable": "Увімкнути виявлення", + "disable": "Вимкнути виявлення" + }, + "recording": { + "enable": "Увімкнути запис", + "disable": "Вимкнути запис" + }, + "audioDetect": { + "enable": "Увімкнути виявлення звуку", + "disable": "Вимкнути виявлення звуку" + }, + "autotracking": { + "disable": "Вимкнути автотрекінг", + "enable": "Увімкнути автотрекінг" + }, + "streamStats": { + "enable": "Показати статистику потоку", + "disable": "Сховати статистику потоку" + }, + "streamingSettings": "Параметри потокового передавання", + "notifications": "Повідомлення", + "audio": "Аудіо", + "suspend": { + "forTime": "Призупинити до: " + }, + "cameraSettings": { + "title": "{{camera}} Налаштування", + "cameraEnabled": "Камера включена", + "objectDetection": "Виявлення об'єктів", + "recording": "Записування", + "snapshots": "Знімки", + "audioDetection": "Виявлення звуку", + "autotracking": "Автотрекiнг" + }, + "history": { + "label": "Показати історичні кадри" + }, + "effectiveRetainMode": { + "modes": { + "all": "Всi", + "motion": "Рух", + "active_objects": "Активні об'єкти" + } + } +} diff --git a/web/public/locales/uk/views/recording.json b/web/public/locales/uk/views/recording.json new file mode 100644 index 000000000..a1ae10e01 --- /dev/null +++ b/web/public/locales/uk/views/recording.json @@ -0,0 +1,12 @@ +{ + "export": "Експорт", + "toast": { + "error": { + "noValidTimeSelected": "Вибраний діапазон часу не є коректним", + "endTimeMustAfterStartTime": "Час закінчення повинен бути пізніше часу початку" + } + }, + "calendar": "Календар", + "filter": "Фiльтр", + "filters": "Фiльтри" +} diff --git a/web/public/locales/uk/views/search.json b/web/public/locales/uk/views/search.json new file mode 100644 index 000000000..c2d9d2a22 --- /dev/null +++ b/web/public/locales/uk/views/search.json @@ -0,0 +1,72 @@ +{ + "search": "Пошук", + "filter": { + "tips": { + "desc": { + "step1": "Введіть назву ключа фільтра, а потім двокрапку (наприклад, «камери:»).", + "step2": "Виберіть значення з пропозицій або введіть своє.", + "step3": "Використовуйте кілька фільтрів, додаючи їх один за одним з проміжком між ними.", + "step5": "Фільтр діапазону часу використовує формат {{exampleTime}}.", + "step6": "Видалити фільтри, натиснувши 'x' поруч з ними.", + "exampleLabel": "Наприклад:", + "step4": "Фільтри дат (до: і після:) використовують формат {{DateFormat}}.", + "text": "Фільтри допомагають звузити результати пошуку. Ось як використовувати їх у полі вводу:" + }, + "title": "Як використовувати текстові фільтри" + }, + "header": { + "currentFilterType": "Фільтрувати значення", + "activeFilters": "Активнi фiльтри", + "noFilters": "Фiлтри" + }, + "label": { + "zones": "Зони", + "sub_labels": "Суб-меткi", + "search_type": "Тип пошуку", + "cameras": "Камери", + "labels": "Етикеткi", + "time_range": "Часовий діапазон", + "before": "Перед", + "after": "Пiсля", + "min_score": "Мінімальний бал", + "max_score": "Найвищий бал", + "min_speed": "Мінімальна швидкість", + "max_speed": "Максимальна швидкість", + "recognized_license_plate": "Розпізнаний номерний знак", + "has_clip": "Має клiп", + "has_snapshot": "Має знiмок" + }, + "searchType": { + "thumbnail": "Мініатюра", + "description": "Опис" + }, + "toast": { + "error": { + "beforeDateBeLaterAfter": "Дата 'до' повинна бути пізнішою, ніж дата 'після'.", + "afterDatebeEarlierBefore": "Дата 'після' повинна бути раніше, ніж дата 'до'.", + "minScoreMustBeLessOrEqualMaxScore": "Значення 'min_score' має бути меншим або дорівнювати 'max_score'.", + "maxScoreMustBeGreaterOrEqualMinScore": "Значення 'max_score' має бути більшим або дорівнювати 'min_score'.", + "minSpeedMustBeLessOrEqualMaxSpeed": "Значення 'min_speed' має бути меншим або дорівнювати 'max_speed'.", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "Значення 'max_speed' має бути більшим або дорівнювати 'min_speed'." + } + } + }, + "similaritySearch": { + "title": "Пошук подібності", + "active": "Активнi пошук подібності", + "clear": "Очистити пошук подібності" + }, + "placeholder": { + "search": "Пошук…" + }, + "button": { + "save": "Зберегти пошук", + "delete": "Видалити збережений пошук", + "filterInformation": "Фільтрувати інформацію", + "clear": "Очистити пошук", + "filterActive": "Активни фільтри" + }, + "savedSearches": "Збережені пошуки", + "searchFor": "Пошук да {{inputValue}}", + "trackedObjectId": "Iдентифікатори об'єктів" +} diff --git a/web/public/locales/uk/views/settings.json b/web/public/locales/uk/views/settings.json new file mode 100644 index 000000000..1fa74923f --- /dev/null +++ b/web/public/locales/uk/views/settings.json @@ -0,0 +1,59 @@ +{ + "notification": { + "notificationSettings": { + "documentation": "Прочитати документацію" + }, + "notificationUnavailable": { + "desc": "Веб-повідомлення вимагають безпечного контексту (https://…). Це обмеження браузера. Безпечний доступ до фрегатів для використання сповіщень.", + "documentation": "Прочитати документацію" + } + }, + "camera": { + "streams": { + "title": "Потоки" + }, + "reviewClassification": { + "readTheDocumentation": "Прочитати документацію" + } + }, + "masksAndZones": { + "motionMasks": { + "polygonAreaTooLarge": { + "documentation": "Прочитати документацію" + }, + "context": { + "documentation": "Прочитати документацію", + "title": "Маски руху використовуються для запобігання виявлення небажаних типів руху (наприклад: гілки дерева, часові мітки камери). Слід використовувати маски рухудуже економно, надмірне маскування ускладнить відстеження об'єктів." + } + }, + "zones": { + "label": "Зони", + "name": { + "inputPlaceHolder": "Введіть назву…" + } + } + }, + "debug": { + "zones": { + "title": "Зони" + }, + "objectShapeFilterDrawing": { + "document": "Прочитати документацію " + } + }, + "classification": { + "licensePlateRecognition": { + "readTheDocumentation": "Прочитати документацію", + "title": "Розпізнавання номерних знаків" + }, + "faceRecognition": { + "readTheDocumentation": "Прочитати документацію" + } + }, + "frigatePlus": { + "modelInfo": { + "loading": "Завантаження інформації про модель…", + "loadingAvailableModels": "Завантаження доступних моделей…" + } + } +} diff --git a/web/public/locales/uk/views/system.json b/web/public/locales/uk/views/system.json new file mode 100644 index 000000000..bd1e4d366 --- /dev/null +++ b/web/public/locales/uk/views/system.json @@ -0,0 +1,30 @@ +{ + "cameras": { + "label": { + "ffmpeg": "FFmpeg", + "cameraSkippedDetectionsPerSecond": "{{camName}} пропущених виявлень на секунду", + "cameraDetect": "{{camName}} виявлення", + "cameraFfmpeg": "{{camName}} FFmpeg", + "overallDetectionsPerSecond": "загальна кiлькiсть виявлень за секунду", + "cameraDetectionsPerSecond": "{{camName}} виявлень на секунду", + "overallFramesPerSecond": "загальна кiлкiсть кадрiв на секунду", + "overallSkippedDetectionsPerSecond": "загальна кiлкiсть пропущених виявлень за секунду", + "cameraCapture": "{{camName}} захоплення", + "cameraFramesPerSecond": "{{camName}} кадрiв на секунду", + "skipped": "пропущено" + }, + "toast": { + "success": { + "copyToClipboard": "Тестові дані копіюються в буфер обміну." + } + } + }, + "enrichments": { + "embeddings": { + "plate_recognition": "Розпiзнавання номерiв" + } + }, + "general": { + "title": "Загальний" + } +} diff --git a/web/public/locales/vi/audio.json b/web/public/locales/vi/audio.json new file mode 100644 index 000000000..4a55da6aa --- /dev/null +++ b/web/public/locales/vi/audio.json @@ -0,0 +1,429 @@ +{ + "babbling": "Nói líu lo", + "bellow": "Gầm rú", + "whoop": "Hò reo", + "whispering": "Thì thầm", + "laughter": "Tiếng cười", + "snicker": "Cười khúc khích", + "sigh": "Thở dài", + "singing": "Hát", + "choir": "Dàn hợp xướng", + "yodeling": "Hát ngân nga", + "chant": "Hát đồng ca", + "mantra": "Thần chú", + "synthetic_singing": "Giọng hát tổng hợp", + "rapping": "Rap", + "humming": "Ngân nga", + "groan": "Rên rỉ", + "grunt": "Gằn giọng", + "whistling": "Huýt sáo", + "breathing": "Hít thở", + "wheeze": "Thở khò khè", + "gasp": "Thở hổn hển", + "pant": "Thở gấp", + "snort": "Khịt mũi", + "cough": "Ho", + "throat_clearing": "Hắng giọng", + "sneeze": "Hắt hơi", + "sniff": "Hít mũi", + "crying": "Khóc", + "yell": "La hét", + "snoring": "Ngáy", + "speech": "Giọng nói", + "child_singing": "Trẻ con hát", + "run": "Chạy", + "shuffle": "Kéo lê chân", + "footsteps": "Tiếng bước chân", + "chewing": "Nhai", + "biting": "Cắn", + "gargling": "Súc miệng", + "stomach_rumble": "Bụng sôi", + "burping": "Ợ", + "hiccup": "Nấc cụt", + "fart": "Đánh rắm", + "artillery_fire": "tiếng pháo kích", + "cap_gun": "tiếng súng giấy", + "fireworks": "tiếng pháo hoa", + "firecracker": "tiếng pháo nổ", + "burst": "tiếng nổ bung", + "eruption": "tiếng phun trào", + "boom": "tiếng bùm", + "wood": "tiếng gỗ", + "chop": "tiếng chặt", + "splinter": "tiếng gỗ vỡ", + "crack": "tiếng nứt", + "glass": "tiếng thủy tinh", + "chink": "tiếng leng keng", + "shatter": "tiếng vỡ vụn", + "silence": "sự im lặng", + "sound_effect": "hiệu ứng âm thanh", + "environmental_noise": "tiếng ồn môi trường", + "static": "tiếng nhiễu", + "white_noise": "tiếng trắng", + "pink_noise": "tiếng hồng", + "television": "tiếng tivi", + "hands": "Tay", + "finger_snapping": "Búng tay", + "clapping": "Vỗ tay", + "heartbeat": "Nhịp tim", + "heart_murmur": "Tiếng thổi tim", + "cheering": "Cổ vũ", + "applause": "Tràng pháo tay", + "chatter": "Nói chuyện rì rầm", + "crowd": "Đám đông", + "children_playing": "Trẻ con chơi", + "animal": "Động vật", + "pets": "Thú cưng", + "dog": "Chó", + "bark": "Sủa", + "yip": "Sủa nhỏ", + "howl": "Hú", + "bow_wow": "Gâu gâu", + "growling": "Gầm gừ", + "whimper_dog": "Rên rỉ (chó)", + "livestock": "Gia súc", + "cat": "Mèo", + "purr": "Rù rì", + "meow": "Meo meo", + "hiss": "Phì phì", + "caterwaul": "Tiếng mèo gào", + "horse": "Ngựa", + "clip_clop": "Lộc cộc", + "neigh": "Hí (ngựa)", + "cattle": "Bò", + "moo": "Bò rống", + "cowbell": "Chuông bò", + "pig": "Heo", + "oink": "Ụt ịt", + "goat": "Dê", + "bleat": "Kêu be be", + "sheep": "Cừu", + "fowl": "Gia cầm", + "chicken": "Gà", + "cluck": "Cục tác", + "cock_a_doodle_doo": "Gáy (gà trống)", + "turkey": "Gà tây", + "gobble": "Gù gù (gà tây)", + "duck": "Vịt", + "quack": "Quạc quạc", + "goose": "Ngỗng", + "roar": "Gầm rú", + "bird": "Chim", + "chirp": "Hót líu lo", + "squawk": "Kêu the thé", + "honk": "Kêu vang (ngỗng)", + "wild_animals": "Động vật hoang dã", + "roaring_cats": "Mèo lớn gầm", + "pigeon": "Bồ câu", + "coo": "Cục cu", + "crow": "Quạ", + "caw": "Kêu quạ quạ", + "owl": "Cú mèo", + "hoot": "Kêu tu hú", + "flapping_wings": "Vỗ cánh", + "dogs": "Nhiều con chó", + "rats": "Chuột cống", + "mouse": "Chuột nhắt", + "patter": "Lách cách (bước chân nhỏ)", + "insect": "Côn trùng", + "cricket": "Dế", + "mosquito": "Muỗi", + "fly": "Ruồi", + "buzz": "Vo ve", + "frog": "Ếch", + "croak": "Ếch kêu", + "snake": "Rắn", + "rattle": "Lắc lư / lách cách", + "whale_vocalization": "Tiếng cá voi", + "music": "âm nhạc", + "musical_instrument": "nhạc cụ", + "plucked_string_instrument": "nhạc cụ dây gảy", + "guitar": "đàn guitar", + "electric_guitar": "đàn guitar điện", + "bass_guitar": "đàn guitar bass", + "acoustic_guitar": "đàn guitar acoustic", + "steel_guitar": "đàn steel guitar", + "tapping": "kỹ thuật tapping", + "strum": "gảy đàn", + "banjo": "đàn banjo", + "sitar": "đàn sitar", + "mandolin": "đàn mandolin", + "zither": "đàn tranh", + "ukulele": "đàn ukulele", + "keyboard": "bàn phím nhạc", + "piano": "đàn piano", + "electric_piano": "đàn piano điện", + "organ": "đàn organ", + "electronic_organ": "đàn organ điện tử", + "hammond_organ": "đàn organ Hammond", + "synthesizer": "bộ tổng hợp âm", + "sampler": "thiết bị lấy mẫu âm thanh", + "harpsichord": "đàn harpsichord", + "percussion": "bộ gõ", + "drum_kit": "bộ trống", + "drum_machine": "máy trống", + "drum": "trống", + "snare_drum": "trống snare", + "rimshot": "gõ vành trống", + "drum_roll": "cuộn trống", + "bass_drum": "trống bass", + "timpani": "trống timpani", + "tabla": "trống tabla", + "cymbal": "tiếng chũm chọe", + "hi_hat": "tiếng hi-hat", + "wood_block": "khối gỗ gõ", + "tambourine": "trống lắc", + "maraca": "tiếng lắc maraca", + "gong": "tiếng chiêng", + "tubular_bells": "chuông ống", + "mallet_percussion": "nhạc cụ gõ bằng dùi", + "marimba": "đàn marimba", + "glockenspiel": "chuông gõ glockenspiel", + "vibraphone": "đàn vibraphone", + "steelpan": "trống thép", + "orchestra": "dàn nhạc giao hưởng", + "brass_instrument": "nhạc cụ đồng", + "french_horn": "kèn Pháp", + "trumpet": "kèn trumpet", + "trombone": "kèn trombone", + "bowed_string_instrument": "nhạc cụ dây kéo", + "string_section": "dàn dây", + "violin": "đàn violin", + "pizzicato": "gảy dây pizzicato", + "cello": "đàn cello", + "double_bass": "đàn contrabass", + "wind_instrument": "nhạc cụ hơi", + "flute": "tiếng sáo", + "saxophone": "kèn saxophone", + "clarinet": "kèn clarinet", + "harp": "đàn harp", + "bell": "chuông", + "church_bell": "chuông nhà thờ", + "jingle_bell": "chuông leng keng", + "bicycle_bell": "chuông xe đạp", + "tuning_fork": "âm thoa", + "chime": "tiếng chuỗi chuông", + "wind_chime": "tiếng chuông gió", + "harmonica": "tiếng kèn harmonica", + "accordion": "tiếng đàn accordion", + "bagpipes": "tiếng kèn túi", + "didgeridoo": "tiếng kèn didgeridoo", + "theremin": "tiếng nhạc cụ theremin", + "singing_bowl": "tiếng chuông xoay Tây Tạng", + "scratching": "scratch nhạc (xoay đĩa)", + "pop_music": "nhạc pop", + "hip_hop_music": "nhạc hip hop", + "beatboxing": "beatbox", + "rock_music": "nhạc rock", + "heavy_metal": "nhạc heavy metal", + "punk_rock": "nhạc punk rock", + "grunge": "nhạc grunge", + "progressive_rock": "nhạc rock tiến bộ", + "rock_and_roll": "nhạc rock and roll", + "psychedelic_rock": "nhạc rock ảo giác", + "rhythm_and_blues": "nhạc R&B", + "soul_music": "nhạc soul", + "reggae": "nhạc reggae", + "country": "nhạc đồng quê", + "swing_music": "nhạc swing", + "bluegrass": "nhạc bluegrass", + "funk": "nhạc funk", + "folk_music": "nhạc dân gian", + "middle_eastern_music": "nhạc Trung Đông", + "jazz": "nhạc jazz", + "disco": "nhạc disco", + "classical_music": "nhạc cổ điển", + "opera": "nhạc opera", + "electronic_music": "nhạc điện tử", + "house_music": "nhạc house", + "techno": "nhạc techno", + "dubstep": "nhạc dubstep", + "drum_and_bass": "nhạc trống và bass", + "electronica": "nhạc electronica", + "electronic_dance_music": "nhạc nhảy điện tử", + "ambient_music": "nhạc nền", + "trance_music": "nhạc trance", + "music_of_latin_america": "nhạc Mỹ Latinh", + "salsa_music": "nhạc salsa", + "flamenco": "nhạc flamenco", + "blues": "nhạc blues", + "music_for_children": "nhạc thiếu nhi", + "new-age_music": "nhạc thời đại mới", + "vocal_music": "nhạc thanh nhạc", + "a_capella": "nhạc a cappella", + "music_of_africa": "nhạc châu Phi", + "afrobeat": "nhạc afrobeat", + "christian_music": "nhạc Cơ Đốc", + "gospel_music": "nhạc phúc âm", + "music_of_asia": "nhạc châu Á", + "carnatic_music": "nhạc Carnatic", + "music_of_bollywood": "nhạc Bollywood", + "ska": "nhạc ska", + "traditional_music": "nhạc truyền thống", + "independent_music": "nhạc indie", + "song": "bài hát", + "background_music": "nhạc nền", + "theme_music": "nhạc chủ đề", + "jingle": "nhạc quảng cáo", + "soundtrack_music": "nhạc phim", + "lullaby": "tiếng ru", + "video_game_music": "nhạc trò chơi", + "christmas_music": "nhạc Giáng Sinh", + "dance_music": "nhạc khiêu vũ", + "wedding_music": "nhạc đám cưới", + "happy_music": "nhạc vui", + "sad_music": "nhạc buồn", + "tender_music": "nhạc nhẹ nhàng", + "exciting_music": "nhạc sôi động", + "angry_music": "nhạc tức giận", + "scary_music": "nhạc rùng rợn", + "wind": "tiếng gió", + "rustling_leaves": "tiếng lá xào xạc", + "wind_noise": "tiếng gió rít", + "thunderstorm": "tiếng giông bão", + "water": "tiếng nước", + "thunder": "tiếng sấm", + "rain": "tiếng mưa", + "raindrop": "tiếng giọt mưa", + "rain_on_surface": "tiếng mưa rơi", + "stream": "tiếng suối", + "waterfall": "tiếng thác nước", + "ocean": "tiếng biển", + "waves": "tiếng sóng", + "steam": "tiếng hơi nước", + "gurgling": "tiếng róc rách", + "fire": "tiếng lửa", + "crackle": "tiếng tí tách", + "vehicle": "tiếng phương tiện", + "boat": "tiếng thuyền", + "sailboat": "tiếng thuyền buồm", + "rowboat": "tiếng chèo thuyền", + "motorboat": "tiếng xuồng máy", + "ship": "tiếng tàu", + "motor_vehicle": "tiếng xe cơ giới", + "car": "tiếng xe ô tô", + "toot": "tiếng bấm còi", + "car_alarm": "tiếng báo động ô tô", + "power_windows": "tiếng cửa kính xe", + "skidding": "tiếng trượt bánh", + "tire_squeal": "tiếng lốp rít", + "car_passing_by": "tiếng xe chạy qua", + "race_car": "tiếng xe đua", + "truck": "tiếng xe tải", + "ice_cream_truck": "tiếng xe kem", + "air_brake": "tiếng phanh hơi", + "air_horn": "tiếng còi hơi", + "reversing_beeps": "tiếng kêu lùi xe", + "bus": "tiếng xe buýt", + "emergency_vehicle": "tiếng xe khẩn cấp", + "police_car": "tiếng xe cảnh sát", + "ambulance": "tiếng xe cứu thương", + "fire_engine": "tiếng xe cứu hỏa", + "motorcycle": "tiếng xe máy", + "traffic_noise": "tiếng giao thông", + "rail_transport": "tiếng đường sắt", + "train_horn": "tiếng còi tàu hỏa", + "railroad_car": "tiếng toa tàu", + "train": "tiếng tàu hỏa", + "train_whistle": "tiếng còi tàu", + "train_wheels_squealing": "tiếng bánh tàu rít", + "subway": "tiếng tàu điện ngầm", + "aircraft": "tiếng máy bay", + "aircraft_engine": "tiếng động cơ máy bay", + "jet_engine": "tiếng động cơ phản lực", + "propeller": "tiếng cánh quạt", + "helicopter": "tiếng trực thăng", + "fixed-wing_aircraft": "tiếng máy bay cánh cố định", + "bicycle": "tiếng xe đạp", + "skateboard": "tiếng ván trượt", + "engine": "tiếng động cơ", + "light_engine": "tiếng động cơ nhẹ", + "dental_drill's_drill": "tiếng khoan nha khoa", + "lawn_mower": "tiếng máy cắt cỏ", + "chainsaw": "tiếng cưa máy", + "medium_engine": "tiếng động cơ vừa", + "heavy_engine": "tiếng động cơ nặng", + "engine_knocking": "tiếng gõ máy", + "engine_starting": "tiếng khởi động động cơ", + "ding-dong": "tiếng ding-dong", + "idling": "tiếng nổ không tải", + "accelerating": "tiếng tăng tốc", + "door": "tiếng cửa", + "doorbell": "tiếng chuông cửa", + "sliding_door": "tiếng cửa trượt", + "slam": "tiếng đóng sầm", + "knock": "tiếng gõ cửa", + "tap": "tiếng gõ nhẹ", + "squeak": "tiếng kêu cót két", + "cupboard_open_or_close": "tiếng mở/đóng tủ", + "drawer_open_or_close": "tiếng mở/đóng ngăn kéo", + "dishes": "tiếng bát đĩa", + "cutlery": "tiếng dao nĩa", + "chopping": "tiếng băm chặt", + "frying": "tiếng chiên xào", + "microwave_oven": "tiếng lò vi sóng", + "blender": "tiếng máy xay", + "water_tap": "tiếng vòi nước", + "sink": "tiếng bồn rửa", + "bathtub": "tiếng bồn tắm", + "coin": "tiếng đồng xu", + "hair_dryer": "tiếng máy sấy tóc", + "toilet_flush": "tiếng xả nước", + "toothbrush": "tiếng bàn chải", + "electric_toothbrush": "tiếng bàn chải điện", + "vacuum_cleaner": "tiếng máy hút bụi", + "zipper": "tiếng dây kéo", + "keys_jangling": "tiếng chìa khóa leng keng", + "scissors": "tiếng kéo cắt", + "electric_shaver": "tiếng máy cạo râu", + "shuffling_cards": "tiếng xào bài", + "typing": "tiếng gõ phím", + "typewriter": "tiếng máy đánh chữ", + "computer_keyboard": "tiếng bàn phím", + "writing": "tiếng viết", + "alarm": "tiếng báo động", + "telephone": "tiếng điện thoại", + "telephone_bell_ringing": "tiếng chuông điện thoại", + "ringtone": "tiếng nhạc chuông", + "telephone_dialing": "tiếng quay số", + "dial_tone": "tiếng âm quay số", + "busy_signal": "tiếng tín hiệu bận", + "alarm_clock": "tiếng đồng hồ báo thức", + "siren": "tiếng còi báo động", + "civil_defense_siren": "tiếng còi phòng không", + "buzzer": "tiếng chuông báo", + "smoke_detector": "tiếng báo khói", + "fire_alarm": "tiếng báo cháy", + "foghorn": "tiếng còi sương", + "whistle": "tiếng còi", + "steam_whistle": "tiếng còi hơi", + "mechanisms": "tiếng cơ khí", + "ratchet": "tiếng cơ cấu bánh cóc", + "clock": "tiếng đồng hồ", + "tick": "tiếng tích", + "tick-tock": "tiếng tích tắc", + "gears": "tiếng bánh răng", + "pulleys": "tiếng ròng rọc", + "sewing_machine": "tiếng máy may", + "camera": "tiếng máy ảnh", + "single-lens_reflex_camera": "tiếng máy ảnh DSLR", + "mechanical_fan": "tiếng quạt máy", + "air_conditioning": "tiếng máy lạnh", + "cash_register": "tiếng máy tính tiền", + "printer": "tiếng máy in", + "tools": "tiếng dụng cụ", + "hammer": "tiếng búa", + "jackhammer": "tiếng khoan bê tông", + "sawing": "tiếng cưa", + "filing": "tiếng giũa", + "sanding": "tiếng chà nhám", + "power_tool": "tiếng dụng cụ điện", + "drill": "tiếng máy khoan", + "explosion": "tiếng nổ", + "gunshot": "tiếng súng", + "machine_gun": "tiếng súng máy", + "fusillade": "tiếng loạt súng", + "radio": "tiếng radio", + "field_recording": "ghi âm hiện trường", + "scream": "tiếng hét" +} diff --git a/web/public/locales/vi/common.json b/web/public/locales/vi/common.json new file mode 100644 index 000000000..97b5d2b75 --- /dev/null +++ b/web/public/locales/vi/common.json @@ -0,0 +1,228 @@ +{ + "time": { + "untilRestart": "còn lại đến khi khởi động lại", + "untilForTime": "Cho đến khi {{time}}", + "untilForRestart": "Cho đến khi Frigate khởi động lại.", + "ago": "{{timeAgo}} trước", + "formattedTimestamp": { + "12hour": "định dạng thời gian 12 giờ", + "24hour": "định dạng thời gian 24 giờ" + }, + "year_other": "{{time}} năm", + "month_other": "{{time}} tháng", + "day_other": "{{time}} ngày", + "hour_other": "{{time}} giờ", + "minute_other": "{{time}} phút", + "second_other": "{{time}} giây", + "justNow": "vừa xong", + "today": "hôm nay", + "yesterday": "hôm qua", + "last7": "7 ngày qua", + "last14": "14 ngày qua", + "last30": "30 ngày qua", + "thisWeek": "tuần này", + "lastWeek": "tuần trước", + "thisMonth": "tháng này", + "lastMonth": "tháng trước", + "5minutes": "5 phút", + "10minutes": "10 phút", + "30minutes": "30 phút", + "1hour": "1 giờ", + "12hours": "12 giờ", + "24hours": "24 giờ", + "pm": "chiều", + "am": "sáng", + "mo": "{{time}}tháng", + "d": "{{time}}ngày", + "m": "{{time}}phút", + "s": "{{time}}giây", + "formattedTimestamp2": { + "12hour": "định dạng thời gian 12 giờ (2)", + "24hour": "định dạng thời gian 24 giờ (2)" + }, + "formattedTimestampExcludeSeconds": { + "12hour": "thời gian 12 giờ (không giây)", + "24hour": "thời gian 24 giờ (không giây)" + }, + "formattedTimestampWithYear": { + "12hour": "thời gian 12 giờ kèm năm", + "24hour": "thời gian 24 giờ kèm năm" + }, + "formattedTimestampOnlyMonthAndDay": "chỉ tháng và ngày", + "yr": "{{time}}năm", + "h": "{{time}}giờ" + }, + "menu": { + "systemLogs": "nhật ký hệ thống", + "user": { + "account": "tài khoản", + "anonymous": "ẩn danh", + "logout": "đăng xuất", + "setPassword": "đặt mật khẩu", + "current": "Người dùng hiện tại: {{user}}", + "title": "người dùng" + }, + "language": { + "en": "Tiếng Anh", + "es": "Tiếng Tây Ban Nha", + "zhCN": "Tiếng Trung (Giản thể)", + "ar": "Tiếng Ả Rập", + "hi": "Tiếng Hindi", + "fr": "Tiếng Pháp", + "pt": "Tiếng Bồ Đào Nha", + "ru": "Tiếng Nga", + "de": "Tiếng Đức", + "ja": "Tiếng Nhật", + "tr": "Tiếng Thổ Nhĩ Kỳ", + "it": "Tiếng Ý", + "nl": "Tiếng Hà Lan", + "sv": "Tiếng Thụy Điển", + "cs": "Tiếng Séc", + "nb": "Tiếng Na Uy", + "ko": "Tiếng Hàn", + "pl": "Tiếng Ba Lan", + "vi": "Tiếng Việt", + "fa": "Tiếng Ba Tư", + "uk": "Tiếng Ukraina", + "he": "Tiếng Do Thái", + "el": "Tiếng Hy Lạp", + "ro": "Tiếng Romania", + "hu": "Tiếng Hungary", + "fi": "Tiếng Phần Lan", + "da": "Tiếng Đan Mạch", + "sk": "Tiếng Slovakia", + "withSystem": { + "label": "Theo hệ thống" + } + }, + "system": "hệ thống", + "systemMetrics": "thông số hệ thống", + "configuration": "cấu hình", + "settings": "cài đặt", + "configurationEditor": "trình chỉnh sửa cấu hình", + "languages": "ngôn ngữ", + "appearance": "giao diện", + "darkMode": { + "label": "chế độ tối", + "light": "sáng", + "dark": "tối", + "withSystem": { + "label": "theo hệ thống" + } + }, + "withSystem": "theo hệ thống", + "theme": { + "label": "giao diện", + "red": "đỏ", + "contrast": "tương phản", + "blue": "xanh dương", + "green": "xanh lá", + "nord": "nord", + "default": "mặc định" + }, + "help": "trợ giúp", + "documentation": { + "title": "tài liệu", + "label": "hướng dẫn" + }, + "restart": "khởi động lại", + "live": { + "title": "trực tiếp", + "allCameras": "tất cả camera", + "cameras": { + "title": "camera", + "count_other": "{{count}} Camera" + } + }, + "review": "xem lại", + "explore": "khám phá", + "export": "xuất", + "uiPlayground": "UI Playground", + "faceLibrary": "thư viện khuôn mặt" + }, + "unit": { + "speed": { + "mph": "mph (dặm/giờ)", + "kph": "km/h (kilômét/giờ)" + } + }, + "label": { + "back": "quay lại" + }, + "button": { + "apply": "áp dụng", + "reset": "đặt lại", + "done": "xong", + "enabled": "đã bật", + "enable": "bật", + "disabled": "đã tắt", + "disable": "tắt", + "save": "Lưu", + "cancel": "hủy", + "close": "đóng", + "copy": "sao chép", + "back": "quay lại", + "history": "lịch sử", + "fullscreen": "toàn màn hình", + "on": "bật", + "exitFullscreen": "thoát toàn màn hình", + "pictureInPicture": "hình trong hình", + "twoWayTalk": "đàm thoại hai chiều", + "cameraAudio": "âm thanh camera", + "off": "tắt", + "edit": "chỉnh sửa", + "copyCoordinates": "sao chép tọa độ", + "delete": "Xóa", + "yes": "có", + "no": "không", + "download": "tải xuống", + "info": "thông tin", + "suspended": "tạm dừng", + "unsuspended": "khôi phục", + "play": "phát", + "unselect": "bỏ chọn", + "export": "xuất", + "deleteNow": "xóa ngay", + "next": "tiếp theo", + "saving": "Đang lưu…" + }, + "toast": { + "copyUrlToClipboard": "Đã sao chép liên kết.", + "save": { + "title": "lưu thành công", + "error": { + "noMessage": "không có thông báo lỗi", + "title": "Lỗi khi lưu thay đổi cấu hình: {{errorMessage}}" + } + } + }, + "role": { + "title": "vai trò", + "admin": "quản trị viên", + "viewer": "người xem", + "desc": "Quản trị viên có toàn quyền truy cập tất cả các tính năng trong giao diện Frigate. Người xem chỉ được phép xem camera, mục đã ghi lại và các đoạn video lịch sử trong giao diện." + }, + "pagination": { + "label": "trang", + "previous": { + "title": "trước đó", + "label": "trước" + }, + "next": { + "title": "kế tiếp", + "label": "tiếp" + }, + "more": "xem thêm" + }, + "accessDenied": { + "documentTitle": "từ chối truy cập", + "title": "truy cập bị từ chối", + "desc": "Bạn không có quyền truy cập vào trang này." + }, + "notFound": { + "documentTitle": "không tìm thấy", + "title": "không tìm thấy", + "desc": "trang bạn đang tìm không tồn tại" + }, + "selectItem": "Chọn mục {{item}}" +} diff --git a/web/public/locales/vi/components/auth.json b/web/public/locales/vi/components/auth.json new file mode 100644 index 000000000..3d942b9c2 --- /dev/null +++ b/web/public/locales/vi/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "user": "Tên người dùng", + "password": "Mật khẩu", + "login": "Đăng nhập", + "errors": { + "usernameRequired": "Tên người dùng là bắt buộc", + "passwordRequired": "Mật khẩu là bắt buộc", + "rateLimit": "Đã vượt quá giới hạn tốc độ. Hãy thử lại sau.", + "loginFailed": "Đăng nhập không thành công", + "unknownError": "Lỗi không xác định. Kiểm tra nhật ký.", + "webUnknownError": "Lỗi không xác định. Kiểm tra nhật ký bảng điều khiển." + } + } +} diff --git a/web/public/locales/vi/components/camera.json b/web/public/locales/vi/components/camera.json new file mode 100644 index 000000000..2e74eeb29 --- /dev/null +++ b/web/public/locales/vi/components/camera.json @@ -0,0 +1,12 @@ +{ + "group": { + "delete": { + "label": "Xóa nhóm camera", + "confirm": { + "title": "Xác nhận xóa" + } + }, + "label": "Các nhóm Camera", + "add": "Thêm nhóm Camera" + } +} diff --git a/web/public/locales/vi/components/dialog.json b/web/public/locales/vi/components/dialog.json new file mode 100644 index 000000000..49edf5f85 --- /dev/null +++ b/web/public/locales/vi/components/dialog.json @@ -0,0 +1,62 @@ +{ + "restart": { + "title": "Bạn có chắc chắn muốn khởi động lại Frigate không?", + "button": "Khởi động lại", + "restarting": { + "title": "Đang khởi động lại Frigate", + "content": "Trang này sẽ tải lại sau {{countdown}} giây." + } + }, + "explore": { + "plus": { + "review": { + "question": { + "ask_a": "Đây có phải là {{label}} không?", + "ask_an": "Đây có phải là {{label}} không?", + "label": "Xác nhận nhãn này cho Frigate Plus", + "ask_full": "Đây có phải là {{untranslatedLabel}} ({{translatedLabel}}) không?" + }, + "state": { + "submitted": "Đã gửi" + } + }, + "submitToPlus": { + "label": "Gửi lên Frigate+", + "desc": "Đối tượng xuất hiện ở các khu vực bạn muốn tránh không được xem là phát hiện sai. Gửi chúng lên dưới dạng phát hiện sai có thể làm mô hình bị nhầm lẫn." + } + }, + "video": { + "viewInHistory": "Xem lại trong Lịch sử" + } + }, + "export": { + "time": { + "fromTimeline": "Chọn từ Dòng thời gian", + "custom": "Tuỳ chọn", + "start": { + "title": "Thời gian bắt đầu", + "label": "Chọn thời gian bắt đầu" + }, + "end": { + "title": "Thời gian kết thúc", + "label": "Chọn thời gian kết thúc" + } + }, + "name": { + "placeholder": "Đặt tên cho bản xuất" + }, + "select": "Chọn", + "export": "Xuất", + "selectOrExport": "Chọn hay xuất", + "toast": { + "error": { + "endTimeMustAfterStartTime": "Thời gian kết thúc phải sau thời gian bắt đầu", + "noVaildTimeSelected": "Chưa chọn khoảng thời gian hợp lệ" + } + }, + "fromTimeline": { + "saveExport": "Lưu bản xuất", + "previewExport": "Xem trước bản xuất" + } + } +} diff --git a/web/public/locales/vi/components/filter.json b/web/public/locales/vi/components/filter.json new file mode 100644 index 000000000..d8b825b31 --- /dev/null +++ b/web/public/locales/vi/components/filter.json @@ -0,0 +1,10 @@ +{ + "filter": "Lọc", + "labels": { + "label": "Nhãn", + "all": { + "title": "Tất cả các nhãn", + "short": "Nhãn" + } + } +} diff --git a/web/public/locales/vi/components/icons.json b/web/public/locales/vi/components/icons.json new file mode 100644 index 000000000..666736ef0 --- /dev/null +++ b/web/public/locales/vi/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "Chọn một biểu tượng", + "search": { + "placeholder": "Tìm kiếm một biểu tượng…" + } + } +} diff --git a/web/public/locales/vi/components/input.json b/web/public/locales/vi/components/input.json new file mode 100644 index 000000000..bc5aa1a5a --- /dev/null +++ b/web/public/locales/vi/components/input.json @@ -0,0 +1,7 @@ +{ + "button": { + "downloadVideo": { + "label": "Tải xuống video" + } + } +} diff --git a/web/public/locales/vi/components/player.json b/web/public/locales/vi/components/player.json new file mode 100644 index 000000000..cd4112d89 --- /dev/null +++ b/web/public/locales/vi/components/player.json @@ -0,0 +1,5 @@ +{ + "noRecordingsFoundForThisTime": "Không tìm thấy bản ghi nào cho thời điểm này", + "noPreviewFound": "Không tìm thấy bản xem trước", + "noPreviewFoundFor": "Không tìm thấy bản xem trước cho {{cameraName}}" +} diff --git a/web/public/locales/vi/objects.json b/web/public/locales/vi/objects.json new file mode 100644 index 000000000..e5d369d14 --- /dev/null +++ b/web/public/locales/vi/objects.json @@ -0,0 +1,29 @@ +{ + "mouse": "Chuột nhắt", + "keyboard": "bàn phím nhạc", + "blender": "tiếng máy xay", + "sink": "tiếng bồn rửa", + "animal": "Động vật", + "dog": "Chó", + "bark": "Sủa", + "cat": "Mèo", + "horse": "Ngựa", + "goat": "Dê", + "sheep": "Cừu", + "bird": "Chim", + "vehicle": "tiếng phương tiện", + "boat": "tiếng thuyền", + "car": "tiếng xe ô tô", + "bus": "tiếng xe buýt", + "motorcycle": "tiếng xe máy", + "train": "tiếng tàu hỏa", + "bicycle": "tiếng xe đạp", + "skateboard": "tiếng ván trượt", + "door": "tiếng cửa", + "hair_dryer": "tiếng máy sấy tóc", + "toothbrush": "tiếng bàn chải", + "scissors": "tiếng kéo cắt", + "clock": "tiếng đồng hồ", + "person": "Người", + "airplane": "Máy bay" +} diff --git a/web/public/locales/vi/views/configEditor.json b/web/public/locales/vi/views/configEditor.json new file mode 100644 index 000000000..c9577f82a --- /dev/null +++ b/web/public/locales/vi/views/configEditor.json @@ -0,0 +1,5 @@ +{ + "copyConfig": "Sao chép cấu hình", + "saveAndRestart": "Lưu & Khởi động lại", + "saveOnly": "Chỉ lưu" +} diff --git a/web/public/locales/vi/views/events.json b/web/public/locales/vi/views/events.json new file mode 100644 index 000000000..ad469617b --- /dev/null +++ b/web/public/locales/vi/views/events.json @@ -0,0 +1,9 @@ +{ + "camera": "tiếng máy ảnh", + "alerts": "Cảnh báo", + "detections": "Phát hiện", + "motion": { + "only": "Chỉ chuyển động" + }, + "allCameras": "Tất cả Camera" +} diff --git a/web/public/locales/vi/views/explore.json b/web/public/locales/vi/views/explore.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/web/public/locales/vi/views/explore.json @@ -0,0 +1 @@ +{} diff --git a/web/public/locales/vi/views/exports.json b/web/public/locales/vi/views/exports.json new file mode 100644 index 000000000..ee3936522 --- /dev/null +++ b/web/public/locales/vi/views/exports.json @@ -0,0 +1,3 @@ +{ + "search": "Tìm kiếm" +} diff --git a/web/public/locales/vi/views/faceLibrary.json b/web/public/locales/vi/views/faceLibrary.json new file mode 100644 index 000000000..9cc90f14f --- /dev/null +++ b/web/public/locales/vi/views/faceLibrary.json @@ -0,0 +1,9 @@ +{ + "selectItem": "Chọn mục {{item}}", + "description": { + "addFace": "Hướng dẫn thêm bộ sưu tập mới vào Thư viện khuôn mặt." + }, + "details": { + "person": "Người" + } +} diff --git a/web/public/locales/vi/views/live.json b/web/public/locales/vi/views/live.json new file mode 100644 index 000000000..b75aa66db --- /dev/null +++ b/web/public/locales/vi/views/live.json @@ -0,0 +1,8 @@ +{ + "documentTitle": "Trực tiếp - Frigate", + "documentTitle.withCamera": "{{camera}} - Trực tiếp - Frigate", + "lowBandwidthMode": "Chế độ băng thông thấp", + "twoWayTalk": { + "enable": "Bật chế độ đàm thoại hai chiều" + } +} diff --git a/web/public/locales/vi/views/recording.json b/web/public/locales/vi/views/recording.json new file mode 100644 index 000000000..27146b13d --- /dev/null +++ b/web/public/locales/vi/views/recording.json @@ -0,0 +1,6 @@ +{ + "filter": "Lọc", + "export": "Xuất", + "calendar": "Lịch", + "filters": "Bộ lọc" +} diff --git a/web/public/locales/vi/views/search.json b/web/public/locales/vi/views/search.json new file mode 100644 index 000000000..873702ca7 --- /dev/null +++ b/web/public/locales/vi/views/search.json @@ -0,0 +1,10 @@ +{ + "search": "Tìm kiếm", + "savedSearches": "Lưu tìm kiếm", + "searchFor": "Tìm kiếm {{inputValue}}", + "button": { + "clear": "Xóa tìm kiếm", + "save": "Lưu tìm kiếm", + "delete": "Xóa lưu tìm kiếm" + } +} diff --git a/web/public/locales/vi/views/settings.json b/web/public/locales/vi/views/settings.json new file mode 100644 index 000000000..54c2f22a2 --- /dev/null +++ b/web/public/locales/vi/views/settings.json @@ -0,0 +1,7 @@ +{ + "documentTitle": { + "default": "Cài đặt - Frigate", + "authentication": "Cài đặt xác thực - Frigate", + "camera": "Cài đặt camera - Frigate" + } +} diff --git a/web/public/locales/vi/views/system.json b/web/public/locales/vi/views/system.json new file mode 100644 index 000000000..7bb2dcc99 --- /dev/null +++ b/web/public/locales/vi/views/system.json @@ -0,0 +1,6 @@ +{ + "documentTitle": { + "storage": "Thống kê lưu trữ - Frigate", + "general": "Thống kê chung - Frigate" + } +} diff --git a/web/public/locales/yue-Hant/audio.json b/web/public/locales/yue-Hant/audio.json new file mode 100644 index 000000000..8d29100d5 --- /dev/null +++ b/web/public/locales/yue-Hant/audio.json @@ -0,0 +1,429 @@ +{ + "speech": "講話", + "babbling": "牙牙學語", + "yell": "大嗌", + "bellow": "咆哮", + "whoop": "歡呼聲", + "whispering": "細細聲", + "laughter": "笑聲", + "sigh": "歎氣聲", + "crying": "喊聲", + "yodeling": "山歌", + "choir": "合唱", + "snicker": "偷笑聲", + "mantra": "咒語", + "singing": "歌聲", + "chant": "唸經", + "breathing": "呼吸聲", + "child_singing": "兒童歌聲", + "rapping": "饒舌", + "humming": "哼歌", + "whistling": "口哨聲", + "synthetic_singing": "人造歌聲", + "groan": "呻吟聲", + "grunt": "哼聲", + "snort": "哼哼聲", + "throat_clearing": "清喉嚨", + "wheeze": "氣喘聲", + "snoring": "鼻鼾聲", + "gasp": "喘氣", + "pant": "急促喘氣", + "cough": "咳嗽", + "sneeze": "打乞嚏", + "shuffle": "拖步行", + "sniff": "嗅嗅聲", + "footsteps": "腳步聲", + "chewing": "咀嚼聲", + "biting": "咬嘢聲", + "gargling": "漱口聲", + "run": "跑步", + "stomach_rumble": "肚餓聲", + "burping": "打嗝聲", + "clapping": "掌聲", + "children_playing": "兒童玩耍聲", + "applause": "掌聲", + "heartbeat": "心跳", + "growling": "狗咆哮聲", + "bow_wow": "狗汪汪聲", + "caterwaul": "貓嚎叫", + "howl": "狗慘叫聲", + "livestock": "牲畜", + "clip_clop": "馬蹄聲", + "cattle": "牛", + "horse": "馬", + "heart_murmur": "心臟雜音", + "fart": "放屁", + "hands": "手", + "cheering": "歡呼聲", + "dog": "狗", + "bark": "樹皮", + "yip": "狗尖叫聲", + "chatter": "嘈雜聲", + "purr": "貓呼嚕聲", + "whimper_dog": "狗嗚咽聲", + "hiccup": "打嗝聲", + "finger_snapping": "彈手指聲", + "crowd": "人群聲", + "animal": "動物", + "pets": "寵物", + "cat": "貓", + "meow": "貓喵喵聲", + "hiss": "貓嘶嘶聲", + "neigh": "馬嘶聲", + "cowbell": "牛鈴", + "moo": "牛哞哞聲", + "gobble": "火雞叫聲", + "turkey": "火雞", + "chicken": "雞", + "cluck": "雞咯咯聲", + "fowl": "家禽", + "sheep": "羊", + "duck": "鴨子", + "goat": "山羊", + "pig": "豬", + "oink": "豬哼聲", + "bleat": "咩咩聲", + "cock_a_doodle_doo": "公雞叫聲", + "honk": "鵝叫聲", + "quack": "鴨叫聲", + "goose": "鵝", + "wild_animals": "野生動物", + "crow": "烏鴉", + "coo": "白鴿咕咕聲", + "pigeon": "白鴿", + "roaring_cats": "貓咆哮聲", + "roar": "咆哮聲", + "bird": "鳥", + "chirp": "鳥啾啾聲", + "squawk": "鳥嘎嘎聲", + "caw": "烏鴉呱呱聲", + "mouse": "滑鼠", + "owl": "貓頭鷹", + "rats": "大老鼠", + "hoot": "貓頭鷹咕咕聲", + "patter": "老鼠腳步聲", + "flapping_wings": "拍打翅膀聲", + "dogs": "狗", + "snake": "蛇", + "insect": "昆蟲", + "whale_vocalization": "鯨魚叫聲", + "rattle": "蛇叫聲", + "fly": "蒼蠅", + "croak": "青蛙呱呱聲", + "mosquito": "蚊", + "music": "音樂", + "frog": "青蛙", + "cricket": "蟋蟀", + "buzz": "嗡嗡聲", + "musical_instrument": "樂器", + "steel_guitar": "鋼弦結他", + "tapping": "拍擊", + "guitar": "結他", + "strum": "撥弦聲", + "electric_guitar": "電結他", + "plucked_string_instrument": "撥弦樂器", + "bass_guitar": "低音結他", + "banjo": "班祖琴", + "acoustic_guitar": "原聲結他", + "piano": "鋼琴", + "synthesizer": "合成器", + "keyboard": "鍵盤", + "organ": "風琴", + "sitar": "錫塔琴", + "mandolin": "曼陀鈴", + "zither": "齊特琴", + "ukulele": "烏克麗麗", + "sampler": "採樣器", + "hammond_organ": "哈蒙德風琴", + "electric_piano": "電子鋼琴", + "electronic_organ": "電子風琴", + "rimshot": "鼓邊敲擊", + "bass_drum": "低音鼓", + "drum_kit": "鼓套", + "drum_machine": "鼓機", + "drum": "鼓", + "snare_drum": "小鼓", + "timpani": "定音鼓", + "drum_roll": "鼓聲", + "harpsichord": "大鍵琴", + "percussion": "打擊樂器", + "trumpet": "小號", + "cymbal": "銅鈸", + "french_horn": "法國號", + "string_section": "弦樂組", + "saxophone": "色士風", + "marimba": "馬林巴琴", + "mallet_percussion": "鎚擊樂器", + "maraca": "沙槌", + "harp": "豎琴", + "orchestra": "管弦樂團", + "violin": "小提琴", + "gong": "鑼", + "flute": "長笛", + "bowed_string_instrument": "弓弦樂器", + "vibraphone": "顫音琴", + "tabla": "塔布拉鼓", + "trombone": "長號", + "tambourine": "鈴鼓", + "double_bass": "低音提琴", + "brass_instrument": "銅管樂器", + "cello": "大提琴", + "clarinet": "單簧管", + "pizzicato": "撥奏", + "hi_hat": "高帽鈸", + "wood_block": "木魚", + "tubular_bells": "管鐘", + "glockenspiel": "鐘琴", + "steelpan": "鋼鼓", + "wind_instrument": "管樂器", + "bell": "鐘", + "bicycle_bell": "單車鈴", + "wind_chime": "風鈴", + "church_bell": "教堂鐘聲", + "chime": "鈴聲", + "tuning_fork": "音叉", + "jingle_bell": "鈴鐺", + "accordion": "手風琴", + "bagpipes": "風笛", + "didgeridoo": "迪吉里杜管", + "theremin": "特雷門琴", + "singing_bowl": "頌缽", + "scratching": "抓碟聲", + "pop_music": "流行音樂", + "hip_hop_music": "嘻哈音樂", + "harmonica": "口琴", + "beatboxing": "人聲節奏", + "country": "鄉村音樂", + "water": "水", + "scary_music": "恐怖音樂", + "music_of_asia": "亞洲音樂", + "dance_music": "舞曲", + "video_game_music": "電子遊戲音樂", + "thunderstorm": "雷雨", + "bluegrass": "藍草音樂", + "train_wheels_squealing": "火車車輪聲", + "techno": "電子舞曲", + "new-age_music": "新世紀音樂", + "background_music": "背景音樂", + "theme_music": "主題音樂", + "jingle": "鈴聲", + "bus": "巴士", + "emergency_vehicle": "緊急車輛", + "aircraft": "飛機", + "ice_cream_truck": "雪糕車", + "dubstep": "杜步音樂", + "aircraft_engine": "飛機引擎聲", + "funk": "放克音樂", + "lullaby": "搖籃曲", + "rain": "雨", + "happy_music": "快樂音樂", + "music_of_latin_america": "拉丁美洲音樂", + "soundtrack_music": "配樂", + "rock_music": "搖滾樂", + "rock_and_roll": "搖滾樂", + "psychedelic_rock": "迷幻搖滾", + "rhythm_and_blues": "節奏藍調", + "soul_music": "靈魂音樂", + "reggae": "雷鬼音樂", + "folk_music": "民謠音樂", + "middle_eastern_music": "中東音樂", + "jazz": "爵士樂", + "disco": "迪斯可音樂", + "classical_music": "古典音樂", + "opera": "歌劇", + "electronic_music": "電子音樂", + "house_music": "浩室音樂", + "electronic_dance_music": "電子舞曲", + "ambient_music": "環境音樂", + "trance_music": "迷幻音樂", + "salsa_music": "薩爾薩音樂", + "flamenco": "佛朗明哥", + "blues": "藍調音樂", + "music_for_children": "兒童音樂", + "vocal_music": "聲樂", + "a_capella": "無伴奏合唱", + "music_of_africa": "非洲音樂", + "afrobeat": "非洲節拍", + "christian_music": "基督教音樂", + "gospel_music": "福音音樂", + "music_of_bollywood": "寶萊塢音樂", + "ska": "斯卡音樂", + "traditional_music": "傳統音樂", + "independent_music": "獨立音樂", + "song": "歌曲", + "raindrop": "雨點聲", + "rain_on_surface": "雨打地面聲", + "stream": "小溪", + "waterfall": "瀑布", + "ocean": "海洋", + "waves": "波浪", + "steam": "蒸氣", + "gurgling": "咕嚕聲", + "fire": "火", + "crackle": "劈啪聲", + "vehicle": "車輛", + "boat": "船", + "sailboat": "帆船", + "rowboat": "划艇", + "motorboat": "機動船", + "ship": "船", + "motor_vehicle": "機動車", + "car": "車", + "toot": "汽車響咹聲", + "car_alarm": "汽車防盜器", + "power_windows": "電動車窗", + "skidding": "車胎打滑聲", + "tire_squeal": "車胎尖叫聲", + "car_passing_by": "車駛過聲", + "race_car": "賽車", + "truck": "貨車", + "air_brake": "煞車聲", + "air_horn": "空氣喇叭", + "police_car": "警車", + "ambulance": "救護車", + "fire_engine": "消防車", + "motorcycle": "電單車", + "rail_transport": "鐵路運輸", + "train_whistle": "火車汽笛聲", + "train_horn": "火車喇叭聲", + "railroad_car": "火車車廂", + "propeller": "螺旋槳", + "helicopter": "直升機", + "fixed-wing_aircraft": "固定翼飛機", + "bicycle": "單車", + "skateboard": "滑板", + "engine": "引擎", + "light_engine": "小型引擎", + "dental_drill's_drill": "牙科鑽機", + "lawn_mower": "剪草機", + "chainsaw": "電鋸", + "medium_engine": "中型引擎", + "heavy_engine": "大型引擎", + "engine_knocking": "引擎敲擊聲", + "engine_starting": "引擎啟動聲", + "idling": "引擎空轉聲", + "accelerating": "加速聲", + "door": "門", + "doorbell": "門鈴", + "ding-dong": "叮咚聲", + "sliding_door": "趟門", + "knock": "敲門", + "tap": "輕敲門", + "squeak": "吱吱聲", + "cupboard_open_or_close": "櫃門開關聲", + "drawer_open_or_close": "抽屜開關聲", + "dishes": "餐具聲", + "cutlery": "刀叉", + "chopping": "切菜聲", + "frying": "炒煮", + "microwave_oven": "微波爐", + "water_tap": "水龍頭", + "electric_toothbrush": "電動牙刷", + "vacuum_cleaner": "吸塵機", + "zipper": "拉鍊", + "keys_jangling": "鎖匙碰撞聲", + "coin": "硬幣", + "scissors": "剪刀", + "electric_shaver": "電鬚刨", + "shuffling_cards": "洗牌", + "typing": "打字", + "computer_keyboard": "電腦鍵盤", + "telephone": "電話", + "telephone_bell_ringing": "電話鈴聲", + "siren": "警報聲", + "steam_whistle": "蒸氣汽笛", + "mechanisms": "機械聲", + "ratchet": "棘輪聲", + "clock": "時鐘", + "tick": "滴答聲", + "tick-tock": "滴答滴答聲", + "sewing_machine": "衣車", + "mechanical_fan": "機械風扇", + "printer": "印表機", + "camera": "鏡頭", + "single-lens_reflex_camera": "單反相機", + "tools": "工具", + "hammer": "鎚仔", + "sawing": "鋸", + "filing": "銼", + "sanding": "打磨", + "power_tool": "電動工具", + "drill": "鑽", + "explosion": "爆炸", + "fusillade": "連環射擊", + "artillery_fire": "火砲", + "cap_gun": "玩具槍", + "fireworks": "煙花", + "firecracker": "炮仗", + "burst": "爆裂", + "eruption": "爆發", + "wood": "木頭", + "chop": "劈木聲", + "splinter": "木刺聲", + "crack": "裂聲", + "shatter": "破碎聲", + "silence": "寂靜", + "sound_effect": "音效", + "white_noise": "白噪音", + "pink_noise": "粉紅噪音", + "television": "電視", + "radio": "收音機", + "field_recording": "現場錄音", + "angry_music": "憤怒音樂", + "sad_music": "悲傷音樂", + "wind": "風", + "wind_noise": "風聲", + "drum_and_bass": "鼓和貝斯", + "wedding_music": "婚禮音樂", + "progressive_rock": "前衛搖滾", + "grunge": "垃圾搖滾", + "punk_rock": "朋克搖滾", + "christmas_music": "聖誕音樂", + "subway": "地鐵", + "thunder": "雷聲", + "carnatic_music": "卡納蒂克音樂", + "traffic_noise": "交通噪音", + "train": "火車", + "slam": "砰門聲", + "tender_music": "溫柔音樂", + "reversing_beeps": "倒車提示聲", + "heavy_metal": "重金屬音樂", + "jet_engine": "噴射機引擎聲", + "rustling_leaves": "樹葉沙沙聲", + "electronica": "電子樂", + "swing_music": "搖擺音樂", + "exciting_music": "刺激音樂", + "ringtone": "鈴聲", + "pulleys": "滑輪", + "jackhammer": "風鑽", + "writing": "寫作", + "toilet_flush": "沖廁", + "whistle": "哨子聲", + "gunshot": "槍聲", + "alarm_clock": "鬧鐘", + "dial_tone": "電話按號聲", + "boom": "轟隆", + "typewriter": "打字機", + "blender": "攪拌機", + "toothbrush": "牙刷", + "cash_register": "收銀機", + "civil_defense_siren": "民防警報", + "machine_gun": "機關槍", + "sink": "洗手盆", + "fire_alarm": "火警鐘", + "bathtub": "浴缸", + "busy_signal": "線路繁忙聲", + "smoke_detector": "煙霧偵測器", + "hair_dryer": "吹風機", + "alarm": "警報", + "gears": "齒輪", + "telephone_dialing": "電話撥號聲", + "foghorn": "霧號", + "buzzer": "蜂鳴器聲", + "air_conditioning": "冷氣機", + "glass": "玻璃", + "chink": "碰撞聲", + "environmental_noise": "環境噪音", + "static": "靜電聲", + "scream": "尖叫聲" +} diff --git a/web/public/locales/yue-Hant/common.json b/web/public/locales/yue-Hant/common.json new file mode 100644 index 000000000..3f4b4d468 --- /dev/null +++ b/web/public/locales/yue-Hant/common.json @@ -0,0 +1,242 @@ +{ + "time": { + "untilForTime": "直到 {{time}}", + "untilRestart": "直到重新啟動", + "yesterday": "昨日", + "last7": "過去7日", + "last14": "過去14日", + "last30": "過去30日", + "thisWeek": "今個星期", + "lastMonth": "上個月", + "10minutes": "10分鐘", + "12hours": "12 小時", + "24hours": "24 小時", + "am": "上午", + "year_other": "{{time}}年", + "mo": "{{time}}月", + "m": "{{time}}分鐘", + "minute_other": "{{time}}分鐘", + "formattedTimestamp": { + "12hour": "M月d日 ah:mm:ss", + "24hour": "M月d日 HH:mm:ss" + }, + "formattedTimestampHourMinute": { + "12hour": "a h:mm", + "24hour": "HH:mm" + }, + "formattedTimestampHourMinuteSecond": { + "12hour": "ah:mm:ss", + "24hour": "HH:mm:ss" + }, + "formattedTimestampFilename": { + "24hour": "yy年MM月dd日 HH時mm分ss秒", + "12hour": "yy年MM月dd日 ah時mm分ss秒" + }, + "s": "{{time}}秒", + "formattedTimestamp2": { + "12hour": "MM月dd日 ah:mm:ss", + "24hour": "MM月dd日 HH:mm:ss" + }, + "thisMonth": "今個月", + "pm": "下午", + "formattedTimestampMonthDayHourMinute": { + "24hour": "M月d日 HH:mm", + "12hour": "M月d日 ah:mm" + }, + "justNow": "剛剛", + "day_other": "{{time}}日", + "hour_other": "{{time}}小時", + "30minutes": "30分鐘", + "5minutes": "5分鐘", + "yr": "{{time}}年", + "today": "今日", + "month_other": "{{time}}月", + "second_other": "{{time}}秒", + "untilForRestart": "直到 Frigate 重新啟動。", + "ago": "{{timeAgo}} 前", + "d": "{{time}}日", + "lastWeek": "上個星期", + "formattedTimestampMonthDayYearHourMinute": { + "12hour": "yyyy年M月d日 ah:mm", + "24hour": "yyyy年M月d日 HH:mm" + }, + "1hour": "1 小時", + "h": "{{time}}小時", + "formattedTimestampMonthDay": "M月d日" + }, + "unit": { + "speed": { + "mph": "英里/小時", + "kph": "公里/小時" + } + }, + "label": { + "back": "返回" + }, + "button": { + "apply": "套用", + "reset": "重置", + "done": "完成", + "enabled": "已啟用", + "enable": "啟用", + "disabled": "已停用", + "disable": "停用", + "save": "儲存", + "saving": "儲存中…", + "cancel": "取消", + "close": "關閉", + "copy": "複製", + "back": "返回", + "history": "歷史記錄", + "fullscreen": "全螢幕", + "exitFullscreen": "離開全螢幕", + "pictureInPicture": "畫中畫", + "twoWayTalk": "雙向通話", + "cameraAudio": "鏡頭音訊", + "suspended": "已暫停", + "export": "匯出", + "deleteNow": "立即刪除", + "next": "下一步", + "play": "播放", + "no": "否", + "copyCoordinates": "複製座標", + "delete": "刪除", + "off": "關閉", + "edit": "編輯", + "on": "開啟", + "yes": "是", + "info": "資訊", + "download": "下載", + "unsuspended": "取消暫停", + "unselect": "取消選取" + }, + "menu": { + "system": "系統", + "systemMetrics": "系統指標", + "configuration": "設定", + "systemLogs": "系統日誌", + "settings": "設定", + "configurationEditor": "設定編輯器", + "languages": "語言", + "language": { + "en": "English (英文)", + "es": "Español (西班牙文)", + "zhCN": "简体中文 (簡體中文)", + "hi": "हिन्दी (印地文)", + "fr": "Français (法文)", + "de": "Deutsch (德文)", + "ja": "日本語 (日文)", + "it": "Italiano (意大利文)", + "tr": "Türkçe (土耳其文)", + "nl": "Nederlands (荷蘭文)", + "cs": "Čeština (捷克文)", + "nb": "Norsk Bokmål (挪威文)", + "ko": "한국어 (韓文)", + "vi": "Tiếng Việt (越南文)", + "fa": "فارسی (波斯文)", + "pl": "Polski (波蘭文)", + "el": "Ελληνικά (希臘文)", + "ro": "Română (羅馬尼亞文)", + "hu": "Magyar (匈牙利文)", + "fi": "Suomi (芬蘭文)", + "da": "Dansk (丹麥文)", + "sk": "Slovenčina (斯洛伐克文)", + "withSystem": { + "label": "使用系統語言設定" + }, + "ru": "Русский (俄文)", + "sv": "Svenska (瑞典文)", + "ar": "العربية (阿拉伯文)", + "pt": "Português (葡萄牙文)", + "uk": "Українська (烏克蘭文)", + "he": "עברית (希伯來文)", + "yue": "粵語 (廣東話)" + }, + "appearance": "外觀", + "darkMode": { + "label": "深色模式", + "light": "淺色", + "dark": "深色", + "withSystem": { + "label": "使用系統模式設定" + } + }, + "withSystem": "系統", + "theme": { + "label": "主題", + "blue": "藍色", + "green": "綠色", + "nord": "北歐風", + "red": "紅色", + "default": "預設", + "contrast": "高對比", + "highcontrast": "高對比度" + }, + "documentation": { + "title": "文件", + "label": "Frigate 文件" + }, + "restart": "重新啟動 Frigate", + "live": { + "title": "即時", + "allCameras": "所有鏡頭", + "cameras": { + "title": "鏡頭", + "count_other": "{{count}} 個鏡頭" + } + }, + "review": "審查", + "explore": "瀏覽", + "export": "匯出", + "uiPlayground": "UI 測試場", + "faceLibrary": "臉部資料庫", + "user": { + "title": "使用者", + "logout": "登出", + "account": "帳戶", + "current": "當前使用者:{{user}}", + "anonymous": "匿名", + "setPassword": "設定密碼" + }, + "help": "幫助" + }, + "role": { + "admin": "管理員", + "viewer": "檢視者", + "desc": "管理員擁有 Frigate UI 全功能存取權限。檢視者只能查看鏡頭、審查項目和歷史影像。", + "title": "角色" + }, + "pagination": { + "label": "分頁", + "previous": { + "title": "上一頁", + "label": "前往上一頁" + }, + "next": { + "title": "下一頁", + "label": "前往下一頁" + }, + "more": "更多頁數" + }, + "accessDenied": { + "title": "拒絕存取", + "documentTitle": "拒絕存取 - Frigate", + "desc": "你無權查看此頁面。" + }, + "selectItem": "選擇 {{item}}", + "toast": { + "save": { + "error": { + "noMessage": "儲存設定變更失敗", + "title": "儲存設定變更失敗:{{errorMessage}}" + }, + "title": "儲存" + }, + "copyUrlToClipboard": "已複製 URL 到剪貼簿。" + }, + "notFound": { + "documentTitle": "找不到頁面 - Frigate", + "desc": "找不到頁面", + "title": "404" + } +} diff --git a/web/public/locales/yue-Hant/components/auth.json b/web/public/locales/yue-Hant/components/auth.json new file mode 100644 index 000000000..ebc3b8df7 --- /dev/null +++ b/web/public/locales/yue-Hant/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "errors": { + "webUnknownError": "未知錯誤。請檢查控制台日誌。", + "rateLimit": "超過速率限制。請稍後再試。", + "usernameRequired": "必須填寫用戶名", + "passwordRequired": "必須填寫密碼", + "loginFailed": "登入失敗", + "unknownError": "未知錯誤。請檢查日誌。" + }, + "user": "用戶名", + "password": "密碼", + "login": "登入" + } +} diff --git a/web/public/locales/yue-Hant/components/camera.json b/web/public/locales/yue-Hant/components/camera.json new file mode 100644 index 000000000..80646f1ac --- /dev/null +++ b/web/public/locales/yue-Hant/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "camera": { + "setting": { + "audio": { + "tips": { + "title": "此串流必須從你的鏡頭輸出音訊並在 go2rtc 中設定。", + "document": "閱讀文件 " + } + }, + "streamMethod": { + "method": { + "continuousStreaming": { + "desc": { + "warning": "持續串流可能導致高頻寬使用及效能問題,請小心使用。", + "title": "即使沒有偵測到活動,只要在控制台上可見,鏡頭影像也會一直保持即時串流。" + }, + "label": "持續串流" + }, + "smartStreaming": { + "label": "智能串流(建議)", + "desc": "當沒有偵測到活動時,智能串流會每分鐘更新一次鏡頭影像以節省頻寬和資源。當偵測到活動時,影像會無縫切換到即時串流。" + }, + "noStreaming": { + "label": "不串流", + "desc": "鏡頭影像每分鐘只會更新一次,不會進行即時串流。" + } + }, + "label": "串流方式" + }, + "compatibilityMode": { + "label": "相容模式", + "desc": "只有當你的鏡頭串流出現色彩異常及右側有斜線時,才啟用此選項。" + }, + "label": "鏡頭串流設定", + "title": "{{cameraName}} 串流設定", + "desc": "更改此鏡頭群組控制台的即時串流選項。這些設定是裝置/瀏覽器專屬的。", + "audioIsAvailable": "此串流有提供音訊", + "audioIsUnavailable": "此串流沒有音訊" + } + }, + "delete": { + "confirm": { + "title": "確認刪除", + "desc": "你確定要刪除鏡頭群組 {{name}} 嗎?" + }, + "label": "刪除鏡頭群組" + }, + "name": { + "errorMessage": { + "exists": "鏡頭群組名稱已存在。", + "invalid": "鏡頭群組名稱無效。", + "mustLeastCharacters": "鏡頭群組名稱必須至少包含兩個字元。", + "nameMustNotPeriod": "鏡頭群組名稱不能包含句號。" + }, + "placeholder": "請輸入名稱…", + "label": "名稱" + }, + "icon": "圖標", + "cameras": { + "desc": "為此群組選擇鏡頭。", + "label": "鏡頭" + }, + "label": "鏡頭群組", + "add": "新增鏡頭群組", + "edit": "編輯鏡頭群組", + "success": "鏡頭群組({{name}})已儲存。" + }, + "debug": { + "options": { + "label": "設定", + "title": "選項", + "showOptions": "顯示選項", + "hideOptions": "隱藏選項" + }, + "mask": "遮罩", + "boundingBox": "框選區", + "motion": "移動", + "regions": "大區域", + "timestamp": "時間戳記", + "zones": "區域" + } +} diff --git a/web/public/locales/yue-Hant/components/dialog.json b/web/public/locales/yue-Hant/components/dialog.json new file mode 100644 index 000000000..f676ce245 --- /dev/null +++ b/web/public/locales/yue-Hant/components/dialog.json @@ -0,0 +1,108 @@ +{ + "restart": { + "title": "你確定要重新啟動 Frigate 嗎?", + "button": "重新啟動", + "restarting": { + "title": "Frigate 正在重新啟動", + "content": "此頁面將在 {{countdown}} 秒後重新載入。", + "button": "立即強制重新載入" + } + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "提交到 Frigate+", + "desc": "位於你想避免的區域的物件並不是誤判。提交這些作為誤判會令模型混淆。" + }, + "review": { + "question": { + "label": "確認此標籤給 Frigate Plus", + "ask_a": "此物件是 {{label}} 嗎?", + "ask_an": "此物件是 {{label}} 嗎?", + "ask_full": "此物件是 {{untranslatedLabel}}({{translatedLabel}})嗎?" + }, + "state": { + "submitted": "已提交" + } + } + }, + "video": { + "viewInHistory": "在歷史記錄中查看" + } + }, + "export": { + "time": { + "fromTimeline": "從時間線選取", + "lastHour_other": "最后{{count}}小時", + "end": { + "label": "選擇結束時間", + "title": "結束時間" + }, + "custom": "自訂", + "start": { + "title": "開始時間", + "label": "選擇開始時間" + } + }, + "name": { + "placeholder": "為匯出命名" + }, + "select": "選取", + "export": "匯出", + "selectOrExport": "選取或匯出", + "toast": { + "error": { + "failed": "無法開始匯出:{{error}}", + "noVaildTimeSelected": "沒有選取有效的時間範圍", + "endTimeMustAfterStartTime": "結束時間必須在開始時間之後" + }, + "success": "成功開始匯出。請到 /exports 資料夾查看檔案。" + }, + "fromTimeline": { + "saveExport": "儲存匯出", + "previewExport": "預覽匯出" + } + }, + "streaming": { + "label": "串流", + "restreaming": { + "disabled": "此鏡頭未啟用重串流。", + "desc": { + "title": "設定 go2rtc 以啟用此鏡頭的更多即時預覽選項及音訊。", + "readTheDocumentation": "閱讀文件" + } + }, + "showStats": { + "desc": "啟用此選項可在鏡頭畫面上顯示串流統計資料。", + "label": "顯示串流統計資料" + }, + "debugView": "除錯檢視" + }, + "search": { + "saveSearch": { + "label": "儲存搜尋", + "desc": "請為這個已儲存的搜尋輸入名稱。", + "placeholder": "請輸入搜尋名稱", + "overwrite": "{{searchName}} 已存在。儲存將會覆蓋現有資料。", + "button": { + "save": { + "label": "儲存此搜尋" + } + }, + "success": "搜尋({{searchName}})已儲存。" + } + }, + "recording": { + "confirmDelete": { + "title": "確認刪除", + "desc": { + "selected": "你確定要刪除與此審查項目相關的所有錄影嗎?

    按住 Shift 鍵可略過未來此對話框。" + } + }, + "button": { + "export": "匯出", + "markAsReviewed": "標記為已審查", + "deleteNow": "立即刪除" + } + } +} diff --git a/web/public/locales/yue-Hant/components/filter.json b/web/public/locales/yue-Hant/components/filter.json new file mode 100644 index 000000000..5168b44e4 --- /dev/null +++ b/web/public/locales/yue-Hant/components/filter.json @@ -0,0 +1,125 @@ +{ + "reset": { + "label": "重設篩選條件為預設值" + }, + "subLabels": { + "all": "所有子標籤", + "label": "子標籤" + }, + "score": "分數", + "features": { + "label": "特徵", + "hasSnapshot": "有快照", + "hasVideoClip": "有影片片段", + "submittedToFrigatePlus": { + "label": "已提交到 Frigate+", + "tips": "你必須先篩選出有快照的追蹤物件。

    沒有快照的追蹤物件無法提交到 Frigate+。" + } + }, + "sort": { + "label": "排序", + "dateAsc": "日期(由舊到新)", + "dateDesc": "日期(由新到舊)", + "scoreAsc": "物件分數(由細到大)", + "scoreDesc": "物件分數(由大到細)", + "speedAsc": "預計速度(由慢到快)", + "speedDesc": "預計速度(由快到慢)", + "relevance": "相關性" + }, + "cameras": { + "label": "鏡頭篩選", + "all": { + "title": "所有鏡頭", + "short": "鏡頭" + } + }, + "review": { + "showReviewed": "顯示已審查" + }, + "motion": { + "showMotionOnly": "只顯示有移動" + }, + "explore": { + "settings": { + "title": "設定", + "defaultView": { + "summary": "摘要", + "unfilteredGrid": "未篩選網格", + "desc": "當未選取篩選條件時,顯示每個標籤最近追蹤物件的摘要,或顯示未篩選的網格。", + "title": "預設檢視" + }, + "gridColumns": { + "title": "網格欄數", + "desc": "選擇網格檢視中的欄數。" + }, + "searchSource": { + "label": "搜尋來源", + "desc": "選擇搜尋追蹤物件的縮圖還是描述。", + "options": { + "thumbnailImage": "縮圖", + "description": "描述" + } + } + }, + "date": { + "selectDateBy": { + "label": "選擇日期進行篩選" + } + } + }, + "logSettings": { + "filterBySeverity": "依嚴重程度篩選日誌", + "loading": { + "desc": "當日誌窗格捲動到底部時,新日誌將自動串流顯示。", + "title": "載入中" + }, + "label": "篩選日誌等級", + "allLogs": "所有日誌", + "disableLogStreaming": "停用日誌串流" + }, + "trackedObjectDelete": { + "title": "確認刪除", + "toast": { + "success": "成功刪除追蹤物件。", + "error": "刪除追蹤物件失敗:{{errorMessage}}" + }, + "desc": "刪除這 {{objectLength}} 個追蹤物件將會移除快照、儲存的嵌入資料,以及相關的物件生命週期記錄。歷史檢視中的錄影檔案不會被刪除。

    你確定要繼續嗎?

    按住 Shift 鍵可略過未來此對話框。" + }, + "recognizedLicensePlates": { + "loading": "載入已識別車牌中…", + "noLicensePlatesFound": "找不到車牌。", + "selectPlatesFromList": "從列表中選取一個或多個車牌。", + "placeholder": "輸入以搜尋車牌…", + "title": "已識別車牌", + "loadFailed": "載入已識別車牌失敗。" + }, + "estimatedSpeed": "預計速度({{unit}})", + "labels": { + "label": "標籤", + "count_one": "{{count}} 個標籤", + "all": { + "title": "所有標籤", + "short": "標籤" + }, + "count_other": "{{count}} 個標籤" + }, + "zoneMask": { + "filterBy": "按區域遮罩篩選" + }, + "zones": { + "label": "區域", + "all": { + "short": "區域", + "title": "所有區域" + } + }, + "filter": "篩選", + "dates": { + "all": { + "title": "所有日期", + "short": "日期" + } + }, + "more": "更多篩選條件", + "timeRange": "時間範圍" +} diff --git a/web/public/locales/yue-Hant/components/icons.json b/web/public/locales/yue-Hant/components/icons.json new file mode 100644 index 000000000..467858b8d --- /dev/null +++ b/web/public/locales/yue-Hant/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "選擇圖示", + "search": { + "placeholder": "搜尋圖示…" + } + } +} diff --git a/web/public/locales/yue-Hant/components/input.json b/web/public/locales/yue-Hant/components/input.json new file mode 100644 index 000000000..ed7eee77c --- /dev/null +++ b/web/public/locales/yue-Hant/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "下載影片", + "toast": { + "success": "你的審查項目影片已開始下載。" + } + } + } +} diff --git a/web/public/locales/yue-Hant/components/player.json b/web/public/locales/yue-Hant/components/player.json new file mode 100644 index 000000000..4fe43d29f --- /dev/null +++ b/web/public/locales/yue-Hant/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "此時間段內沒有錄影", + "noPreviewFound": "找不到預覽", + "submitFrigatePlus": { + "submit": "提交", + "title": "提交此畫面至 Frigate+?" + }, + "streamOffline": { + "desc": "{{cameraName}} 的 detect 串流未接收到任何畫面,請檢查錯誤日誌", + "title": "串流已離線" + }, + "cameraDisabled": "鏡頭已停用", + "stats": { + "bandwidth": { + "short": "頻寬", + "title": "頻寬:" + }, + "latency": { + "value": "{{seconds}} 秒", + "short": { + "value": "{{seconds}} 秒", + "title": "延遲" + }, + "title": "延遲:" + }, + "totalFrames": "總畫面數:", + "droppedFrames": { + "short": { + "title": "已丟棄", + "value": "{{droppedFrames}} 個畫面" + }, + "title": "丟棄畫面數:" + }, + "decodedFrames": "解碼畫面數:", + "droppedFrameRate": "畫面丟棄率:", + "streamType": { + "title": "串流類型:", + "short": "類型" + } + }, + "toast": { + "success": { + "submittedFrigatePlus": "成功提交畫面至 Frigate+" + }, + "error": { + "submitFrigatePlusFailed": "提交畫面至 Frigate+ 失敗" + } + }, + "noPreviewFoundFor": "找不到 {{cameraName}} 的預覽", + "livePlayerRequiredIOSVersion": "此串流類型需要 iOS 17.1 或以上版本。" +} diff --git a/web/public/locales/yue-Hant/objects.json b/web/public/locales/yue-Hant/objects.json new file mode 100644 index 000000000..b0838d796 --- /dev/null +++ b/web/public/locales/yue-Hant/objects.json @@ -0,0 +1,120 @@ +{ + "vehicle": "車輛", + "car": "車", + "boat": "船", + "bus": "巴士", + "motorcycle": "電單車", + "train": "火車", + "bicycle": "單車", + "skateboard": "滑板", + "door": "門", + "blender": "攪拌機", + "sink": "洗手盆", + "scissors": "剪刀", + "clock": "時鐘", + "toothbrush": "牙刷", + "hair_dryer": "吹風機", + "person": "人", + "airplane": "飛機", + "traffic_light": "紅綠燈", + "fire_hydrant": "消防栓", + "street_sign": "街道標誌", + "stop_sign": "停車標誌", + "parking_meter": "咪錶", + "bench": "長凳", + "bird": "鳥", + "cat": "貓", + "sheep": "羊", + "cow": "牛", + "elephant": "大象", + "bear": "熊", + "zebra": "斑馬", + "giraffe": "長頸鹿", + "backpack": "背囊", + "tie": "領呔", + "suitcase": "行李箱", + "frisbee": "飛碟", + "skis": "滑雪板", + "snowboard": "單板滑雪板", + "sports_ball": "運動球", + "kite": "風箏", + "baseball_bat": "棒球棍", + "baseball_glove": "棒球手套", + "surfboard": "衝浪板", + "tennis_racket": "網球拍", + "bottle": "樽", + "plate": "碟", + "wine_glass": "酒杯", + "cup": "杯", + "fork": "叉", + "bowl": "碗", + "banana": "香蕉", + "apple": "蘋果", + "sandwich": "三文治", + "orange": "橙", + "carrot": "紅蘿蔔", + "hot_dog": "熱狗", + "pizza": "薄餅", + "donut": "甜甜圈", + "cake": "蛋糕", + "chair": "凳", + "couch": "梳化", + "laptop": "手提電腦", + "mouse": "滑鼠", + "remote": "遙控器", + "keyboard": "鍵盤", + "cell_phone": "手機", + "microwave": "微波爐", + "oven": "焗爐", + "toaster": "多士爐", + "refrigerator": "雪櫃", + "book": "書", + "vase": "花瓶", + "teddy_bear": "泰迪熊", + "hair_brush": "梳", + "squirrel": "松鼠", + "deer": "鹿", + "animal": "動物", + "bark": "樹皮", + "fox": "狐狸", + "goat": "山羊", + "rabbit": "兔", + "raccoon": "浣熊", + "robot_lawnmower": "自動剪草機", + "waste_bin": "垃圾桶", + "license_plate": "車牌", + "bbq_grill": "燒烤爐", + "amazon": "亞馬遜", + "usps": "美國郵政", + "ups": "UPS", + "postnl": "荷蘭郵政", + "nzpost": "新西蘭郵政", + "postnord": "北歐郵政", + "gls": "GLS", + "dpd": "DPD", + "broccoli": "西蘭花", + "umbrella": "雨傘", + "eye_glasses": "眼鏡", + "dog": "狗", + "desk": "書枱", + "tv": "電視", + "horse": "馬", + "mirror": "鏡", + "spoon": "匙羹", + "hat": "帽", + "shoe": "鞋", + "potted_plant": "盆栽植物", + "fedex": "聯邦快遞", + "handbag": "手袋", + "dining_table": "飯枱", + "an_post": "愛爾蘭郵政", + "knife": "刀", + "window": "窗", + "bed": "床", + "toilet": "廁所", + "purolator": "Purolator", + "on_demand": "按需要提供", + "face": "人臉", + "package": "包裹", + "dhl": "DHL" +} diff --git a/web/public/locales/yue-Hant/views/configEditor.json b/web/public/locales/yue-Hant/views/configEditor.json new file mode 100644 index 000000000..9e2836915 --- /dev/null +++ b/web/public/locales/yue-Hant/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "documentTitle": "設定編輯器 - Frigate", + "configEditor": "設定編輯器", + "copyConfig": "複製設定", + "saveAndRestart": "儲存並重新啟動", + "saveOnly": "只儲存", + "toast": { + "success": { + "copyToClipboard": "設定已複製到剪貼簿。" + }, + "error": { + "savingError": "儲存設定時出錯" + } + } +} diff --git a/web/public/locales/yue-Hant/views/events.json b/web/public/locales/yue-Hant/views/events.json new file mode 100644 index 000000000..1e1039c93 --- /dev/null +++ b/web/public/locales/yue-Hant/views/events.json @@ -0,0 +1,37 @@ +{ + "camera": "鏡頭", + "alerts": "警報", + "empty": { + "alert": "沒有警報需要審查", + "detection": "沒有偵測到的項目需要審查", + "motion": "找不到移動數據" + }, + "timeline": "時間線", + "events": { + "label": "事件", + "noFoundForTimePeriod": "此時段內沒有找到事件。", + "aria": "選擇事件" + }, + "recordings": { + "documentTitle": "錄影 - Frigate" + }, + "calendarFilter": { + "last24Hours": "過去24小時" + }, + "markAsReviewed": "標記為已審查", + "markTheseItemsAsReviewed": "將這些項目標記為已審查", + "newReviewItems": { + "label": "查看新的審查項目", + "button": "有新的審查項目" + }, + "selected_one": "已選擇 {{count}} 項", + "selected_other": "已選擇 {{count}} 項", + "allCameras": "所有鏡頭", + "documentTitle": "審查 - Frigate", + "motion": { + "only": "只顯示移動", + "label": "移動" + }, + "detections": "偵測", + "timeline.aria": "選擇時間線" +} diff --git a/web/public/locales/yue-Hant/views/explore.json b/web/public/locales/yue-Hant/views/explore.json new file mode 100644 index 000000000..bf35cacde --- /dev/null +++ b/web/public/locales/yue-Hant/views/explore.json @@ -0,0 +1,198 @@ +{ + "documentTitle": "瀏覽 - Frigate", + "generativeAI": "生成式人工智能", + "exploreIsUnavailable": { + "title": "無法使用瀏覽功能", + "embeddingsReindexing": { + "startingUp": "啟動中…", + "estimatedTime": "預計剩餘時間:", + "finishingShortly": "即將完成", + "step": { + "thumbnailsEmbedded": "已嵌入縮圖: ", + "descriptionsEmbedded": "已嵌入描述: ", + "trackedObjectsProcessed": "已處理的追蹤物件: " + }, + "context": "完成重新索引追蹤物件的嵌入後即可使用瀏覽功能。" + }, + "downloadingModels": { + "tips": { + "context": "下載完成後,你可能需要重新索引追蹤物件的嵌入。", + "documentation": "閱讀文件" + }, + "error": "發生錯誤。請檢查 Frigate 日誌。", + "context": "Frigate 正在下載必要的嵌入模型以支援語意搜尋功能。這可能需要幾分鐘,視乎你的網絡速度。", + "setup": { + "textTokenizer": "文字分詞器", + "textModel": "文字模型", + "visionModelFeatureExtractor": "視覺模型特徵提取器", + "visionModel": "視覺模型" + } + } + }, + "trackedObjectDetails": "追蹤物件詳情", + "type": { + "details": "詳情", + "snapshot": "快照", + "video": "影片", + "object_lifecycle": "物件生命周期" + }, + "objectLifecycle": { + "title": "物件生命周期", + "noImageFound": "此時間點找不到圖像。", + "createObjectMask": "建立物件遮罩", + "lifecycleItemDesc": { + "active": "{{label}} 變為活躍", + "stationary": "{{label}} 變為靜止", + "attribute": { + "faceOrLicense_plate": "偵測到 {{label}} 的 {{attribute}}", + "other": "{{label}} 被識別為 {{attribute}}" + }, + "header": { + "zones": "區域", + "ratio": "比例", + "area": "區域範圍" + }, + "heard": "聽到 {{label}}", + "entered_zone": "{{label}} 進入了 {{zones}}", + "gone": "{{label}} 離開了", + "visible": "偵測到 {{label}}", + "external": "偵測到 {{label}}" + }, + "annotationSettings": { + "title": "註解設定", + "showAllZones": { + "title": "顯示所有區域", + "desc": "在物件進入區域的畫面上總是顯示區域。" + }, + "offset": { + "tips": "提示:試想像有一段事件片段,當中有人由左行到右。如果事件時間線上的方框一直偏向人物的左邊,則應該減少數值。相反,如果有人由左行到右,而方框一直走在人物前面,則應該增加數值。", + "desc": "此資料來自鏡頭的偵測串流,但覆蓋在錄影串流的畫面上。兩個串流通常無法完全同步。因此邊界框和影片可能無法完全對齊。不過可以使用 annotation_offset 欄位來調整。", + "label": "註解偏移量", + "documentation": "閱讀文件 ", + "millisecondsToOffset": "偵測註解的偏移毫秒數。預設:0" + } + }, + "carousel": { + "previous": "上一張", + "next": "下一張" + }, + "adjustAnnotationSettings": "調整註解設定", + "scrollViewTips": "滾動以查看此物件生命周期中的重要時刻。", + "autoTrackingTips": "自動追蹤鏡頭的邊界框位置可能不準確。" + }, + "details": { + "item": { + "title": "審查項目詳情", + "desc": "審查項目詳情", + "button": { + "share": "分享此審查項目", + "viewInExplore": "在瀏覽中查看" + }, + "tips": { + "mismatch_other": "偵測到 {{count}} 個不可用的物件並包含在此審查項目中。這些物件可能未符合警報或偵測標準,或已被清除/刪除。", + "hasMissingObjects": "如果你想讓 Frigate 保存下列標籤的追蹤物件,請調整設定:{{objects}}" + }, + "toast": { + "success": { + "updatedSublabel": "成功更新子標籤。", + "updatedLPR": "成功更新車牌號碼。", + "regenerate": "已從 {{provider}} 請求新的描述。根據提供者的速度,生成新的描述可能需要一些時間。" + }, + "error": { + "regenerate": "呼叫 {{provider}} 以獲取新描述失敗:{{errorMessage}}", + "updatedSublabelFailed": "更新子標籤失敗:{{errorMessage}}", + "updatedLPRFailed": "更新車牌號碼失敗:{{errorMessage}}" + } + } + }, + "label": "標籤", + "recognizedLicensePlate": "已識別車牌", + "estimatedSpeed": "預計速度", + "objects": "物件", + "camera": "鏡頭", + "zones": "區域", + "timestamp": "時間戳記", + "tips": { + "descriptionSaved": "成功保存描述", + "saveDescriptionFailed": "更新描述失敗:{{errorMessage}}" + }, + "regenerateFromSnapshot": "從快照重新生成", + "button": { + "regenerate": { + "label": "重新生成追蹤物件描述", + "title": "重新生成" + }, + "findSimilar": "尋找相似項目" + }, + "description": { + "label": "描述", + "placeholder": "追蹤物件的描述", + "aiTips": "Frigate 會等到追蹤物件生命周期結束後,才向你的生成式 AI 提供者請求描述。" + }, + "editLPR": { + "descNoLabel": "為此追蹤物件輸入新的車牌號碼", + "title": "編輯車牌號碼", + "desc": "為此 {{label}} 輸入新的車牌號碼" + }, + "topScore": { + "label": "最高分數", + "info": "最高分數是追蹤物件的最高中位分數,因此可能與搜尋結果縮圖上顯示的分數不同。" + }, + "editSubLabel": { + "desc": "為此 {{label}} 輸入新的子標籤", + "title": "編輯子標籤", + "descNoLabel": "為此追蹤物件輸入新的子標籤" + }, + "snapshotScore": { + "label": "快照分數" + }, + "expandRegenerationMenu": "展開重新生成選單", + "regenerateFromThumbnails": "從縮圖重新生成" + }, + "itemMenu": { + "downloadVideo": { + "label": "下載影片", + "aria": "下載影片" + }, + "downloadSnapshot": { + "label": "下載快照", + "aria": "下載快照" + }, + "viewObjectLifecycle": { + "label": "查看物件生命周期", + "aria": "顯示物件生命周期" + }, + "findSimilar": { + "label": "尋找相似項目", + "aria": "尋找相似追蹤物件" + }, + "submitToPlus": { + "label": "提交到 Frigate+", + "aria": "提交到 Frigate Plus" + }, + "viewInHistory": { + "label": "在歷史記錄中查看", + "aria": "在歷史記錄中查看" + }, + "deleteTrackedObject": { + "label": "刪除此追蹤物件" + } + }, + "dialog": { + "confirmDelete": { + "title": "確認刪除", + "desc": "刪除此追蹤物件會移除快照、所有已保存的嵌入,以及相關的物件生命周期記錄。歷史記錄中的錄影不會被刪除。

    你確定要繼續嗎?" + } + }, + "noTrackedObjects": "找不到追蹤物件", + "fetchingTrackedObjectsFailed": "取得追蹤物件時出錯:{{errorMessage}}", + "searchResult": { + "deleteTrackedObject": { + "toast": { + "success": "追蹤物件已成功刪除。", + "error": "刪除追蹤物件失敗:{{errorMessage}}" + } + } + }, + "trackedObjectsCount_other": "{{count}} 個追蹤物件 " +} diff --git a/web/public/locales/yue-Hant/views/exports.json b/web/public/locales/yue-Hant/views/exports.json new file mode 100644 index 000000000..48d839717 --- /dev/null +++ b/web/public/locales/yue-Hant/views/exports.json @@ -0,0 +1,17 @@ +{ + "documentTitle": "匯出 - Frigate", + "search": "搜尋", + "noExports": "未找到匯出項目", + "deleteExport": "刪除匯出", + "editExport": { + "title": "重新命名匯出", + "desc": "請輸入新的匯出名稱。", + "saveExport": "儲存匯出" + }, + "toast": { + "error": { + "renameExportFailed": "重新命名匯出失敗:{{errorMessage}}" + } + }, + "deleteExport.desc": "你確定要刪除 {{exportName}} 嗎?" +} diff --git a/web/public/locales/yue-Hant/views/faceLibrary.json b/web/public/locales/yue-Hant/views/faceLibrary.json new file mode 100644 index 000000000..a55a0de0a --- /dev/null +++ b/web/public/locales/yue-Hant/views/faceLibrary.json @@ -0,0 +1,82 @@ +{ + "selectItem": "選擇 {{item}}", + "details": { + "timestamp": "時間戳記", + "person": "人", + "confidence": "信心指數", + "face": "人臉詳細資料", + "faceDesc": "人臉及相關物件的詳細資料" + }, + "description": { + "addFace": "逐步了解如何新增一個人臉庫的集合。", + "placeholder": "請輸入此集合的名稱" + }, + "documentTitle": "人臉庫 - Frigate", + "uploadFaceImage": { + "title": "上傳人臉圖片", + "desc": "上傳圖片以掃描人臉並納入 {{pageToggle}}" + }, + "createFaceLibrary": { + "title": "建立集合", + "desc": "建立新集合", + "new": "建立新的人臉", + "nextSteps": "建立穩固基礎:
  • 使用訓練分頁,為每位偵測到的人物選擇並訓練圖片。
  • 以正面照片為主,避免用側面或傾斜角度的人臉作訓練。
  • " + }, + "steps": { + "faceName": "請輸入人臉名稱", + "uploadFace": "上傳人臉圖片", + "nextSteps": "下一步" + }, + "train": { + "title": "訓練", + "aria": "選擇訓練" + }, + "selectFace": "選擇人臉", + "deleteFaceLibrary": { + "title": "刪除名稱", + "desc": "你確定要刪除集合 {{name}} 嗎?這將永久刪除所有相關的人臉資料。" + }, + "renameFace": { + "title": "重新命名人臉", + "desc": "請輸入 {{name}} 的新名稱" + }, + "button": { + "uploadImage": "上傳圖片", + "reprocessFace": "重新處理人臉", + "deleteFace": "刪除人臉", + "addFace": "新增人臉", + "deleteFaceAttempts": "刪除人臉嘗試記錄", + "renameFace": "重新命名人臉" + }, + "imageEntry": { + "validation": { + "selectImage": "請選擇一個圖片檔案。" + }, + "dropActive": "將圖片拖到這裡…", + "dropInstructions": "拖放圖片到此處,或點擊選取", + "maxSize": "最大檔案大小:{{size}}MB" + }, + "readTheDocs": "閱讀文件", + "trainFaceAs": "將人臉訓練為:", + "trainFace": "訓練人臉", + "toast": { + "success": { + "uploadedImage": "成功上傳圖片。", + "renamedFace": "成功將人臉重新命名為 {{name}}", + "trainedFace": "成功訓練人臉。", + "updatedFaceScore": "成功更新人臉分數。", + "deletedFace_other": "成功刪除 {{count}} 個人臉。", + "addFaceLibrary": "{{name}} 已成功加入人臉庫!", + "deletedName_other": "成功刪除 {{count}} 個人臉。" + }, + "error": { + "uploadingImageFailed": "上傳圖片失敗:{{errorMessage}}", + "addFaceLibraryFailed": "設定人臉名稱失敗:{{errorMessage}}", + "deleteFaceFailed": "刪除失敗:{{errorMessage}}", + "deleteNameFailed": "刪除名稱失敗:{{errorMessage}}", + "renameFaceFailed": "重新命名人臉失敗:{{errorMessage}}", + "trainFailed": "訓練失敗:{{errorMessage}}", + "updateFaceScoreFailed": "更新人臉分數失敗:{{errorMessage}}" + } + } +} diff --git a/web/public/locales/yue-Hant/views/live.json b/web/public/locales/yue-Hant/views/live.json new file mode 100644 index 000000000..d9dda2630 --- /dev/null +++ b/web/public/locales/yue-Hant/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "即時畫面 - Frigate", + "cameraAudio": { + "disable": "停用鏡頭音訊", + "enable": "啟用鏡頭音訊" + }, + "ptz": { + "move": { + "clickMove": { + "label": "點擊畫面以置中鏡頭", + "enable": "啟用點擊移動", + "disable": "停用點擊移動" + }, + "up": { + "label": "移動 PTZ 鏡頭向上" + }, + "right": { + "label": "移動 PTZ 鏡頭向右" + }, + "left": { + "label": "移動 PTZ 鏡頭向左" + }, + "down": { + "label": "移動 PTZ 鏡頭向下" + } + }, + "frame": { + "center": { + "label": "點擊畫面以置中 PTZ 鏡頭" + } + }, + "presets": "PTZ 鏡頭預設位置", + "zoom": { + "in": { + "label": "放大 PTZ 鏡頭" + }, + "out": { + "label": "縮小 PTZ 鏡頭" + } + } + }, + "twoWayTalk": { + "enable": "啟用雙向通話", + "disable": "停用雙向通話" + }, + "lowBandwidthMode": "低頻寬模式", + "documentTitle.withCamera": "{{camera}} - 即時畫面 - Frigate", + "recording": { + "disable": "停用錄影", + "enable": "啟用錄影" + }, + "snapshots": { + "enable": "啟用快照", + "disable": "停用快照" + }, + "audioDetect": { + "enable": "啟用音訊偵測", + "disable": "停用音訊偵測" + }, + "autotracking": { + "enable": "啟用自動追蹤", + "disable": "停用自動追蹤" + }, + "streamStats": { + "enable": "顯示串流統計資料", + "disable": "隱藏串流統計資料" + }, + "manualRecording": { + "title": "按需錄影", + "tips": "根據此鏡頭的錄影保留設定手動啟動事件。", + "debugView": "除錯視圖", + "start": "開始按需錄影", + "showStats": { + "label": "顯示統計資料", + "desc": "啟用此選項可在鏡頭畫面上疊加串流統計資料。" + }, + "playInBackground": { + "desc": "啟用此選項可在播放器隱藏時繼續串流播放。", + "label": "背景播放" + }, + "started": "已開始手動按需錄影。", + "end": "結束按需錄影", + "ended": "已結束手動按需錄影。", + "failedToEnd": "無法結束手動按需錄影。", + "failedToStart": "無法開始手動按需錄影。", + "recordDisabledTips": "由於此鏡頭的設定已停用或限制錄影,因此只會儲存快照。" + }, + "camera": { + "enable": "啟用鏡頭", + "disable": "停用鏡頭" + }, + "muteCameras": { + "enable": "所有鏡頭靜音", + "disable": "所有鏡頭取消靜音" + }, + "detect": { + "disable": "停用偵測", + "enable": "啟用偵測" + }, + "streamingSettings": "串流設定", + "notifications": "通知", + "audio": "音訊", + "suspend": { + "forTime": "暫停時間: " + }, + "stream": { + "title": "串流", + "audio": { + "tips": { + "documentation": "閱讀文件 ", + "title": "音訊必須從你的鏡頭輸出,並在 go2rtc 中正確設定此串流。" + }, + "available": "此串流支援音訊", + "unavailable": "此串流不支援音訊" + }, + "twoWayTalk": { + "tips.documentation": "閱讀文件 ", + "available": "此串流支援雙向通話", + "unavailable": "此串流不支援雙向通話", + "tips": "你的裝置必須支援此功能,且需設定 WebRTC 才能使用雙向通話。" + }, + "lowBandwidth": { + "tips": "因緩衝或串流錯誤,即時畫面已切換至低頻寬模式。", + "resetStream": "重置串流" + }, + "playInBackground": { + "tips": "啟用此選項可在播放器隱藏時繼續串流播放。", + "label": "背景播放" + } + }, + "cameraSettings": { + "cameraEnabled": "鏡頭已啟用", + "objectDetection": "物件偵測", + "recording": "錄影", + "snapshots": "快照", + "autotracking": "自動追蹤", + "audioDetection": "音訊偵測", + "title": "{{camera}} 設定" + }, + "history": { + "label": "顯示歷史影像" + }, + "effectiveRetainMode": { + "modes": { + "all": "全部", + "motion": "移動", + "active_objects": "活躍物件" + }, + "notAllTips": "你的 {{source}} 錄影保留設定為 mode: {{effectiveRetainMode}},因此此按需錄影只會保留{{effectiveRetainModeName}}的片段。" + }, + "editLayout": { + "label": "編輯版面配置", + "group": { + "label": "編輯鏡頭群組" + }, + "exitEdit": "結束編輯" + } +} diff --git a/web/public/locales/yue-Hant/views/recording.json b/web/public/locales/yue-Hant/views/recording.json new file mode 100644 index 000000000..34473d299 --- /dev/null +++ b/web/public/locales/yue-Hant/views/recording.json @@ -0,0 +1,12 @@ +{ + "filter": "篩選", + "export": "匯出", + "calendar": "日曆", + "filters": "篩選條件", + "toast": { + "error": { + "noValidTimeSelected": "未選擇有效的時間範圍", + "endTimeMustAfterStartTime": "結束時間必須在開始時間之後" + } + } +} diff --git a/web/public/locales/yue-Hant/views/search.json b/web/public/locales/yue-Hant/views/search.json new file mode 100644 index 000000000..fea893191 --- /dev/null +++ b/web/public/locales/yue-Hant/views/search.json @@ -0,0 +1,72 @@ +{ + "search": "搜尋", + "savedSearches": "已儲存的搜尋", + "searchFor": "搜尋 {{inputValue}}", + "button": { + "clear": "清除搜尋", + "save": "儲存搜尋", + "delete": "刪除已儲存的搜尋", + "filterInformation": "篩選資料", + "filterActive": "篩選中" + }, + "trackedObjectId": "追蹤物件編號", + "filter": { + "label": { + "labels": "標籤", + "zones": "區域", + "search_type": "搜尋類型", + "time_range": "時間範圍", + "after": "之後", + "recognized_license_plate": "已辨識車牌", + "has_clip": "有片段", + "has_snapshot": "有快照", + "min_score": "最低分數", + "before": "之前", + "max_score": "最高分數", + "max_speed": "最高速度", + "min_speed": "最低速度", + "cameras": "鏡頭", + "sub_labels": "子標籤" + }, + "searchType": { + "thumbnail": "縮圖", + "description": "描述" + }, + "toast": { + "error": { + "beforeDateBeLaterAfter": "「結束」日期必須遲於「開始」日期。", + "afterDatebeEarlierBefore": "「開始」日期必須早於「結束」日期。", + "minScoreMustBeLessOrEqualMaxScore": "「最低分數」必須少於或等於「最高分數」。", + "maxScoreMustBeGreaterOrEqualMinScore": "「最高分數」必須多於或等於「最低分數」。", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "「最高速度」必須多於或等於「最低速度」。", + "minSpeedMustBeLessOrEqualMaxSpeed": "「最低速度」必須少於或等於「最高速度」。" + } + }, + "tips": { + "title": "如何使用文字篩選", + "desc": { + "step1": "輸入篩選鍵名後加上冒號(例如:\"cameras:\")。", + "step2": "從建議中選擇一個值,或者自行輸入。", + "step3": "可以用空格隔開,連續使用多個篩選條件。", + "step4": "日期篩選(before: 同 after:)要用 {{DateFormat}} 格式。", + "step5": "時間範圍篩選要用 {{exampleTime}} 格式。", + "step6": "點擊旁邊的「x」就可以移除篩選條件。", + "text": "篩選可以幫你縮窄搜尋結果。以下係使用方法:", + "exampleLabel": "例子:" + } + }, + "header": { + "activeFilters": "啟用中的篩選條件", + "noFilters": "篩選條件", + "currentFilterType": "篩選數值" + } + }, + "similaritySearch": { + "title": "相似搜尋", + "active": "正在進行相似搜尋", + "clear": "清除相似搜尋" + }, + "placeholder": { + "search": "搜尋…" + } +} diff --git a/web/public/locales/yue-Hant/views/settings.json b/web/public/locales/yue-Hant/views/settings.json new file mode 100644 index 000000000..8d83cf33e --- /dev/null +++ b/web/public/locales/yue-Hant/views/settings.json @@ -0,0 +1,593 @@ +{ + "documentTitle": { + "default": "設定 - Frigate", + "authentication": "認證設定 - Frigate", + "camera": "鏡頭設定 - Frigate", + "classification": "進階功能設定 - Frigate", + "masksAndZones": "遮罩與區域編輯器 - Frigate", + "motionTuner": "移動調校器 - Frigate", + "object": "除錯 - Frigate", + "general": "一般設定 - Frigate", + "frigatePlus": "Frigate+ 設定 - Frigate", + "notifications": "通知設定 - Frigate" + }, + "menu": { + "ui": "介面", + "classification": "進階功能", + "cameras": "鏡頭設定", + "masksAndZones": "遮罩/區域", + "motionTuner": "移動調校器", + "debug": "除錯", + "users": "用戶", + "notifications": "通知", + "frigateplus": "Frigate+" + }, + "dialog": { + "unsavedChanges": { + "title": "你有未儲存的更改。", + "desc": "你想在繼續前儲存更改嗎?" + } + }, + "cameraSetting": { + "camera": "鏡頭", + "noCamera": "沒有鏡頭" + }, + "general": { + "title": "一般設定", + "liveDashboard": { + "playAlertVideos": { + "label": "播放警報影片", + "desc": "預設情況下,即時儀表板上的最近警報會以小型循環影片形式播放。停用此選項後,只會在此裝置/瀏覽器上顯示警報的靜態圖片。" + }, + "automaticLiveView": { + "label": "自動即時檢視", + "desc": "當偵測到活動時,自動切換到該鏡頭的即時畫面。若停用此選項,即時儀表板上的鏡頭靜態畫面將每分鐘只更新一次。" + }, + "title": "即時儀表板" + }, + "storedLayouts": { + "title": "儲存的版面配置", + "clearAll": "清除所有版面配置", + "desc": "鏡頭群組內的鏡頭佈局可以拖動或調整大小。位置會儲存在你瀏覽器的本機儲存空間內。" + }, + "cameraGroupStreaming": { + "title": "鏡頭群組串流設定", + "clearAll": "清除所有串流設定", + "desc": "每個鏡頭群組的串流設定會儲存在你瀏覽器的本機儲存空間內。" + }, + "recordingsViewer": { + "defaultPlaybackRate": { + "desc": "錄影播放的預設播放速度。", + "label": "預設播放速度" + }, + "title": "錄影瀏覽器" + }, + "calendar": { + "title": "日曆", + "firstWeekday": { + "label": "每星期的第一天", + "sunday": "星期日", + "monday": "星期一", + "desc": "審查日曆中每星期開始的日子。" + } + }, + "toast": { + "success": { + "clearStoredLayout": "已清除 {{cameraName}} 的儲存版面配置", + "clearStreamingSettings": "已清除所有鏡頭群組的串流設定。" + }, + "error": { + "clearStoredLayoutFailed": "清除儲存版面配置失敗:{{errorMessage}}", + "clearStreamingSettingsFailed": "清除串流設定失敗:{{errorMessage}}" + } + } + }, + "classification": { + "birdClassification": { + "desc": "鳥類分類會使用量化 Tensorflow 模型識別已知鳥類。當辨識到已知鳥類時,牠的常見名稱會加到子標籤上。此資訊會顯示在介面、篩選器及通知中。", + "title": "鳥類分類" + }, + "semanticSearch": { + "title": "語意搜尋", + "desc": "Frigate 的語意搜尋功能讓你可以利用影像本身、自訂文字描述,或自動產生的描述,在審查項目中尋找已追蹤的物件。", + "readTheDocumentation": "閱讀文件", + "reindexNow": { + "label": "立即重建索引", + "confirmTitle": "確認重建索引", + "confirmButton": "重建索引", + "success": "重建索引已成功開始。", + "alreadyInProgress": "重建索引已在進行中。", + "error": "啟動重建索引失敗:{{errorMessage}}", + "confirmDesc": "你確定要重建索引所有已追蹤物件的嵌入向量嗎?這個過程會在背景運行,但可能會用盡你的 CPU,而且需要一定時間。你可以在「瀏覽」頁面查看進度。", + "desc": "重建索引會為所有已追蹤物件重新生成嵌入向量。這個過程會在背景運行,可能會用盡你的 CPU,所需時間取決於已追蹤物件的數量。" + }, + "modelSize": { + "label": "模型大小", + "desc": "用於語意搜尋的模型大小。", + "small": { + "title": "小型", + "desc": "使用小型模型會採用量化版本,較少佔用 RAM,在 CPU 上運行更快,而嵌入品質的差異非常細微。" + }, + "large": { + "title": "大型", + "desc": "使用大型模型會採用完整的 Jina 模型,並在適用情況下自動於 GPU 上運行。" + } + } + }, + "faceRecognition": { + "modelSize": { + "small": { + "title": "小型", + "desc": "使用小型模型會採用 FaceNet 臉部嵌入模型,在大多數 CPU 上能有效運行。" + }, + "large": { + "title": "大型", + "desc": "使用大型模型會採用 ArcFace 臉部嵌入模型,並在適用情況下自動於 GPU 上運行。" + }, + "label": "模型大小", + "desc": "用於人臉識別的模型大小。" + }, + "readTheDocumentation": "閱讀文件", + "title": "人臉識別", + "desc": "人臉識別功能允許為人物分配名字,當辨識到他們的臉孔時,Frigate 會將名字加到子標籤上。此資訊會顯示於介面、篩選器及通知中。" + }, + "licensePlateRecognition": { + "title": "車牌識別", + "readTheDocumentation": "閱讀文件", + "desc": "Frigate 可以識別車輛上的車牌,自動將偵測到的字元加到已辨識車牌欄位,或將已知名稱加到屬於車輛類型的物件的子標籤上。常見用途包括讀取駛入車道或在街道上駛過的車輛的車牌。" + }, + "restart_required": "需要重新啟動(分類設定已變更)", + "toast": { + "error": "儲存設定變更失敗:{{errorMessage}}", + "success": "分類設定已儲存。請重新啟動 Frigate 以套用你的更改。" + }, + "title": "進階功能設定" + }, + "camera": { + "title": "鏡頭設定", + "streams": { + "title": "串流", + "desc": "停用鏡頭會完全停止 Frigate 處理此鏡頭的串流。將會無法使用偵測、錄影和除錯功能。
    注意:這不會停用 go2rtc 的轉播功能。" + }, + "review": { + "title": "審查", + "desc": "啟用或停用此鏡頭的警報和偵測。停用後,將不會產生新的審查項目。", + "alerts": "警報 ", + "detections": "偵測 " + }, + "reviewClassification": { + "readTheDocumentation": "閱讀文件", + "noDefinedZones": "此鏡頭未定義任何區域。", + "zoneObjectAlertsTips": "在{{cameraName}}的{{zone}}區域偵測到的所有{{alertsLabels}}物件將會顯示為警報。", + "objectDetectionsTips": "無論位於哪個區域,在{{cameraName}}上所有未分類的{{detectionsLabels}}物件將會顯示為偵測結果。", + "objectAlertsTips": "在{{cameraName}}上所有{{alertsLabels}}物件將會顯示為警報。", + "zoneObjectDetectionsTips": { + "text": "在{{cameraName}}的{{zone}}區域內所有未分類的{{detectionsLabels}}物件將會顯示為偵測結果。", + "regardlessOfZoneObjectDetectionsTips": "無論位於哪個區域,在{{cameraName}}上所有未分類的{{detectionsLabels}}物件將會顯示為偵測結果。", + "notSelectDetections": "無論位於哪個區域,在{{cameraName}}的{{zone}}區域偵測到、但未分類為警報的{{detectionsLabels}}物件將會顯示為偵測結果。" + }, + "selectDetectionsZones": "選擇偵測的區域", + "limitDetections": "限制偵測至特定區域", + "title": "審查分類", + "desc": "Frigate會將審查項目分類為「警報」同「偵測」。預設情況下,所有 的物件都會被視為警報。你可以透過設定所需區域,細分審查項目分類。", + "selectAlertsZones": "選擇警報的區域", + "toast": { + "success": "審查分類設定已儲存。請重新啟動Frigate以套用更改。" + } + } + }, + "masksAndZones": { + "toast": { + "error": { + "copyCoordinatesFailed": "無法將座標複製到剪貼簿。" + }, + "success": { + "copyCoordinates": "已將{{polyName}}的座標複製到剪貼簿。" + } + }, + "form": { + "zoneName": { + "error": { + "mustBeAtLeastTwoCharacters": "區域名稱必須至少有2個字元。", + "mustNotBeSameWithCamera": "區域名稱不得與鏡頭名稱相同。", + "alreadyExists": "此鏡頭已存在相同名稱的區域。", + "mustNotContainPeriod": "區域名稱不可包含句號。", + "hasIllegalCharacter": "區域名稱包含非法字元。" + } + }, + "distance": { + "error": { + "mustBeFilled": "必須填寫所有距離欄位,才能使用速度估算功能。", + "text": "距離必須大於或等於0.1。" + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "慣性值必須大於0。" + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "逗留時間必須大於或等於0。" + } + }, + "polygonDrawing": { + "removeLastPoint": "移除最後一個點", + "delete": { + "title": "確認刪除", + "desc": "確定要刪除{{type}} {{name}}嗎?", + "success": "已刪除{{name}}。" + }, + "error": { + "mustBeFinished": "必須完成多邊形繪製後才能儲存。" + }, + "snapPoints": { + "false": "不對齊點", + "true": "對齊點" + }, + "reset": { + "label": "清除所有點" + } + } + }, + "zones": { + "label": "區域", + "add": "新增區域", + "edit": "編輯區域", + "point_other": "{{count}}個點", + "clickDrawPolygon": "在圖片上點擊以繪製多邊形。", + "name": { + "title": "名稱", + "inputPlaceHolder": "請輸入名稱…", + "tips": "名稱必須至少有2個字元,且不可與鏡頭或其他區域同名。" + }, + "inertia": { + "title": "慣性", + "desc": "指定物件需在區域內停留多少個畫格,才會被視為進入該區域。預設:3" + }, + "loiteringTime": { + "desc": "設定物件必須於區域內停留的最少秒數,以觸發動作。預設:0", + "title": "逗留時間" + }, + "objects": { + "title": "物件", + "desc": "此區域適用的物件列表。" + }, + "allObjects": "所有物件", + "speedEstimation": { + "title": "速度估算", + "desc": "啟用此區域內物件的速度估算。區域必須正好有4個點。" + }, + "speedThreshold": { + "title": "速度門檻 ({{unit}})", + "desc": "指定物件於此區域被視為有效時所需的最小速度。", + "toast": { + "error": { + "loiteringTimeError": "設有逗留時間大於0的區域,不應同時使用速度估算功能。", + "pointLengthError": "此區域已停用速度估算功能。啟用速度估算的區域必須正好有4個點。" + } + } + }, + "toast": { + "success": "區域({{zoneName}})已儲存。請重新啟動Frigate以套用更改。" + }, + "desc": { + "title": "區域可讓你定義畫面中的特定範圍,以判斷物件是否進入該範圍。", + "documentation": "文件" + }, + "documentTitle": "編輯區域 - Frigate" + }, + "motionMasks": { + "label": "移動遮罩", + "documentTitle": "編輯移動遮罩 - Frigate", + "desc": { + "title": "移動遮罩可防止不需要的移動觸發偵測。遮罩過多會令物件追蹤變得困難。", + "documentation": "文件" + }, + "edit": "編輯移動遮罩", + "point_other": "{{count}}個點", + "clickDrawPolygon": "在圖片上點擊以繪製多邊形。", + "polygonAreaTooLarge": { + "title": "移動遮罩覆蓋了鏡頭畫面{{polygonArea}}%。建議不要使用過大的遮罩。", + "tips": "移動遮罩無法阻止物件被偵測,應使用必要區域來限制範圍。", + "documentation": "閱讀文件" + }, + "context": { + "title": "移動遮罩用於防止某些不需要的移動(如樹枝晃動、鏡頭時間戳記)觸發偵測。移動遮罩應該非常謹慎使用,過度遮罩會令物件追蹤更加困難。", + "documentation": "閱讀文件" + }, + "add": "新增移動遮罩", + "toast": { + "success": { + "title": "{{polygonName}}已儲存。請重新啟動Frigate以套用更改。", + "noName": "移動遮罩已儲存。請重新啟動Frigate以套用更改。" + } + } + }, + "objectMasks": { + "label": "物件遮罩", + "desc": { + "documentation": "文件", + "title": "物件過濾遮罩根據位置,過濾指定物件類型的誤判偵測。" + }, + "add": "新增物件遮罩", + "context": "物件過濾遮罩根據位置,過濾指定物件類型的誤判偵測。", + "point_other": "{{count}}個點", + "clickDrawPolygon": "在圖片上點擊以繪製多邊形。", + "objects": { + "title": "物件", + "desc": "此物件遮罩適用的物件類型。", + "allObjectTypes": "所有物件類型" + }, + "toast": { + "success": { + "title": "{{polygonName}}已儲存。請重新啟動Frigate以套用更改。", + "noName": "物件遮罩已儲存。請重新啟動Frigate以套用更改。" + } + }, + "documentTitle": "編輯物件遮罩 - Frigate", + "edit": "編輯物件遮罩" + }, + "filter": { + "all": "所有遮罩與區域" + }, + "restart_required": "需要重新啟動(遮罩/區域已變更)" + }, + "motionDetectionTuner": { + "title": "移動偵測調校器", + "desc": { + "title": "Frigate首先利用移動偵測作初步篩選,以判斷畫面中是否出現值得進行物件偵測的情況。", + "documentation": "閱讀移動調整指南" + }, + "Threshold": { + "title": "門檻", + "desc": "門檻值決定像素亮度變化多少才會被視為移動。預設:30" + }, + "contourArea": { + "title": "輪廓面積", + "desc": "輪廓面積值用來決定哪些變化像素群符合移動標準。預設:10" + }, + "improveContrast": { + "title": "改善對比度", + "desc": "改善黑暗場景的對比度。預設:開啟" + }, + "toast": { + "success": "移動設定已儲存。" + } + }, + "debug": { + "title": "除錯", + "objectList": "物件列表", + "noObjects": "沒有物件", + "boundingBoxes": { + "title": "邊框框線", + "colors": { + "info": "
  • 啟動時,系統會為每個物件標籤指派不同顏色
  • 深藍色幼線代表目前沒有偵測到該物件
  • 灰色幼線代表該物件被偵測為靜止狀態
  • 粗線代表該物件正被自動追蹤(若已啟用)
  • ", + "label": "物件邊框顏色" + }, + "desc": "顯示追蹤物件周圍的邊框" + }, + "zones": { + "title": "區域", + "desc": "顯示所有已定義區域的輪廓" + }, + "motion": { + "title": "移動方框", + "desc": "顯示偵測到移動的區域方框", + "tips": "

    移動方框

    畫面中偵測到移動的地方將會顯示亮紅色方框

    " + }, + "regions": { + "desc": "顯示屬於物件偵測器感興趣範圍的方框", + "title": "偵測區", + "tips": "

    偵測區方框

    畫面中屬於物件偵測器感興趣的地方將會顯示亮綠色方框,並且進行分析

    " + }, + "desc": "除錯畫面會即時顯示追蹤到的物件及統計資料。物件列表則顯示偵測到物件的延遲總結。", + "timestamp": { + "title": "時間戳記", + "desc": "在圖片上疊加時間戳記" + }, + "detectorDesc": "Frigate 使用你的偵測器({{detectors}})來偵測鏡頭影片串流中的物件。", + "debugging": "除錯中", + "mask": { + "title": "移動遮罩", + "desc": "顯示移動遮罩多邊形" + }, + "objectShapeFilterDrawing": { + "title": "物件形狀篩選繪圖", + "document": "閱讀文件 ", + "score": "分數", + "area": "面積", + "ratio": "比例", + "desc": "在圖片上畫矩形以查看面積與比例詳情", + "tips": "啟用此選項後,會於鏡頭畫面上繪製矩形,以顯示其面積及比例。這些數值可用於設定物件形狀過濾參數。" + } + }, + "users": { + "management": { + "desc": "管理此Frigate個體的用戶帳戶。", + "title": "用戶管理" + }, + "addUser": "新增用戶", + "updatePassword": "更新密碼", + "toast": { + "success": { + "createUser": "成功建立用戶{{user}}", + "deleteUser": "成功刪除用戶{{user}}", + "roleUpdated": "成功更新{{user}}的角色", + "updatePassword": "成功更新密碼。" + }, + "error": { + "createUserFailed": "建立用戶失敗:{{errorMessage}}", + "roleUpdateFailed": "更新角色失敗:{{errorMessage}}", + "setPasswordFailed": "儲存密碼失敗:{{errorMessage}}", + "deleteUserFailed": "刪除用戶失敗:{{errorMessage}}" + } + }, + "table": { + "username": "用戶名稱", + "role": "角色", + "noUsers": "找不到用戶。", + "changeRole": "更改用戶角色", + "password": "密碼", + "deleteUser": "刪除用戶", + "actions": "操作" + }, + "dialog": { + "form": { + "user": { + "title": "用戶名稱", + "desc": "只允許使用字母、數字、句號及底線。", + "placeholder": "輸入用戶名稱" + }, + "password": { + "title": "密碼", + "placeholder": "輸入密碼", + "confirm": { + "placeholder": "確認密碼", + "title": "確認密碼" + }, + "strength": { + "title": "密碼強度: ", + "weak": "弱", + "medium": "中等", + "strong": "強", + "veryStrong": "非常強" + }, + "match": "密碼相符", + "notMatch": "密碼不相符" + }, + "newPassword": { + "confirm": { + "placeholder": "重新輸入新密碼" + }, + "title": "新密碼", + "placeholder": "輸入新密碼" + }, + "usernameIsRequired": "必須輸入用戶名稱" + }, + "createUser": { + "title": "建立新用戶", + "desc": "新增用戶帳戶,並指定可存取Frigate介面各區域的角色。", + "usernameOnlyInclude": "用戶名稱只可包含字母、數字、句號或底線" + }, + "deleteUser": { + "title": "刪除用戶", + "desc": "此操作無法還原,將會永久刪除用戶帳戶及所有相關資料。", + "warn": "確定要刪除{{username}}嗎?" + }, + "changeRole": { + "title": "更改用戶角色", + "desc": "更新{{username}}的權限", + "roleInfo": { + "intro": "為此用戶選擇合適的角色:", + "adminDesc": "可使用所有功能。", + "viewer": "觀看者", + "viewerDesc": "只限使用即時儀表板、審查、瀏覽及匯出功能。", + "admin": "管理員" + } + }, + "passwordSetting": { + "setPassword": "設定密碼", + "updatePassword": "更新{{username}}的密碼", + "desc": "建立強密碼以保障此帳戶安全。" + } + }, + "title": "用戶" + }, + "notification": { + "title": "通知", + "notificationSettings": { + "title": "通知設定", + "desc": "Frigate可原生向你的裝置推送通知,無論在瀏覽器中運行或安裝為PWA。", + "documentation": "閱讀文件" + }, + "notificationUnavailable": { + "title": "無法使用通知功能", + "desc": "網頁推送通知需在安全環境下運作(https://…),這是瀏覽器的限制。請透過安全連線存取Frigate以使用通知功能。", + "documentation": "閱讀文件" + }, + "globalSettings": { + "title": "全域設定", + "desc": "暫停所有已註冊裝置上特定鏡頭的通知。" + }, + "email": { + "placeholder": "例如:example@email.com", + "desc": "需要提供有效的電郵地址,若推送服務出現問題,將會透過此地址通知你。", + "title": "電郵地址" + }, + "cameras": { + "title": "鏡頭", + "noCameras": "沒有可用鏡頭", + "desc": "選擇啟用通知功能的鏡頭。" + }, + "deviceSpecific": "裝置專屬設定", + "registerDevice": "登記此裝置", + "unregisterDevice": "取消登記此裝置", + "sendTestNotification": "發送測試通知", + "active": "通知功能已啟用", + "suspended": "通知功能已暫停{{time}}", + "suspendTime": { + "10minutes": "暫停10分鐘", + "12hours": "暫停12小時", + "30minutes": "暫停30分鐘", + "24hours": "暫停24小時", + "5minutes": "暫停5分鐘", + "1hour": "暫停1小時", + "untilRestart": "暫停至重新啟動", + "suspend": "暫停" + }, + "toast": { + "error": { + "registerFailed": "儲存通知登記失敗。" + }, + "success": { + "registered": "成功登記通知功能。必須重新啟動Frigate後,才能發送任何通知(包括測試通知)。", + "settingSaved": "通知設定已儲存。" + } + }, + "cancelSuspension": "取消暫停" + }, + "frigatePlus": { + "title": "Frigate+設定", + "apiKey": { + "title": "Frigate+ API金鑰", + "validated": "已偵測並驗證Frigate+ API金鑰", + "notValidated": "未偵測到Frigate+ API金鑰或驗證失敗", + "desc": "Frigate+ API金鑰可啟用與Frigate+服務的整合功能。", + "plusLink": "了解更多Frigate+資料" + }, + "snapshotConfig": { + "title": "快照設定", + "documentation": "閱讀文件", + "table": { + "camera": "鏡頭", + "snapshots": "快照", + "cleanCopySnapshots": "clean_copy 快照" + }, + "cleanCopyWarning": "部分鏡頭已啟用快照,但未啟用乾淨副本。你必須於快照設定中啟用clean_copy,才能從這些鏡頭提交影像至Frigate+。", + "desc": "提交至Frigate+需要在設定中同時啟用快照及clean_copy快照功能。" + }, + "modelInfo": { + "title": "模型資料", + "modelType": "模型類型", + "trainDate": "訓練日期", + "baseModel": "基礎模型", + "plusModelType": { + "baseModel": "基礎模型", + "userModel": "微調" + }, + "supportedDetectors": "支援的偵測器", + "cameras": "鏡頭", + "availableModels": "可用模型", + "loadingAvailableModels": "正在載入可用模型…", + "modelSelect": "可於此選擇你在Frigate+上的可用模型。請注意,只能選擇與當前偵測器設定相容的模型。", + "loading": "正在載入模型資料…", + "error": "載入模型資料失敗" + }, + "toast": { + "error": "儲存設定變更失敗:{{errorMessage}}", + "success": "Frigate+設定已儲存。請重新啟動Frigate以套用更改。" + }, + "restart_required": "需要重新啟動(已更改Frigate+模型)" + } +} diff --git a/web/public/locales/yue-Hant/views/system.json b/web/public/locales/yue-Hant/views/system.json new file mode 100644 index 000000000..332520ccb --- /dev/null +++ b/web/public/locales/yue-Hant/views/system.json @@ -0,0 +1,179 @@ +{ + "documentTitle": { + "cameras": "鏡頭統計 - Frigate", + "storage": "儲存裝置統計 - Frigate", + "general": "一般統計 - Frigate", + "enrichments": "進階功能統計 - Frigate", + "logs": { + "frigate": "Frigate 日誌 - Frigate", + "nginx": "Nginx 日誌 - Frigate", + "go2rtc": "Go2RTC 日誌 - Frigate" + } + }, + "title": "系統", + "metrics": "系統指標", + "logs": { + "download": { + "label": "下載日誌" + }, + "type": { + "timestamp": "時間戳記", + "tag": "標籤", + "message": "訊息", + "label": "類型" + }, + "tips": "正在從伺服器串流日誌", + "toast": { + "error": { + "fetchingLogsFailed": "擷取日誌時出錯:{{errorMessage}}", + "whileStreamingLogs": "串流日誌時出錯:{{errorMessage}}" + } + }, + "copy": { + "error": "無法將日誌複製到剪貼簿", + "label": "複製到剪貼簿", + "success": "已將日誌複製到剪貼簿" + } + }, + "general": { + "detector": { + "inferenceSpeed": "偵測器推理速度", + "memoryUsage": "偵測器記憶體使用量", + "title": "偵測器", + "cpuUsage": "偵測器 CPU 使用率", + "temperature": "偵測器溫度" + }, + "hardwareInfo": { + "gpuUsage": "GPU 使用率", + "gpuInfo": { + "vainfoOutput": { + "processOutput": "程序輸出:", + "processError": "程序錯誤:", + "title": "Vainfo 輸出", + "returnCode": "返回代碼:{{code}}" + }, + "nvidiaSMIOutput": { + "title": "Nvidia SMI 輸出", + "vbios": "VBios 資訊:{{vbios}}", + "cudaComputerCapability": "CUDA 計算能力:{{cuda_compute}}", + "name": "名稱:{{name}}", + "driver": "驅動程式:{{driver}}" + }, + "closeInfo": { + "label": "關閉 GPU 資訊" + }, + "toast": { + "success": "已將 GPU 資訊複製到剪貼簿" + }, + "copyInfo": { + "label": "複製 GPU 資訊" + } + }, + "title": "硬件資訊", + "npuUsage": "NPU 使用率", + "gpuMemory": "GPU 記憶體", + "gpuEncoder": "GPU 編碼器", + "gpuDecoder": "GPU 解碼器", + "npuMemory": "NPU 記憶體" + }, + "otherProcesses": { + "title": "其他程序", + "processCpuUsage": "程序 CPU 使用率", + "processMemoryUsage": "程序記憶體使用量" + }, + "title": "一般" + }, + "storage": { + "title": "儲存裝置", + "overview": "概覽", + "recordings": { + "title": "錄影檔案", + "earliestRecording": "最早可用錄影檔案:", + "tips": "此數值代表 Frigate 資料庫中錄影檔案的總儲存使用量。Frigate 不會追蹤磁碟上所有檔案的儲存使用量。" + }, + "cameraStorage": { + "camera": "鏡頭", + "unusedStorageInformation": "未使用儲存資訊", + "storageUsed": "已使用儲存", + "bandwidth": "每小時使用量", + "unused": { + "tips": "若您的磁碟中存有其他檔案,該數值可能無法準確反映 Frigate 可用的空間。Frigate 只追蹤其錄影檔案的儲存使用量。", + "title": "未使用" + }, + "title": "鏡頭儲存", + "percentageOfTotalUsed": "佔總量百分比" + } + }, + "cameras": { + "info": { + "streamDataFromFFPROBE": "串流資料是透過 ffprobe 取得。", + "fetching": "正在取得鏡頭資料", + "video": "影片:", + "codec": "編碼器:", + "resolution": "解像度:", + "tips": { + "title": "鏡頭詳細資訊" + }, + "stream": "串流 {{idx}}", + "audio": "音訊:", + "fps": "每秒影格數 (FPS):", + "unknown": "未知", + "error": "錯誤:{{error}}", + "cameraProbeInfo": "{{camera}} 鏡頭詳細資訊" + }, + "framesAndDetections": "畫面 / 偵測", + "label": { + "camera": "鏡頭", + "detect": "偵測", + "skipped": "略過", + "ffmpeg": "FFmpeg", + "capture": "讀取影像", + "overallFramesPerSecond": "整體每秒畫面數", + "cameraFfmpeg": "{{camName}} FFmpeg", + "cameraDetect": "{{camName}} 偵測", + "cameraFramesPerSecond": "{{camName}} 每秒畫面數", + "cameraDetectionsPerSecond": "{{camName}} 每秒偵測次數", + "cameraSkippedDetectionsPerSecond": "{{camName}} 每秒略過偵測次數", + "overallSkippedDetectionsPerSecond": "整體每秒略過偵測次數", + "cameraCapture": "{{camName}} 讀取影像", + "overallDetectionsPerSecond": "整體每秒偵測次數" + }, + "title": "鏡頭", + "overview": "概覽", + "toast": { + "success": { + "copyToClipboard": "已將鏡頭資料複製到剪貼簿。" + }, + "error": { + "unableToProbeCamera": "無法取得鏡頭資料:{{errorMessage}}" + } + } + }, + "lastRefreshed": "最後更新: ", + "stats": { + "detectIsSlow": "{{detect}} 偵測速度慢 ({{speed}} 毫秒)", + "detectIsVerySlow": "{{detect}} 偵測速度非常慢 ({{speed}} 毫秒)", + "cameraIsOffline": "{{camera}} 已離線", + "detectHighCpuUsage": "{{camera}} 的偵測 CPU 使用率過高 ({{detectAvg}}%)", + "healthy": "系統運作正常", + "ffmpegHighCpuUsage": "{{camera}} 的 FFmpeg CPU 使用率過高 ({{ffmpegAvg}}%)", + "reindexingEmbeddings": "重新索引嵌入資料 (已完成 {{processed}}%)" + }, + "enrichments": { + "title": "進階功能", + "infPerSecond": "每秒推理次數", + "embeddings": { + "image_embedding": "圖片嵌入", + "face_embedding_speed": "人臉嵌入速度", + "face_recognition_speed": "人臉辨識速度", + "plate_recognition_speed": "車牌辨識速度", + "face_recognition": "人臉辨識", + "text_embedding": "文字嵌入", + "yolov9_plate_detection": "YOLOv9 車牌偵測", + "text_embedding_speed": "文字嵌入速度", + "yolov9_plate_detection_speed": "YOLOv9 車牌偵測速度", + "plate_recognition": "車牌辨識", + "image_embedding_speed": "圖片嵌入速度" + } + } +} diff --git a/web/public/locales/zh-CN/audio.json b/web/public/locales/zh-CN/audio.json new file mode 100644 index 000000000..86a9259c8 --- /dev/null +++ b/web/public/locales/zh-CN/audio.json @@ -0,0 +1,429 @@ +{ + "speech": "谈话", + "babbling": "喋喋不休", + "yell": "大喊", + "bellow": "吼叫", + "whoop": "欢呼", + "whispering": "耳语", + "laughter": "笑声", + "snicker": "窃笑", + "crying": "哭泣", + "sigh": "叹息", + "singing": "唱歌", + "choir": "合唱", + "yodeling": "山歌", + "chant": "吟唱", + "mantra": "咒语", + "child_singing": "儿童歌唱", + "synthetic_singing": "合成歌声", + "rapping": "说唱", + "humming": "哼唱", + "groan": "呻吟", + "grunt": "咕哝", + "whistling": "口哨", + "breathing": "呼吸", + "wheeze": "喘息", + "snoring": "打鼾", + "gasp": "倒抽气", + "pant": "喘气", + "snort": "哼声", + "cough": "咳嗽", + "throat_clearing": "清嗓子", + "sneeze": "打喷嚏", + "sniff": "抽鼻子", + "run": "跑步", + "shuffle": "拖步", + "footsteps": "脚步声", + "chewing": "咀嚼", + "biting": "咬", + "gargling": "漱口", + "stomach_rumble": "肚子咕噜", + "burping": "打嗝", + "hiccup": "打嗝", + "fart": "放屁", + "hands": "手", + "finger_snapping": "打响指", + "clapping": "鼓掌", + "heartbeat": "心跳", + "heart_murmur": "心脏杂音", + "cheering": "欢呼", + "applause": "掌声", + "chatter": "闲聊", + "crowd": "人群", + "children_playing": "儿童玩耍", + "animal": "动物", + "pets": "宠物", + "dog": "狗", + "bark": "吠叫", + "yip": "吠叫", + "howl": "嚎叫", + "bow_wow": "汪汪", + "growling": "咆哮", + "whimper_dog": "狗呜咽", + "cat": "猫", + "purr": "咕噜", + "meow": "喵喵", + "hiss": "嘶嘶声", + "caterwaul": "猫叫春", + "livestock": "牲畜", + "horse": "马", + "clip_clop": "蹄声", + "neigh": "嘶鸣", + "cattle": "牛", + "moo": "哞哞", + "cowbell": "牛铃", + "pig": "猪", + "oink": "哼哼", + "goat": "山羊", + "bleat": "咩咩", + "sheep": "绵羊", + "fowl": "家禽", + "chicken": "鸡", + "cluck": "咯咯", + "cock_a_doodle_doo": "喔喔", + "turkey": "火鸡", + "gobble": "咯咯", + "duck": "鸭子", + "quack": "嘎嘎", + "goose": "鹅", + "honk": "鸣笛/鹅叫声", + "wild_animals": "野生动物", + "roaring_cats": "吼叫的猫科动物", + "roar": "吼叫", + "bird": "鸟", + "chirp": "啾啾", + "squawk": "啼叫", + "pigeon": "鸽子", + "coo": "咕咕", + "crow": "乌鸦", + "caw": "呱呱", + "owl": "猫头鹰", + "hoot": "呜呜", + "flapping_wings": "翅膀拍打", + "dogs": "狗群", + "rats": "老鼠", + "mouse": "老鼠", + "patter": "啪嗒声", + "insect": "昆虫", + "cricket": "蟋蟀", + "mosquito": "蚊子", + "fly": "苍蝇", + "buzz": "嗡嗡", + "frog": "青蛙", + "croak": "呱呱", + "snake": "蛇", + "rattle": "响尾", + "whale_vocalization": "鲸鱼叫声", + "music": "音乐", + "musical_instrument": "乐器", + "plucked_string_instrument": "弹拨乐器", + "guitar": "吉他", + "electric_guitar": "电吉他", + "bass_guitar": "贝斯", + "acoustic_guitar": "原声吉他", + "steel_guitar": "钢弦吉他", + "tapping": "敲击", + "strum": "扫弦", + "banjo": "班卓琴", + "sitar": "西塔琴", + "mandolin": "曼陀林", + "zither": "古筝", + "ukulele": "尤克里里", + "keyboard": "键盘", + "piano": "钢琴", + "electric_piano": "电钢琴", + "organ": "风琴", + "electronic_organ": "电子琴", + "hammond_organ": "哈蒙德风琴", + "synthesizer": "合成器", + "sampler": "采样器", + "harpsichord": "大键琴", + "percussion": "打击乐器", + "drum_kit": "架子鼓", + "drum_machine": "鼓机", + "drum": "鼓", + "snare_drum": "军鼓", + "rimshot": "鼓边击", + "drum_roll": "滚鼓", + "bass_drum": "大鼓", + "timpani": "定音鼓", + "tabla": "塔布拉鼓", + "cymbal": "钹", + "hi_hat": "踩镲", + "wood_block": "木鱼", + "tambourine": "铃鼓", + "maraca": "沙锤", + "gong": "锣", + "tubular_bells": "管钟", + "mallet_percussion": "槌击打击乐器", + "marimba": "马林巴", + "glockenspiel": "钟琴", + "vibraphone": "颤音琴", + "steelpan": "钢鼓", + "orchestra": "管弦乐队", + "brass_instrument": "铜管乐器", + "french_horn": "圆号", + "trumpet": "小号", + "trombone": "长号", + "bowed_string_instrument": "弓弦乐器", + "string_section": "弦乐组", + "violin": "小提琴", + "pizzicato": "拨弦", + "cello": "大提琴", + "double_bass": "低音提琴", + "wind_instrument": "管乐器", + "flute": "长笛", + "saxophone": "萨克斯", + "clarinet": "单簧管", + "harp": "竖琴", + "bell": "铃", + "church_bell": "教堂钟", + "jingle_bell": "铃铛", + "bicycle_bell": "自行车铃", + "tuning_fork": "音叉", + "chime": "风铃", + "wind_chime": "风铃", + "harmonica": "口琴", + "accordion": "手风琴", + "bagpipes": "风笛", + "didgeridoo": "迪吉里杜管", + "theremin": "特雷门琴", + "singing_bowl": "颂钵", + "scratching": "刮擦声", + "pop_music": "流行音乐", + "hip_hop_music": "嘻哈音乐", + "beatboxing": "人声节拍", + "rock_music": "摇滚音乐", + "heavy_metal": "重金属", + "punk_rock": "朋克摇滚", + "grunge": "垃圾摇滚", + "progressive_rock": "前卫摇滚", + "rock_and_roll": "摇滚乐", + "psychedelic_rock": "迷幻摇滚", + "rhythm_and_blues": "节奏布鲁斯", + "soul_music": "灵魂乐", + "reggae": "雷鬼", + "country": "乡村音乐", + "swing_music": "摇摆乐", + "bluegrass": "蓝草音乐", + "funk": "放克", + "folk_music": "民谣", + "middle_eastern_music": "中东音乐", + "jazz": "爵士乐", + "disco": "迪斯科", + "classical_music": "古典音乐", + "opera": "歌剧", + "electronic_music": "电子音乐", + "house_music": "浩室音乐", + "techno": "科技舞曲", + "dubstep": "回响贝斯", + "drum_and_bass": "鼓打贝斯", + "electronica": "电子乐", + "electronic_dance_music": "电子舞曲", + "ambient_music": "环境音乐", + "trance_music": "迷幻舞曲", + "music_of_latin_america": "拉丁美洲音乐", + "salsa_music": "萨尔萨", + "flamenco": "弗拉门戈", + "blues": "蓝调", + "music_for_children": "儿童音乐", + "new-age_music": "新世纪音乐", + "vocal_music": "声乐", + "a_capella": "无伴奏合唱", + "music_of_africa": "非洲音乐", + "afrobeat": "非洲节拍", + "christian_music": "基督教音乐", + "gospel_music": "福音音乐", + "music_of_asia": "亚洲音乐", + "carnatic_music": "卡纳提克音乐", + "music_of_bollywood": "宝莱坞音乐", + "ska": "斯卡", + "traditional_music": "传统音乐", + "independent_music": "独立音乐", + "song": "歌曲", + "background_music": "背景音乐", + "theme_music": "主题音乐", + "jingle": "广告歌", + "soundtrack_music": "配乐", + "lullaby": "摇篮曲", + "video_game_music": "电子游戏音乐", + "christmas_music": "圣诞音乐", + "dance_music": "舞曲", + "wedding_music": "婚礼音乐", + "happy_music": "欢快音乐", + "sad_music": "悲伤音乐", + "tender_music": "温柔音乐", + "exciting_music": "激动音乐", + "angry_music": "愤怒音乐", + "scary_music": "恐怖音乐", + "wind": "风", + "rustling_leaves": "树叶沙沙声", + "wind_noise": "风声", + "thunderstorm": "雷暴", + "thunder": "雷声", + "water": "水", + "rain": "雨", + "raindrop": "雨滴", + "rain_on_surface": "雨打表面", + "stream": "溪流", + "waterfall": "瀑布", + "ocean": "海洋", + "waves": "波浪", + "steam": "蒸汽", + "gurgling": "汩汩声", + "fire": "火", + "crackle": "噼啪声", + "vehicle": "车辆", + "boat": "船", + "sailboat": "帆船", + "rowboat": "划艇", + "motorboat": "摩托艇", + "ship": "轮船", + "motor_vehicle": "机动车", + "car": "汽车", + "toot": "鸣笛", + "car_alarm": "汽车警报", + "power_windows": "电动车窗", + "skidding": "轮胎打滑", + "tire_squeal": "轮胎尖叫", + "car_passing_by": "汽车驶过", + "race_car": "赛车", + "truck": "卡车", + "air_brake": "气闸", + "air_horn": "气笛", + "reversing_beeps": "倒车提示音", + "ice_cream_truck": "冰淇淋车", + "bus": "公交车", + "emergency_vehicle": "应急车辆", + "police_car": "警车", + "ambulance": "救护车", + "fire_engine": "消防车", + "motorcycle": "摩托车", + "traffic_noise": "交通噪音", + "rail_transport": "铁路运输", + "train": "火车", + "train_whistle": "火车汽笛", + "train_horn": "火车鸣笛", + "railroad_car": "铁路车厢", + "train_wheels_squealing": "火车轮子尖叫", + "subway": "地铁", + "aircraft": "飞行器", + "aircraft_engine": "飞机引擎", + "jet_engine": "喷气引擎", + "propeller": "螺旋桨", + "helicopter": "直升机", + "fixed-wing_aircraft": "固定翼飞机", + "bicycle": "自行车", + "skateboard": "滑板", + "engine": "引擎", + "light_engine": "轻型引擎", + "dental_drill's_drill": "牙科钻", + "lawn_mower": "割草机", + "chainsaw": "电锯", + "medium_engine": "中型引擎", + "heavy_engine": "重型引擎", + "engine_knocking": "引擎敲击", + "engine_starting": "引擎启动", + "idling": "怠速", + "accelerating": "加速", + "door": "门", + "doorbell": "门铃", + "ding-dong": "叮咚", + "sliding_door": "滑动门", + "slam": "猛关", + "knock": "敲门", + "tap": "轻敲", + "squeak": "吱吱声", + "cupboard_open_or_close": "橱柜开关", + "drawer_open_or_close": "抽屉开关", + "dishes": "餐具", + "cutlery": "刀叉", + "chopping": "切菜", + "frying": "煎炸", + "microwave_oven": "微波炉", + "blender": "搅拌机", + "water_tap": "水龙头", + "sink": "水槽", + "bathtub": "浴缸", + "hair_dryer": "吹风机", + "toilet_flush": "马桶冲水", + "toothbrush": "牙刷", + "electric_toothbrush": "电动牙刷", + "vacuum_cleaner": "吸尘器", + "zipper": "拉链", + "keys_jangling": "钥匙叮当", + "coin": "硬币", + "scissors": "剪刀", + "electric_shaver": "电动剃须刀", + "shuffling_cards": "洗牌", + "typing": "打字", + "typewriter": "打字机", + "computer_keyboard": "电脑键盘", + "writing": "书写", + "alarm": "警报", + "telephone": "电话", + "telephone_bell_ringing": "电话铃声", + "ringtone": "手机铃声", + "telephone_dialing": "电话拨号", + "dial_tone": "拨号音", + "busy_signal": "忙音", + "alarm_clock": "闹钟", + "siren": "警笛", + "civil_defense_siren": "防空警报", + "buzzer": "蜂鸣器", + "smoke_detector": "烟雾探测器", + "fire_alarm": "火灾警报器", + "foghorn": "雾笛", + "whistle": "哨子", + "steam_whistle": "蒸汽汽笛", + "mechanisms": "机械装置", + "ratchet": "棘轮", + "clock": "时钟", + "tick": "滴答", + "tick-tock": "滴答滴答", + "gears": "齿轮", + "pulleys": "滑轮", + "sewing_machine": "缝纫机", + "mechanical_fan": "机械风扇", + "air_conditioning": "空调", + "cash_register": "收银机", + "printer": "打印机", + "camera": "相机", + "single-lens_reflex_camera": "单反相机", + "tools": "工具", + "hammer": "锤子", + "jackhammer": "风镐", + "sawing": "锯", + "filing": "锉", + "sanding": "砂磨", + "power_tool": "电动工具", + "drill": "电钻", + "explosion": "爆炸", + "gunshot": "枪声", + "machine_gun": "机关枪", + "fusillade": "齐射", + "artillery_fire": "炮火", + "cap_gun": "玩具枪", + "fireworks": "烟花", + "firecracker": "鞭炮", + "burst": "爆裂", + "eruption": "爆发", + "boom": "轰隆", + "wood": "木头", + "chop": "砍", + "splinter": "碎裂", + "crack": "破裂", + "glass": "玻璃", + "chink": "叮当", + "shatter": "粉碎", + "silence": "寂静", + "sound_effect": "音效", + "environmental_noise": "环境噪音", + "static": "静电噪音", + "white_noise": "白噪音", + "pink_noise": "粉红噪音", + "television": "电视", + "radio": "收音机", + "field_recording": "实地录音", + "scream": "尖叫" +} diff --git a/web/public/locales/zh-CN/common.json b/web/public/locales/zh-CN/common.json new file mode 100644 index 000000000..883984507 --- /dev/null +++ b/web/public/locales/zh-CN/common.json @@ -0,0 +1,251 @@ +{ + "time": { + "untilForTime": "直到 {{time}}", + "untilForRestart": "直到 Frigate 重启。", + "untilRestart": "直到重启", + "ago": "{{timeAgo}} 前", + "justNow": "刚才", + "today": "今天", + "yesterday": "昨天", + "last7": "最后 7 天", + "last14": "最后 14 天", + "last30": "最后 30 天", + "thisWeek": "本周", + "lastWeek": "上个周", + "thisMonth": "本月", + "lastMonth": "上个月", + "5minutes": "5 分钟", + "10minutes": "10 分钟", + "30minutes": "30 分钟", + "1hour": "1 小时", + "12hours": "12 小时", + "24hours": "24 小时", + "pm": "下午", + "am": "上午", + "yr": "{{time}}年", + "year_other": "{{time}}年", + "mo": "{{time}}月", + "month_other": "{{time}}月", + "d": "{{time}}天", + "day_other": "{{time}}天", + "h": "{{time}}小时", + "hour_other": "{{time}}小时", + "m": "{{time}}分钟", + "minute_other": "{{time}}分钟", + "s": "{{time}}秒", + "second_other": "{{time}}秒", + "formattedTimestamp": { + "12hour": "M月d日 ah:mm:ss", + "24hour": "M月d日 HH:mm:ss" + }, + "formattedTimestamp2": { + "12hour": "MM月dd日 ah:mm:ss", + "24hour": "MM月dd日 HH:mm:ss" + }, + "formattedTimestampExcludeSeconds": { + "12hour": "%m月%-d日 %I:%M %p", + "24hour": "%m月%-d日 %H:%M" + }, + "formattedTimestampWithYear": { + "12hour": "%Y年%m月%-d日 %I:%M:%S %p", + "24hour": "%Y年%m月%-d日 %H:%M" + }, + "formattedTimestampOnlyMonthAndDay": "%m月%-d日", + "formattedTimestampHourMinute": { + "12hour": "a h:mm", + "24hour": "HH:mm" + }, + "formattedTimestampHourMinuteSecond": { + "12hour": "ah:mm:ss", + "24hour": "HH:mm:ss" + }, + "formattedTimestampMonthDayHourMinute": { + "12hour": "M月d日 ah:mm", + "24hour": "M月d日 HH:mm" + }, + "formattedTimestampMonthDayYearHourMinute": { + "24hour": "yyyy年M月d日 HH:mm", + "12hour": "yyyy年M月d日 ah:mm" + }, + "formattedTimestampMonthDay": "M月d日", + "formattedTimestampFilename": { + "12hour": "yy年MM月dd日 ah时mm分ss秒", + "24hour": "yy年MM月dd日 HH时mm分ss秒" + } + }, + "unit": { + "speed": { + "mph": "英里/小时", + "kph": "公里/小时" + } + }, + "label": { + "back": "返回" + }, + "pagination": { + "label": "分页", + "previous": { + "title": "上一页", + "label": "转到上一页" + }, + "next": { + "title": "下一页", + "label": "转到下一页" + }, + "more": "更多页面" + }, + "button": { + "apply": "应用", + "reset": "重置", + "done": "完成", + "enabled": "启用", + "enable": "启用", + "disabled": "禁用", + "disable": "禁用", + "save": "保存", + "saving": "保存中…", + "cancel": "取消", + "close": "关闭", + "copy": "复制", + "back": "返回", + "history": "历史", + "fullscreen": "全屏", + "exitFullscreen": "退出全屏", + "pictureInPicture": "画中画", + "on": "开", + "off": "关", + "edit": "编辑", + "copyCoordinates": "复制坐标", + "delete": "删除", + "yes": "是", + "no": "否", + "download": "下载", + "info": "信息", + "suspended": "已暂停", + "unsuspended": "取消暂停", + "play": "播放", + "unselect": "取消选择", + "export": "导出", + "deleteNow": "立即删除", + "next": "下一个", + "cameraAudio": "摄像头音频", + "twoWayTalk": "双向对话" + }, + "menu": { + "system": "系统", + "systemMetrics": "系统信息", + "configuration": "配置", + "systemLogs": "系统日志", + "settings": "设置", + "configurationEditor": "配置编辑器", + "languages": "Languages / 语言", + "language": { + "en": "英语 (English)", + "zhCN": "简体中文", + "withSystem": { + "label": "使用系统语言设置" + }, + "hi": "印地语 (हिन्दी)", + "es": "西班牙语 (Español)", + "fr": "法语 (Français)", + "ar": "阿拉伯语 (العربية)", + "pt": "葡萄牙语 (Português)", + "de": "德语 (Deutsch)", + "ja": "日语 (日本語)", + "tr": "土耳其语 (Türkçe)", + "it": "意大利语 (Italiano)", + "nl": "荷兰语 (Nederlands)", + "sv": "瑞典语 (Svenska)", + "nb": "挪威博克马尔语 (Norsk Bokmål)", + "ko": "韩语 (한국어)", + "vi": "越南语 (Tiếng Việt)", + "fa": "波斯语 (فارسی)", + "pl": "波兰语 (Polski)", + "uk": "乌克兰语 (Українська)", + "he": "希伯来语 (עברית)", + "el": "希腊语 (Ελληνικά)", + "ro": "罗马尼亚语 (Română)", + "hu": "马扎尔语 (Magyar)", + "fi": "芬兰语 (Suomi)", + "da": "丹麦语 (Dansk)", + "sk": "斯拉夫语 (Slovenčina)", + "ru": "俄语 (Русский)", + "cs": "捷克语 (Čeština)", + "yue": "粤语 (粵語)" + }, + "appearance": "外观", + "darkMode": { + "label": "深色模式", + "light": "浅色", + "dark": "深色", + "withSystem": { + "label": "使用系统深色模式设置" + } + }, + "withSystem": "跟随系统", + "theme": { + "label": "主题", + "blue": "蓝色", + "green": "绿色", + "nord": "Nord", + "red": "红色", + "contrast": "高对比度", + "default": "默认", + "highcontrast": "高对比" + }, + "help": "帮助", + "documentation": { + "title": "文档", + "label": "Frigate 的官方文档" + }, + "live": { + "title": "实时监控", + "allCameras": "所有摄像头", + "cameras": { + "title": "摄像头", + "count_other": "{{count}} 个摄像头" + } + }, + "review": "核查", + "explore": "探测", + "export": "导出", + "uiPlayground": "UI 演示", + "faceLibrary": "人脸管理", + "user": { + "account": "账号", + "current": "当前用户:{{user}}", + "anonymous": "匿名", + "logout": "登出", + "setPassword": "设置密码", + "title": "用户" + }, + "restart": "重启 Frigate" + }, + "toast": { + "copyUrlToClipboard": "已复制链接到剪贴板。", + "save": { + "title": "保存", + "error": { + "title": "保存配置信息失败: {{errorMessage}}", + "noMessage": "保存配置信息失败" + } + } + }, + "role": { + "title": "权限组", + "admin": "管理员", + "viewer": "成员", + "desc": "管理员可以完全访问Frigate界面上所有功能。成员则仅能查看摄像头、核查项和历史录像。" + }, + "accessDenied": { + "documentTitle": "没有权限 - Frigate", + "title": "没有权限", + "desc": "您没有权限查看此页面。" + }, + "notFound": { + "documentTitle": "没有找到页面 - Frigate", + "title": "404", + "desc": "页面未找到" + }, + "selectItem": "选择 {{item}}" +} diff --git a/web/public/locales/zh-CN/components/auth.json b/web/public/locales/zh-CN/components/auth.json new file mode 100644 index 000000000..015fa0ba8 --- /dev/null +++ b/web/public/locales/zh-CN/components/auth.json @@ -0,0 +1,15 @@ +{ + "form": { + "user": "用户名", + "password": "密码", + "login": "登录", + "errors": { + "usernameRequired": "用户名不能为空", + "passwordRequired": "密码不能为空", + "rateLimit": "超出请求限制,请稍后再试。", + "loginFailed": "登录失败", + "unknownError": "未知错误,请检查日志。", + "webUnknownError": "未知错误,请检查控制台日志。" + } + } +} diff --git a/web/public/locales/zh-CN/components/camera.json b/web/public/locales/zh-CN/components/camera.json new file mode 100644 index 000000000..982c74b30 --- /dev/null +++ b/web/public/locales/zh-CN/components/camera.json @@ -0,0 +1,83 @@ +{ + "group": { + "label": "摄像头组", + "add": "添加摄像头组", + "edit": "编辑摄像头组", + "delete": { + "label": "删除摄像头组", + "confirm": { + "title": "确认删除", + "desc": "你确定要删除摄像头组 {{name}} 吗?" + } + }, + "name": { + "label": "名称", + "placeholder": "请输入名称…", + "errorMessage": { + "mustLeastCharacters": "摄像头组的名称必须至少有 2 个字符。", + "exists": "摄像头组名称已存在。", + "nameMustNotPeriod": "摄像头组名称不能包含英文句号(.)。", + "invalid": "无效的摄像头组名称。" + } + }, + "cameras": { + "label": "摄像头", + "desc": "选择添加至该组的摄像头。" + }, + "icon": "图标", + "success": "摄像头组({{name}})保存成功。", + "camera": { + "setting": { + "label": "摄像头视频流设置", + "title": "{{cameraName}} 视频流设置", + "desc": "更改此摄像头组仪表板的实时视频流选项。这些设置特定于设备/浏览器。", + "audioIsAvailable": "此视频流支持音频", + "audioIsUnavailable": "此视频流不支持音频", + "audio": { + "tips": { + "title": "音频必须从您的摄像头输出并在 go2rtc 中配置此流。", + "document": "阅读文档(英文) " + } + }, + "streamMethod": { + "label": "视频流方法", + "method": { + "noStreaming": { + "label": "无视频流", + "desc": "摄像头图像每分钟仅更新一次,不会进行实时视频流播放。" + }, + "smartStreaming": { + "label": "智能视频流(推荐)", + "desc": "智能视频流在没有检测到活动时,每分钟更新一次摄像头图像,以节省带宽和资源。当检测到活动时,图像会无缝切换到实时视频流。" + }, + "continuousStreaming": { + "label": "持续视频流", + "desc": { + "title": "当摄像头画面在仪表板上可见时,始终为实时视频流,即使未检测到活动。", + "warning": "持续视频流可能会导致高带宽使用和性能问题,请谨慎使用。" + } + } + } + }, + "compatibilityMode": { + "label": "兼容模式", + "desc": "仅在摄像头的实时视频流显示颜色伪影,并且图像右侧有一条对角线时启用此选项。" + } + } + } + }, + "debug": { + "options": { + "label": "设置", + "title": "选项", + "showOptions": "显示选项", + "hideOptions": "隐藏选项" + }, + "boundingBox": "边界框", + "timestamp": "时间戳", + "zones": "区域", + "mask": "遮罩", + "motion": "运动", + "regions": "区域" + } +} diff --git a/web/public/locales/zh-CN/components/dialog.json b/web/public/locales/zh-CN/components/dialog.json new file mode 100644 index 000000000..6a1631c35 --- /dev/null +++ b/web/public/locales/zh-CN/components/dialog.json @@ -0,0 +1,116 @@ +{ + "restart": { + "title": "你确定要重启 Frigate?", + "button": "重启", + "restarting": { + "title": "Frigate 正在重启", + "content": "该页面将会在 {{countdown}} 秒后自动刷新。", + "button": "强制刷新" + } + }, + "explore": { + "plus": { + "submitToPlus": { + "label": "提交至 Frigate+", + "desc": "您希望避开的地点中的物体不应被视为误报。若将其作为误报提交,可能会导致AI模型容易混淆相关物体的识别。" + }, + "review": { + "true": { + "label": "为 Frigate Plus 确认此标签", + "true_other": "这是 {{label}}" + }, + "false": { + "label": "不为 Frigate Plus 确认此标签", + "false_other": "这不是 {{label}}" + }, + "state": { + "submitted": "已提交" + }, + "question": { + "label": "为 Frigate Plus 确认此标签", + "ask_a": "这个对象是 {{label}} 吗?", + "ask_an": "这个对象是 {{label}} 吗?", + "ask_full": "这个对象是 {{untranslatedLabel}} ({{translatedLabel}}) 吗?" + } + } + }, + "video": { + "viewInHistory": "在历史中查看" + } + }, + "export": { + "time": { + "fromTimeline": "从时间线选择", + "lastHour_other": "最后 {{count}} 小时", + "custom": "自定义", + "start": { + "title": "开始时间", + "label": "选择开始时间" + }, + "end": { + "title": "结束时间", + "label": "选择结束时间" + } + }, + "name": { + "placeholder": "导出项目的名字" + }, + "select": "选择", + "export": "导出", + "selectOrExport": "选择或导出", + "toast": { + "success": "导出成功。进入 /exports 目录查看文件。", + "error": { + "failed": "导出失败:{{error}}", + "endTimeMustAfterStartTime": "结束时间必须在开始时间之后", + "noVaildTimeSelected": "未选择有效的时间范围" + } + }, + "fromTimeline": { + "saveExport": "保存导出", + "previewExport": "预览导出" + } + }, + "streaming": { + "label": "视频流", + "restreaming": { + "disabled": "此摄像头未启用视频流转发功能。", + "desc": { + "title": "为此摄像头设置 go2rtc,以获取额外的实时预览选项和音频支持。", + "readTheDocumentation": "阅读文档(英文)" + } + }, + "showStats": { + "label": "显示视频流统计信息", + "desc": "启用后将在摄像头画面上叠加显示视频流统计信息。" + }, + "debugView": "调试界面" + }, + "search": { + "saveSearch": { + "label": "保存搜索", + "desc": "请为此已保存的搜索提供一个名称。", + "placeholder": "请输入搜索名称", + "overwrite": "{{searchName}} 已存在。保存将覆盖现有值。", + "success": "搜索 ({{searchName}}) 已保存。", + "button": { + "save": { + "label": "保存此搜索" + } + } + } + }, + "recording": { + "confirmDelete": { + "title": "确认删除", + "desc": { + "selected": "你确定要删除与此核查项相关的所有录制视频吗?

    提示:按住 Shift 键点击删除可跳过此对话框。" + } + }, + "button": { + "export": "导出", + "markAsReviewed": "标记为已核查", + "deleteNow": "立即删除" + } + } +} diff --git a/web/public/locales/zh-CN/components/filter.json b/web/public/locales/zh-CN/components/filter.json new file mode 100644 index 000000000..e8c9d57bc --- /dev/null +++ b/web/public/locales/zh-CN/components/filter.json @@ -0,0 +1,126 @@ +{ + "filter": "过滤器", + "labels": { + "label": "标签", + "all": { + "title": "所有标签", + "short": "标签" + }, + "count": "{{count}} 个标签", + "count_other": "{{count}} 个标签", + "count_one": "{{count}} 个标签" + }, + "zones": { + "all": { + "title": "所有区域", + "short": "区域" + }, + "label": "区域" + }, + "dates": { + "all": { + "title": "所有日期", + "short": "日期" + } + }, + "more": "更多筛选项", + "reset": { + "label": "重置筛选器为默认值" + }, + "timeRange": "时间范围", + "subLabels": { + "label": "子标签", + "all": "所有子标签" + }, + "score": "分值", + "estimatedSpeed": "预计速度({{unit}})", + "features": { + "label": "特性", + "hasSnapshot": "包含快照", + "hasVideoClip": "包含视频片段", + "submittedToFrigatePlus": { + "label": "提交至 Frigate+", + "tips": "你必须要先筛选具有快照的探测对象。

    没有快照的跟踪对象无法提交至 Frigate+." + } + }, + "sort": { + "label": "排序", + "dateAsc": "日期 (正序)", + "dateDesc": "日期 (倒序)", + "scoreAsc": "对象分值 (正序)", + "scoreDesc": "对象分值 (倒序)", + "speedAsc": "预计速度 (正序)", + "speedDesc": "预计速度 (倒序)", + "relevance": "关联性" + }, + "cameras": { + "label": "摄像头筛选", + "all": { + "title": "所有摄像头", + "short": "摄像头" + } + }, + "review": { + "showReviewed": "显示已核查的项目" + }, + "motion": { + "showMotionOnly": "仅显示运动" + }, + "explore": { + "settings": { + "title": "设置", + "defaultView": { + "title": "默认视图", + "desc": "当未选择任何过滤器时,显示每个标签最近跟踪对象的摘要,或显示未过滤的网格。", + "summary": "摘要", + "unfilteredGrid": "未过滤网格" + }, + "gridColumns": { + "title": "网格列数", + "desc": "选择网格视图中的列数。" + }, + "searchSource": { + "label": "搜索源", + "desc": "选择是搜索缩略图还是跟踪对象的描述。", + "options": { + "thumbnailImage": "缩略图", + "description": "描述" + } + } + }, + "date": { + "selectDateBy": { + "label": "选择日期进行筛选" + } + } + }, + "logSettings": { + "label": "日志级别筛选", + "filterBySeverity": "按严重程度筛选日志", + "loading": { + "title": "加载中", + "desc": "当日志面板滚动到底部时,新的日志会自动流式加载。" + }, + "disableLogStreaming": "禁用日志流式加载", + "allLogs": "所有日志" + }, + "trackedObjectDelete": { + "title": "确认删除", + "desc": "删除这 {{objectLength}} 个跟踪对象将移除快照、任何已保存的嵌入和任何相关的对象生命周期条目。历史视图中这些跟踪对象的录制片段将不会被删除。

    您确定要继续吗?

    按住 Shift 键可在将来跳过此对话框。", + "toast": { + "success": "跟踪对象删除成功。", + "error": "删除跟踪对象失败:{{errorMessage}}" + } + }, + "zoneMask": { + "filterBy": "按区域遮罩筛选" + }, + "recognizedLicensePlates": { + "title": "识别的车牌", + "loadFailed": "加载识别的车牌失败。", + "loading": "正在加载识别的车牌…", + "placeholder": "输入以搜索车牌…", + "noLicensePlatesFound": "未找到车牌。", + "selectPlatesFromList": "从列表中选择一个或多个车牌。" + } +} diff --git a/web/public/locales/zh-CN/components/icons.json b/web/public/locales/zh-CN/components/icons.json new file mode 100644 index 000000000..20f201249 --- /dev/null +++ b/web/public/locales/zh-CN/components/icons.json @@ -0,0 +1,8 @@ +{ + "iconPicker": { + "selectIcon": "选择图标", + "search": { + "placeholder": "搜索图标…" + } + } +} diff --git a/web/public/locales/zh-CN/components/input.json b/web/public/locales/zh-CN/components/input.json new file mode 100644 index 000000000..add854a48 --- /dev/null +++ b/web/public/locales/zh-CN/components/input.json @@ -0,0 +1,10 @@ +{ + "button": { + "downloadVideo": { + "label": "下载视频", + "toast": { + "success": "你的核查视频已开始下载。" + } + } + } +} diff --git a/web/public/locales/zh-CN/components/player.json b/web/public/locales/zh-CN/components/player.json new file mode 100644 index 000000000..df6648048 --- /dev/null +++ b/web/public/locales/zh-CN/components/player.json @@ -0,0 +1,51 @@ +{ + "noRecordingsFoundForThisTime": "找不到此次录制", + "noPreviewFound": "没有找到预览", + "noPreviewFoundFor": "没有在 {{cameraName}} 下找到预览", + "submitFrigatePlus": { + "title": "提交此帧到 Frigate+?", + "submit": "提交" + }, + "livePlayerRequiredIOSVersion": "此直播流类型需要 iOS 17.1 或更高版本。", + "streamOffline": { + "title": "视频流离线", + "desc": "未在 {{cameraName}} 的 detect 流上接收到任何帧,请检查错误日志" + }, + "cameraDisabled": "摄像机已禁用", + "stats": { + "streamType": { + "title": "流类型:", + "short": "类型" + }, + "bandwidth": { + "title": "带宽:", + "short": "带宽" + }, + "latency": { + "title": "延迟:", + "value": "{{seconds}} 秒", + "short": { + "title": "延迟", + "value": "{{seconds}} 秒" + } + }, + "totalFrames": "总帧数:", + "droppedFrames": { + "title": "丢帧数:", + "short": { + "title": "丢帧", + "value": "{{droppedFrames}} 帧" + } + }, + "decodedFrames": "解码帧数:", + "droppedFrameRate": "丢帧率:" + }, + "toast": { + "success": { + "submittedFrigatePlus": "已成功提交帧到 Frigate+" + }, + "error": { + "submitFrigatePlusFailed": "提交帧到 Frigate+ 失败" + } + } +} diff --git a/web/public/locales/zh-CN/objects.json b/web/public/locales/zh-CN/objects.json new file mode 100644 index 000000000..270db56c1 --- /dev/null +++ b/web/public/locales/zh-CN/objects.json @@ -0,0 +1,120 @@ +{ + "person": "人", + "bicycle": "自行车", + "car": "汽车", + "motorcycle": "摩托车", + "airplane": "飞机", + "bus": "公交车", + "train": "火车", + "boat": "船", + "traffic_light": "交通灯", + "fire_hydrant": "消防栓", + "street_sign": "路标", + "stop_sign": "停车标志", + "parking_meter": "停车计时器", + "bench": "长椅", + "bird": "鸟", + "cat": "猫", + "dog": "狗", + "horse": "马", + "sheep": "绵羊", + "cow": "牛", + "elephant": "大象", + "bear": "熊", + "zebra": "斑马", + "giraffe": "长颈鹿", + "hat": "帽子", + "backpack": "背包", + "umbrella": "雨伞", + "shoe": "鞋子", + "eye_glasses": "眼镜", + "handbag": "手提包", + "tie": "领带", + "suitcase": "手提箱", + "frisbee": "飞盘", + "skis": "滑雪板", + "snowboard": "滑雪板", + "sports_ball": "运动球", + "kite": "风筝", + "baseball_bat": "棒球棒", + "baseball_glove": "棒球手套", + "skateboard": "滑板", + "surfboard": "冲浪板", + "tennis_racket": "网球拍", + "bottle": "瓶子", + "plate": "盘子", + "wine_glass": "酒杯", + "cup": "杯子", + "fork": "叉子", + "knife": "刀", + "spoon": "勺子", + "bowl": "碗", + "banana": "香蕉", + "apple": "苹果", + "sandwich": "三明治", + "orange": "橙子", + "broccoli": "西兰花", + "carrot": "胡萝卜", + "hot_dog": "热狗", + "pizza": "披萨", + "donut": "甜甜圈", + "cake": "蛋糕", + "chair": "椅子", + "couch": "沙发", + "potted_plant": "盆栽植物", + "bed": "床", + "mirror": "镜子", + "dining_table": "餐桌", + "window": "窗户", + "desk": "桌子", + "toilet": "厕所", + "door": "门", + "tv": "电视", + "laptop": "笔记本电脑", + "mouse": "老鼠", + "remote": "遥控器", + "keyboard": "键盘", + "cell_phone": "手机", + "microwave": "微波炉", + "oven": "烤箱", + "toaster": "烤面包机", + "sink": "水槽", + "refrigerator": "冰箱", + "blender": "搅拌机", + "book": "书", + "clock": "时钟", + "vase": "花瓶", + "scissors": "剪刀", + "teddy_bear": "泰迪熊", + "hair_dryer": "吹风机", + "toothbrush": "牙刷", + "hair_brush": "发刷", + "vehicle": "车辆", + "squirrel": "松鼠", + "deer": "鹿", + "animal": "动物", + "bark": "树皮", + "fox": "狐狸", + "goat": "山羊", + "rabbit": "兔子", + "raccoon": "浣熊", + "robot_lawnmower": "自动割草机", + "waste_bin": "垃圾桶", + "on_demand": "手动", + "face": "人脸", + "license_plate": "车牌", + "package": "包裹", + "bbq_grill": "烧烤架", + "amazon": "亚马逊", + "usps": "美国邮政", + "ups": "UPS", + "fedex": "联邦快递", + "dhl": "DHL", + "an_post": "爱尔兰邮政", + "purolator": "普罗莱特", + "postnl": "荷兰邮政", + "nzpost": "新西兰邮政", + "postnord": "北欧邮政", + "gls": "GLS", + "dpd": "DPD" +} diff --git a/web/public/locales/zh-CN/views/configEditor.json b/web/public/locales/zh-CN/views/configEditor.json new file mode 100644 index 000000000..d3b858308 --- /dev/null +++ b/web/public/locales/zh-CN/views/configEditor.json @@ -0,0 +1,15 @@ +{ + "documentTitle": "配置编辑器 - Frigate", + "configEditor": "配置编辑器", + "copyConfig": "复制配置", + "saveAndRestart": "保存并重启", + "saveOnly": "只保存", + "toast": { + "success": { + "copyToClipboard": "配置已复制到剪贴板。" + }, + "error": { + "savingError": "保存配置时出错" + } + } +} diff --git a/web/public/locales/zh-CN/views/events.json b/web/public/locales/zh-CN/views/events.json new file mode 100644 index 000000000..7e17cc5a4 --- /dev/null +++ b/web/public/locales/zh-CN/views/events.json @@ -0,0 +1,38 @@ +{ + "alerts": "警报", + "detections": "检测", + "motion": { + "label": "运动", + "only": "仅运动画面" + }, + "allCameras": "所有摄像头", + "empty": { + "alert": "还没有“警报”类核查项", + "detection": "还没有“探测”类核查项", + "motion": "还没有运动类数据" + }, + "timeline": "时间线", + "timeline.aria": "选择时间线", + "events": { + "label": "事件", + "aria": "选择事件", + "noFoundForTimePeriod": "未找到该时间段的事件。" + }, + "documentTitle": "核查 - Frigate", + "recordings": { + "documentTitle": "回放 - Frigate" + }, + "calendarFilter": { + "last24Hours": "过去24小时" + }, + "markAsReviewed": "标记为已核查", + "markTheseItemsAsReviewed": "将这些项目标记为已核查", + "newReviewItems": { + "label": "查看新的核查项目", + "button": "核查新项目" + }, + "camera": "摄像头", + "selected": "已选择 {{count}} 个", + "selected_one": "已选择 {{count}} 个", + "selected_other": "已选择 {{count}} 个" +} diff --git a/web/public/locales/zh-CN/views/explore.json b/web/public/locales/zh-CN/views/explore.json new file mode 100644 index 000000000..7fd2c8096 --- /dev/null +++ b/web/public/locales/zh-CN/views/explore.json @@ -0,0 +1,198 @@ +{ + "documentTitle": "浏览 - Frigate", + "generativeAI": "生成式 AI", + "exploreIsUnavailable": { + "title": "浏览功能不可用", + "embeddingsReindexing": { + "context": "跟踪对象嵌入重新索引完成后,可以使用浏览功能。", + "startingUp": "启动中…", + "estimatedTime": "预计剩余时间:", + "finishingShortly": "即将完成", + "step": { + "thumbnailsEmbedded": "缩略图嵌入:", + "descriptionsEmbedded": "描述嵌入:", + "trackedObjectsProcessed": "跟踪对象已处理:" + } + }, + "downloadingModels": { + "context": "Frigate正在下载支持语义搜索功能所需的嵌入模型。根据网络连接速度,这可能需要几分钟。", + "setup": { + "visionModel": "视觉模型", + "visionModelFeatureExtractor": "视觉模型特征提取器", + "textModel": "文本模型", + "textTokenizer": "文本分词器" + }, + "tips": { + "context": "模型下载完成后,您可能需要重新索引跟踪对象的嵌入。", + "documentation": "阅读文档(英文)" + }, + "error": "发生错误。请检查Frigate日志。" + } + }, + "trackedObjectDetails": "跟踪对象详情", + "type": { + "details": "详情", + "snapshot": "快照", + "video": "视频", + "object_lifecycle": "对象生命周期" + }, + "objectLifecycle": { + "title": "对象生命周期", + "noImageFound": "未找到此时间戳的图像。", + "createObjectMask": "创建对象遮罩", + "adjustAnnotationSettings": "调整标注设置", + "scrollViewTips": "滚动查看此对象生命周期的重要时刻。", + "autoTrackingTips": "自动跟踪摄像头的边界框位置可能不准确。", + "lifecycleItemDesc": { + "visible": "检测到 {{label}}", + "entered_zone": "{{label}} 进入 {{zones}}", + "active": "{{label}} 变为活动状态", + "stationary": "{{label}} 变为静止状态", + "attribute": { + "faceOrLicense_plate": "检测到 {{label}} 的 {{attribute}}", + "other": "{{label}} 识别为 {{attribute}}" + }, + "gone": "{{label}} 离开", + "heard": "听到 {{label}}", + "external": "检测到 {{label}}", + "header": { + "ratio": "得分", + "zones": "区域", + "area": "坐标区域" + } + }, + "annotationSettings": { + "title": "标注设置", + "showAllZones": { + "title": "显示所有区域", + "desc": "在对象进入区域的帧上始终显示区域。" + }, + "offset": { + "label": "标注偏移", + "desc": "这些数据来自摄像头的检测源,但是叠加在录制源的图像上。这两个流不太可能完全同步。因此,边界框和录像不会完全对齐。但是,可以使用 annotation_offset 字段来调整这个问题。", + "documentation": "阅读文档(英文) ", + "millisecondsToOffset": "检测标注的偏移毫秒数。默认值:0", + "tips": "提示:假设有一个人从左向右走的事件片段。如果事件时间线上的边界框始终在人的左侧,则应该减小该值。同样,如果一个人从左向右走,而边界框始终在人的前面,则应该增加该值。" + } + }, + "carousel": { + "previous": "上一张", + "next": "下一张" + } + }, + "details": { + "item": { + "title": "回放项目详情", + "desc": "核查项详情", + "button": { + "share": "分享该核查项", + "viewInExplore": "在 浏览 中查看" + }, + "tips": { + "mismatch_other": "检测到 {{count}} 个不可用的对象,并已包含在此核查项中。这些对象可能未达到警报或检测标准,或者已被清理/删除。", + "hasMissingObjects": "如果希望 Frigate 保存以下标签的跟踪对象,请调整您的配置:{{objects}}" + }, + "toast": { + "success": { + "regenerate": "已向 {{provider}} 请求新的描述。根据提供商的速度,生成新描述可能需要一些时间。", + "updatedSublabel": "成功更新子标签。", + "updatedLPR": "成功更新车牌。" + }, + "error": { + "regenerate": "调用 {{provider}} 生成新描述失败:{{errorMessage}}", + "updatedSublabelFailed": "更新子标签失败:{{errorMessage}}", + "updatedLPRFailed": "更新车牌失败:{{errorMessage}}" + } + } + }, + "label": "标签", + "editSubLabel": { + "title": "编辑子标签", + "desc": "为 {{label}} 输入新的子标签", + "descNoLabel": "为此跟踪对象输入新的子标签" + }, + "topScore": { + "label": "最高得分", + "info": "最高分是跟踪对象的最高中位数得分,因此可能与搜索结果缩略图上显示的得分不同。" + }, + "estimatedSpeed": "预计速度", + "objects": "对象", + "camera": "摄像头", + "zones": "区域", + "timestamp": "时间戳", + "button": { + "findSimilar": "查找相似项", + "regenerate": { + "title": "重新生成", + "label": "重新生成跟踪对象描述" + } + }, + "description": { + "label": "描述", + "placeholder": "跟踪对象的描述", + "aiTips": "在跟踪对象的生命周期结束之前,Frigate 不会向您的生成式 AI 提供商请求描述。" + }, + "expandRegenerationMenu": "展开重新生成菜单", + "regenerateFromSnapshot": "从快照重新生成", + "regenerateFromThumbnails": "从缩略图重新生成", + "tips": { + "descriptionSaved": "已保存描述", + "saveDescriptionFailed": "更新描述失败:{{errorMessage}}" + }, + "editLPR": { + "desc": "为 {{label}} 输入新的车牌值", + "descNoLabel": "为探测到的对象输入新的车牌值", + "title": "编辑车牌" + }, + "recognizedLicensePlate": "识别的车牌", + "snapshotScore": { + "label": "快照得分" + } + }, + "itemMenu": { + "downloadVideo": { + "label": "下载视频", + "aria": "下载视频" + }, + "downloadSnapshot": { + "label": "下载快照", + "aria": "下载快照" + }, + "viewObjectLifecycle": { + "label": "查看对象生命周期", + "aria": "显示对象的生命周期" + }, + "findSimilar": { + "label": "查找相似项", + "aria": "查看相似的对象" + }, + "submitToPlus": { + "label": "提交至 Frigate+", + "aria": "提交至 Frigate Plus" + }, + "viewInHistory": { + "label": "在历史记录中查看", + "aria": "在历史记录中查看" + }, + "deleteTrackedObject": { + "label": "删除此跟踪对象" + } + }, + "dialog": { + "confirmDelete": { + "title": "确认删除", + "desc": "删除此跟踪对象将移除快照、所有已保存的嵌入数据以及任何关联的对象生命周期条目。但在历史视图中的录制视频不会被删除。

    你确定要继续删除吗?" + } + }, + "noTrackedObjects": "未找到跟踪对象", + "fetchingTrackedObjectsFailed": "获取跟踪对象失败:{{errorMessage}}", + "trackedObjectsCount_other": "{{count}} 个跟踪对象 ", + "searchResult": { + "deleteTrackedObject": { + "toast": { + "success": "跟踪对象删除成功。", + "error": "删除跟踪对象失败:{{errorMessage}}" + } + } + } +} diff --git a/web/public/locales/zh-CN/views/exports.json b/web/public/locales/zh-CN/views/exports.json new file mode 100644 index 000000000..b22d035f1 --- /dev/null +++ b/web/public/locales/zh-CN/views/exports.json @@ -0,0 +1,17 @@ +{ + "documentTitle": "导出 - Frigate", + "search": "搜索", + "noExports": "没有找到导出的项目", + "deleteExport": "删除导出的项目", + "deleteExport.desc": "你确定要删除 {{exportName}} 吗?", + "editExport": { + "title": "重命名导出", + "desc": "为此导出项目输入新名称。", + "saveExport": "保存导出" + }, + "toast": { + "error": { + "renameExportFailed": "重命名导出失败:{{errorMessage}}" + } + } +} diff --git a/web/public/locales/zh-CN/views/faceLibrary.json b/web/public/locales/zh-CN/views/faceLibrary.json new file mode 100644 index 000000000..da156177e --- /dev/null +++ b/web/public/locales/zh-CN/views/faceLibrary.json @@ -0,0 +1,82 @@ +{ + "description": { + "addFace": "我们将引导你如何向人脸库中添加新的特征集。", + "placeholder": "请输入此特征集的名称" + }, + "details": { + "person": "人", + "confidence": "置信度", + "face": "人脸详情", + "faceDesc": "人脸及相关对象的详细信息", + "timestamp": "时间戳" + }, + "documentTitle": "人脸库 - Frigate", + "uploadFaceImage": { + "title": "上传人脸图片", + "desc": "上传图片以扫描人脸并包含在{{pageToggle}}中" + }, + "createFaceLibrary": { + "title": "创建特征库", + "desc": "创建一个新的特征库", + "new": "新建人脸", + "nextSteps": "建议按以下步骤建立可靠的特征库:
  • 使用训练选项卡为每个检测到的人员选择并训练图像
  • 优先使用正脸图像以获得最佳效果,尽可能避免使用侧脸图像进行训练
  • " + }, + "train": { + "title": "训练", + "aria": "选择训练" + }, + "selectItem": "选择 {{item}}", + "selectFace": "选择人脸", + "deleteFaceLibrary": { + "title": "删除名称", + "desc": "确定要删除特征库 {{name}} 吗?此操作将永久删除所有关联的人脸特征数据。" + }, + "button": { + "deleteFaceAttempts": "尝试删除人脸", + "addFace": "添加人脸", + "uploadImage": "上传图片", + "reprocessFace": "重新处理人脸", + "renameFace": "重命名人脸", + "deleteFace": "删除人脸" + }, + "imageEntry": { + "validation": { + "selectImage": "请选择图片文件。" + }, + "dropActive": "拖动图片文件到这里…", + "dropInstructions": "拖动图片文件到此处或点击选择", + "maxSize": "最大文件大小:{{size}}MB" + }, + "readTheDocs": "阅读文档", + "trainFaceAs": "将人脸特征训练为:", + "trainFace": "训练人脸特征", + "toast": { + "success": { + "uploadedImage": "图片上传成功。", + "addFaceLibrary": "{{name}} 已成功添加至人脸库!", + "deletedFace_other": "成功删除 {{count}} 个 人脸特征。", + "deletedName_other": "成功删除 {{count}} 个 人脸特征。", + "trainedFace": "人脸特征训练成功。", + "updatedFaceScore": "更新人脸特征评分成功。", + "renamedFace": "成功重命名人脸为{{name}}" + }, + "error": { + "uploadingImageFailed": "图片上传失败:{{errorMessage}}", + "addFaceLibraryFailed": "人脸命名失败:{{errorMessage}}", + "deleteFaceFailed": "删除失败:{{errorMessage}}", + "deleteNameFailed": "特征集删除失败:{{errorMessage}}", + "trainFailed": "训练失败:{{errorMessage}}", + "updateFaceScoreFailed": "更新人脸评分失败:{{errorMessage}}", + "renameFaceFailed": "重命名人脸失败:{{errorMessage}}" + } + }, + "steps": { + "faceName": "输入人脸姓名", + "uploadFace": "上传人脸照片", + "nextSteps": "下一步" + }, + "renameFace": { + "desc": "为 {{name}} 输入新的名称", + "title": "重命名人脸" + } +} diff --git a/web/public/locales/zh-CN/views/live.json b/web/public/locales/zh-CN/views/live.json new file mode 100644 index 000000000..43c1ee7cc --- /dev/null +++ b/web/public/locales/zh-CN/views/live.json @@ -0,0 +1,158 @@ +{ + "documentTitle": "实时监控 - Frigate", + "documentTitle.withCamera": "{{camera}} - 实时监控 - Frigate", + "lowBandwidthMode": "低带宽模式", + "twoWayTalk": { + "enable": "开启实时对话", + "disable": "关闭实时通话" + }, + "cameraAudio": { + "enable": "开启音频输出", + "disable": "关闭音频输出" + }, + "ptz": { + "move": { + "clickMove": { + "label": "点击画面以使摄像头居中", + "enable": "启用点击移动", + "disable": "禁用点击移动" + }, + "left": { + "label": "PTZ摄像头向左移动" + }, + "up": { + "label": "PTZ摄像头向上移动" + }, + "down": { + "label": "PTZ摄像头向下移动" + }, + "right": { + "label": "PTZ摄像头向右移动" + } + }, + "zoom": { + "in": { + "label": "PTZ摄像头放大" + }, + "out": { + "label": "PTZ摄像头缩小" + } + }, + "frame": { + "center": { + "label": "点击将PTZ摄像头画面居中" + } + }, + "presets": "PTZ摄像头预设" + }, + "camera": { + "enable": "开启摄像头", + "disable": "关闭摄像头" + }, + "muteCameras": { + "enable": "屏蔽所有摄像头", + "disable": "取消屏蔽所有摄像头" + }, + "detect": { + "enable": "启用检测", + "disable": "关闭检测" + }, + "recording": { + "enable": "启用录制", + "disable": "关闭录制" + }, + "snapshots": { + "enable": "启用快照", + "disable": "关闭快照" + }, + "audioDetect": { + "enable": "启用音频检测", + "disable": "关闭音频检测" + }, + "autotracking": { + "enable": "启用自动追踪", + "disable": "关闭自动追踪" + }, + "streamStats": { + "enable": "显示视频流统计信息", + "disable": "隐藏视频流统计信息" + }, + "manualRecording": { + "title": "按需录制", + "tips": "根据此摄像头的录制保留设置,手动启动事件。", + "playInBackground": { + "label": "后台播放", + "desc": "启用此选项可在播放器隐藏时继续视频流播放。" + }, + "showStats": { + "label": "显示统计信息", + "desc": "启用此选项可在摄像头画面上叠加显示视频流统计信息。" + }, + "debugView": "调试视图", + "start": "开始手动按需录制", + "started": "已启用手动按需录制。", + "failedToStart": "启动手动录制失败。", + "recordDisabledTips": "由于此摄像头的配置中禁用了录制或对其进行了限制,将只会保存快照。", + "end": "停止手动按需录制", + "ended": "已完成手动按需录制。", + "failedToEnd": "停止手动录制失败。" + }, + "streamingSettings": "视频流设置", + "notifications": "通知", + "audio": "音频", + "suspend": { + "forTime": "暂停时长:" + }, + "stream": { + "title": "视频流", + "audio": { + "tips": { + "title": "音频必须从摄像头输出并在 go2rtc 中配置为此视频流使用。", + "documentation": "阅读文档 " + }, + "available": "此视频流支持音频", + "unavailable": "此视频流不支持音频" + }, + "twoWayTalk": { + "tips": "您的设备必须支持此功能,并且必须配置 WebRTC 以支持双向对讲。", + "tips.documentation": "阅读文档 ", + "available": "此视频流支持双向对讲", + "unavailable": "此视频流不支持双向对讲" + }, + "lowBandwidth": { + "tips": "由于缓冲或视频流错误,实时视图处于低带宽模式。", + "resetStream": "重置视频流" + }, + "playInBackground": { + "label": "后台播放", + "tips": "启用此选项可在播放器隐藏时继续视频流播放。" + } + }, + "cameraSettings": { + "title": "{{camera}} 设置", + "cameraEnabled": "摄像头已启用", + "objectDetection": "对象检测", + "recording": "录制", + "snapshots": "快照", + "audioDetection": "音频检测", + "autotracking": "自动跟踪" + }, + "history": { + "label": "显示历史录像" + }, + "effectiveRetainMode": { + "modes": { + "all": "全部", + "motion": "运动", + "active_objects": "活动对象" + }, + "notAllTips": "您的 {{source}} 录制保留配置设置为 mode: {{effectiveRetainMode}},因此此按需录制将仅保留包含 {{effectiveRetainModeName}} 的片段。" + }, + "editLayout": { + "label": "编辑布局", + "group": { + "label": "编辑摄像机分组" + }, + "exitEdit": "退出编辑" + } +} diff --git a/web/public/locales/zh-CN/views/recording.json b/web/public/locales/zh-CN/views/recording.json new file mode 100644 index 000000000..77443e172 --- /dev/null +++ b/web/public/locales/zh-CN/views/recording.json @@ -0,0 +1,12 @@ +{ + "export": "导出", + "calendar": "日历", + "filter": "过滤器", + "filters": "筛选条件", + "toast": { + "error": { + "noValidTimeSelected": "未选择有效的时间范围", + "endTimeMustAfterStartTime": "结束时间必须晚于开始时间" + } + } +} diff --git a/web/public/locales/zh-CN/views/search.json b/web/public/locales/zh-CN/views/search.json new file mode 100644 index 000000000..2f1bdf7ad --- /dev/null +++ b/web/public/locales/zh-CN/views/search.json @@ -0,0 +1,74 @@ +{ + "search": "搜索", + "savedSearches": "已保存的搜索", + "searchFor": "搜索 {{inputValue}}", + "button": { + "clear": "清除搜索", + "save": "保存搜索", + "delete": "删除已保存的搜索", + "filterInformation": "筛选信息", + "filterActive": "筛选器已激活" + }, + "trackedObjectId": "跟踪对象 ID", + "filter": { + "label": { + "cameras": "摄像机", + "labels": "标签", + "zones": "区域", + "sub_labels": "子标签", + "search_type": "搜索类型", + "time_range": "时间范围", + "before": "之前", + "after": "之后", + "min_score": "最低分数", + "max_score": "最高分数", + "min_speed": "最低速度", + "max_speed": "最高速度", + "recognized_license_plate": "识别的车牌", + "has_clip": "包含片段", + "has_snapshot": "包含快照" + }, + "searchType": { + "thumbnail": "缩略图", + "description": "描述" + }, + "toast": { + "error": { + "beforeDateBeLaterAfter": "结束日期必须晚于开始日期。", + "afterDatebeEarlierBefore": "开始日期必须早于结束日期。", + "minScoreMustBeLessOrEqualMaxScore": "最低分数必须小于或等于最高分数。", + "maxScoreMustBeGreaterOrEqualMinScore": "最高分数必须大于或等于最低分数。", + "minSpeedMustBeLessOrEqualMaxSpeed": "最低速度必须小于或等于最高速度。", + "maxSpeedMustBeGreaterOrEqualMinSpeed": "最高速度必须大于或等于最低速度。" + } + }, + "tips": { + "title": "如何使用文本筛选器(英文)", + "desc": { + "text": "筛选器可帮助您缩小搜索范围。注意,目前还暂不支持中文搜索。以下是在输入字段中使用筛选器的方法:", + "step": "
    • 输入筛选器名称后跟一个冒号(例如:“cameras:”)。
    • 从建议中选择一个值或输入您自己的值。
    • 使用多个筛选器时,可以在它们之间用空格分隔。
    • 日期筛选器(before: 和 after:)使用 {{DateFormat}} 格式。
    • 时间范围筛选器使用 {{exampleTime}} 格式。
    • 点击筛选器旁边的“x”即可移除筛选条件。
    ", + "example": "示例:cameras:front_door label:person before:01012024 time_range:3:00PM-4:00PM", + "step2": "选择给出的建议值或自行输入;", + "step3": "多个过滤器之间用空格分隔;", + "step5": "时间范围过滤器使用 {{exampleTime}} 格式;", + "step6": "点击过滤器旁的'x'可移除该过滤选项。", + "exampleLabel": "范例:", + "step1": "输入过滤键名后接冒号(例如 \"cameras:\" );", + "step4": "日期过滤器(before: 和 after:)使用 {{DateFormat}} 格式;" + } + }, + "header": { + "currentFilterType": "筛选值", + "noFilters": "筛选条件", + "activeFilters": "激活的筛选项" + } + }, + "similaritySearch": { + "title": "相似搜索", + "active": "相似搜索已激活", + "clear": "清除相似搜索" + }, + "placeholder": { + "search": "搜索…" + } +} diff --git a/web/public/locales/zh-CN/views/settings.json b/web/public/locales/zh-CN/views/settings.json new file mode 100644 index 000000000..cd651d72e --- /dev/null +++ b/web/public/locales/zh-CN/views/settings.json @@ -0,0 +1,594 @@ +{ + "documentTitle": { + "default": "设置 - Frigate", + "authentication": "身份验证设置 - Frigate", + "camera": "摄像头设置 - Frigate", + "classification": "分类设置 - Frigate", + "masksAndZones": "遮罩和区域编辑器 - Frigate", + "motionTuner": "运动调整器 - Frigate", + "object": "调试 - Frigate", + "general": "常规设置 - Frigate", + "frigatePlus": "Frigate+ 设置 - Frigate", + "notifications": "通知设置 - Frigate" + }, + "menu": { + "ui": "界面设置", + "classification": "分类设置", + "cameras": "摄像头设置", + "masksAndZones": "遮罩/ 区域", + "motionTuner": "运动调整器", + "debug": "调试", + "users": "用户", + "notifications": "通知", + "frigateplus": "Frigate+" + }, + "dialog": { + "unsavedChanges": { + "title": "你有未保存的更改。", + "desc": "是否要在继续之前保存更改?" + } + }, + "cameraSetting": { + "camera": "摄像头", + "noCamera": "没有摄像头" + }, + "general": { + "title": "常规设置", + "liveDashboard": { + "title": "实时监控面板", + "automaticLiveView": { + "label": "自动实时预览", + "desc": "检测到画面活动时将自动切换至该摄像头实时画面。禁用此选项会导致实时监控页面的摄像头图像每分钟只更新一次。" + }, + "playAlertVideos": { + "label": "播放警报视频", + "desc": "默认情况下,实时监控页面上的最新警报会以一小段循环视频的形式进行播放。禁用此选项将仅显示浏览器本地缓存的静态图片。" + } + }, + "storedLayouts": { + "title": "存储监控面板布局", + "desc": "可以在监控面板调整或拖动摄像头的布局。这些设置将保存在浏览器的本地存储中。", + "clearAll": "清除所有布局" + }, + "cameraGroupStreaming": { + "title": "摄像头组视频流设置", + "desc": "每个摄像头组的视频流设置将保存在浏览器的本地存储中。", + "clearAll": "清除所有视频流设置" + }, + "recordingsViewer": { + "title": "回放查看", + "defaultPlaybackRate": { + "label": "默认播放速率", + "desc": "调整播放录像时默认的速率。" + } + }, + "calendar": { + "title": "日历", + "firstWeekday": { + "label": "每周第一天", + "desc": "设置每周第一天是星期几。", + "sunday": "星期天", + "monday": "星期一" + } + }, + "toast": { + "success": { + "clearStoredLayout": "已清除 {{cameraName}} 的存储布局", + "clearStreamingSettings": "已清除所有摄像头组的视频流设置。" + }, + "error": { + "clearStoredLayoutFailed": "清除存储布局失败:{{errorMessage}}", + "clearStreamingSettingsFailed": "清除视频流设置失败:{{errorMessage}}" + } + } + }, + "classification": { + "title": "分类设置", + "semanticSearch": { + "title": "语义搜索", + "desc": "Frigate的语义搜索能够让你使用自然语言根据图像本身、自定义的文本描述或自动生成的描述来搜索视频。", + "readTheDocumentation": "阅读文档(英文)", + "reindexNow": { + "label": "立即重建索引", + "desc": "重建索引将为所有跟踪对象重新生成特征向量。该过程将在后台运行,可能会使CPU满载,所需时间取决于跟踪对象的数量。", + "confirmTitle": "确认重建索引", + "confirmDesc": "确定要为所有跟踪对象重建特征向量索引吗?此过程将在后台运行,但可能会导致CPU满载并耗费较长时间。您可以在 浏览 页面查看进度。", + "confirmButton": "重建索引", + "success": "重建索引已成功启动。", + "alreadyInProgress": "重建索引已在执行中。", + "error": "启动重建索引失败:{{errorMessage}}" + }, + "modelSize": { + "label": "模型大小", + "desc": "用于语义搜索的语言模型大小。", + "small": { + "title": "小", + "desc": "使用 模型。该模型将使用较少的内存,在CPU上也能较快的运行。质量较好。" + }, + "large": { + "title": "大", + "desc": "使用 模型。该模型采用了完整的Jina模型,并在适用的情况下使用GPU。" + } + } + }, + "faceRecognition": { + "title": "人脸识别", + "desc": "人脸识别功能允许为人物分配名称,当识别到他们的面孔时,Frigate 会将人物的名字作为子标签进行分配。这些信息会显示在界面、过滤器以及通知中。", + "readTheDocumentation": "阅读文档(英文)", + "modelSize": { + "label": "模型大小", + "desc": "用于人脸识别的模型尺寸。", + "small": { + "title": "小", + "desc": "使用模型将采用FaceNet人脸特征提取模型,可在大多数CPU上高效运行。" + }, + "large": { + "title": "大", + "desc": "使用模型将采用ArcFace人脸特征提取模型,若条件允许将自动使用GPU运行。" + } + } + }, + "licensePlateRecognition": { + "title": "车牌识别", + "desc": "Frigate 可以识别车辆的车牌,并自动将检测到的字符添加到 recognized_license_plate 字段中,或将已知名称作为子标签添加到汽车类型的对象中。常见的使用场景可能是读取驶入车道的汽车车牌或经过街道的汽车车牌。", + "readTheDocumentation": "阅读文档(英文)" + }, + "toast": { + "success": "分类设置已保存,请重启 Frigate 以应用更改。", + "error": "保存配置更改失败:{{errorMessage}}" + }, + "birdClassification": { + "title": "鸟类识别分类", + "desc": "鸟类识别分类采用量化TensorFlow模型识别已知鸟类。当识别到已知鸟类时,其通用名称将作为子标签(sub_label)添加。该信息将显示在用户界面、过滤器及通知中。" + }, + "restart_required": "需要重启(分类设置已修改)" + }, + "camera": { + "title": "摄像头设置", + "streams": { + "title": "视频流", + "desc": "禁用摄像头将完全停止 Frigate 对该摄像头视频流的处理。检测、录制和调试功能都将不可用。
    注意:该选项不会禁用 go2rtc 转播。" + }, + "review": { + "title": "核查", + "desc": "启用/禁用摄像头的警报和检测。禁用后,不会生成新的核查项。", + "alerts": "警报 ", + "detections": "检测 " + }, + "reviewClassification": { + "title": "核查分级", + "desc": "Frigate 将核查项分为“警报”和“检测”。默认情况下,所有的 汽车 对象都将视为警报。你可以通过修改配置文件配置区域来细分。", + "readTheDocumentation": "阅读文档(英文)", + "noDefinedZones": "该摄像头没有设置区域。", + "objectAlertsTips": "所有 {{alertsLabels}} 对象在 {{cameraName}} 下都将显示为警报。", + "zoneObjectAlertsTips": "所有 {{alertsLabels}} 对象在 {{cameraName}} 下的 {{zone}} 区内都将显示为警报。", + "objectDetectionsTips": "所有未在 {{cameraName}} 归类的 {{detectionsLabels}} 对象,无论它位于哪个区,都将显示为检测。", + "zoneObjectDetectionsTips": { + "text": "所有未在 {{cameraName}} 上归类为 {{detectionsLabels}} 的对象在 {{zone}} 区都将显示为检测。", + "notSelectDetections": "所有在 {{cameraName}} 下的 {{zone}} 区内检测到的 {{detectionsLabels}} 对象,如果它未归类为警报,无论它位于哪个区,都将显示为检测。", + "regardlessOfZoneObjectDetectionsTips": "所有未在 {{cameraName}} 归类的 {{detectionsLabels}} 对象,无论它位于哪个区域,都将显示为检测。" + }, + "selectAlertsZones": "选择警报区", + "selectDetectionsZones": "选择检测区域", + "limitDetections": "限制仅在特定区域内进行检测", + "toast": { + "success": "核查分级配置已保存。请重启 Frigate 以应用更改。" + } + } + }, + "masksAndZones": { + "filter": { + "all": "所有遮罩和区域" + }, + "toast": { + "success": { + "copyCoordinates": "已复制 {{polyName}} 的坐标到剪贴板。" + }, + "error": { + "copyCoordinatesFailed": "无法复制坐标到剪贴板。" + } + }, + "form": { + "zoneName": { + "error": { + "mustBeAtLeastTwoCharacters": "区域名称必须至少包含 2 个字符。", + "mustNotBeSameWithCamera": "区域名称不能与摄像头名称相同。", + "alreadyExists": "该摄像头已有相同的区域名称。", + "mustNotContainPeriod": "区域名称不能包含句点。", + "hasIllegalCharacter": "区域名称包含非法字符。" + } + }, + "distance": { + "error": { + "text": "距离必须大于或等于 0.1。", + "mustBeFilled": "所有距离字段必须填写才能使用速度估算。" + } + }, + "inertia": { + "error": { + "mustBeAboveZero": "惯性必须大于 0。" + } + }, + "loiteringTime": { + "error": { + "mustBeGreaterOrEqualZero": "徘徊时间必须大于或等于 0。" + } + }, + "polygonDrawing": { + "removeLastPoint": "删除最后一个点", + "reset": { + "label": "清除所有点" + }, + "snapPoints": { + "true": "启用点对齐", + "false": "禁用点对齐" + }, + "delete": { + "title": "确认删除", + "desc": "你确定要删除{{type}} {{name}} 吗?", + "success": "{{name}} 已被删除。" + }, + "error": { + "mustBeFinished": "多边形绘制必须完成闭合后才能保存。" + } + } + }, + "zones": { + "label": "区域", + "documentTitle": "编辑区域 - Frigate", + "desc": { + "title": "该功能允许你定义特定区域,以便你可以确定特定对象是否在该区域内。", + "documentation": "文档(英文)" + }, + "add": "添加区域", + "edit": "编辑区域", + "point_other": "{{count}} 点", + "clickDrawPolygon": "在图像上点击添加点绘制多边形区域。", + "name": { + "title": "区域名称", + "inputPlaceHolder": "请输入名称…", + "tips": "名称至少包含两个字符,且不能和摄像头或其他区域同名。
    当前仅支持英文与数字组合。" + }, + "inertia": { + "title": "惯性", + "desc": "识别指定对象前该对象必须在这个区域内出现了多少帧。默认值:3" + }, + "loiteringTime": { + "title": "停留时间", + "desc": "设置对象必须在区域中活动的最小时间(单位为秒)。默认值:0" + }, + "objects": { + "title": "对象", + "desc": "将在此区域应用的对象列表。" + }, + "allObjects": "所有对象", + "speedEstimation": { + "title": "速度估算", + "desc": "启用此区域内物体的速度估算。该区域必须恰好包含 4 个点。" + }, + "speedThreshold": { + "title": "速度阈值 ({{unit}})", + "desc": "指定物体在此区域内被视为有效的最低速度。", + "toast": { + "error": { + "pointLengthError": "此区域的速度估算已禁用。启用速度估算的区域必须恰好包含 4 个点。", + "loiteringTimeError": "徘徊时间大于 0 的区域不应与速度估算一起使用。" + } + } + }, + "toast": { + "success": "区域 ({{zoneName}}) 已保存。请重启 Frigate 以应用更改。" + } + }, + "motionMasks": { + "label": "运动遮罩", + "documentTitle": "编辑运动遮罩 - Frigate", + "desc": { + "title": "运动遮罩用于防止触发不必要的运动类型。过度的设置遮罩将使对象更加难以被追踪。", + "documentation": "文档(英文)" + }, + "add": "添加运动遮罩", + "edit": "编辑运动遮罩", + "context": { + "title": "运动遮罩用于防止不需要的运动类型触发检测(例如:树枝、摄像头显示的时间等)。运动遮罩需要谨慎使用,过度的遮罩会导致追踪对象变得更加困难。", + "documentation": "阅读文档(英文)" + }, + "point_other": "{{count}} 点", + "clickDrawPolygon": "在图像上点击添加点绘制多边形区域。", + "polygonAreaTooLarge": { + "title": "运动遮罩的大小达到了摄像头画面的{{polygonArea}}%。不建议设置太大的运动遮罩。", + "tips": "运动遮罩不会阻止检测到对象,你应该使用区域来限制检测对象。", + "documentation": "阅读文档(英文)" + }, + "toast": { + "success": { + "title": "{{polygonName}} 已保存。请重启 Frigate 以应用更改。", + "noName": "运动遮罩已保存。请重启 Frigate 以应用更改。" + } + } + }, + "objectMasks": { + "label": "对象遮罩", + "documentTitle": "编辑对象遮罩 - Frigate", + "desc": { + "title": "对象过滤器用于防止特定位置的指定对象被误报。", + "documentation": "文档(英文)" + }, + "add": "添加对象遮罩", + "edit": "编辑对象遮罩", + "context": "对象过滤器用于防止特定位置的指定对象被误报。", + "point_other": "{{count}} 点", + "clickDrawPolygon": "在图像上点击添加点绘制多边形区域。", + "objects": { + "title": "对象", + "desc": "将应用于此对象遮罩的对象列表。", + "allObjectTypes": "所有对象类型" + }, + "toast": { + "success": { + "title": "{{polygonName}} 已保存。请重启 Frigate 以应用更改。", + "noName": "对象遮罩已保存。请重启 Frigate 以应用更改。" + } + } + }, + "restart_required": "需要重启(遮罩与区域已修改)" + }, + "motionDetectionTuner": { + "title": "运动检测调整器", + "desc": { + "title": "Frigate 将使用运动检测作为首个步骤,以确认一帧画面中是否有对象需要使用对象检测。", + "documentation": "阅读有关运动检测的文档(英文)" + }, + "Threshold": { + "title": "阈值", + "desc": "阈值决定像素亮度高于多少时会被认为是运动。默认值:30" + }, + "contourArea": { + "title": "轮廓面积", + "desc": "轮廓面积决定哪些变化的像素组符合运动条件。默认值:10" + }, + "improveContrast": { + "title": "提高对比度", + "desc": "提高较暗场景的对比度。默认值:启用" + }, + "toast": { + "success": "运动设置已保存。" + } + }, + "debug": { + "title": "调试", + "detectorDesc": "Frigate 将使用探测器({{detectors}})来检测摄像头视频流中的对象。", + "desc": "调试界面将实时显示被追踪的对象以及统计信息,对象列表将显示检测到的对象和延迟显示的概览。", + "debugging": "调试选项", + "objectList": "对象列表", + "noObjects": "没有对象", + "boundingBoxes": { + "title": "边界框", + "desc": "将在被追踪的对象周围显示边界框", + "colors": { + "label": "对象边界框颜色定义", + "info": "
  • 启用后,将会为每个对象标签分配不同的颜色
  • 深蓝色细线代表该对象在当前时间点未被检测到
  • 灰色细线代表检测到的物体静止不动
  • 粗线表示该对象为自动跟踪的主体(在启动时)
  • " + } + }, + "timestamp": { + "title": "时间戳", + "desc": "在图像上显示时间戳" + }, + "zones": { + "title": "区域", + "desc": "显示已定义的区域图层" + }, + "mask": { + "title": "运动遮罩", + "desc": "显示运动遮罩图层" + }, + "motion": { + "title": "运动区域框", + "desc": "在检测到运动的区域显示区域框", + "tips": "

    运动区域框


    将在当前检测到运动的区域内显示红色区域框。

    " + }, + "regions": { + "title": "范围", + "desc": "显示发送到运动检测器感兴趣范围的框", + "tips": "

    范围框


    将在帧中发送到目标检测器的感兴趣范围上叠加绿色框。

    " + }, + "objectShapeFilterDrawing": { + "title": "允许绘制“对象形状过滤器”", + "desc": "在图像上绘制矩形,以查看区域和比例详细信息", + "tips": "启用此选项,能够在摄像头图像上绘制矩形,将显示其区域和比例。然后,您可以使用这些值在配置中设置对象形状过滤器参数。", + "document": "阅读文档(英文) ", + "score": "分数", + "ratio": "比例", + "area": "区域" + } + }, + "users": { + "title": "用户", + "management": { + "title": "用户管理", + "desc": "管理此 Frigate 实例的用户账户。" + }, + "addUser": "添加用户", + "updatePassword": "修改密码", + "toast": { + "success": { + "createUser": "用户 {{user}} 创建成功", + "deleteUser": "用户 {{user}} 删除成功", + "updatePassword": "已成功修改密码。", + "roleUpdated": "已更新 {{user}} 的权限组" + }, + "error": { + "setPasswordFailed": "保存密码出现错误:{{errorMessage}}", + "createUserFailed": "创建用户失败:{{errorMessage}}", + "deleteUserFailed": "删除用户失败:{{errorMessage}}", + "roleUpdateFailed": "更新权限组失败:{{errorMessage}}" + } + }, + "table": { + "username": "用户名", + "actions": "操作", + "role": "权限组", + "noUsers": "未找到用户。", + "changeRole": "更改用户角色", + "password": "密码", + "deleteUser": "删除用户" + }, + "dialog": { + "form": { + "user": { + "title": "用户名", + "desc": "仅允许使用字母、数字、句点和下划线。", + "placeholder": "请输入用户名" + }, + "password": { + "title": "密码", + "placeholder": "请输入密码", + "confirm": { + "title": "确认密码", + "placeholder": "请再次输入密码" + }, + "strength": { + "title": "密码强度: ", + "weak": "弱", + "medium": "中等", + "strong": "强", + "veryStrong": "非常强" + }, + "match": "密码匹配", + "notMatch": "密码不匹配" + }, + "newPassword": { + "title": "新密码", + "placeholder": "请输入新密码", + "confirm": { + "placeholder": "请再次输入新密码" + } + }, + "usernameIsRequired": "用户名为必填项" + }, + "createUser": { + "title": "创建新用户", + "desc": "创建一个新用户账户,并指定一个角色以控制访问 Frigate UI 的权限。", + "usernameOnlyInclude": "用户名只能包含字母、数字和 _" + }, + "deleteUser": { + "title": "删除该用户", + "desc": "此操作无法撤销。这将永久删除用户账户并移除所有相关数据。", + "warn": "你确定要删除 {{username}} 吗?" + }, + "passwordSetting": { + "updatePassword": "更新 {{username}} 的密码", + "setPassword": "设置密码", + "desc": "创建一个强密码来保护此账户。" + }, + "changeRole": { + "title": "更改用户权限组", + "desc": "更新 {{username}} 的权限", + "roleInfo": { + "admin": "管理员", + "viewer": "成员", + "viewerDesc": "仅能够查看实时监控面板、核查、浏览和导出功能。", + "adminDesc": "完全功能与访问权限。", + "intro": "为该用户选择一个合适的权限组:" + } + } + } + }, + "notification": { + "title": "通知", + "notificationSettings": { + "title": "通知设置", + "desc": "Frigate 在浏览器中运行或作为 PWA 安装时,可以原生向您的设备发送推送通知。", + "documentation": "阅读文档(英文)" + }, + "globalSettings": { + "title": "全局设置", + "desc": "临时暂停所有已注册设备上特定摄像头的通知。" + }, + "notificationUnavailable": { + "title": "通知功能不可用", + "desc": "网页推送通知需要安全连接(https://…)。这是浏览器的限制。请通过安全方式访问 Frigate 以使用通知功能。", + "documentation": "阅读文档(英文)" + }, + "email": { + "title": "电子邮箱", + "placeholder": "例如:example@email.com", + "desc": "需要输入有效的电子邮件,在推送服务出现问题时,将使用此电子邮件进行通知。" + }, + "cameras": { + "title": "摄像头", + "noCameras": "没有可用的摄像头", + "desc": "选择要启用通知的摄像头。" + }, + "deviceSpecific": "设备专用设置", + "registerDevice": "注册该设备", + "unregisterDevice": "取消注册该设备", + "sendTestNotification": "发送测试通知", + "active": "通知已启用", + "suspended": "通知已暂停 {{time}}", + "suspendTime": { + "5minutes": "暂停 5 分钟", + "10minutes": "暂停 10 分钟", + "30minutes": "暂停 30 分钟", + "1hour": "暂停 1 小时", + "12hours": "暂停 12 小时", + "24hours": "暂停 24 小时", + "untilRestart": "暂停直到重启", + "suspend": "暂停" + }, + "cancelSuspension": "取消暂停", + "toast": { + "success": { + "registered": "已成功注册通知。需要重启 Frigate 才能发送任何通知(包括测试通知)。", + "settingSaved": "通知设置已保存。" + }, + "error": { + "registerFailed": "通知注册失败。" + } + } + }, + "frigatePlus": { + "title": "Frigate+ 设置", + "apiKey": { + "title": "Frigate+ API 密钥", + "validated": "Frigate+ API 密钥已检测并验证通过", + "notValidated": "未检测到 Frigate+ API 密钥或验证未通过", + "desc": "Frigate+ API 密钥用于启用与 Frigate+ 服务的集成。", + "plusLink": "了解更多关于 Frigate+" + }, + "snapshotConfig": { + "title": "快照配置", + "desc": "提交到 Frigate+ 需要同时在配置中启用快照和 clean_copy 快照。", + "documentation": "阅读文档", + "cleanCopyWarning": "部分摄像头已启用快照但未启用 clean_copy。您需要在快照配置中启用 clean_copy,才能将这些摄像头的图像提交到 Frigate+。", + "table": { + "camera": "摄像头", + "snapshots": "快照", + "cleanCopySnapshots": "clean_copy 快照" + } + }, + "modelInfo": { + "title": "模型信息", + "modelType": "模型类型", + "trainDate": "训练日期", + "baseModel": "基础模型", + "supportedDetectors": "支持的检测器", + "dimensions": "大小", + "cameras": "摄像头", + "loading": "正在加载模型信息…", + "error": "加载模型信息失败", + "availableModels": "可用模型", + "loadingAvailableModels": "正在加载可用模型…", + "modelSelect": "您可以在Frigate+上选择可用的模型。请注意,只能选择与当前探测器配置兼容的模型。", + "plusModelType": { + "baseModel": "基础模型", + "userModel": "定向调优" + } + }, + "toast": { + "success": "Frigate+ 设置已保存。请重启 Frigate 以应用更改。", + "error": "配置更改保存失败:{{errorMessage}}" + }, + "restart_required": "需要重启(Frigate+模型已修改)" + } +} diff --git a/web/public/locales/zh-CN/views/system.json b/web/public/locales/zh-CN/views/system.json new file mode 100644 index 000000000..efbdb3a72 --- /dev/null +++ b/web/public/locales/zh-CN/views/system.json @@ -0,0 +1,170 @@ +{ + "documentTitle": { + "cameras": "摄像头统计 - Frigate", + "storage": "存储统计 - Frigate", + "general": "常规统计 - Frigate", + "enrichments": "增强功能统计 - Frigate", + "logs": { + "frigate": "Frigate 日志 - Frigate", + "go2rtc": "Go2RTC 日志 - Frigate", + "nginx": "Nginx 日志 - Frigate" + } + }, + "title": "系统", + "metrics": "系统指标", + "logs": { + "download": { + "label": "下载日志" + }, + "copy": { + "label": "复制到剪贴板", + "success": "已复制日志到剪贴板", + "error": "无法复制日志到剪贴板" + }, + "type": { + "label": "类型", + "timestamp": "时间戳", + "tag": "标签", + "message": "消息" + }, + "tips": "日志正在从服务器流式传输", + "toast": { + "error": { + "fetchingLogsFailed": "获取日志出错:{{errorMessage}}", + "whileStreamingLogs": "流式传输日志时出错:{{errorMessage}}" + } + } + }, + "general": { + "title": "常规", + "detector": { + "title": "探测器", + "inferenceSpeed": "探测器推理速度", + "cpuUsage": "探测器CPU使用率", + "memoryUsage": "探测器内存使用率", + "temperature": "探测器温度" + }, + "hardwareInfo": { + "title": "硬件信息", + "gpuUsage": "GPU使用率", + "gpuMemory": "GPU显存", + "gpuEncoder": "GPU编码", + "gpuDecoder": "GPU解码", + "gpuInfo": { + "vainfoOutput": { + "title": "Vainfo 输出", + "returnCode": "返回代码:{{code}}", + "processOutput": "进程输出:", + "processError": "进程错误:" + }, + "nvidiaSMIOutput": { + "title": "Nvidia SMI 输出", + "name": "名称:{{name}}", + "driver": "驱动:{{driver}}", + "cudaComputerCapability": "CUDA计算能力:{{cuda_compute}}", + "vbios": "VBios信息:{{vbios}}" + }, + "closeInfo": { + "label": "关闭GPU信息" + }, + "copyInfo": { + "label": "复制GPU信息" + }, + "toast": { + "success": "已复制GPU信息到剪贴板" + } + }, + "npuMemory": "NPU内存", + "npuUsage": "NPU使用率" + }, + "otherProcesses": { + "title": "其他进程", + "processCpuUsage": "主进程CPU使用率", + "processMemoryUsage": "主进程内存使用率" + } + }, + "storage": { + "title": "存储", + "overview": "概览", + "recordings": { + "title": "录制内容", + "tips": "该值表示 Frigate 数据库中录制内容所使用的总存储空间。Frigate 不会追踪磁盘上所有文件的存储使用情况。", + "earliestRecording": "最早的可用录制:" + }, + "cameraStorage": { + "title": "摄像头存储", + "camera": "摄像头", + "unusedStorageInformation": "未使用存储信息", + "storageUsed": "存储使用", + "percentageOfTotalUsed": "总使用率", + "bandwidth": "带宽", + "unused": { + "title": "未使用", + "tips": "如果您的驱动器上存储了除 Frigate 录制内容之外的其他文件,该值可能无法准确反映 Frigate 可用的剩余空间。Frigate 不会追踪录制内容以外的存储使用情况。" + } + } + }, + "cameras": { + "title": "摄像头", + "overview": "概览", + "info": { + "cameraProbeInfo": "{{camera}} 的摄像头信息", + "streamDataFromFFPROBE": "流数据信息通过ffprobe获取。", + "fetching": "正在获取摄像头数据", + "stream": "视频流{{idx}}", + "video": "视频:", + "codec": "编解码器:", + "resolution": "分辨率:", + "fps": "帧率:", + "unknown": "未知", + "audio": "音频:", + "error": "错误:{{error}}", + "tips": { + "title": "摄像头信息" + } + }, + "framesAndDetections": "帧数/检测次数", + "label": { + "camera": "摄像头", + "detect": "探测", + "skipped": "跳过", + "ffmpeg": "FFmpeg编码器", + "capture": "捕获" + }, + "toast": { + "success": { + "copyToClipboard": "已复制探测数据到剪贴板。" + }, + "error": { + "unableToProbeCamera": "无法探测摄像头:{{errorMessage}}" + } + } + }, + "lastRefreshed": "最后刷新时间:", + "stats": { + "ffmpegHighCpuUsage": "{{camera}} 的 FFMPEG CPU 使用率较高({{ffmpegAvg}}%)", + "detectHighCpuUsage": "{{camera}} 的 探测 CPU 使用率较高({{detectAvg}}%)", + "healthy": "系统运行正常", + "reindexingEmbeddings": "正在重新索引嵌入(已完成 {{processed}}%)", + "detectIsSlow": "{{detect}} 运行缓慢({{speed}}毫秒)", + "detectIsVerySlow": "{{detect}} 运行非常缓慢({{speed}}毫秒)", + "cameraIsOffline": "{{camera}} 已离线" + }, + "enrichments": { + "title": "增强功能", + "infPerSecond": "每秒推理次数", + "embeddings": { + "image_embedding_speed": "图像特征提取速度", + "face_embedding_speed": "人脸特征提取速度", + "plate_recognition_speed": "车牌识别速度", + "text_embedding_speed": "文本编码速度", + "face_recognition_speed": "人脸识别速度", + "image_embedding": "图像特征提取", + "text_embedding": "文字编码", + "face_recognition": "人脸特征提取", + "plate_recognition": "车牌识别", + "yolov9_plate_detection_speed": "YOLOv9 车牌检测速度", + "yolov9_plate_detection": "YOLOv9 车牌检测" + } + } +} diff --git a/web/site.webmanifest b/web/site.webmanifest index 94e455ec8..7040ce5c9 100644 --- a/web/site.webmanifest +++ b/web/site.webmanifest @@ -1,28 +1,28 @@ { "name": "Frigate", "short_name": "Frigate", - "start_url": "/", + "start_url": "/BASE_PATH/", "icons": [ { - "src": "/images/android-chrome-512x512.png", + "src": "/BASE_PATH/images/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/images/android-chrome-192x192.png", + "src": "/BASE_PATH/images/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/images/maskable-icon.png", + "src": "/BASE_PATH/images/maskable-icon.png", "sizes": "180x180", "type": "image/png", "purpose": "maskable" }, { - "src": "/images/maskable-badge.png", + "src": "/BASE_PATH/images/maskable-badge.png", "sizes": "96x96", "type": "image/png", "purpose": "maskable" diff --git a/web/src/api/ws.tsx b/web/src/api/ws.tsx index 5eedcdbcd..3e9c8c14f 100644 --- a/web/src/api/ws.tsx +++ b/web/src/api/ws.tsx @@ -44,7 +44,8 @@ function useValue(): useValueReturn { return; } - const cameraActivity: { [key: string]: object } = JSON.parse(activityValue); + const cameraActivity: { [key: string]: FrigateCameraState } = + JSON.parse(activityValue); if (Object.keys(cameraActivity).length === 0) { return; @@ -64,9 +65,7 @@ function useValue(): useValueReturn { autotracking, alerts, detections, - } = - // @ts-expect-error we know this is correct - state["config"]; + } = state["config"]; cameraStates[`${name}/recordings/state`] = record ? "ON" : "OFF"; cameraStates[`${name}/enabled/state`] = enabled ? "ON" : "OFF"; cameraStates[`${name}/detect/state`] = detect ? "ON" : "OFF"; @@ -174,7 +173,7 @@ export function useEnabledState(camera: string): { value: { payload }, send, } = useWs(`${camera}/enabled/state`, `${camera}/enabled/set`); - return { payload: (payload ?? "ON") as ToggleableSetting, send }; + return { payload: payload as ToggleableSetting, send }; } export function useDetectState(camera: string): { diff --git a/web/src/components/Statusbar.tsx b/web/src/components/Statusbar.tsx index 1b20b26f6..0ac6d10a4 100644 --- a/web/src/components/Statusbar.tsx +++ b/web/src/components/Statusbar.tsx @@ -5,12 +5,16 @@ import { } from "@/context/statusbar-provider"; import useStats, { useAutoFrigateStats } from "@/hooks/use-stats"; import { useContext, useEffect, useMemo } from "react"; +import { useTranslation } from "react-i18next"; + import { FaCheck } from "react-icons/fa"; import { IoIosWarning } from "react-icons/io"; import { MdCircle } from "react-icons/md"; import { Link } from "react-router-dom"; export default function Statusbar() { + const { t } = useTranslation(["views/system"]); + const { messages, addMessage, clearMessages } = useContext( StatusBarMessagesContext, )!; @@ -50,14 +54,19 @@ export default function Statusbar() { clearMessages("embeddings-reindex"); addMessage( "embeddings-reindex", - `Reindexing embeddings (${Math.floor((reindexState.processed_objects / reindexState.total_objects) * 100)}% complete)`, + t("stats.reindexingEmbeddings", { + processed: Math.floor( + (reindexState.processed_objects / reindexState.total_objects) * + 100, + ), + }), ); } if (reindexState.status === "completed") { clearMessages("embeddings-reindex"); } } - }, [reindexState, addMessage, clearMessages]); + }, [reindexState, addMessage, clearMessages, t]); return (
    @@ -92,6 +101,9 @@ export default function Statusbar() { case "intel-qsv": gpuTitle = "Intel GPU"; break; + case "rockchip": + gpuTitle = "Rockchip GPU"; + break; default: gpuTitle = name; break; @@ -129,7 +141,7 @@ export default function Statusbar() { {Object.entries(messages).length === 0 ? (
    - System is healthy + {t("stats.healthy")}
    ) : ( Object.entries(messages).map(([key, messageArray]) => ( diff --git a/web/src/components/auth/AuthForm.tsx b/web/src/components/auth/AuthForm.tsx index 85bd6bccb..dcf8eaa55 100644 --- a/web/src/components/auth/AuthForm.tsx +++ b/web/src/components/auth/AuthForm.tsx @@ -21,16 +21,18 @@ import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { AuthContext } from "@/context/auth-context"; +import { useTranslation } from "react-i18next"; interface UserAuthFormProps extends React.HTMLAttributes {} export function UserAuthForm({ className, ...props }: UserAuthFormProps) { + const { t } = useTranslation(["components/auth"]); const [isLoading, setIsLoading] = React.useState(false); const { login } = React.useContext(AuthContext); const formSchema = z.object({ - user: z.string().min(1, "Username is required"), - password: z.string().min(1, "Password is required"), + user: z.string().min(1, t("form.errors.usernameRequired")), + password: z.string().min(1, t("form.errors.passwordRequired")), }); const form = useForm>({ @@ -62,20 +64,20 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) { if (axios.isAxiosError(error)) { const err = error as AxiosError; if (err.response?.status === 429) { - toast.error("Exceeded rate limit. Try again later.", { + toast.error(t("form.errors.rateLimit"), { position: "top-center", }); } else if (err.response?.status === 401) { - toast.error("Login failed", { + toast.error(t("form.errors.loginFailed"), { position: "top-center", }); } else { - toast.error("Unknown error. Check logs.", { + toast.error(t("form.errors.unknownError"), { position: "top-center", }); } } else { - toast.error("Unknown error. Check console logs.", { + toast.error(t("form.errors.webUnknownError"), { position: "top-center", }); } @@ -92,7 +94,7 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) { name="user" render={({ field }) => ( - User + {t("form.user")} ( - Password + {t("form.password")} {isLoading && } - Login + {t("form.login")}
    diff --git a/web/src/components/button/DownloadVideoButton.tsx b/web/src/components/button/DownloadVideoButton.tsx index 750b35607..607458af4 100644 --- a/web/src/components/button/DownloadVideoButton.tsx +++ b/web/src/components/button/DownloadVideoButton.tsx @@ -3,6 +3,11 @@ import { toast } from "sonner"; import { FaDownload } from "react-icons/fa"; import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; import { cn } from "@/lib/utils"; +import { useTranslation } from "react-i18next"; +import useSWR from "swr"; +import { FrigateConfig } from "@/types/frigateConfig"; +import { useDateLocale } from "@/hooks/use-date-locale"; +import { useMemo } from "react"; type DownloadVideoButtonProps = { source: string; @@ -17,15 +22,23 @@ export function DownloadVideoButton({ startTime, className, }: DownloadVideoButtonProps) { + const { t } = useTranslation(["components/input"]); + const { data: config } = useSWR("config"); + const locale = useDateLocale(); + + const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour"; + const format = useMemo(() => { + return t(`time.formattedTimestampFilename.${timeFormat}`, { ns: "common" }); + }, [t, timeFormat]); + const formattedDate = formatUnixTimestampToDateTime(startTime, { - strftime_fmt: "%D-%T", - time_style: "medium", - date_style: "medium", + date_format: format, + locale, }); const filename = `${camera}_${formattedDate}.mp4`; const handleDownloadStart = () => { - toast.success("Your review item video has started downloading.", { + toast.success(t("button.downloadVideo.toast.success"), { position: "top-center", }); }; @@ -36,7 +49,7 @@ export function DownloadVideoButton({ asChild className="flex items-center gap-2" size="sm" - aria-label="Download Video" + aria-label={t("button.downloadVideo.label")} > ( `${cameraConfig?.name}-feed`, @@ -59,17 +61,21 @@ export default function DebugCameraImage({ onClick={handleToggleSettings} variant="link" size="sm" - aria-label="Settings" + aria-label={t("debug.options.label")} > {" "} - {showSettings ? "Hide" : "Show"} Options + + {showSettings + ? t("debug.options.hideOptions") + : t("debug.options.showOptions")} + {showSettings ? ( - Options + {t("debug.options.title")}
    @@ -99,7 +106,7 @@ function DebugSettings({ handleSetOption, options }: DebugSettingsProps) { handleSetOption("bbox", isChecked); }} /> - +
    - +
    - +
    - +
    - +
    - +
    ); diff --git a/web/src/components/card/AnimatedEventCard.tsx b/web/src/components/card/AnimatedEventCard.tsx index a41e2252a..d46509eb6 100644 --- a/web/src/components/card/AnimatedEventCard.tsx +++ b/web/src/components/card/AnimatedEventCard.tsx @@ -18,6 +18,7 @@ import { Skeleton } from "../ui/skeleton"; import { Button } from "../ui/button"; import { FaCircleCheck } from "react-icons/fa6"; import { cn } from "@/lib/utils"; +import { useTranslation } from "react-i18next"; type AnimatedEventCardProps = { event: ReviewSegment; @@ -29,6 +30,7 @@ export function AnimatedEventCard({ selectedGroup, updateEvents, }: AnimatedEventCardProps) { + const { t } = useTranslation(["views/events"]); const { data: config } = useSWR("config"); const apiHost = useApiHost(); @@ -121,7 +123,7 @@ export function AnimatedEventCard({ - Mark as Reviewed + {t("markAsReviewed")} )} {previews != undefined && ( @@ -227,7 +229,7 @@ export function AnimatedEventCard({ .map((text) => text.charAt(0).toUpperCase() + text.substring(1)) .sort() .join(", ") - .replaceAll("-verified", "")} detected`} + .replaceAll("-verified", "")} ` + t("detected")} ); diff --git a/web/src/components/card/ExportCard.tsx b/web/src/components/card/ExportCard.tsx index c47532df8..9115e0509 100644 --- a/web/src/components/card/ExportCard.tsx +++ b/web/src/components/card/ExportCard.tsx @@ -20,6 +20,7 @@ import { MdEditSquare } from "react-icons/md"; import { baseUrl } from "@/api/baseUrl"; import { cn } from "@/lib/utils"; import { shareOrCopy } from "@/utils/browserUtil"; +import { useTranslation } from "react-i18next"; type ExportProps = { className: string; @@ -36,6 +37,7 @@ export default function ExportCard({ onRename, onDelete, }: ExportProps) { + const { t } = useTranslation(["views/exports"]); const [hovered, setHovered] = useState(false); const [loading, setLoading] = useState( exportedRecording.thumb_path.length > 0, @@ -89,10 +91,8 @@ export default function ExportCard({ } }} > - Rename Export - - Enter a new name for this export. - + {t("editExport.title")} + {t("editExport.desc")} {editName && ( <> @@ -207,7 +207,7 @@ export default function ExportCard({ {!exportedRecording.in_progress && ( diff --git a/web/src/components/dynamic/TimeAgo.tsx b/web/src/components/dynamic/TimeAgo.tsx index 13892180e..15731470a 100644 --- a/web/src/components/dynamic/TimeAgo.tsx +++ b/web/src/components/dynamic/TimeAgo.tsx @@ -1,3 +1,4 @@ +import { t } from "i18next"; import { FunctionComponent, useEffect, useMemo, useState } from "react"; interface IProp { @@ -40,7 +41,7 @@ const timeAgo = ({ const elapsed: number = elapsedTime / 1000; if (elapsed < 10) { - return "just now"; + return t("time.justNow", { ns: "common" }); } for (let i = 0; i < timeUnits.length; i++) { @@ -64,11 +65,21 @@ const timeAgo = ({ if (monthDiff > 0) { const unitAmount = monthDiff; - return `${unitAmount}${dense ? timeUnits[i].unit : ` ${timeUnits[i].full}`}${dense ? "" : "s"} ago`; + return t("time.ago", { + ns: "common", + timeAgo: t(`time.${dense ? timeUnits[i].unit : timeUnits[i].full}`, { + time: unitAmount, + }), + }); } } else if (elapsed >= timeUnits[i].value) { const unitAmount: number = Math.floor(elapsed / timeUnits[i].value); - return `${unitAmount}${dense ? timeUnits[i].unit : ` ${timeUnits[i].full}`}${dense ? "" : "s"} ago`; + return t("time.ago", { + ns: "common", + timeAgo: t(`time.${dense ? timeUnits[i].unit : timeUnits[i].full}`, { + time: unitAmount, + }), + }); } } return "Invalid Time"; diff --git a/web/src/components/filter/CalendarFilterButton.tsx b/web/src/components/filter/CalendarFilterButton.tsx index afa70b4e5..f16368d63 100644 --- a/web/src/components/filter/CalendarFilterButton.tsx +++ b/web/src/components/filter/CalendarFilterButton.tsx @@ -14,6 +14,7 @@ import { DateRangePicker } from "../ui/calendar-range"; import { DateRange } from "react-day-picker"; import { useState } from "react"; import PlatformAwareDialog from "../overlay/dialog/PlatformAwareDialog"; +import { useTranslation } from "react-i18next"; type CalendarFilterButtonProps = { reviewSummary?: ReviewSummary; @@ -27,16 +28,17 @@ export default function CalendarFilterButton({ day, updateSelectedDay, }: CalendarFilterButtonProps) { + const { t } = useTranslation(["components/filter", "views/events"]); const [open, setOpen] = useState(false); const selectedDate = useFormattedTimestamp( day == undefined ? 0 : day?.getTime() / 1000 + 1, - "%b %-d", + t("time.formattedTimestampMonthDay", { ns: "common" }), ); const trigger = ( ); @@ -61,12 +65,12 @@ export default function CalendarFilterButton({
    @@ -93,18 +97,19 @@ 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, - "%b %-d", + t("time.formattedTimestampMonthDay", { ns: "common" }), ); const trigger = ( - - All Cameras + + {t("menu.live.allCameras", { ns: "common" })} @@ -175,7 +179,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { ? "bg-blue-900 bg-opacity-60 text-selected focus:bg-blue-900 focus:bg-opacity-60" : "bg-secondary text-secondary-foreground" } - aria-label="Camera Group" + aria-label={t("group.label")} size="xs" onClick={() => setGroup(name, group != "default")} onMouseEnter={() => (isDesktop ? showTooltip(name) : null)} @@ -192,7 +196,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { - + {name} @@ -202,7 +206,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { diff --git a/web/src/components/filter/CamerasFilterButton.tsx b/web/src/components/filter/CamerasFilterButton.tsx index d9deb87bd..247555a0a 100644 --- a/web/src/components/filter/CamerasFilterButton.tsx +++ b/web/src/components/filter/CamerasFilterButton.tsx @@ -12,6 +12,7 @@ import { isMobile } from "react-device-detect"; import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer"; import FilterSwitch from "./FilterSwitch"; import { FaVideo } from "react-icons/fa"; +import { useTranslation } from "react-i18next"; type CameraFilterButtonProps = { allCameras: string[]; @@ -29,6 +30,7 @@ export function CamerasFilterButton({ mainCamera, updateCameraFilter, }: CameraFilterButtonProps) { + const { t } = useTranslation(["components/filter"]); const [open, setOpen] = useState(false); const [currentCameras, setCurrentCameras] = useState( selectedCameras, @@ -36,15 +38,19 @@ export function CamerasFilterButton({ const buttonText = useMemo(() => { if (isMobile) { - return "Cameras"; + return t("menu.live.cameras.title", { ns: "common" }); } if (!selectedCameras || selectedCameras.length == 0) { - return "All Cameras"; + return t("menu.live.allCameras", { ns: "common" }); } - - return `${selectedCameras.includes("birdseye") ? selectedCameras.length - 1 : selectedCameras.length} Camera${selectedCameras.length !== 1 ? "s" : ""}`; - }, [selectedCameras]); + return t("menu.live.cameras.count", { + ns: "common", + count: selectedCameras.includes("birdseye") + ? selectedCameras.length - 1 + : selectedCameras.length, + }); + }, [selectedCameras, t]); // ui @@ -56,8 +62,8 @@ export function CamerasFilterButton({ const trigger = ( diff --git a/web/src/components/filter/FilterSwitch.tsx b/web/src/components/filter/FilterSwitch.tsx index fa5c7d34a..f2dc8eeef 100644 --- a/web/src/components/filter/FilterSwitch.tsx +++ b/web/src/components/filter/FilterSwitch.tsx @@ -16,7 +16,7 @@ export default function FilterSwitch({ return (