Compare commits

...

25 Commits

Author SHA1 Message Date
Hosted Weblate
9f631e6fa2
Added translation using Weblate (Zuni)
Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Added translation using Weblate (Zuni)

Co-authored-by: Firas <firas.amm@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
2026-06-01 21:52:07 +00:00
Hosted Weblate
7e1ad58a08
Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (473 of 473 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (811 of 811 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (1171 of 1171 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (53 of 53 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: OverTheHillsAndFarAway <prosjektx@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/nb_NO/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-settings
2026-06-01 21:52:06 +00:00
Hosted Weblate
516a68f103
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (807 of 807 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (473 of 473 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1268 of 1268 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 94.6% (1196 of 1263 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1195 of 1195 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1186 of 1186 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1183 of 1183 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1181 of 1181 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (811 of 811 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (53 of 53 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (238 of 238 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1176 of 1176 strings)

Co-authored-by: GuoQing Liu <842607283@qq.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/zh_Hans/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-settings
2026-06-01 21:52:06 +00:00
Hosted Weblate
2a4c5b9fe0
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 99.5% (237 of 238 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (26 of 26 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: KelvinKueh <kelvin.kueh@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/zh_Hant/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player
2026-06-01 21:52:05 +00:00
Hosted Weblate
618cb76f3b
Translated using Weblate (Uzbek)
Currently translated at 0.3% (2 of 501 strings)

Co-authored-by: Hamza Foziljonov <hamza.uztranslator@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/uz/
Translation: Frigate NVR/audio
2026-06-01 21:52:05 +00:00
Hosted Weblate
0b74a93606
Translated using Weblate (Khmer (Central))
Currently translated at 0.9% (5 of 501 strings)

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Added translation using Weblate (Khmer (Central))

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: reanyouda <mr.reanyouda@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/km/
Translation: Frigate NVR/audio
2026-06-01 21:52:04 +00:00
Hosted Weblate
caf75a6edb
Translated using Weblate (French)
Currently translated at 67.0% (850 of 1268 strings)

Translated using Weblate (French)

Currently translated at 85.1% (86 of 101 strings)

Translated using Weblate (French)

Currently translated at 100.0% (238 of 238 strings)

Translated using Weblate (French)

Currently translated at 82.1% (83 of 101 strings)

Co-authored-by: Gloup <emeric.denis@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: LeBuzzy <bwinster2@outlook.com>
Co-authored-by: Lorent Felix <comloren@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/fr/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-settings
2026-06-01 21:52:03 +00:00
Hosted Weblate
b900701601
Translated using Weblate (Spanish)
Currently translated at 100.0% (807 of 807 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (473 of 473 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (1268 of 1268 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (1263 of 1263 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (1263 of 1263 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Spanish)

Currently translated at 99.2% (1253 of 1263 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (1186 of 1186 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (1183 of 1183 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (1181 of 1181 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (238 of 238 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (1176 of 1176 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: jjavin <javiernovoa@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/es/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-settings
2026-06-01 21:52:03 +00:00
Hosted Weblate
1fb70c1d7d
Translated using Weblate (Dutch)
Currently translated at 83.9% (397 of 473 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (127 of 127 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (60 of 60 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Dutch)

Currently translated at 97.9% (794 of 811 strings)

Translated using Weblate (Dutch)

Currently translated at 93.7% (224 of 239 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Dutch)

Currently translated at 92.8% (221 of 238 strings)

Translated using Weblate (Dutch)

Currently translated at 98.0% (1148 of 1171 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Hosted Weblate user 151476 <marijndekker3@gmail.com>
Co-authored-by: Hosted Weblate user 151476 <micel@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/nl/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-06-01 21:52:02 +00:00
Hosted Weblate
87fd03723d
Translated using Weblate (Indonesian)
Currently translated at 5.0% (24 of 473 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (127 of 127 strings)

Translated using Weblate (Indonesian)

Currently translated at 1.8% (15 of 811 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (501 of 501 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (64 of 64 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (59 of 59 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (45 of 45 strings)

Translated using Weblate (Indonesian)

Currently translated at 86.6% (52 of 60 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (175 of 175 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (49 of 49 strings)

Translated using Weblate (Indonesian)

Currently translated at 59.3% (38 of 64 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (501 of 501 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (1176 of 1176 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (238 of 238 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Indonesian)

Currently translated at 30.7% (39 of 127 strings)

Co-authored-by: Arif Budiman <arifpedia@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Joseph K <o.joseph.k@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-replay/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/id/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-replay
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-06-01 21:52:01 +00:00
Hosted Weblate
1697577fa1
Translated using Weblate (Arabic)
Currently translated at 28.3% (142 of 501 strings)

Translated using Weblate (Arabic)

Currently translated at 18.8% (24 of 127 strings)

Co-authored-by: Firas <firas.amm@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/ar/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/ar/
Translation: Frigate NVR/audio
Translation: Frigate NVR/objects
2026-06-01 21:52:00 +00:00
Hosted Weblate
ea02cb6fa0
Translated using Weblate (Italian)
Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Italian)

Currently translated at 26.4% (125 of 473 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (1195 of 1195 strings)

Translated using Weblate (Italian)

Currently translated at 28.3% (230 of 811 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Italian)

Currently translated at 26.2% (124 of 473 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Italian)

Currently translated at 28.2% (229 of 811 strings)

Translated using Weblate (Italian)

Currently translated at 28.1% (228 of 811 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (238 of 238 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (1183 of 1183 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Italian)

Currently translated at 26.0% (123 of 473 strings)

Co-authored-by: Frank_ai <cyberpez.ai@gmail.com>
Co-authored-by: Gringo <ita.translations@tiscali.it>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/it/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-06-01 21:52:00 +00:00
Hosted Weblate
112e6d94fb
Translated using Weblate (Polish)
Currently translated at 100.0% (501 of 501 strings)

Translated using Weblate (Polish)

Currently translated at 94.1% (224 of 238 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (501 of 501 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: magnumek <m4gnumek@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/pl/
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
2026-06-01 21:51:59 +00:00
Hosted Weblate
d209f88282
Translated using Weblate (Catalan)
Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (473 of 473 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1268 of 1268 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (807 of 807 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1263 of 1263 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (45 of 45 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1263 of 1263 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1195 of 1195 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1186 of 1186 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (811 of 811 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1183 of 1183 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (175 of 175 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1181 of 1181 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (238 of 238 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1176 of 1176 strings)

Co-authored-by: Eduardo Pastor Fernández <123eduardoneko123@gmail.com>
Co-authored-by: Gerard Ricart Castells <gerard.ricart@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-replay/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ca/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-replay
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-06-01 21:51:58 +00:00
Hosted Weblate
9b65e6c88b
Translated using Weblate (Japanese)
Currently translated at 100.0% (1263 of 1263 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (473 of 473 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (811 of 811 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (811 of 811 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (1263 of 1263 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Japanese)

Currently translated at 93.9% (1186 of 1263 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (238 of 238 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (501 of 501 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (175 of 175 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (59 of 59 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (101 of 101 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (811 of 811 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (1186 of 1186 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (60 of 60 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (127 of 127 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (64 of 64 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (473 of 473 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (74 of 74 strings)

Translated using Weblate (Japanese)

Currently translated at 100.0% (45 of 45 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: alpha <etc@alpha-line.org>
Co-authored-by: yhi264 <yhiraki@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-auth/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-replay/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ja/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ja/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-replay
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-06-01 21:51:58 +00:00
Hosted Weblate
712cff33c5
Translated using Weblate (Ukrainian)
Currently translated at 93.0% (120 of 129 strings)

Translated using Weblate (Ukrainian)

Currently translated at 77.7% (136 of 175 strings)

Translated using Weblate (Ukrainian)

Currently translated at 54.9% (649 of 1181 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (101 of 101 strings)

Translated using Weblate (Ukrainian)

Currently translated at 92.2% (119 of 129 strings)

Translated using Weblate (Ukrainian)

Currently translated at 96.1% (25 of 26 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (238 of 238 strings)

Translated using Weblate (Ukrainian)

Currently translated at 54.7% (644 of 1176 strings)

Translated using Weblate (Ukrainian)

Currently translated at 90.0% (91 of 101 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: ivabil <ivanbilych@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/uk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/uk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/uk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/uk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/uk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/uk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/uk/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-06-01 21:51:57 +00:00
Hosted Weblate
70a2779eb2
Translated using Weblate (Romanian)
Currently translated at 100.0% (1263 of 1263 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1263 of 1263 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1186 of 1186 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1183 of 1183 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (53 of 53 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1176 of 1176 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (811 of 811 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (238 of 238 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: lukasig <lukasig@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ro/
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-06-01 21:51:56 +00:00
Hosted Weblate
ce4d22a3d6
Translated using Weblate (Estonian)
Currently translated at 35.0% (21 of 60 strings)

Translated using Weblate (Estonian)

Currently translated at 2.5% (12 of 473 strings)

Translated using Weblate (Estonian)

Currently translated at 13.9% (18 of 129 strings)

Translated using Weblate (Estonian)

Currently translated at 41.3% (60 of 145 strings)

Translated using Weblate (Estonian)

Currently translated at 18.5% (234 of 1263 strings)

Translated using Weblate (Estonian)

Currently translated at 1.8% (15 of 811 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (49 of 49 strings)

Translated using Weblate (Estonian)

Currently translated at 14.8% (8 of 54 strings)

Translated using Weblate (Estonian)

Currently translated at 11.4% (20 of 175 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Estonian)

Currently translated at 26.6% (12 of 45 strings)

Translated using Weblate (Estonian)

Currently translated at 3.3% (2 of 59 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (238 of 238 strings)

Translated using Weblate (Estonian)

Currently translated at 1.6% (8 of 473 strings)

Translated using Weblate (Estonian)

Currently translated at 0.3% (3 of 811 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Priit Jõerüüt <jrthwlate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-replay/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/et/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-replay
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-06-01 21:51:55 +00:00
Hosted Weblate
c4606141ca
Translated using Weblate (German)
Currently translated at 100.0% (807 of 807 strings)

Translated using Weblate (German)

Currently translated at 100.0% (473 of 473 strings)

Translated using Weblate (German)

Currently translated at 100.0% (1268 of 1268 strings)

Translated using Weblate (German)

Currently translated at 100.0% (61 of 61 strings)

Translated using Weblate (German)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (German)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (German)

Currently translated at 95.6% (1208 of 1263 strings)

Translated using Weblate (German)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (German)

Currently translated at 100.0% (238 of 238 strings)

Translated using Weblate (German)

Currently translated at 100.0% (811 of 811 strings)

Translated using Weblate (German)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (German)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (German)

Currently translated at 100.0% (473 of 473 strings)

Translated using Weblate (German)

Currently translated at 99.5% (1178 of 1183 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Sebastian Sie <sebastian.neuplanitz@googlemail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/de/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-settings
2026-06-01 21:51:55 +00:00
Hosted Weblate
052f159ca4
Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.5% (238 of 239 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 80.1% (81 of 101 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (47 of 47 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 99.6% (499 of 501 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 98.3% (234 of 238 strings)

Co-authored-by: AmilcarNetto <amilcar.netto@gmail.com>
Co-authored-by: Geraldo Fensterseifer Júnior <gerafenster@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/pt_BR/
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
2026-06-01 21:51:54 +00:00
Hosted Weblate
46465cea63
Translated using Weblate (Turkish)
Currently translated at 88.1% (89 of 101 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Turhan Munis <turhan.munis@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/tr/
Translation: Frigate NVR/components-dialog
2026-06-01 21:51:54 +00:00
Josh Hawkins
db9e64c598
replace motion activity resample apply/agg lambdas with vectorized max() and first() (#23383)
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / Assemble and push default build (push) Blocked by required conditions
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
2026-06-01 15:51:43 -06:00
Josh Hawkins
570e21340a
Miscellaneous fixes (#23373)
* republish MQTT switch states when a profile is activated or deactivated

* fix object mask default name when created from Explore tracking details

* tweak annotation offset max in UI

* optimize recordings/unavailable gap detection and drop empty motion activity buckets

* add tests
2026-06-01 13:55:52 -06:00
Josh Hawkins
8073174c20
Refactor motion search (#23378)
* refactor motion search

* cleanup dead code and tests

* tweaks

* fix multi-day seeking

* start playback a few seconds before the change so the motion is in view
2026-06-01 12:08:46 -05:00
Josh Hawkins
47a06c8b30
Tweaks (#23367)
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* add ptz presets and default role widgets

* language tweaks

* fix width in triggers view

* tweak iOS PWA message in notifications settings

* deprecate ui.date_style and ui.time_style

these have been unused since date/time formatting has been pushed to i18n

* add config migrator to remove date_style and time_style

* remove date_style and time_style from reference config

* fix camera list scrolling in state classification wizard on mobile
2026-05-31 15:09:10 -06:00
243 changed files with 11521 additions and 1322 deletions

View File

@ -1083,22 +1083,6 @@ ui:
# Optional: Set the time format used.
# Options are browser, 12hour, or 24hour (default: shown below)
time_format: browser
# Optional: Set the date style for a specified length.
# Options are: full, long, medium, short
# Examples:
# short: 2/11/23
# medium: Feb 11, 2023
# full: Saturday, February 11, 2023
# (default: shown below).
date_style: short
# Optional: Set the time style for a specified length.
# Options are: full, long, medium, short
# Examples:
# short: 8:14 PM
# medium: 8:15:22 PM
# full: 8:15:22 PM Mountain Standard Time
# (default: shown below).
time_style: medium
# Optional: Set the unit system to either "imperial" or "metric" (default: metric)
# Used in the UI and in MQTT topics
unit_system: metric

View File

@ -155,21 +155,22 @@ Motion Search lets you scan recorded footage for changes inside a region of inte
To start a search, open the Actions menu in History or click the kebab menu on a camera in the <NavPath path="Review > Motion" /> page and choose **Motion Search**. In the dialog:
1. Pick the camera and time range to scan.
1. Pick the camera and time range to scan. In the date pickers, days that have recordings available are underlined.
2. Draw a polygon on the camera frame to define the region of interest.
3. Adjust the search parameters if needed:
| Field | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sensitivity Threshold** | Per-pixel luminance change required to count as motion inside the ROI. Behaves like Frigate's motion detection `threshold` setting. |
| **Minimum Change Area** | Minimum percentage of the region of interest that must change for a frame to be considered significant. Raise it to ignore small movements (leaves, distant motion); lower it when the object you care about only covers a small slice of the ROI. |
| **Frame Skip** | Number of frames to skip between samples — at a camera recording 20 fps, a skip value of 20 takes motion samples roughly once per second. Higher values scan much faster and are usually the right choice; lower it only when you need to catch the exact appearance or disappearance of a fast-moving object. |
| **Maximum Results** | Maximum number of matching timestamps to return. |
| **Parallel mode** | Process multiple recording segments in parallel. Speeds up large time ranges at the cost of higher CPU usage. |
| Field | Description |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sensitivity Threshold** | Per-pixel luminance change required to count as motion inside the ROI. Behaves like Frigate's motion detection `threshold` setting. |
| **Minimum Change Area** | Minimum size of a single moving region, as a percentage of the ROI, for a frame to count as significant. Raise it to ignore small movements (leaves, distant motion); lower it when your subject covers only a small slice of the ROI. Every result shows the percentage it scored, so you can use those values to tune this. |
| **Maximum Results** | Maximum number of matching timestamps to return. The search stops once it reaches this many results, so a lower value finishes sooner while a higher value scans further into the range. |
| **Parallel mode** | Decode multiple recording ranges at the same time. Speeds up large time ranges at the cost of higher decoding and CPU usage. |
Motion Search samples each recording's keyframes automatically, so there is no frame-rate or sampling setting to tune.
Once running, Frigate scans the recording segments that overlap the time range and reports timestamps where changes were detected inside the polygon, along with the percentage of the ROI that changed. Clicking a result seeks the player to that moment so you can review what happened.
The status panel shows live progress and metrics such as how many segments were scanned, how many were skipped because no motion was recorded for that segment (using the stored motion heatmap), how many frames were decoded, and the total wall-clock time. Segments with no recorded motion in the selected ROI are skipped automatically, which is what makes searching long time ranges practical.
The results panel shows the time range being scanned, a live progress bar with the timestamp currently being analyzed, and the running result count. A collapsible **Search Metrics** section reports how many segments were scanned and processed, how many were skipped because no motion was recorded in the ROI (using the stored motion heatmap), how many frames were decoded, and the total search time. Skipping segments with no recorded motion in the selected ROI is what makes searching long time ranges practical.
#### Common use cases
@ -179,6 +180,15 @@ Frigate's main use case is to record and surface tracked objects, so Motion Sear
- **An object that was never detected.** Something Frigate doesn't have a model label for, an object too small or distant to be detected, or movement in a region where detection isn't running. The activity left no tracked object but did change the pixels, so a search can still find it.
- **Activity while detection was effectively paused.** Changes that occurred while object detection was disabled, motion was suppressed by `skip_motion_threshold`, or inside an area covered by a motion mask, won't appear as review items or tracked objects but can be recovered by searching the recordings directly.
#### Examples
These show how to choose the ROI and **Minimum Change Area** for two common goals. Minimum Change Area is the size of a single moving region as a percentage of the ROI you draw, so the right value depends on how much of the ROI your subject — and its movement between samples — covers.
Because samples are a second or more apart, a moving subject usually appears in two places at once in the comparison, so even ordinary motion often scores tens of percent and a low threshold lets in almost everything. The most reliable approach is to **run a search, look at the percentage each result scored, and set Minimum Change Area just below the values for the events you care about.** The default is 20%; the suggestions below are starting points.
- **When did this item first appear (or disappear)?** A package was dropped off, a car parked, or a trash can was moved, and you want the exact moment. Draw a **tight ROI** around the spot the item occupies and **raise Minimum Change Area** (start around 4060%). Because the item fills most of a tight ROI, its arrival or removal is a large change, while smaller nearby motion (shadows, a passing pedestrian) stays below the threshold. The **earliest result** is when it appeared; if you only care about that moment, a low Maximum Results finishes faster. If you get no hits, the ROI is probably looser than the item — lower the threshold or tighten the ROI.
- **What's been getting into the garden?** Something has been trampling a flower bed overnight and no object was ever tracked. Draw a **looser ROI** covering the whole bed and use a **lower Minimum Change Area than the case above** — start near the 20% default and lower it (toward 510%) only if a small or distant subject is missed, since it covers just a slice of a large region. Expect more results to scan through — step through the timestamps and jump to each to see what triggered it. If wind-blown plants add noise, raise Minimum Change Area or the Sensitivity Threshold.
#### Expected performance
Motion Search analyzes the saved recordings on demand rather than reading a pre-built index, so a search over a long range takes longer than browsing Motion Previews. Cost scales mainly with how much footage has to be examined: segments with no recorded motion in your ROI are skipped using the stored motion heatmap (shown as "segments skipped" in the status panel), so a quiet range finishes quickly while a busy one takes longer.
@ -186,5 +196,6 @@ Motion Search analyzes the saved recordings on demand rather than reading a pre-
To increase the speed of searches:
- Draw a tight ROI. Because **Minimum Change Area** is measured as a percentage of the region you draw, a tight ROI around where you expect the change makes the object fill a larger share of the area, so it clears the threshold more easily. A loose ROI makes the same object a small fraction of the region, so it can fall below the threshold and be missed — forcing you to lower Minimum Change Area, which lets in more noise.
- Keep Frame Skip high. A higher value samples fewer frames and speeds up the search considerably, while still landing within a few seconds of when the motion or object appeared — close enough to seek to in the recording. Only lower it when you need to pinpoint the exact frame something appears or disappears.
- Use Parallel mode to shorten wall-clock time on multi-core systems, at the cost of higher CPU usage while it runs.
- Narrow the time range to the window you care about, so there is less footage to examine.
- Lower **Maximum Results** when you only need the first few hits. Because the search stops once it reaches that many results, a smaller value lets a busy range finish early instead of scanning the whole window.
- Use Parallel mode to shorten wall-clock time on multi-core systems, at the cost of higher decoding and CPU usage while it runs.

View File

@ -7288,13 +7288,6 @@ components:
title: Min Area
description: Minimum change area as a percentage of the ROI
default: 5
frame_skip:
type: integer
maximum: 30
minimum: 1
title: Frame Skip
description: "Process every Nth frame (1=all frames, 5=every 5th frame)"
default: 5
parallel:
type: boolean
title: Parallel
@ -7380,6 +7373,16 @@ components:
anyOf:
- $ref: "#/components/schemas/MotionSearchMetricsResponse"
- type: "null"
scanning_timestamp:
anyOf:
- type: number
- type: "null"
title: Scanning Timestamp
progress:
anyOf:
- type: number
- type: "null"
title: Progress
type: object
required:
- success

View File

@ -41,12 +41,6 @@ class MotionSearchRequest(BaseModel):
le=100.0,
description="Minimum change area as a percentage of the ROI",
)
frame_skip: int = Field(
default=30,
ge=1,
le=120,
description="Process every Nth frame (1=all frames, 5=every 5th frame)",
)
parallel: bool = Field(
default=False,
description="Enable parallel scanning across segments",
@ -97,6 +91,8 @@ class MotionSearchStatusResponse(BaseModel):
total_frames_processed: Optional[int] = None
error_message: Optional[str] = None
metrics: Optional[MotionSearchMetricsResponse] = None
scanning_timestamp: Optional[float] = None
progress: Optional[float] = None
@router.post(
@ -151,7 +147,6 @@ async def start_motion_search(
polygon_points=body.polygon_points,
threshold=body.threshold,
min_area=body.min_area,
frame_skip=body.frame_skip,
parallel=body.parallel,
max_results=body.max_results,
)
@ -231,6 +226,9 @@ async def get_motion_search_status_endpoint(
if job.metrics:
response_content["metrics"] = job.metrics.to_dict()
response_content["scanning_timestamp"] = job.scanning_timestamp
response_content["progress"] = job.progress
return JSONResponse(content=response_content)

View File

@ -299,22 +299,36 @@ async def no_recordings(
.iterator()
)
# Convert recordings to list of (start, end) tuples
# Convert recordings to list of (start, end) tuples, ordered by start_time
recordings = [(r["start_time"], r["end_time"]) for r in data]
# Merge overlapping/adjacent recordings into covered intervals. The query
# orders by start_time, so a single pass merges them
covered: list[tuple[float, float]] = []
for rec_start, rec_end in recordings:
if covered and rec_start <= covered[-1][1]:
covered[-1] = (covered[-1][0], max(covered[-1][1], rec_end))
else:
covered.append((rec_start, rec_end))
# Iterate through time segments and check if each has any recording
no_recording_segments = []
current = after
current_gap_start = None
idx = 0
covered_count = len(covered)
while current < before:
segment_end = min(current + scale, before)
# Check if this segment overlaps with any recording
has_recording = any(
rec_start < segment_end and rec_end > current
for rec_start, rec_end in recordings
)
# Advance past covered intervals that end before this segment begins;
# they cannot overlap this or any later segment.
while idx < covered_count and covered[idx][1] <= current:
idx += 1
# A covered interval overlaps the segment when it starts before the
# segment ends (its end is already known to be > current).
has_recording = idx < covered_count and covered[idx][0] < segment_end
if not has_recording:
# This segment has no recordings

View File

@ -605,9 +605,10 @@ def motion_activity(
if not filtered:
return JSONResponse(content=[])
camera_list = list(filtered)
clauses.append((Recordings.camera << camera_list))
else:
clauses.append((Recordings.camera << allowed_cameras))
camera_list = list(allowed_cameras)
clauses.append((Recordings.camera << camera_list))
data: list[Recordings] = (
Recordings.select(
@ -635,14 +636,12 @@ def motion_activity(
df.set_index(["start_time"], inplace=True)
# normalize data
motion = (
df["motion"]
.resample(f"{scale}s")
.apply(lambda x: max(x, key=abs, default=0.0))
.fillna(0.0)
.to_frame()
)
cameras = df["camera"].resample(f"{scale}s").agg(lambda x: ",".join(set(x)))
motion = df["motion"].resample(f"{scale}s").max().fillna(0.0).to_frame()
if len(camera_list) == 1:
cameras = df["camera"].resample(f"{scale}s").first().fillna("")
else:
cameras = df["camera"].resample(f"{scale}s").agg(lambda x: ",".join(set(x)))
df = motion.join(cameras)
length = df.shape[0]
@ -658,6 +657,11 @@ def motion_activity(
else:
df.iloc[i : i + chunk, 0] = 0.0
# Drop resample gap-fill buckets. The resample above emits a row for every
# {scale}s bucket spanning the range, and buckets with no recording get a
# motion of 0 (from fillna) and an empty camera (from joining an empty set).
df = df[df["camera"] != ""]
# change types for output
df.index = df.index.astype(int) // (10**9)
normalized = df.reset_index().to_dict("records")

View File

@ -146,7 +146,7 @@ class CameraConfig(FrigateBaseModel):
timestamp_style: TimestampStyleConfig = Field(
default_factory=TimestampStyleConfig,
title="Timestamp style",
description="Styling options for in-feed timestamps applied to recordings and snapshots.",
description="Styling options for timestamps applied to snapshots and Debug view.",
)
# Options without global fallback

View File

@ -5,7 +5,7 @@ import json
import logging
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional
from typing import Any, Callable, Optional
from frigate.config.camera.updater import (
CameraConfigUpdateEnum,
@ -34,6 +34,45 @@ PROFILE_SECTION_UPDATES: dict[str, CameraConfigUpdateEnum] = {
"zones": CameraConfigUpdateEnum.zones,
}
# Retained MQTT switch topics per profile section, with a payload getter.
# Republished on profile change so MQTT/HA don't show a stale toggle.
SECTION_STATE_TOPICS: dict[str, list[tuple[str, Callable[[Any], Any]]]] = {
"audio": [("audio", lambda c: "ON" if c.audio.enabled else "OFF")],
"birdseye": [
("birdseye", lambda c: "ON" if c.birdseye.enabled else "OFF"),
(
"birdseye_mode",
lambda c: c.birdseye.mode.value.upper() if c.birdseye.enabled else "OFF",
),
],
"detect": [("detect", lambda c: "ON" if c.detect.enabled else "OFF")],
"motion": [
("motion", lambda c: "ON" if c.motion.enabled else "OFF"),
("improve_contrast", lambda c: "ON" if c.motion.improve_contrast else "OFF"),
("motion_threshold", lambda c: c.motion.threshold),
("motion_contour_area", lambda c: c.motion.contour_area),
],
"notifications": [
("notifications", lambda c: "ON" if c.notifications.enabled else "OFF"),
],
"objects": [
("object_descriptions", lambda c: "ON" if c.objects.genai.enabled else "OFF"),
],
"record": [("recordings", lambda c: "ON" if c.record.enabled else "OFF")],
"review": [
("review_alerts", lambda c: "ON" if c.review.alerts.enabled else "OFF"),
(
"review_detections",
lambda c: "ON" if c.review.detections.enabled else "OFF",
),
(
"review_descriptions",
lambda c: "ON" if c.review.genai.enabled else "OFF",
),
],
"snapshots": [("snapshots", lambda c: "ON" if c.snapshots.enabled else "OFF")],
}
PERSISTENCE_FILE = Path(CONFIG_DIR) / ".profiles"
@ -310,6 +349,15 @@ class ProfileManager:
settings,
)
# republish MQTT switch states
if self.dispatcher is not None:
for suffix, get_payload in SECTION_STATE_TOPICS.get(section, ()):
self.dispatcher.publish(
f"{cam_name}/{suffix}/state",
get_payload(cam_config),
retain=True,
)
def _persist_active_profile(self, profile_name: Optional[str]) -> None:
"""Persist the active profile state to disk as JSON."""
try:

View File

@ -45,7 +45,7 @@ class ProxyConfig(FrigateBaseModel):
default_role: Optional[str] = Field(
default="viewer",
title="Default role",
description="Default role assigned to proxy-authenticated users when no role mapping applies (admin or viewer).",
description="Default role assigned to proxy-authenticated users when no role mapping applies.",
)
separator: Optional[str] = Field(
default=",",

View File

@ -5,7 +5,7 @@ from pydantic import Field
from .base import FrigateBaseModel
__all__ = ["TimeFormatEnum", "DateTimeStyleEnum", "UnitSystemEnum", "UIConfig"]
__all__ = ["TimeFormatEnum", "UnitSystemEnum", "UIConfig"]
class TimeFormatEnum(str, Enum):
@ -14,13 +14,6 @@ class TimeFormatEnum(str, Enum):
hours24 = "24hour"
class DateTimeStyleEnum(str, Enum):
full = "full"
long = "long"
medium = "medium"
short = "short"
class UnitSystemEnum(str, Enum):
imperial = "imperial"
metric = "metric"
@ -37,16 +30,6 @@ class UIConfig(FrigateBaseModel):
title="Time format",
description="Time format to use in the UI (browser, 12hour, or 24hour).",
)
date_style: DateTimeStyleEnum = Field(
default=DateTimeStyleEnum.short,
title="Date style",
description="Date style to use in the UI (full, long, medium, short).",
)
time_style: DateTimeStyleEnum = Field(
default=DateTimeStyleEnum.medium,
title="Time style",
description="Time style to use in the UI (full, long, medium, short).",
)
unit_system: UnitSystemEnum = Field(
default=UnitSystemEnum.metric,
title="Unit system",

View File

@ -3,6 +3,8 @@
import logging
import os
import threading
import time
from collections.abc import Callable, Generator, Iterable
from concurrent.futures import Future, ThreadPoolExecutor, as_completed
from dataclasses import asdict, dataclass, field
from datetime import datetime
@ -19,6 +21,18 @@ from frigate.jobs.manager import (
get_job_by_id,
set_current_job,
)
from frigate.jobs.motion_search_batch import (
build_segment_time_map,
coalesce_runs,
stream_time_to_absolute,
)
from frigate.jobs.motion_search_decode import (
iter_vod_frames,
keyframe_sampling_eligible,
probe_video_dimensions,
probe_vod_keyframe_pts,
resolve_motion_decode_args,
)
from frigate.models import Recordings
from frigate.types import JobStatusTypesEnum
@ -26,6 +40,18 @@ logger = logging.getLogger(__name__)
# Constants
HEATMAP_GRID_SIZE = 16
# Max wall-clock span of one VOD run request (seconds). Bounds per-request size
# and gives streaming/cancel/early-exit granularity.
MAX_RUN_SECONDS = 600.0
# Treat segments within this many seconds end-to-start as time-contiguous.
RUN_GAP_EPSILON = 1.0
# Longest-side pixels for the ROI downscale before motion detection.
SCALE_TARGET = 400
# Minimum wall seconds between intra-run progress broadcasts.
PROGRESS_BROADCAST_INTERVAL = 1.0
# Output frame rate for the fixed-cadence fallback used on long-GOP cameras
# (where keyframe sampling is too sparse). Keyframe cameras ignore this.
FALLBACK_SAMPLE_FPS = 2.0
@dataclass
@ -69,13 +95,16 @@ class MotionSearchJob(Job):
polygon_points: list[list[float]] = field(default_factory=list)
threshold: int = 30
min_area: float = 5.0
frame_skip: int = 5
parallel: bool = False
max_results: int = 25
# Track progress
total_frames_processed: int = 0
# Live progress (ride the existing to_dict() websocket broadcast)
scanning_timestamp: Optional[float] = None
progress: float = 0.0
# Metrics for observability
metrics: Optional[MotionSearchMetrics] = None
@ -100,6 +129,113 @@ def create_polygon_mask(
return mask
def compute_roi_crop_and_scale(
polygon_points: list[list[float]],
frame_width: int,
frame_height: int,
scale_target: int,
) -> tuple[tuple[int, int, int, int], tuple[int, int]]:
"""Compute the ROI crop box and never-upscale scaled dimensions.
Returns ((crop_w, crop_h, crop_x, crop_y), (scaled_w, scaled_h)) in pixels.
The crop is the polygon's bounding box in frame pixels; the scaled size fits
the crop's longest side to ``scale_target`` without ever enlarging it.
"""
xs = [p[0] for p in polygon_points]
ys = [p[1] for p in polygon_points]
# nv12 (4:2:0) hwdownload requires even crop offsets and even crop/scale
# dimensions; otherwise ffmpeg rounds the chroma planes and the raw byte
# stream stops matching the expected frame size. Force even values, and the
# mask is built from these same values so the two stay aligned.
crop_x = int(min(xs) * frame_width)
crop_y = int(min(ys) * frame_height)
crop_x -= crop_x % 2
crop_y -= crop_y % 2
crop_w = max(2, int(max(xs) * frame_width) - crop_x)
crop_h = max(2, int(max(ys) * frame_height) - crop_y)
crop_w -= crop_w % 2
crop_h -= crop_h % 2
longest = max(crop_w, crop_h)
factor = min(1.0, scale_target / longest)
scaled_w = max(2, round(crop_w * factor))
scaled_h = max(2, round(crop_h * factor))
scaled_w -= scaled_w % 2
scaled_h -= scaled_h % 2
return (crop_w, crop_h, crop_x, crop_y), (scaled_w, scaled_h)
def build_scaled_roi_mask(
polygon_points: list[list[float]],
frame_width: int,
frame_height: int,
crop: tuple[int, int, int, int],
scaled: tuple[int, int],
) -> np.ndarray:
"""Rasterize the polygon mask at the scaled ROI size.
Builds the full-resolution mask, crops it to the ROI box, and nearest-
neighbor resizes it to the scaled dimensions so it lines up exactly with the
frames ffmpeg crops and scales.
"""
crop_w, crop_h, crop_x, crop_y = crop
scaled_w, scaled_h = scaled
full_mask = create_polygon_mask(polygon_points, frame_width, frame_height)
cropped = full_mask[crop_y : crop_y + crop_h, crop_x : crop_x + crop_w]
return cv2.resize(cropped, (scaled_w, scaled_h), interpolation=cv2.INTER_NEAREST)
def detect_motion_scaled(
frames: Iterable[tuple[int, np.ndarray]],
mask: np.ndarray,
threshold: int,
min_area: float,
timestamp_fn: Callable[[int], float],
) -> list[MotionSearchResult]:
"""Detect motion across pre-cropped, pre-scaled gray frames.
``frames`` yields (absolute_frame_index, gray_roi_frame); ``mask`` is the
scaled ROI mask. ``min_area`` is a percentage of the masked ROI. Mirrors the
full-res detection math (absdiff -> blur -> threshold -> dilate -> contours)
on the already-reduced frames.
"""
results: list[MotionSearchResult] = []
mask_area = np.count_nonzero(mask)
if mask_area == 0:
return results
min_area_pixels = int((min_area / 100.0) * mask_area)
prev: np.ndarray | None = None
for frame_idx, gray in frames:
masked = cv2.bitwise_and(gray, gray, mask=mask)
if prev is not None:
diff = cv2.absdiff(prev, masked)
diff_blurred = cv2.GaussianBlur(diff, (3, 3), 0)
_, thresh = cv2.threshold(diff_blurred, threshold, 255, cv2.THRESH_BINARY)
thresh_dilated = cv2.dilate(thresh, None, iterations=1) # type: ignore[call-overload]
thresh_masked = cv2.bitwise_and(thresh_dilated, thresh_dilated, mask=mask)
change_pixels = cv2.countNonZero(thresh_masked)
if change_pixels > min_area_pixels:
contours, _ = cv2.findContours(
thresh_masked, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
total_change_area = sum(
cv2.contourArea(c)
for c in contours
if cv2.contourArea(c) >= min_area_pixels
)
if total_change_area > 0:
change_percentage = (total_change_area / mask_area) * 100
results.append(
MotionSearchResult(
timestamp=timestamp_fn(frame_idx),
change_percentage=round(change_percentage, 2),
)
)
prev = masked
return results
def compute_roi_bbox_normalized(
polygon_points: list[list[float]],
) -> tuple[float, float, float, float]:
@ -184,6 +320,22 @@ def segment_passes_heatmap_gate(
return heatmap_overlaps_roi(heatmap, roi_bbox)
def resolve_internal_port(config: FrigateConfig) -> int:
"""Return the unauthenticated internal nginx port for VOD requests."""
listen = config.networking.listen.internal
if isinstance(listen, str):
return int(listen.split(":")[-1])
return int(listen)
def build_vod_url(internal_port: int, camera: str, start: float, end: float) -> str:
"""Build the internal VOD HLS URL for a camera time range."""
return (
f"http://127.0.0.1:{internal_port}/vod/{camera}"
f"/start/{start}/end/{end}/index.m3u8"
)
class MotionSearchRunner(threading.Thread):
"""Thread-based runner for motion search jobs with parallel verification."""
@ -206,6 +358,23 @@ class MotionSearchRunner(threading.Thread):
cpu_count = os.cpu_count() or 1
self.max_workers = min(4, cpu_count)
# Resolved once per job in _execute_search
self.ffmpeg_path: str = "ffmpeg"
self.ffprobe_path: str = "ffprobe"
self.decode_args: list[str] = []
# Keyframe sampling decision, decided once per job from the first run's
# GOP. The fallback cadence is a fixed rate (see FALLBACK_SAMPLE_FPS).
self.use_keyframe: bool = True
self.fps_rate: float = FALLBACK_SAMPLE_FPS
# ROI crop/scale + scaled mask, computed once from the VOD-stream
# dimensions (which can differ from the detect resolution).
self.crop: tuple[int, int, int, int] = (0, 0, 0, 0)
self.scaled: tuple[int, int] = (0, 0)
self.scaled_mask: np.ndarray = np.zeros((0, 0), dtype=np.uint8)
self.channels: int = 1
self.internal_port: int = 5000
self._last_progress_broadcast: float = 0.0
def run(self) -> None:
"""Execute the motion search job."""
try:
@ -281,6 +450,9 @@ class MotionSearchRunner(threading.Thread):
if frame_width is None or frame_height is None:
raise ValueError(f"Camera {camera_name} detect dimensions not configured")
self.ffmpeg_path = camera_config.ffmpeg.ffmpeg_path
self.ffprobe_path = camera_config.ffmpeg.ffprobe_path
# Create polygon mask
polygon_mask = create_polygon_mask(
self.job.polygon_points, frame_width, frame_height
@ -384,205 +556,274 @@ class MotionSearchRunner(threading.Thread):
self.metrics.heatmap_roi_skip_segments,
)
if self.job.parallel:
return self._search_motion_parallel(filtered_recordings, polygon_mask)
# Resolve decode backend (allowlisted hwaccel or software), coalesce the
# gate-passing segments into time-contiguous runs, and probe the first
# run's VOD stream once for dimensions + keyframe layout. VOD output is
# what we decode, so crop/scale/mask are computed against it.
self.internal_port = resolve_internal_port(self.config)
self.decode_args = resolve_motion_decode_args(camera_config)
ffprobe_path = self.ffprobe_path
return self._search_motion_sequential(filtered_recordings, polygon_mask)
runs = coalesce_runs(filtered_recordings, MAX_RUN_SECONDS, RUN_GAP_EPSILON)
if not runs:
return []
def _search_motion_parallel(
self,
recordings: list[Recordings],
polygon_mask: np.ndarray,
) -> list[MotionSearchResult]:
"""Search for motion in parallel across segments, streaming results."""
all_results: list[MotionSearchResult] = []
total_frames = 0
next_recording_idx_to_merge = 0
first_run = runs[0]
first_url = build_vod_url(
self.internal_port,
camera_name,
float(first_run[0].start_time),
float(first_run[-1].end_time),
)
dims = probe_video_dimensions(ffprobe_path, first_url)
if dims is None:
raise ValueError(f"Could not probe VOD dimensions for camera {camera_name}")
rec_width, rec_height, _rec_fps = dims
self.crop, self.scaled = compute_roi_crop_and_scale(
self.job.polygon_points, rec_width, rec_height, SCALE_TARGET
)
self.scaled_mask = build_scaled_roi_mask(
self.job.polygon_points, rec_width, rec_height, self.crop, self.scaled
)
self.channels = 1 # always gray output
# Decide keyframe vs fixed-cadence sampling once from the first run's GOP
# (keyframe structure is a per-camera constant).
first_pts = probe_vod_keyframe_pts(ffprobe_path, first_url)
self.use_keyframe = keyframe_sampling_eligible(first_pts)
logger.debug(
"Motion search job %s: starting motion search with %d workers "
"across %d segments",
"Motion search job %s: %d runs, sampling=%s, hwaccel=%s, vod=%dx%d",
self.job.id,
self.max_workers,
len(recordings),
len(runs),
"keyframe" if self.use_keyframe else "cadence",
bool(self.decode_args),
rec_width,
rec_height,
)
# Initialize partial results on the job so they stream to the frontend
return self._search_runs(runs)
def _emit_progress(self, abs_ts: float) -> None:
"""Throttled intra-run progress broadcast (scanning cursor)."""
now = time.monotonic()
if now - self._last_progress_broadcast < PROGRESS_BROADCAST_INTERVAL:
return
self._last_progress_broadcast = now
self.job.scanning_timestamp = abs_ts
self._broadcast_status()
def _detect_with_progress(
self,
indexed_frames: list[tuple[int, np.ndarray]],
timestamp_fn: Callable[[int], float],
) -> list[MotionSearchResult]:
"""Run detection while firing throttled progress as frames are scanned."""
def _gen() -> Generator[tuple[int, np.ndarray], None, None]:
for i, frame in indexed_frames:
if not self._should_stop():
self._emit_progress(timestamp_fn(i))
yield i, frame
return detect_motion_scaled(
_gen(),
self.scaled_mask,
self.job.threshold,
self.job.min_area,
timestamp_fn,
)
def _process_run(
self, run: list[Recordings]
) -> tuple[list[MotionSearchResult], int]:
"""Decode one run's VOD stream and detect motion.
Keyframe mode compares every decoded keyframe (free recall, since they
are all decoded anyway) paired with its probed PTS; if the decoded and
probed counts disagree (the decoder ignored ``-skip_frame nokey`` or the
stream is corrupt) this run re-runs in the fixed-cadence fallback.
Returns ``(results, frame_count)``.
"""
run_start: float = run[0].start_time # type: ignore[assignment]
run_end: float = run[-1].end_time # type: ignore[assignment]
vod_url = build_vod_url(self.internal_port, self.job.camera, run_start, run_end)
time_map = build_segment_time_map(run)
if self.use_keyframe:
kf_pts = probe_vod_keyframe_pts(self.ffprobe_path, vod_url)
frames = list(
iter_vod_frames(
self.ffmpeg_path,
vod_url,
self.scaled[0],
self.scaled[1],
self.channels,
self.decode_args,
self.crop,
self.scaled,
True,
self._should_stop,
skip_nonkey=True,
fps_rate=None,
)
)
if kf_pts and len(frames) == len(kf_pts):
abs_times = [stream_time_to_absolute(time_map, p) for p in kf_pts]
indexed = list(enumerate(frames))
def _ts_kf(i: int) -> float:
return abs_times[i]
results = self._detect_with_progress(indexed, _ts_kf)
return results, len(frames)
logger.debug(
"Keyframe count mismatch (%d decoded vs %d probed), using cadence",
len(frames),
len(kf_pts),
)
return self._process_run_cadence(vod_url, time_map)
def _process_run_cadence(
self, vod_url: str, time_map: list[tuple[float, float, float]]
) -> tuple[list[MotionSearchResult], int]:
"""Fixed-cadence fallback: fps-filtered VOD decode, evenly spaced times."""
frames = list(
iter_vod_frames(
self.ffmpeg_path,
vod_url,
self.scaled[0],
self.scaled[1],
self.channels,
self.decode_args,
self.crop,
self.scaled,
True,
self._should_stop,
skip_nonkey=False,
fps_rate=self.fps_rate,
)
)
indexed = list(enumerate(frames))
def _ts_fps(i: int) -> float:
return stream_time_to_absolute(time_map, i / self.fps_rate)
results = self._detect_with_progress(indexed, _ts_fps)
return results, len(frames)
def _merge_run(
self,
run: list[Recordings],
run_results: list[MotionSearchResult],
frames: int,
state: dict[str, Any],
) -> bool:
"""Fold one run's output into the running results; stream + dedup.
Returns True once ``max_results`` deduped hits have accumulated.
"""
state["completed_runs"] += 1
state["all_results"].extend(run_results)
state["total_frames"] += frames
self.job.total_frames_processed = state["total_frames"]
self.metrics.frames_decoded = state["total_frames"]
self.metrics.segments_processed += len(run)
self.job.progress = state["completed_runs"] / state["total_runs"]
state["all_results"].sort(key=lambda r: r.timestamp)
deduped = self._deduplicate_results(state["all_results"])[
: self.job.max_results
]
self.job.results = {
"results": [r.to_dict() for r in deduped],
"total_frames_processed": state["total_frames"],
}
self._broadcast_status()
return len(deduped) >= self.job.max_results
def _search_runs(self, runs: list[list[Recordings]]) -> list[MotionSearchResult]:
"""Decode runs (parallel pool when enabled), merge in order, stream."""
state: dict[str, Any] = {
"all_results": [],
"total_frames": 0,
"completed_runs": 0,
"total_runs": len(runs),
}
self.job.results = {"results": [], "total_frames_processed": 0}
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
futures: dict[Future, int] = {}
completed_segments: dict[int, tuple[list[MotionSearchResult], int]] = {}
logger.debug(
"Motion search job %s: searching %d runs (parallel=%s, workers=%d)",
self.job.id,
len(runs),
self.job.parallel,
self.max_workers,
)
for idx, recording in enumerate(recordings):
if self._should_stop():
break
if self.job.parallel and len(runs) > 1:
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
futures: dict[Future, int] = {}
for idx, run in enumerate(runs):
if self._should_stop():
break
futures[executor.submit(self._process_run, run)] = idx
rec_start: float = recording.start_time # type: ignore[assignment]
rec_end: float = recording.end_time # type: ignore[assignment]
future = executor.submit(
self._process_recording_for_motion,
str(recording.path),
rec_start,
rec_end,
self.job.start_time_range,
self.job.end_time_range,
polygon_mask,
self.job.threshold,
self.job.min_area,
self.job.frame_skip,
)
futures[future] = idx
completed: dict[int, tuple[list[MotionSearchResult], int]] = {}
next_idx = 0
for future in as_completed(futures):
if self._should_stop():
break
run_idx = futures[future]
try:
completed[run_idx] = future.result()
except Exception as e:
self.metrics.segments_with_errors += 1
logger.warning("Error processing run %d: %s", run_idx, e)
completed[run_idx] = ([], 0)
for future in as_completed(futures):
if self._should_stop():
# Cancel remaining futures
for f in futures:
f.cancel()
break
recording_idx = futures[future]
recording = recordings[recording_idx]
try:
results, frames = future.result()
self.metrics.segments_processed += 1
completed_segments[recording_idx] = (results, frames)
while next_recording_idx_to_merge in completed_segments:
segment_results, segment_frames = completed_segments.pop(
next_recording_idx_to_merge
)
all_results.extend(segment_results)
total_frames += segment_frames
self.job.total_frames_processed = total_frames
self.metrics.frames_decoded = total_frames
if segment_results:
deduped = self._deduplicate_results(all_results)
self.job.results = {
"results": [
r.to_dict() for r in deduped[: self.job.max_results]
],
"total_frames_processed": total_frames,
}
self._broadcast_status()
if segment_results and len(deduped) >= self.job.max_results:
while next_idx in completed:
run_results, frames = completed.pop(next_idx)
if self._merge_run(runs[next_idx], run_results, frames, state):
self.internal_stop_event.set()
for pending_future in futures:
pending_future.cancel()
for pending in futures:
pending.cancel()
break
next_recording_idx_to_merge += 1
next_idx += 1
if self.internal_stop_event.is_set():
break
else:
for run in runs:
if self._should_stop():
break
try:
run_results, frames = self._process_run(run)
except Exception as e:
self.metrics.segments_processed += 1
self.metrics.segments_with_errors += 1
self.metrics.segments_processed += len(run)
self._broadcast_status()
logger.warning(
"Error processing segment %s: %s",
recording.path,
e,
)
self.job.total_frames_processed = total_frames
self.metrics.frames_decoded = total_frames
logger.debug(
"Motion search job %s: motion search complete, "
"found %d raw results, decoded %d frames, %d segment errors",
self.job.id,
len(all_results),
total_frames,
self.metrics.segments_with_errors,
)
# Sort and deduplicate results
all_results.sort(key=lambda x: x.timestamp)
return self._deduplicate_results(all_results)[: self.job.max_results]
def _search_motion_sequential(
self,
recordings: list[Recordings],
polygon_mask: np.ndarray,
) -> list[MotionSearchResult]:
"""Search for motion sequentially across segments, streaming results."""
all_results: list[MotionSearchResult] = []
total_frames = 0
logger.debug(
"Motion search job %s: starting sequential motion search across %d segments",
self.job.id,
len(recordings),
)
self.job.results = {"results": [], "total_frames_processed": 0}
for recording in recordings:
if self.cancel_event.is_set():
break
try:
rec_start: float = recording.start_time # type: ignore[assignment]
rec_end: float = recording.end_time # type: ignore[assignment]
results, frames = self._process_recording_for_motion(
str(recording.path),
rec_start,
rec_end,
self.job.start_time_range,
self.job.end_time_range,
polygon_mask,
self.job.threshold,
self.job.min_area,
self.job.frame_skip,
)
all_results.extend(results)
total_frames += frames
self.job.total_frames_processed = total_frames
self.metrics.frames_decoded = total_frames
self.metrics.segments_processed += 1
if results:
all_results.sort(key=lambda x: x.timestamp)
deduped = self._deduplicate_results(all_results)[
: self.job.max_results
]
self.job.results = {
"results": [r.to_dict() for r in deduped],
"total_frames_processed": total_frames,
}
self._broadcast_status()
if results and len(deduped) >= self.job.max_results:
logger.warning("Error processing run: %s", e)
continue
if self._merge_run(run, run_results, frames, state):
break
except Exception as e:
self.metrics.segments_processed += 1
self.metrics.segments_with_errors += 1
self._broadcast_status()
logger.warning("Error processing segment %s: %s", recording.path, e)
self.job.total_frames_processed = total_frames
self.metrics.frames_decoded = total_frames
all_results: list[MotionSearchResult] = state["all_results"]
self.job.total_frames_processed = state["total_frames"]
self.metrics.frames_decoded = state["total_frames"]
self.job.progress = 1.0
logger.debug(
"Motion search job %s: sequential motion search complete, "
"found %d raw results, decoded %d frames, %d segment errors",
"Motion search job %s: complete, %d raw results, %d frames, %d errors",
self.job.id,
len(all_results),
total_frames,
state["total_frames"],
self.metrics.segments_with_errors,
)
all_results.sort(key=lambda x: x.timestamp)
all_results.sort(key=lambda r: r.timestamp)
return self._deduplicate_results(all_results)[: self.job.max_results]
def _deduplicate_results(
@ -602,160 +843,6 @@ class MotionSearchRunner(threading.Thread):
return deduplicated
def _process_recording_for_motion(
self,
recording_path: str,
recording_start: float,
recording_end: float,
search_start: float,
search_end: float,
polygon_mask: np.ndarray,
threshold: int,
min_area: float,
frame_skip: int,
) -> tuple[list[MotionSearchResult], int]:
"""Process a single recording file for motion detection.
This method is designed to be called from a thread pool.
Args:
min_area: Minimum change area as a percentage of the ROI (0-100).
"""
results: list[MotionSearchResult] = []
frames_processed = 0
if not os.path.exists(recording_path):
logger.warning("Recording file not found: %s", recording_path)
return results, frames_processed
cap = cv2.VideoCapture(recording_path)
if not cap.isOpened():
logger.error("Could not open recording: %s", recording_path)
return results, frames_processed
try:
fps = cap.get(cv2.CAP_PROP_FPS) or 30.0
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
recording_duration = recording_end - recording_start
# Calculate frame range
start_offset = max(0, search_start - recording_start)
end_offset = min(recording_duration, search_end - recording_start)
start_frame = int(start_offset * fps)
end_frame = int(end_offset * fps)
start_frame = max(0, min(start_frame, total_frames - 1))
end_frame = max(0, min(end_frame, total_frames))
if start_frame >= end_frame:
return results, frames_processed
cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
# Get ROI bounding box
roi_bbox = cv2.boundingRect(polygon_mask)
roi_x, roi_y, roi_w, roi_h = roi_bbox
prev_frame_gray = None
frame_step = max(frame_skip, 1)
frame_idx = start_frame
while frame_idx < end_frame:
if self._should_stop():
break
ret, frame = cap.read()
if not ret:
frame_idx += 1
continue
if (frame_idx - start_frame) % frame_step != 0:
frame_idx += 1
continue
frames_processed += 1
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Handle frame dimension changes
if gray.shape != polygon_mask.shape:
resized_mask = cv2.resize(
polygon_mask,
(gray.shape[1], gray.shape[0]),
interpolation=cv2.INTER_NEAREST,
)
current_bbox = cv2.boundingRect(resized_mask)
else:
resized_mask = polygon_mask
current_bbox = roi_bbox
roi_x, roi_y, roi_w, roi_h = current_bbox
cropped_gray = gray[roi_y : roi_y + roi_h, roi_x : roi_x + roi_w]
cropped_mask = resized_mask[
roi_y : roi_y + roi_h, roi_x : roi_x + roi_w
]
cropped_mask_area = np.count_nonzero(cropped_mask)
if cropped_mask_area == 0:
frame_idx += 1
continue
# Convert percentage to pixel count for this ROI
min_area_pixels = int((min_area / 100.0) * cropped_mask_area)
masked_gray = cv2.bitwise_and(
cropped_gray, cropped_gray, mask=cropped_mask
)
if prev_frame_gray is not None:
diff = cv2.absdiff(prev_frame_gray, masked_gray) # type: ignore[unreachable]
diff_blurred = cv2.GaussianBlur(diff, (3, 3), 0)
_, thresh = cv2.threshold(
diff_blurred, threshold, 255, cv2.THRESH_BINARY
)
thresh_dilated = cv2.dilate(thresh, None, iterations=1)
thresh_masked = cv2.bitwise_and(
thresh_dilated, thresh_dilated, mask=cropped_mask
)
change_pixels = cv2.countNonZero(thresh_masked)
if change_pixels > min_area_pixels:
contours, _ = cv2.findContours(
thresh_masked, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
total_change_area = sum(
cv2.contourArea(c)
for c in contours
if cv2.contourArea(c) >= min_area_pixels
)
if total_change_area > 0:
frame_time_offset = (frame_idx - start_frame) / fps
timestamp = (
recording_start + start_offset + frame_time_offset
)
change_percentage = (
total_change_area / cropped_mask_area
) * 100
results.append(
MotionSearchResult(
timestamp=timestamp,
change_percentage=round(change_percentage, 2),
)
)
prev_frame_gray = masked_gray
frame_idx += 1
finally:
cap.release()
logger.debug(
"Motion search segment complete: %s, %d frames processed, %d results found",
recording_path,
frames_processed,
len(results),
)
return results, frames_processed
# Module-level state for managing per-camera jobs
_motion_search_jobs: dict[str, tuple[MotionSearchJob, threading.Event]] = {}
@ -779,7 +866,6 @@ def start_motion_search_job(
polygon_points: list[list[float]],
threshold: int = 30,
min_area: float = 5.0,
frame_skip: int = 5,
parallel: bool = False,
max_results: int = 25,
) -> str:
@ -794,7 +880,6 @@ def start_motion_search_job(
polygon_points=polygon_points,
threshold=threshold,
min_area=min_area,
frame_skip=frame_skip,
parallel=parallel,
max_results=max_results,
)
@ -812,14 +897,13 @@ def start_motion_search_job(
logger.debug(
"Started motion search job %s for camera %s: "
"time_range=%.1f-%.1f, threshold=%d, min_area=%.1f%%, "
"frame_skip=%d, parallel=%s, max_results=%d, polygon_points=%d vertices",
"parallel=%s, max_results=%d, polygon_points=%d vertices",
job.id,
camera_name,
start_time,
end_time,
threshold,
min_area,
frame_skip,
parallel,
max_results,
len(polygon_points),

View File

@ -0,0 +1,75 @@
"""Pure helpers for VOD-batched motion search.
Coalescing gate-passing segments into time-contiguous runs, mapping a frame's
VOD stream time back to an absolute timestamp, and thinning sample times to a
target interval. No I/O or ffmpeg here so the tricky math stays unit-testable.
"""
from bisect import bisect_right
from typing import Any
def coalesce_runs(
segments: list[Any], max_seconds: float, epsilon: float
) -> list[list[Any]]:
"""Group gate-passing segments into time-contiguous runs.
A run extends while each segment's ``start_time`` is within ``epsilon`` of
the previous segment's ``end_time`` (no recording gap) and the run's total
span stays at or below ``max_seconds``. A gap or the cap starts a new run.
Each segment must expose ``start_time`` / ``end_time``.
"""
runs: list[list[Any]] = []
current: list[Any] = []
for seg in segments:
if not current:
current = [seg]
continue
prev_end = float(current[-1].end_time)
run_start = float(current[0].start_time)
contiguous = abs(float(seg.start_time) - prev_end) <= epsilon
within_cap = (float(seg.end_time) - run_start) <= max_seconds
if contiguous and within_cap:
current.append(seg)
else:
runs.append(current)
current = [seg]
if current:
runs.append(current)
return runs
def build_segment_time_map(
run: list[Any],
) -> list[tuple[float, float, float]]:
"""Build a (stream_offset, abs_start, duration) row per segment in a run.
``stream_offset`` is the segment's start in continuous VOD stream time (the
cumulative sum of preceding segment durations); ``abs_start`` is its absolute
``start_time``. Built from each segment's own duration; for a gap-free run
this makes stream time equal ``run_start + offset``.
"""
rows: list[tuple[float, float, float]] = []
offset = 0.0
for seg in run:
duration = float(seg.end_time) - float(seg.start_time)
rows.append((offset, float(seg.start_time), duration))
offset += duration
return rows
def stream_time_to_absolute(
time_map: list[tuple[float, float, float]], stream_time: float
) -> float:
"""Map a VOD stream time to an absolute timestamp via the run's table.
Binary-searches the segment whose stream range contains ``stream_time`` and
returns ``abs_start + (stream_time - stream_offset)``. Times past the last
segment map into the last segment (clamped at the run edge).
"""
offsets = [row[0] for row in time_map]
idx = bisect_right(offsets, stream_time) - 1
if idx < 0:
idx = 0
stream_offset, abs_start, _duration = time_map[idx]
return abs_start + (stream_time - stream_offset)

View File

@ -0,0 +1,382 @@
"""Hardware-accelerated ffmpeg decode for motion search.
Decodes a recording run's VOD/HLS stream with an ffmpeg subprocess, optionally
selecting only keyframes, and streams raw frames over a pipe for the motion
math. Output is the requested ``pix_fmt`` (gray or ``bgr24``) with optional
crop/scale applied in the filter graph so downstream pixels are unchanged.
"""
import json
import logging
import subprocess as sp
import tempfile
from collections.abc import Callable, Generator
from typing import IO
import numpy as np
from frigate.config import CameraConfig
from frigate.ffmpeg_presets import parse_preset_hardware_acceleration_decode
from frigate.util.services import auto_detect_hwaccel
logger = logging.getLogger(__name__)
# Output-format surfaces that download cleanly to nv12 via the fixed
# ``hwdownload,format=nv12`` step the decode path appends. Other surfaces
# (drm_prime from rkmpp, vulkan, amf) need a different download step, so motion
# search decodes them in software to keep results byte-identical rather than risk
# a wrong-but-valid-sized frame the zero-frame fallback gate would not catch.
_NV12_OUTPUT_FORMATS = frozenset({"vaapi", "cuda", "qsv"})
def _hwaccel_output_format(decode_args: list[str]) -> str | None:
"""Return the ``-hwaccel_output_format`` value in ffmpeg args, or None."""
try:
idx = decode_args.index("-hwaccel_output_format")
except ValueError:
return None
return decode_args[idx + 1] if idx + 1 < len(decode_args) else None
def resolve_motion_decode_args(camera_config: CameraConfig) -> list[str]:
"""Resolve the ffmpeg hwaccel decode args for a camera's recordings.
``auto`` is resolved via ``auto_detect_hwaccel`` and the preset is expanded
by ``parse_preset_hardware_acceleration_decode`` (the same table the live
pipeline uses). Acceleration is kept only when the decoded surface downloads
cleanly to nv12 -- decided by reading ``-hwaccel_output_format`` back from the
resolved args rather than a separate preset allowlist that could drift from
``PRESETS_HW_ACCEL_DECODE``. Anything else (custom args, a software-only
preset, or an nv12-incompatible surface) returns an empty list, meaning
software decode, so results stay byte-identical.
"""
raw = camera_config.ffmpeg.hwaccel_args
preset = auto_detect_hwaccel() if raw == "auto" else raw
# Custom args (a list) decode in software so results stay byte-identical.
if not isinstance(preset, str):
return []
decode_args = parse_preset_hardware_acceleration_decode(
preset,
camera_config.detect.fps,
camera_config.detect.width or 0,
camera_config.detect.height or 0,
camera_config.ffmpeg.gpu,
)
if not decode_args:
return []
if _hwaccel_output_format(decode_args) not in _NV12_OUTPUT_FORMATS:
return []
return decode_args
def _read_exact(stream: IO[bytes], size: int) -> bytes | None:
"""Read exactly ``size`` bytes from a pipe, or None at clean EOF.
Pipe reads can return fewer bytes than requested, so loop until the frame
is complete. A short read at the start of a frame means end-of-stream.
"""
buf = bytearray()
while len(buf) < size:
chunk = stream.read(size - len(buf))
if not chunk:
return None
buf.extend(chunk)
return bytes(buf)
def _terminate(proc: sp.Popen[bytes]) -> None:
"""Stop an ffmpeg decode process promptly."""
# Close the read end first so a blocked ffmpeg write unblocks (ffmpeg then
# sees a broken pipe), then signal it. The resulting ffmpeg write error is
# harmless and goes to the captured stderr.
if proc.stdout is not None:
try:
proc.stdout.close()
except OSError:
pass
if proc.poll() is None:
proc.terminate()
try:
proc.wait(timeout=5)
except sp.TimeoutExpired:
proc.kill()
proc.wait()
KEYFRAME_MAX_GAP_SECONDS = 2.0
def keyframe_sampling_eligible(
keyframe_pts: list[float], max_gap: float = KEYFRAME_MAX_GAP_SECONDS
) -> bool:
"""True if keyframes are dense and regular enough for keyframe-only sampling.
Requires at least two keyframes and no gap longer than ``max_gap`` seconds, so
a multi-second motion event necessarily spans a sampled keyframe.
"""
if len(keyframe_pts) < 2:
return False
gaps = [b - a for a, b in zip(keyframe_pts, keyframe_pts[1:])]
return max(gaps) <= max_gap
VOD_PROTOCOL_ARGS = ["-protocol_whitelist", "pipe,file,http,tcp"]
def build_vod_decode_command(
ffmpeg_path: str,
vod_url: str,
decode_args: list[str],
crop: tuple[int, int, int, int] | None,
scale: tuple[int, int] | None,
gray: bool,
*,
skip_nonkey: bool,
fps_rate: float | None,
) -> list[str]:
"""Build the ffmpeg argv to decode a VOD HLS URL.
``skip_nonkey`` adds ``-skip_frame nokey`` (keyframe-only). ``fps_rate`` adds
an ``fps`` filter for the fixed-cadence fallback. They are mutually
exclusive: keyframe mode passes ``skip_nonkey=True``/``fps_rate=None``; the
fallback passes ``skip_nonkey=False`` with a rate.
"""
filters: list[str] = []
# With hwaccel the decoded frames are GPU surfaces; pull them back to system
# memory before the CPU fps/crop/scale filters and the rawvideo encoder.
if decode_args:
filters.append("hwdownload")
filters.append("format=nv12")
if fps_rate is not None:
filters.append(f"fps={fps_rate}")
if crop is not None:
cw, ch, cx, cy = crop
filters.append(f"crop={cw}:{ch}:{cx}:{cy}")
if scale is not None:
sw, sh = scale
filters.append(f"scale={sw}:{sh}")
pix_fmt = "gray" if gray else "bgr24"
cmd = [ffmpeg_path, "-hide_banner", "-loglevel", "error"]
if skip_nonkey:
cmd += ["-skip_frame", "nokey"]
cmd += [*decode_args, *VOD_PROTOCOL_ARGS, "-i", vod_url, "-an"]
if filters:
cmd += ["-vf", ",".join(filters)]
cmd += ["-vsync", "0", "-f", "rawvideo", "-pix_fmt", pix_fmt, "pipe:"]
return cmd
def _run_vod_decode(
ffmpeg_path: str,
vod_url: str,
out_width: int,
out_height: int,
channels: int,
decode_args: list[str],
crop: tuple[int, int, int, int] | None,
scale: tuple[int, int] | None,
gray: bool,
should_stop: Callable[[], bool],
*,
skip_nonkey: bool,
fps_rate: float | None,
software_retry: bool,
) -> Generator[np.ndarray, None, None]:
"""Run one VOD decode, yielding raw frames; retry in software if empty."""
cmd = build_vod_decode_command(
ffmpeg_path,
vod_url,
decode_args,
crop,
scale,
gray,
skip_nonkey=skip_nonkey,
fps_rate=fps_rate,
)
frame_size = out_width * out_height * channels
stderr_file = tempfile.SpooledTemporaryFile(max_size=65536)
proc = sp.Popen(cmd, stdout=sp.PIPE, stderr=stderr_file)
assert proc.stdout is not None
count = 0
try:
while True:
if should_stop():
break
buf = _read_exact(proc.stdout, frame_size)
if buf is None:
break
if channels == 1:
frame = np.frombuffer(buf, dtype=np.uint8).reshape(
(out_height, out_width)
)
else:
frame = np.frombuffer(buf, dtype=np.uint8).reshape(
(out_height, out_width, channels)
)
count += 1
yield frame
finally:
_terminate(proc)
stderr_file.close()
if count == 0 and software_retry and not should_stop():
logger.warning("Hardware VOD decode produced no frames, retrying in software")
yield from _run_vod_decode(
ffmpeg_path,
vod_url,
out_width,
out_height,
channels,
[],
crop,
scale,
gray,
should_stop,
skip_nonkey=skip_nonkey,
fps_rate=fps_rate,
software_retry=False,
)
def iter_vod_frames(
ffmpeg_path: str,
vod_url: str,
out_width: int,
out_height: int,
channels: int,
decode_args: list[str],
crop: tuple[int, int, int, int] | None,
scale: tuple[int, int] | None,
gray: bool,
should_stop: Callable[[], bool],
*,
skip_nonkey: bool,
fps_rate: float | None,
) -> Generator[np.ndarray, None, None]:
"""Decode a VOD HLS URL and yield raw frames in order.
Pair keyframe-mode output with probed keyframe PTS; pair fallback output with
a fixed cadence. Falls back once to software decode if a hwaccel decode yields
no frames.
"""
yield from _run_vod_decode(
ffmpeg_path,
vod_url,
out_width,
out_height,
channels,
decode_args,
crop,
scale,
gray,
should_stop,
skip_nonkey=skip_nonkey,
fps_rate=fps_rate,
software_retry=bool(decode_args),
)
def probe_vod_keyframe_pts(ffprobe_path: str, vod_url: str) -> list[float]:
"""Return keyframe presentation timestamps (VOD stream time) in order.
Reads packet flags via ffprobe over the VOD URL (no decode). Returns [] on
any failure so the caller can fall back.
"""
cmd = [
ffprobe_path,
"-v",
"error",
*VOD_PROTOCOL_ARGS,
"-i",
vod_url,
"-select_streams",
"v:0",
"-show_packets",
"-show_entries",
"packet=pts_time,flags",
"-of",
"json",
]
try:
completed = sp.run(cmd, capture_output=True, text=True, timeout=120)
except (OSError, sp.SubprocessError):
logger.warning("ffprobe failed for VOD keyframe probe")
return []
if completed.returncode != 0 or not completed.stdout:
return []
try:
packets = json.loads(completed.stdout).get("packets", [])
except json.JSONDecodeError:
return []
pts: list[float] = []
for pkt in packets:
flags = pkt.get("flags", "")
pts_time = pkt.get("pts_time")
if flags.startswith("K") and pts_time is not None:
try:
pts.append(float(pts_time))
except ValueError:
continue
return sorted(pts)
def probe_video_dimensions(
ffprobe_path: str, recording_path: str
) -> tuple[int, int, float] | None:
"""Return (width, height, fps) for a recording's video stream, or None.
Reads stream metadata via ffprobe (no decode). The record stream resolution
can differ from the camera's detect resolution, so this is probed once per
job against a real segment.
"""
cmd = [
ffprobe_path,
"-v",
"error",
"-select_streams",
"v:0",
"-show_entries",
"stream=width,height,avg_frame_rate",
"-of",
"json",
recording_path,
]
try:
completed = sp.run(cmd, capture_output=True, text=True, timeout=30)
except (OSError, sp.SubprocessError):
return None
if completed.returncode != 0 or not completed.stdout:
return None
try:
streams = json.loads(completed.stdout).get("streams", [])
except json.JSONDecodeError:
return None
if not streams:
return None
stream = streams[0]
width = int(stream.get("width", 0) or 0)
height = int(stream.get("height", 0) or 0)
rate = stream.get("avg_frame_rate", "0/0") or "0/0"
try:
num, _, den = rate.partition("/")
fps = float(num) / float(den) if float(den) != 0 else 0.0
except (ValueError, ZeroDivisionError):
fps = 0.0
if width <= 0 or height <= 0:
return None
return width, height, fps

View File

@ -403,3 +403,75 @@ class TestHttpMedia(BaseTestHttp):
assert len(summary) == 1
assert "2024-03-10" in summary
assert summary["2024-03-10"] is True
def test_recordings_unavailable_reports_gap_between_recordings(self):
"""A gap between two recordings is reported as an unavailable segment."""
with AuthTestClient(self.app) as client:
# Two recordings with a 20s gap (1010-1030) between them.
Recordings.insert(
id="rec_a",
path="/media/recordings/a.mp4",
camera="front_door",
start_time=1000,
end_time=1010,
duration=10,
motion=0,
).execute()
Recordings.insert(
id="rec_b",
path="/media/recordings/b.mp4",
camera="front_door",
start_time=1030,
end_time=1040,
duration=10,
motion=0,
).execute()
response = client.get(
"/recordings/unavailable",
params={
"after": 1000,
"before": 1040,
"scale": 5,
"cameras": "front_door",
},
)
assert response.status_code == 200
assert response.json() == [{"start_time": 1010, "end_time": 1030}]
def test_recordings_unavailable_merges_overlapping_recordings(self):
"""Overlapping recordings are merged so no false gap is reported."""
with AuthTestClient(self.app) as client:
# Overlapping recordings spanning the whole requested range.
Recordings.insert(
id="rec_a",
path="/media/recordings/a.mp4",
camera="front_door",
start_time=1000,
end_time=1020,
duration=20,
motion=0,
).execute()
Recordings.insert(
id="rec_b",
path="/media/recordings/b.mp4",
camera="front_door",
start_time=1010,
end_time=1030,
duration=20,
motion=0,
).execute()
response = client.get(
"/recordings/unavailable",
params={
"after": 1000,
"before": 1030,
"scale": 5,
"cameras": "front_door",
},
)
assert response.status_code == 200
assert response.json() == []

View File

@ -610,19 +610,16 @@ class TestHttpReview(BaseTestHttp):
response = client.get("/review/activity/motion", params=params)
assert response.status_code == 200
response_json = response.json()
assert len(response_json) == 61
# Only buckets with an actual recording are returned. Empty
# gap-fill buckets between the two recordings are dropped.
assert len(response_json) == 2
self.assertDictEqual(
{"motion": 50.5, "camera": "front_door", "start_time": now + 1},
response_json[0],
)
for item in response_json[1:-1]:
self.assertDictEqual(
{"motion": 0.0, "camera": "", "start_time": item["start_time"]},
item,
)
self.assertDictEqual(
{"motion": 100.0, "camera": "front_door", "start_time": one_m + 1},
response_json[len(response_json) - 1],
response_json[1],
)
####################################################################################################################

View File

@ -0,0 +1,58 @@
"""Tests for motion search batch helpers (runs + timestamp mapping)."""
import unittest
from dataclasses import dataclass
from frigate.jobs.motion_search_batch import (
build_segment_time_map,
coalesce_runs,
stream_time_to_absolute,
)
@dataclass
class _Seg:
path: str
start_time: float
end_time: float
def _run_seconds(run):
return float(run[-1].end_time) - float(run[0].start_time)
class TestCoalesceRuns(unittest.TestCase):
def test_contiguous_segments_form_one_run(self):
segs = [_Seg("a", 0.0, 10.0), _Seg("b", 10.0, 20.0), _Seg("c", 20.0, 30.0)]
runs = coalesce_runs(segs, max_seconds=600.0, epsilon=0.5)
self.assertEqual(len(runs), 1)
self.assertEqual(len(runs[0]), 3)
def test_time_gap_splits_runs(self):
# b ends 20, c starts 25 -> 5s gap > epsilon -> two runs.
segs = [_Seg("a", 0.0, 10.0), _Seg("b", 10.0, 20.0), _Seg("c", 25.0, 35.0)]
runs = coalesce_runs(segs, max_seconds=600.0, epsilon=0.5)
self.assertEqual([len(r) for r in runs], [2, 1])
def test_max_duration_caps_a_run(self):
# Five contiguous 10s segments, cap 25s.
segs = [_Seg(str(i), i * 10.0, i * 10.0 + 10.0) for i in range(5)]
runs = coalesce_runs(segs, max_seconds=25.0, epsilon=0.5)
self.assertTrue(all(_run_seconds(r) <= 30.0 for r in runs))
self.assertEqual(sum(len(r) for r in runs), 5)
def test_empty(self):
self.assertEqual(coalesce_runs([], max_seconds=600.0, epsilon=0.5), [])
class TestTimestampMapping(unittest.TestCase):
def test_gapfree_run_maps_to_start_plus_pts(self):
run = [_Seg("a", 1000.0, 1010.0), _Seg("b", 1010.0, 1020.0)]
time_map = build_segment_time_map(run)
self.assertAlmostEqual(stream_time_to_absolute(time_map, 3.0), 1003.0)
self.assertAlmostEqual(stream_time_to_absolute(time_map, 12.0), 1012.0)
def test_past_end_clamps(self):
run = [_Seg("a", 1000.0, 1010.0)]
time_map = build_segment_time_map(run)
self.assertAlmostEqual(stream_time_to_absolute(time_map, 9.9), 1009.9)

View File

@ -0,0 +1,190 @@
"""Tests for the motion search hardware-accelerated decode helpers."""
import unittest
from types import SimpleNamespace
from unittest import mock
from frigate.jobs.motion_search_decode import (
KEYFRAME_MAX_GAP_SECONDS,
build_vod_decode_command,
keyframe_sampling_eligible,
probe_video_dimensions,
probe_vod_keyframe_pts,
resolve_motion_decode_args,
)
def _fake_camera_config(
hwaccel_args, gpu=0, fps=5, width=1280, height=720, ffmpeg_path="ffmpeg"
):
return SimpleNamespace(
ffmpeg=SimpleNamespace(
hwaccel_args=hwaccel_args, gpu=gpu, ffmpeg_path=ffmpeg_path
),
detect=SimpleNamespace(fps=fps, width=width, height=height),
)
class TestResolveMotionDecodeArgs(unittest.TestCase):
def test_vaapi_preset_is_accelerated(self):
args = resolve_motion_decode_args(_fake_camera_config("preset-vaapi"))
self.assertIn("-hwaccel", args)
self.assertIn("vaapi", args)
def test_non_nv12_preset_falls_back_to_software(self):
# rkmpp produces drm_prime surfaces that do not download to nv12, so it
# must resolve to software decode (empty args) rather than risk corrupt
# frames.
self.assertEqual(
resolve_motion_decode_args(_fake_camera_config("preset-rkmpp")), []
)
def test_custom_args_fall_back_to_software(self):
# Arbitrary custom hwaccel args (a list, not a preset) decode in software
# to preserve byte-identical results.
self.assertEqual(
resolve_motion_decode_args(_fake_camera_config(["-hwaccel", "vulkan"])),
[],
)
def test_nvidia_codec_preset_is_accelerated(self):
# Codec-specific nvidia presets resolve to the same cuda decode args as
# the bare preset, so eligibility is derived from -hwaccel_output_format
# rather than a hardcoded list that omitted these aliases.
args = resolve_motion_decode_args(_fake_camera_config("preset-nvidia-h264"))
self.assertIn("-hwaccel_output_format", args)
self.assertIn("cuda", args)
def test_software_only_preset_falls_back_to_software(self):
# A preset with no -hwaccel_output_format (decoder-based, no GPU surface)
# cannot use the nv12 download step, so it decodes in software.
self.assertEqual(
resolve_motion_decode_args(_fake_camera_config("preset-rpi-64-h264")), []
)
class TestKeyframeEligibility(unittest.TestCase):
def test_regular_short_gop_is_eligible(self):
pts = [0.0, 0.5, 1.0, 1.5, 2.0] # 0.5s gaps
self.assertTrue(keyframe_sampling_eligible(pts))
def test_long_gop_is_ineligible(self):
pts = [0.0, 5.0, 10.0] # 5s gaps
self.assertFalse(keyframe_sampling_eligible(pts))
def test_irregular_gop_ineligible_when_a_gap_is_long(self):
pts = [0.0, 0.5, 1.0, 8.0] # one 7s gap
self.assertFalse(keyframe_sampling_eligible(pts))
def test_too_few_keyframes_ineligible(self):
self.assertFalse(keyframe_sampling_eligible([1.0]))
self.assertFalse(keyframe_sampling_eligible([]))
def test_default_max_gap_constant(self):
self.assertEqual(KEYFRAME_MAX_GAP_SECONDS, 2.0)
class TestVodDecodeCommand(unittest.TestCase):
URL = "http://127.0.0.1:5000/vod/cam/start/1/end/2/index.m3u8"
def test_keyframe_command_shape(self):
cmd = build_vod_decode_command(
"ffmpeg",
self.URL,
decode_args=[],
crop=(100, 80, 10, 20),
scale=(50, 40),
gray=True,
skip_nonkey=True,
fps_rate=None,
)
joined = " ".join(cmd)
self.assertIn("-skip_frame nokey", joined)
self.assertIn("-protocol_whitelist pipe,file,http,tcp", joined)
self.assertIn(f"-i {self.URL}", joined)
self.assertIn("crop=100:80:10:20", joined)
self.assertIn("scale=50:40", joined)
self.assertIn("-pix_fmt gray", joined)
self.assertNotIn("fps=", joined)
def test_fps_command_uses_fps_filter_not_skip_frame(self):
cmd = build_vod_decode_command(
"ffmpeg",
self.URL,
decode_args=[],
crop=None,
scale=None,
gray=False,
skip_nonkey=False,
fps_rate=2.0,
)
joined = " ".join(cmd)
self.assertNotIn("skip_frame", joined)
self.assertIn("fps=2.0", joined)
self.assertIn("-pix_fmt bgr24", joined)
def test_hwaccel_inserts_hwdownload(self):
cmd = build_vod_decode_command(
"ffmpeg",
self.URL,
decode_args=["-hwaccel", "vaapi"],
crop=None,
scale=None,
gray=True,
skip_nonkey=True,
fps_rate=None,
)
joined = " ".join(cmd)
self.assertIn("hwdownload", joined)
self.assertIn("format=nv12", joined)
class TestProbeVodKeyframePts(unittest.TestCase):
def test_parses_keyframe_packets(self):
sample = (
'{"packets":['
'{"pts_time":"0.000000","flags":"K__"},'
'{"pts_time":"1.000000","flags":"___"},'
'{"pts_time":"2.000000","flags":"K__"}]}'
)
completed = mock.Mock(stdout=sample, returncode=0)
with mock.patch(
"frigate.jobs.motion_search_decode.sp.run", return_value=completed
):
pts = probe_vod_keyframe_pts("ffprobe", "http://x/index.m3u8")
self.assertEqual(pts, [0.0, 2.0])
def test_returns_empty_on_failure(self):
with mock.patch(
"frigate.jobs.motion_search_decode.sp.run",
side_effect=OSError("boom"),
):
self.assertEqual(probe_vod_keyframe_pts("ffprobe", "http://x"), [])
class TestProbeVideoDimensions(unittest.TestCase):
def test_parses_dimensions_and_fps(self):
sample = (
'{"streams":[{"width":1920,"height":1080,"avg_frame_rate":"30000/1001"}]}'
)
completed = mock.Mock(stdout=sample, returncode=0)
with mock.patch(
"frigate.jobs.motion_search_decode.sp.run", return_value=completed
):
dims = probe_video_dimensions("ffprobe", "/tmp/a.mp4")
assert dims is not None
width, height, fps = dims
self.assertEqual((width, height), (1920, 1080))
self.assertAlmostEqual(fps, 29.97, places=2)
def test_returns_none_on_zero_dimensions(self):
sample = '{"streams":[{"width":0,"height":0,"avg_frame_rate":"0/0"}]}'
completed = mock.Mock(stdout=sample, returncode=0)
with mock.patch(
"frigate.jobs.motion_search_decode.sp.run", return_value=completed
):
self.assertIsNone(probe_video_dimensions("ffprobe", "/tmp/a.mp4"))
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,87 @@
"""Tests for motion search spatial (crop/scale/mask) helpers."""
import unittest
import numpy as np
from frigate.jobs.motion_search import (
build_scaled_roi_mask,
compute_roi_crop_and_scale,
detect_motion_scaled,
)
class TestComputeRoiCropAndScale(unittest.TestCase):
def test_crop_box_in_record_pixels(self):
# ROI covering x [0.25, 0.75], y [0.5, 1.0] of a 1000x600 frame.
polygon = [[0.25, 0.5], [0.75, 0.5], [0.75, 1.0], [0.25, 1.0]]
crop, scaled = compute_roi_crop_and_scale(polygon, 1000, 600, scale_target=125)
cw, ch, cx, cy = crop
self.assertEqual((cx, cy), (250, 300))
self.assertEqual((cw, ch), (500, 300))
# longest side 500 -> factor 0.25 -> (125, 75), rounded down to even.
self.assertEqual(scaled, (124, 74))
def test_never_upscales(self):
polygon = [[0.0, 0.0], [0.1, 0.0], [0.1, 0.1], [0.0, 0.1]]
crop, scaled = compute_roi_crop_and_scale(polygon, 200, 200, scale_target=400)
cw, ch, _, _ = crop
# crop is 20x20; target 400 would upscale, so scaled == crop size.
self.assertEqual(scaled, (cw, ch))
def test_scaled_dims_are_at_least_one(self):
polygon = [[0.0, 0.0], [0.02, 0.0], [0.02, 0.02], [0.0, 0.02]]
crop, scaled = compute_roi_crop_and_scale(polygon, 50, 50, scale_target=1)
self.assertGreaterEqual(scaled[0], 1)
self.assertGreaterEqual(scaled[1], 1)
def test_all_dims_are_even_for_nv12(self):
# Odd-aligned ROI on an odd-ish frame must still yield even crop/scale so
# the nv12 hwdownload byte stream matches the expected frame size.
polygon = [[0.123, 0.321], [0.777, 0.321], [0.777, 0.901], [0.123, 0.901]]
crop, scaled = compute_roi_crop_and_scale(polygon, 1377, 911, scale_target=257)
for value in (*crop, *scaled):
self.assertEqual(value % 2, 0, f"{value} is not even")
class TestBuildScaledRoiMask(unittest.TestCase):
def test_mask_matches_scaled_dims_and_has_coverage(self):
polygon = [[0.25, 0.5], [0.75, 0.5], [0.75, 1.0], [0.25, 1.0]]
crop, scaled = compute_roi_crop_and_scale(polygon, 1000, 600, scale_target=125)
mask = build_scaled_roi_mask(polygon, 1000, 600, crop, scaled)
self.assertEqual(mask.shape, (scaled[1], scaled[0]))
self.assertEqual(mask.dtype, np.uint8)
# A full rectangle ROI fills its whole crop -> mask is all 255.
self.assertGreater(np.count_nonzero(mask), 0)
self.assertEqual(np.count_nonzero(mask), mask.size)
class TestDetectMotionScaled(unittest.TestCase):
def _ts(self, idx):
return float(idx)
def test_finds_change_between_frames(self):
mask = np.full((60, 80), 255, dtype=np.uint8)
f0 = np.zeros((60, 80), dtype=np.uint8)
f1 = np.zeros((60, 80), dtype=np.uint8)
f1[10:50, 20:60] = 255 # big bright block appears
frames = [(0, f0), (30, f1)]
results = detect_motion_scaled(
frames, mask, threshold=30, min_area=1.0, timestamp_fn=self._ts
)
self.assertEqual(len(results), 1)
self.assertEqual(results[0].timestamp, 30.0)
self.assertGreater(results[0].change_percentage, 0.0)
def test_no_change_yields_nothing(self):
mask = np.full((60, 80), 255, dtype=np.uint8)
f0 = np.zeros((60, 80), dtype=np.uint8)
f1 = np.zeros((60, 80), dtype=np.uint8)
results = detect_motion_scaled(
[(0, f0), (30, f1)], mask, threshold=30, min_area=1.0, timestamp_fn=self._ts
)
self.assertEqual(results, [])
if __name__ == "__main__":
unittest.main()

View File

@ -1,5 +1,6 @@
"""Tests for the profiles system."""
import copy
import json
import os
import unittest
@ -746,6 +747,36 @@ class TestProfileManager(unittest.TestCase):
manager.activate_profile(None)
dispatcher.clear_runtime_state.assert_called_once_with()
@patch.object(ProfileManager, "_persist_active_profile")
def test_profile_change_republishes_switch_states(self, mock_persist):
"""Profile changes republish MQTT switch states so HA stays in sync.
Regression: activating/deactivating a profile updated the in-memory
config (and Frigate's behavior) but left the retained MQTT state
topics stale, so external integrations like Home Assistant kept
showing the pre-profile toggle position.
"""
config_data = copy.deepcopy(self.config_data)
config_data["cameras"]["front"]["profiles"]["disarmed"]["review"] = {
"alerts": {"enabled": False},
}
config = FrigateConfig(**config_data)
dispatcher = MagicMock()
manager = ProfileManager(config, self.mock_updater, dispatcher)
# Activating disarmed turns alerts off -> MQTT state must follow
manager.activate_profile("disarmed")
dispatcher.publish.assert_any_call(
"front/review_alerts/state", "OFF", retain=True
)
# Deactivating restores the base (alerts on) -> MQTT state must follow
dispatcher.publish.reset_mock()
manager.activate_profile(None)
dispatcher.publish.assert_any_call(
"front/review_alerts/state", "ON", retain=True
)
@patch.object(ProfileManager, "_persist_active_profile")
def test_startup_replay_does_not_clear_runtime_state(self, mock_persist):
"""Startup callers pass clear_runtime_overrides=False to preserve state."""

View File

@ -618,6 +618,16 @@ def migrate_018_0(config: dict[str, dict[str, Any]]) -> dict[str, dict[str, Any]
new_config["cameras"][name] = camera_config
# Remove deprecated date_style and time_style from global ui config
global_ui = new_config.get("ui", {})
if global_ui.get("date_style") is not None:
del new_config["ui"]["date_style"]
if global_ui.get("time_style") is not None:
del new_config["ui"]["time_style"]
# Remove ui section if empty
if "ui" in new_config and not new_config["ui"]:
del new_config["ui"]
new_config["version"] = "0.18-0"
return new_config

View File

@ -23,7 +23,7 @@
"singing": "غناء",
"choir": "فرقة غناء",
"chant": "تَرْنِيم",
"mantra": َرْنِيمَة",
"mantra": عويذة",
"child_singing": "غِنَاء طِفْل",
"synthetic_singing": "غِنَاء اِصْطِنَاعِيّ",
"rapping": "رَاب",
@ -50,7 +50,7 @@
"hands": "أَيْدِي",
"finger_snapping": "طَقْطَقَة الأَصَابِع",
"clapping": "تَصْفِيق",
"heart_murmur": "لَغَط القَلْب",
"heart_murmur": "نفخة القَلْب",
"cheering": "صِيَاح",
"applause": "تَصْفِيق",
"chatter": "حَدِيث",
@ -74,5 +74,80 @@
"bus": "حافلة",
"train": "قطار",
"boat": "زورق",
"bird": "طائر"
"bird": "طائر",
"sine_wave": "موجة الإشارة",
"harmonic": "أوزة",
"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": "أجراس أنبوبية",
"cattle": "ماشية",
"moo": "خوار",
"cowbell": "جرس البقر",
"pig": "خنزير",
"oink": "أوينك",
"goat": "معزة",
"bleat": "ثغاء",
"sheep": "غنم",
"fowl": "الدواجن",
"chicken": "دجاجة",
"cluck": "قرقرة",
"cock_a_doodle_doo": "كوكو-كو-كوووووو",
"turkey": "ديك رومى",
"gobble": "كركرة"
}

View File

@ -18,5 +18,9 @@
"train": "قطار",
"boat": "زورق",
"bench": "مقعدة",
"bird": "طائر"
"bird": "طائر",
"mouse": "فأر",
"keyboard": "لوحة المفاتيح",
"goat": "معزة",
"sheep": "غنم"
}

View File

@ -50,7 +50,8 @@
"id": "Bahasa Indonesia (Indonesi)",
"ur": "اردو (Urdú)",
"hr": "Hrvatski (croat)",
"bs": "Bosanski (Bosni)"
"bs": "Bosanski (Bosni)",
"zhHant": "繁體中文 (Xinès Tradicional)"
},
"system": "Sistema",
"systemMetrics": "Mètriques del sistema",
@ -323,5 +324,8 @@
"internalID": "L'ID intern que Frigate s'utilitza a la configuració i a la base de dades"
},
"no_items": "Sense elements",
"validation_errors": "Errors de validació"
"validation_errors": "Errors de validació",
"credentialField": {
"savedPlaceholder": "Desat — deixa en blanc per mantenir l'actual"
}
}

View File

@ -48,5 +48,6 @@
"error": {
"submitFrigatePlusFailed": "Error al enviar fotograma a Frigate+"
}
}
},
"cameraOff": "La càmera està apagada"
}

View File

@ -686,7 +686,7 @@
},
"timestamp_style": {
"label": "Estil de la marca horària",
"description": "Opcions d'estilització per a marques de temps d'alimentació aplicades a enregistraments i instantànies.",
"description": "Opcions d'estilització per a marques de temps aplicades instantànies i la vista de depuració.",
"position": {
"label": "Posició de la marca horària",
"description": "Posició de la marca horària a la imatge (tl/tr/bl/br)."

View File

@ -524,11 +524,11 @@
},
"reindex": {
"label": "Reindexa en iniciar",
"description": "Activa un reíndex complet d'objectes rastrejats històrics a la base de dades d'incrustacions."
"description": "Activa un reindexat complet d'objectes rastrejats històrics a la base de dades d'incrustacions."
},
"model": {
"label": "Model de cerca semàntica o nom del proveïdor GenAI",
"description": "El model d'incrustació a utilitzar per a la cerca semàntica (per exemple 'jinav1'), o el nom d'un proveïdor de GenAI amb el rol d'incrustació."
"description": "El model de vectors a utilitzar per a la cerca semàntica (per exemple 'jinav1'), o el nom d'un proveïdor de GenAI amb el rol de vectors."
},
"model_size": {
"label": "Mida del model",
@ -808,7 +808,7 @@
},
"model_size": {
"label": "Mida del model",
"description": "Mida del model a utilitzar per a incrustacions facials (petit/gran); més gran pot requerir GPU."
"description": "Mida del model a utilitzar per als vectors facials (petit/gran); més gran pot requerir GPU."
},
"unknown_score": {
"label": "Llindar de puntuació desconegut",
@ -984,7 +984,7 @@
},
"default_role": {
"label": "Rol predeterminat",
"description": "Rol predeterminat assignat als usuaris intermediaris autenticats quan no s'aplica cap mapatge de rols (administrador o visor)."
"description": "Rol predeterminat assignat als usuaris intermediaris autenticats quan no s'aplica cap mapatge de rols."
},
"separator": {
"label": "Caràcter separador",

View File

@ -28,5 +28,8 @@
"detectRequired": "Almenys un flux d'entrada ha de tenir assignat el rol «detecta».",
"hwaccelDetectOnly": "Només el flux d'entrada amb el rol detect pot definir arguments d'acceleració del maquinari."
}
},
"detect": {
"dimensionMustBeEven": "Ha de ser un nombre parell."
}
}

View File

@ -65,5 +65,8 @@
"active": "Raonant…",
"show": "Mostra el raonament",
"hide": "Amaga el raonament"
},
"thinking": {
"toggle": "Commuta el pensament"
}
}

View File

@ -2,10 +2,10 @@
"exploreIsUnavailable": {
"downloadingModels": {
"tips": {
"context": "Potser voldreu reindexar les incrustacions dels objectes seguits un cop s'hagin descarregat els models.",
"context": "Potser voldreu reindexar els vectors dels objectes seguits un cop s'hagin descarregat els models.",
"documentation": "Llegir la documentació"
},
"context": "Frigate està descarregant els models d'embeddings necessaris per a donar suport a la funció de cerca semàntica. Això pot trigar diversos minuts, depenent de la velocitat de la teva connexió de xarxa.",
"context": "El Frigate està baixant els models de vectors necessaris per a admetre la funció de Cerca Semàntica. Això pot trigar uns quants minuts depenent de la velocitat de la vostra connexió de xarxa.",
"setup": {
"visionModel": "Model de visió",
"visionModelFeatureExtractor": "Extractor de característiques del model de visió",
@ -248,7 +248,7 @@
"dialog": {
"confirmDelete": {
"title": "Confirmar la supressió",
"desc": "Suprimir aquest objecte rastrejat elimina la instantània, qualsevol incrustació desada, i qualsevol entrada de detalls de seguiment associada. Les imatges gravades d'aquest objecte seguit en l'historial <em>NO</em> seràn eliminades.<br /><br />Estas segur que vols continuar?"
"desc": "En eliminar aquest objecte detectat, s'esborrarà la instantània, els vectors desats i qualsevol entrada associada als detalls de seguiment d'aquest objecte. El metratge enregistrat d'aquest objecte detectat a la vista de l'Historial <em>NO</em> s'esborrarà.<br /><br />Segur que voleu continuar?"
},
"toast": {
"error": "S'ha produït un error en suprimir aquest objecte rastrejat: {{errorMessage}}"
@ -282,7 +282,7 @@
"faceOrLicense_plate": "{{attribute}} detectat per {{label}}",
"other": "{{label}} reconegut com a {{attribute}}"
},
"gone": "{{label}} esquerra",
"gone": "{{label}} ha sortit",
"heard": "{{label}} sentit",
"external": "{{label}} detectat",
"header": {

View File

@ -58,7 +58,9 @@
},
"camera": {
"enable": "Habilitar la càmera",
"disable": "Deshabilita la càmera"
"disable": "Deshabilita la càmera",
"turnOn": "Activa la càmera",
"turnOff": "Apaga la càmera"
},
"muteCameras": {
"enable": "Silencia totes les càmeres",
@ -151,7 +153,8 @@
"autotracking": "Seguiment automàtic",
"objectDetection": "Detecció d'objectes",
"audioDetection": "Detecció d'àudio",
"transcription": "Transcripció d'audio"
"transcription": "Transcripció d'audio",
"camera": "Càmera"
},
"history": {
"label": "Mostrar gravacions històriques"

View File

@ -26,7 +26,9 @@
"points_many": "{{count}} punts",
"points_other": "{{count}} punts",
"undo": "Desfés l'últim punt",
"reset": "Restableix el polígon"
"reset": "Restableix el polígon",
"drawMode": "Dibuxa",
"moveMode": "Moure"
},
"motionHeatmapLabel": "Mapa de calor del moviment",
"dialog": {
@ -42,11 +44,11 @@
"settings": {
"title": "Configuració de la cerca",
"parallelMode": "Mode paral·lel",
"parallelModeDesc": "Escaneja múltiples segments d'enregistrament al mateix temps (més ràpid, però significativament més intensiu en CPU)",
"parallelModeDesc": "Escaneja múltiples intervals d'enregistrament al mateix temps (més ràpid; utilitza més recursos de descodificació)",
"threshold": "Llindar de la sensibilitat",
"thresholdDesc": "Els valors més baixos detecten canvis més petits (1-255)",
"minArea": "Àrea de canvi mínim",
"minAreaDesc": "Percentatge mínim de la regió d'interès que s'ha de canviar per considerar-se significatiu",
"minAreaDesc": "Mida mínima d'una sola regió en moviment, com a percentatge de la regió d'interès",
"frameSkip": "Omet el fotograma",
"frameSkipDesc": "Processa cada N fotograma. Establiu això a la velocitat de fotogrames de la càmera per processar un fotograma per segon (p. ex. 5 per a una càmera de 5 FPS, 30 per a una càmera de 30 FPS). Els valors més alts seran més ràpids, però poden perdre els esdeveniments de curt moviment.",
"maxResults": "Resultats màxims",
@ -72,6 +74,9 @@
"framesDecoded": "Fotogrames descodificats",
"wallTime": "Temps de cerca",
"segmentErrors": "Errors del segment",
"seconds": "{{seconds}}s"
}
"seconds": "{{seconds}}s",
"scanSummary": "{{segments}} segments · {{time}}",
"minutesSeconds": "{{minutes}}m {{seconds}}s"
},
"scanning": "S'està analitzant {{time}}"
}

View File

@ -55,5 +55,5 @@
"goToReplay": "Ves a la repetició"
}
},
"description": "Reprodueix els enregistraments de la càmera per a la depuració. La llista d'objectes mostra un resum retardat en el temps dels objectes detectats i la pestanya Missatges mostra un flux de missatges interns de la fragata a partir del metratge de reproducció."
"description": "Reprodueix els enregistraments de la càmera per a la depuració. La llista d'objectes mostra un resum retardat en el temps dels objectes detectats i la pestanya Missatges mostra un flux de missatges interns de frigate a partir del metratge de reproducció."
}

View File

@ -29,7 +29,7 @@
"frigateplus": "Frigate+",
"enrichments": "Enriquiments",
"triggers": "Disparadors",
"cameraManagement": "Gestió",
"cameraManagement": "Gestió de la càmera",
"cameraReview": "Revisió",
"roles": "Rols",
"general": "General",
@ -136,7 +136,7 @@
"clearAll": "Esborra tots els paràmetres de transmissió"
},
"recordingsViewer": {
"title": "Visor d'enregistraments",
"title": "Visualitzador d'enregistraments",
"defaultPlaybackRate": {
"label": "Velocitat de reproducció predeterminada",
"desc": "Velocitat de reproducció predeterminada per a la reproducció de gravacions."
@ -426,7 +426,8 @@
"notificationUnavailable": {
"title": "Notificacions no disponibles",
"documentation": "Llegir la documentació",
"desc": "Les notificacions push web requereixen un context segur (<code>https://…</code>). Aquesta és una limitació del navegador. Accedeix a Frigate de manera segura per utilitzar les notificacions."
"desc": "Les notificacions push web requereixen un context segur (<code>https://…</code>). Aquesta és una limitació del navegador. Accedeix a Frigate de manera segura per utilitzar les notificacions.",
"descPwa": "A iOS, les notificacions push web només estàn disponibles quan Frigate està instalat a la pantalla principal. Obre el menú <strong>Compartir</strong> , selecciona <strong>Afegir a la pantalla</strong>, i obre Frigate des del nou icona per registrar les notificacions en aquest dispositiu."
},
"unsavedChanges": "Canvis de notificació no desats",
"globalSettings": {
@ -773,22 +774,22 @@
"modelSize": {
"small": {
"title": "petit",
"desc": "Lopció <em>small</em> fa servir una versió quantitzada del model que consumeix menys RAM i sexecuta més ràpidament a la CPU, amb una diferència gairebé inapreciable en la qualitat de les incrustacions (embeddings)."
"desc": "Si s'utilitza <em>small</em>, s'empra una versió quantitzada del model que consumeix menys memòria RAM i s'executa més ràpidament a la CPU, amb una diferència inapreciable en la qualitat dels vectors."
},
"label": "Mida del model",
"large": {
"title": "gran",
"desc": "Lopció <em>large</em> fa servir el model complet de Jina i sexecutarà automàticament a la GPU si està disponible."
},
"desc": "La mida del model utilitzat per incrustacions de cerca semàntica."
"desc": "La mida del model utilitzat per als vectors de la cerca semàntica."
},
"reindexNow": {
"confirmButton": "Reindexar",
"success": "La reindexació ha començat amb èxit.",
"label": "Reindexar ara",
"confirmTitle": "Confirmar la reindexació",
"desc": "La reindexació regenerarà les incrustacions per a tots els objectes rastrejats. Aquest procés s'executa en segon pla i pot treure el màxim de la CPU i prendre una quantitat de temps raonable depenent del nombre d'objectes rastrejats que tingueu.",
"confirmDesc": "Estàs segur que vols reindexar totes les incrustacions (embeddings) dels objectes seguits? Aquest procés sexecutarà en segon pla, però pot arribar a saturar la CPU i trigar bastant temps. Pots seguir-ne el progrés a la pàgina dExplora.",
"desc": "La reindexació tornarà a generar els vectors de tots els objectes detectats. Aquest procés s'executa en segon pla, pot posar la CPU al màxim i trigar una bona estona segons el nombre d'objectes detectats que tingueu.",
"confirmDesc": "Segur que voleu tornar a indexar els vectors de tots els objectes detectats? Aquest procés s'executa en segon pla, però pot posar la CPU al màxim i trigar una bona estona. En podeu veure el progrés a la pàgina Explora.",
"alreadyInProgress": "La reindexació ja està en curs.",
"error": "Error en iniciar la reindexació: {{errorMessage}}"
},
@ -1059,7 +1060,7 @@
"brands": {
"reolink-rtsp": "No es recomana Reolink RST. Es recomana habilitar HTTP a la configuració de la càmera i reiniciar l'assistent de la càmera."
},
"customUrlRtspRequired": "Els URL personalitzats han de començar amb \"rtsp://\". Es requereix configuració manual per a fluxos de càmera no RTSP."
"customUrlRtspRequired": "Els URL personalitzats han de començar amb \"rtsp://\" o \"rtsps://\". Es requereix configuració manual per a fluxos de càmera no RTSP."
},
"selectBrand": "Seleccioneu la marca de la càmera per a la plantilla d'URL",
"customUrl": "URL de flux personalitzat",
@ -1303,13 +1304,13 @@
"selectCamera": "Selecciona una càmera",
"backToSettings": "Torna a la configuració de la càmera",
"streams": {
"title": "Habilita / Inhabilita les càmeres",
"title": "Estat i detalls de la càmera",
"desc": "Inhabilita temporalment una càmera fins que es reiniciï la fragata. La inhabilitació d'una càmera atura completament el processament de Frigate dels fluxos d'aquesta càmera. La detecció, l'enregistrament i la depuració no estaran disponibles.<br /> <em>Nota: això no desactiva les retransmissions de go2rtc.</em>",
"enableLabel": "Càmeres habilitades",
"enableDesc": "Inhabilita temporalment una càmera habilitada fins que es reiniciï Frigate. La inhabilitació d'una càmera atura completament el processament de Frigate dels fluxos d'aquesta càmera. La detecció, l'enregistrament i la depuració no estaran disponibles.<br /> <em>Nota: això no inhabilita els restreams go2rtc.</em><br /><br />Drag el handle per reordenar les càmeres tal com apareixen a la interfície d'usuari. L'ordre de les càmeres habilitades es reflectirà en tota la interfície d'usuari, incloent el tauler en viu i els desplegables de selecció de càmeres.",
"disableLabel": "Càmeres inhabilitades",
"disableDesc": "Habilita una càmera que actualment no és visible a la interfície d'usuari i està desactivada a la configuració. Es requereix un reinici de Frigate després d'activar-la.",
"enableSuccess": "{{cameraName}} activat a la configuració. Reinicia Frigate per aplicar els canvis.",
"enableSuccess": "{{cameraName}} activat. Reinicia Frigate a aplicar.",
"friendlyName": {
"edit": "Edita el nom de la pantalla de la càmera",
"title": "Edita el nom de la pantalla",
@ -1318,7 +1319,26 @@
},
"reorderHandle": "Arrossega per reordenar",
"saving": "S'està desant…",
"saved": "Desat"
"saved": "Desat",
"details": {
"edit": "Edita els detalls de la càmera",
"title": "Edita els detalls de la càmera",
"description": "Actualitzeu el nom de la pantalla i l'URL extern utilitzat per a aquesta càmera a tota la interfície d'usuari de Frigate.",
"friendlyNameLabel": "Nom a mostrar",
"friendlyNameHelp": "Nom amistós que es mostra per a aquesta càmera a tota la interfície d'usuari de Frigate. Deixeu-ho en blanc per utilitzar l'ID de la càmera.",
"webuiUrlLabel": "URL de la interfície web de la càmera",
"webuiUrlHelp": "URL per a visitar la interfície d'usuari web de la càmera directament des de la vista de depuració. Deixeu-ho en blanc per desactivar l'enllaç.",
"webuiUrlInvalid": "Ha de ser un URL vàlid (p. ex., https://example.com)."
},
"label": "Estat de la càmera",
"description": "Estableix l'estat operatiu de cada càmera.<br /><br /><strong>A</strong>: els fluxos es processen normalment.<br /><strong>Off</strong>: pausa temporalment el processament. No persisteix a través de reinicis de Frigate.<br /><strong>Inhabilitat</strong>: deixa de processar i desa el canvi a la configuració. Es requereix un reinici per a tornar a habilitar una càmera inhabilitada.<br /><br /><em>Nota: La inhabilitació no afecta els restreams de go2rtc.</em><br /><br />Arrossegueu l'ansa per a reordenar les càmeres actives a mesura que apareguin a tota la interfície d'usuari, inclosos els desplegables de selecció de quadres en viu i de càmera.",
"disabledSubheading": "Desactivat en la configuració",
"status": {
"on": "Engegat",
"off": "Apagat",
"disabled": "Desactivat"
},
"disableSuccess": "{{cameraName}} desactivat i desat a la configuració."
},
"cameraConfig": {
"add": "Afegeix una càmera",
@ -1364,20 +1384,110 @@
"profiles": {
"title": "Sobreescriu la càmera de perfil",
"selectLabel": "Seleccioneu el perfil",
"description": "Configura quines càmeres estan habilitades o desactivades quan s'activa un perfil. Les càmeres establertes a «Inherit» mantenen el seu estat base habilitat.",
"description": "Configura quines càmeres estan activades o desactivades quan s'activa un perfil. Les càmeres establertes a «herit» mantenen el seu estat per defecte.",
"inherit": "Hereta",
"enabled": "Habilitat",
"disabled": "Desactivat"
"disabled": "Desactivat",
"on": "Engegat",
"off": "Apagat"
},
"cameraType": {
"title": "Tipus de càmera",
"label": "Tipus de càmera",
"description": "Estableix el tipus per a cada càmera. Les càmeres LPR dedicades són càmeres d'un sol ús amb un potent zoom òptic per capturar matrícules en vehicles distants. La majoria de les càmeres haurien d'utilitzar el tipus de càmera normal llevat que la càmera sigui específicament per a LPR i tingui una vista molt centrada en les matrícules.",
"dedicatedLpr": "LPR dedicat",
"saveSuccess": "Tipus de càmera actualitzat per {{cameraName}}. Reinicia la fragata per aplicar els canvis.",
"saveSuccess": "Tipus de càmera actualitzat per {{cameraName}}. Reinicia Frigate per aplicar els canvis.",
"normal": "Normal"
},
"description": "Afegiu, editeu i suprimiu les càmeres, controleu quines càmeres estan habilitades, i configureu les superposicions per perfil i tipus de càmera. Per a configurar fluxos, detecció, moviment i altres paràmetres específics de la càmera, trieu la secció específica a Configuració de la càmera."
"description": "Afegiu, editeu i suprimiu les càmeres, controleu l'estat de cada càmera, i configureu les superposicions per perfil i tipus de càmera. Per a configurar fluxos, detecció, moviment i altres paràmetres específics de la càmera, trieu la secció específica a Configuració de la càmera.",
"clone": {
"sectionTitle": "Clona la configuració",
"sectionDescription": "Copia la configuració d'una càmera a una altra càmera o una de nova.",
"button": "Clona la configuració",
"title": "Clona la configuració de la càmera",
"description": "Copia la configuració d'una càmera a una o més càmeres o a una càmera nova. La identitat (nom, nom amigable, URL de la interfície d'usuari web, ordre de visualització) no es copia mai.",
"source": {
"label": "Càmera d'origen",
"placeholder": "Seleccioneu una càmera d'origen",
"required": "Seleccioneu una càmera d'origen"
},
"target": {
"legend": "Objectiu",
"newRadio": "Càmara nova",
"newNameLabel": "Nom de la càmera",
"newNamePlaceholder": "p. ex., porta enrere orporta o porta posterior",
"newNameInvalid": "Es requereix el nom de la càmera",
"newNameCollision": "Ja existeix una càmera amb aquest nom",
"newStreamsForced": "Els fluxos sempre es copien per a una càmera nova.",
"existingCamerasRadio": "Càmeres existents",
"allCameras": "Totes les càmeres",
"existingPlaceholder": "Selecciona almenys una càmera",
"existingDisabled": "No hi ha cap altra càmera a la qual copiar",
"newNameRequired": "Es requereix el nom de la càmera"
},
"categories": {
"legend": "Configuració per clonar",
"description": "Trieu quina configuració voleu copiar de la càmera d'origen.",
"selectAll": "Selecciona-ho tot",
"selectNone": "No en seleccioneu cap",
"resetDefaults": "Restableix als valors predeterminats",
"general": "General",
"spatial": "Paràmetres espacials",
"streams": "Fluxos",
"spatialWarningTitle": "La resolució no coincideix",
"spatialWarning": "La càmera d'origen {{srcCamera}} detecta la resolució ({{srcWidth}}.{{srcHeight}}) difereix de: {{cameras}}. És possible que els polígons no s'alineïn en aquestes càmeres. Aquests valors predeterminats estan desactivats; habiliteu-ho per a copiar tal qual.",
"restartHint": "Reinicia requerit",
"items": {
"record": "Enregistrament",
"snapshots": "Instantànies",
"review": "Revisió",
"motion": "Detecció de moviment",
"objects": "Objectes",
"audio": "Detecció d'àudio",
"audio_transcription": "Transcripció d'àudio",
"notifications": "Notificacions",
"birdseye": "Birdseye",
"timestamp_style": "Estil de la marca horària",
"lpr": "Reconeixement de la matrícula",
"face_recognition": "Reconeixement de cares",
"semantic_search": "Cerca semàntica",
"genai": "IA generativa",
"type": "Tipus de càmera (LPR normal / dedicat)",
"profiles": "Perfils",
"detect": "Detecta les dimensions",
"zones": "Zones",
"motion_mask": "Màscares de moviment",
"object_masks": "Màscares d'objecte",
"ffmpeg_live": "URL i rols de flux",
"mqtt": "MQTT",
"onvif": "ONVIF"
}
},
"footer": {
"changeCount_one": "{{count}} s'aplicarà el canvi",
"changeCount_many": "{{count}} canvis s'aplicaran",
"changeCount_other": "{{count}} canvis s'aplicaran",
"restartNeeded": "Es requerirà reiniciar per a alguns canvis.",
"liveOnly": "Tots els canvis s'aplicaran en viu sense reiniciar.",
"submit": "Clona",
"submitting": "S'està clonant…"
},
"toast": {
"success": "Configuració copiada a {{cameraName}}",
"successWithRestart": "Configuració copiada a {{cameraName}}. Reinicia Frigate per aplicar tots els canvis.",
"successMulti_one": "Configuració copiada a la càmera {{count}}",
"successMulti_many": "Configuració copiada a {{count}} càmeres",
"successMulti_other": "Configuració copiada a {{count}} càmeres",
"successMultiWithRestart_one": "Configuració copiada a la càmera {{count}}. Reinicia Frigate per aplicar tots els canvis.",
"successMultiWithRestart_many": "Configuració copiada a {{count}} càmeres. Reinicia Frigate per aplicar tots els canvis.",
"successMultiWithRestart_other": "Configuració copiada a {{count}} càmeres. Reinicia la fragata per aplicar tots els canvis.",
"partialFailure": "{{successCount}} seccions aplicades; «{{failedSection}}» ha fallat: {{errorMessage}}",
"partialFailureMulti": "S'ha copiat a {{successCount}} càmera(es); ha fallat {{failed}}: {{errorMessage}}",
"newCameraPartialFailure": "S'ha creat la càmera {{cameraName}} però no s'han pogut copiar alguns paràmetres: {{errorMessage}}",
"sourceMissing": "La càmera d'origen ja no existeix",
"submitError": "No s'ha pogut clonar la càmera: {{errorMessage}}"
}
}
},
"cameraReview": {
"object_descriptions": {
@ -1499,7 +1609,7 @@
"desc": "La quadrícula de regions és una optimització que aprèn on solen aparèixer objectes de diferents mides en el camp de visió de cada càmera. Frigate utilitza aquestes dades per detectar regions de mida eficient. La quadrícula es construeix automàticament amb el temps a partir de dades d'objectes rastrejats.",
"clear": "Neteja la quadrícula de la regió",
"clearConfirmTitle": "Neteja la quadrícula de la regió",
"clearConfirmDesc": "No es recomana netejar la quadrícula de la regió tret que hagi canviat recentment la mida del model del detector o hagi canviat la posició física de la càmera i tingui problemes de seguiment d'objectes. La quadrícula es reconstruirà automàticament amb el temps a mesura que els objectes siguin rastrejats. Es requereix un reinici de la fragata perquè els canvis tinguin efecte.",
"clearConfirmDesc": "No es recomana netejar la quadrícula de la regió tret que hagi canviat recentment la mida del model del detector o hagi canviat la posició física de la càmera i tingui problemes de seguiment d'objectes. La quadrícula es reconstruirà automàticament amb el temps a mesura que els objectes siguin rastrejats. Es requereix un reinici de Frigate perquè els canvis tinguin efecte.",
"clearSuccess": "La quadrícula de la regió s'ha netejat correctament",
"clearError": "Ha fallat en netejar la graella de la regió",
"restartRequired": "Cal reiniciar per a que els canvis de la quadrícula de la regió tinguin efecte"
@ -1674,7 +1784,7 @@
"searchPlaceholder": "Cerca...",
"genaiRoles": {
"options": {
"embeddings": "Incrustació",
"embeddings": "Vectors",
"vision": "Visió",
"tools": "Eines",
"descriptions": "Descripcions",
@ -1693,13 +1803,43 @@
},
"addCustomLabel": "Afegeix una etiqueta personalitzada...",
"genaiModel": {
"placeholder": "Selecciona el model…",
"search": "Cerca models…",
"noModels": "No hi ha models disponibles"
"placeholder": "Seleccioneu o introduïu un model…",
"search": "Cerca o introdueix un model…",
"noModels": "No hi ha models disponibles",
"available": "Models disponibles",
"useCustom": "Utilitza \"{{value}}\"",
"refresh": "Actualitza els models",
"probeFailed": "No s'han pogut investigar els models",
"fetchedModels": "S'ha obtingut correctament la llista de models"
},
"knownPlates": {
"namePlaceholder": "per exemple. Cotxe de la parella",
"platePlaceholder": "Matricula o regex"
},
"semanticSearchModelSize": {
"notApplicable": "No aplicable als proveïdors de GenAI"
},
"liveStreams": {
"streamNameLabel": "Nom del flux",
"streamNamePlaceholder": "p. ex., corrent HD principal",
"go2rtcStreamLabel": "flux go2rtc",
"go2rtcStreamPlaceholder": "Selecciona un flux go2rtc",
"go2rtcStreamSearch": "Cerca o introdueix un nom de flux…",
"noGo2rtcStreams": "No s'ha configurat cap flux go2rtc",
"availableStreams": "Fluxos disponibles",
"useCustom": "Utilitza \"{{value}}\"",
"addStream": "Afegeix un flux"
},
"ptzPresets": {
"placeholder": "Selecciona o entra una configuració...",
"search": "Busca o entra una configuració...",
"noPresets": "No hi ha configuracions disponibles",
"available": "Parámetres de Cámera",
"useCustom": "Usa \"{{value}}\""
},
"defaultRole": {
"admin": "Administrar",
"viewer": "Visor"
}
},
"globalConfig": {
@ -1736,9 +1876,9 @@
"saveAllPartial_other": "{{successCount}} de {{totalCount}} seccions desades. {{failCount}} ha fallat.",
"saveAllFailure": "Ha fallat en desar totes les seccions.",
"applied": "La configuració s'ha aplicat correctament",
"saveAllSuccessRestartRequired_one": "S'ha desat la secció {{count}} correctament. Reinicia la fragata per aplicar els canvis.",
"saveAllSuccessRestartRequired_many": "Totes les {{count}} seccions s'han desat correctament. Reinicia la fragata per aplicar els canvis.",
"saveAllSuccessRestartRequired_other": "Totes les {{count}} seccions s'han desat correctament. Reinicia la fragata per aplicar els canvis."
"saveAllSuccessRestartRequired_one": "S'ha desat la secció {{count}} correctament. Reinicia Frigate per aplicar els canvis.",
"saveAllSuccessRestartRequired_many": "Totes les {{count}} seccions s'han desat correctament. Reinicia Frigate per aplicar els canvis.",
"saveAllSuccessRestartRequired_other": "Totes les {{count}} seccions s'han desat correctament. Reinicia Frigate per aplicar els canvis."
},
"unsavedChanges": "Teniu canvis sense desar",
"confirmReset": "Confirma el restabliment",
@ -1865,7 +2005,8 @@
"hardwareDxva2": "DXVA2",
"hardwareVideotoolbox": "VideoToolbox"
},
"streamNumber": "Flux {{index}}"
"streamNumber": "Flux {{index}}",
"sourceNumber": "Font {{index}}"
},
"timestampPosition": {
"tl": "A dalt a l'esquerra",
@ -1889,7 +2030,7 @@
"recordDisabled": "L'enregistrament està desactivat, els elements de revisió no es generaran.",
"detectDisabled": "La detecció d'objectes està desactivada. Els elements de revisió requereixen objectes detectats per categoritzar alertes i deteccions.",
"allNonAlertDetections": "Totes les activitats no alertes s'inclouran com a deteccions.",
"genaiImageSourceRecordingsRecordDisabled": "La font d'imatges està configurada com a 'enregistraments', però l'enregistrament està desactivat. La fragata tornarà a la vista prèvia de les imatges."
"genaiImageSourceRecordingsRecordDisabled": "La font d'imatges està configurada com a 'enregistraments', però l'enregistrament està desactivat. Frigate tornarà a la vista prèvia de les imatges."
},
"audio": {
"noAudioRole": "Cap flux té definit el rol d'àudio. Heu d'habilitar el rol d'àudio per a la detecció d'àudio perquè funcioni."
@ -1899,7 +2040,9 @@
},
"detect": {
"fpsGreaterThanFive": "No es recomana establir el detect FPS superior a 5. Els valors més alts poden causar problemes de rendiment i no proporcionaran cap benefici.",
"disabled": "La detecció d'objectes està desactivada. Les instantànies, articles de revisió i enriquiments com el reconeixement de rostres, el reconeixement de matrícules i la IA Generativa no funcionaran."
"disabled": "La detecció d'objectes està desactivada. Les instantànies, articles de revisió i enriquiments com el reconeixement de rostres, el reconeixement de matrícules i la IA Generativa no funcionaran.",
"resolutionShouldBeMultipleOfFour": "Per obtenir els millors resultats, detectar l'amplada i l'alçada han de ser múltiples de 4. Altres valors parells poden produir artefactes visuals o una lleugera distorsió en el flux de detecció.",
"aspectRatioMismatch": "L'amplada i alçada que heu introduït no coincideixen amb la relació d'aspecte de la resolució de detecció actual. Això pot produir una imatge estirada o distorsionada."
},
"faceRecognition": {
"globalDisabled": "L'enriquiment del reconeixement facial s'ha d'habilitar perquè les funcions de reconeixement facial funcionin en aquesta càmera.",
@ -1928,7 +2071,11 @@
"genaiNoDescriptionsProvider": "Heu de configurar un proveïdor de GenAI amb el rol 'descripcions' per a les descripcions que es generaran."
},
"semanticSearch": {
"jinav2SmallModelSize": "La mida 'petita' amb el model Jina V2 té un alt cost de RAM i d'inferència. Es recomana el model 'gran' amb una GPU discreta."
"jinav2SmallModelSize": "La mida 'petita' amb el model Jina V2 té un alt cost de RAM i d'inferència. Es recomana el model 'gran' amb una GPU discreta.",
"modelSizeIgnoredForProvider": "La mida del model només s'aplica als models de Jina incorporats. Aquest valor s'ignorarà quan s'utilitzi un proveïdor d'incrustació GenAI."
},
"onvif": {
"autotrackingNoZones": "Autotraquejar requereix al menys una zona. Defineix una zona per aquesta cámera a Mascares/Zones, després usa'l com a requerit a la part inferior."
}
},
"modelSize": {

View File

@ -66,10 +66,10 @@
},
"general": {
"detector": {
"memoryUsage": "Ús de memòria del detector",
"memoryUsage": "Ús de la memòria del detector",
"title": "Detectors",
"inferenceSpeed": "Velocitat d'inferència del detector",
"cpuUsage": "Ús de CPU del detector",
"cpuUsage": "Ús de la CPU del detector",
"temperature": "Temperatura del detector",
"cpuUsageInformation": "CPU usada en la preparació d'entrades i sortides desde/cap als models de detecció. Aquest valor no mesura l'utilització d'inferència, encara que usis una GPU o accelerador."
},
@ -118,11 +118,11 @@
"otherProcesses": {
"title": "Altres processos",
"processMemoryUsage": "Ús de memòria de procés",
"processCpuUsage": "Ús de la CPU del procés",
"processCpuUsage": "Ús de la CPU per procés",
"series": {
"recording": "gravant",
"review_segment": "segment de revisió",
"embeddings": "incrustacions",
"embeddings": "Vectors",
"audio_detector": "detector d'àudio",
"go2rtc": "go2rtc"
}
@ -220,7 +220,7 @@
},
"lastRefreshed": "Darrera actualització: ",
"stats": {
"reindexingEmbeddings": "Reindexant incrustacions ({{processed}}% completat)",
"reindexingEmbeddings": "Reindexant vectors ({{processed}}% completat)",
"healthy": "El sistema és saludable",
"cameraIsOffline": "{{camera}} està fora de línia",
"ffmpegHighCpuUsage": "{{camera}} te un ús elevat de CPU per FFmpeg ({{ffmpegAvg}}%)",
@ -234,14 +234,14 @@
"title": "Enriquiments",
"embeddings": {
"face_recognition_speed": "Velocitat de reconeixement facial",
"image_embedding": "Incrustació d'imatges",
"text_embedding": "Incrustació de text",
"image_embedding": "Vectors d'imatges",
"text_embedding": "Vectors de text",
"face_recognition": "Reconeixement de rostres",
"plate_recognition": "Reconeixemnt de matrícules",
"image_embedding_speed": "Velocitat d'ncrustació d'imatges",
"face_embedding_speed": "Velocitat d'incrustació de rostres",
"image_embedding_speed": "Velocitat de generació de vectors",
"face_embedding_speed": "Velocitat de generació de vectors facials",
"plate_recognition_speed": "Velocitat de reconeixement de matrícules",
"text_embedding_speed": "Velocitat d'incrustació de text",
"text_embedding_speed": "Velocitat de generació de vectors de text",
"yolov9_plate_detection": "Detecció de matrícules YOLOv9",
"yolov9_plate_detection_speed": "Velocitat de detecció de matrícules YOLOv9",
"review_description": "Descripció de la revisió",

View File

@ -193,7 +193,8 @@
"gl": "Galego (Galicisch)",
"id": "Bahasa Indonesia (Indonesisch)",
"hr": "Hrvatski (Kroatisch)",
"bs": "Bosnisch"
"bs": "Bosnisch",
"zhHant": "Traditional Chinese"
},
"appearance": "Erscheinung",
"theme": {
@ -326,5 +327,8 @@
"separatorWithSpace": ", "
},
"no_items": "Keine Artikel",
"validation_errors": "Validierungsfehler"
"validation_errors": "Validierungsfehler",
"credentialField": {
"savedPlaceholder": "Gespeichert leer lassen, um den aktuellen Stand beizubehalten"
}
}

View File

@ -48,5 +48,6 @@
"submittedFrigatePlus": "Bild erfolgreich an Frigate+ gesendet"
}
},
"noPreviewFoundFor": "Keine Vorschau für {{cameraName}} gefunden"
"noPreviewFoundFor": "Keine Vorschau für {{cameraName}} gefunden",
"cameraOff": "Kamera ist ausgeschaltet"
}

View File

@ -9,7 +9,7 @@
"description": "Aktiviert"
},
"audio": {
"label": "Audioerkennung",
"label": "Audioereignisse",
"description": "Einstellungen für audiobasierte Ereigniserkennung für diese Kamera.",
"enabled": {
"label": "Aktivieren der Audioerkennung",
@ -826,7 +826,7 @@
},
"timestamp_style": {
"label": "Format für Zeitstempel",
"description": "Gestaltungsmöglichkeiten für Zeitstempel im Feed, die auf Aufzeichnungen und Momentaufnahmen angewendet werden.",
"description": "Gestaltungsoptionen für Zeitstempel, die auf Momentaufnahmen und die Debug-Ansicht angewendet werden.",
"position": {
"label": "Position des Zeitstempels",
"description": "Position des Zeitstempels auf dem Bild (tl/tr/bl/br)."

View File

@ -8,7 +8,7 @@
"description": "Wenn aktiviert, startet Frigate im abgesicherten Modus mit reduzierten Features für die Fehlersuche."
},
"audio": {
"label": "Audioerkennung",
"label": "Audioereignisse",
"enabled": {
"label": "Aktivieren der Audioerkennung",
"description": "Aktivieren oder deaktivieren Sie die Erkennung von Audioereignissen für alle Kameras; diese Einstellung kann für jede Kamera individuell überschrieben werden."
@ -496,7 +496,7 @@
},
"default_role": {
"label": "Standardrolle",
"description": "Standardrolle, die proxy-authentifizierten Benutzern zugewiesen wird, wenn keine Rollenzuordnung gilt (Admin oder Betrachter)."
"description": "Standardrolle, die proxy-authentifizierten Benutzern zugewiesen wird, wenn keine Rollenzuordnung vorliegt."
},
"separator": {
"label": "Trennzeichen",
@ -1279,6 +1279,41 @@
},
"raw_mask": {
"label": "Rohmaske"
},
"filters_attribute": {
"label": "Attributfilter",
"description": "Auf erkannte Attribute angewendete Filter zur Reduzierung von Fehlalarmen (Fläche, Verhältnis, Konfidenz).",
"min_area": {
"label": "Mindestfläche des Attributs",
"description": "Für dieses Attribut erforderliche Mindestfläche des Begrenzungsrahmens (in Pixeln oder Prozent). Kann als Pixelwert (Ganzzahl) oder als Prozentwert (Gleitkommawert zwischen 0,000001 und 0,99) angegeben werden."
},
"max_area": {
"label": "Maximale Attributfläche",
"description": "Maximal zulässige Fläche des Begrenzungsrahmens (in Pixeln oder Prozent) für dieses Attribut. Kann als Pixelwert (Ganzzahl) oder als Prozentwert (Gleitkommawert zwischen 0,000001 und 0,99) angegeben werden."
},
"min_ratio": {
"label": "Mindestseitenverhältnis",
"description": "Erforderliches Mindestverhältnis von Breite zu Höhe, damit die Begrenzungsbox die Anforderungen erfüllt."
},
"max_ratio": {
"label": "Maximales Seitenverhältnis",
"description": "Maximal zulässiges Verhältnis von Breite zu Höhe für die Begrenzungsbox, damit diese die Anforderungen erfüllt."
},
"threshold": {
"label": "Konfidenzschwelle",
"description": "Durchschnittlicher Schwellenwert für die Erkennungssicherheit, der erforderlich ist, damit das Merkmal als echtes Positiv gewertet wird."
},
"min_score": {
"label": "Mindestvertrauen",
"description": "Mindestwert für die Erkennungssicherheit eines einzelnen Bildes, der erforderlich ist, um dieses Attribut seinem übergeordneten Objekt zuzuordnen."
},
"mask": {
"label": "Filtermaske",
"description": "Polygonkoordinaten, die festlegen, wo dieser Filter innerhalb des Bildausschnitts angewendet wird."
},
"raw_mask": {
"label": "Rohmaske"
}
}
},
"record": {

View File

@ -28,5 +28,8 @@
"detectRequired": "Es muss mindestens ein input stream die Rolle 'erkennen' tragen.",
"hwaccelDetectOnly": "Nur der input-stream mit der Rolle 'erkennen' kann Hardwarebeschleunigungs Argumente definieren."
}
},
"detect": {
"dimensionMustBeEven": "Es muss eine gerade Zahl sein."
}
}

View File

@ -60,5 +60,13 @@
"stats": {
"context": "{{tokens}} tokens",
"tokens_per_second": "{{rate}} t/s"
},
"reasoning": {
"active": "Begründung…",
"show": "Begründung anzeigen",
"hide": "Begründung ausblenden"
},
"thinking": {
"toggle": "Umschalten"
}
}

View File

@ -144,7 +144,9 @@
},
"camera": {
"enable": "Kamera aktivieren",
"disable": "Kamera deaktivieren"
"disable": "Kamera deaktivieren",
"turnOn": "Schalte die Kamera ein",
"turnOff": "Schalte die Kamera aus"
},
"audioDetect": {
"enable": "Audioerkennung aktivieren",
@ -162,7 +164,8 @@
"autotracking": "Autotracking",
"audioDetection": "Audioerkennung",
"title": "{{camera}} Einstellungen",
"transcription": "Audio Transkription"
"transcription": "Audio Transkription",
"camera": "Kamera"
},
"history": {
"label": "Historisches Filmmaterial zeigen"

View File

@ -24,7 +24,9 @@
"points_one": "{{count}} Punkt",
"points_other": "{{count}} Punkte",
"undo": "Letzten Schritt rückgängig machen",
"reset": "Polygon zurücksetzen"
"reset": "Polygon zurücksetzen",
"drawMode": "ziehen",
"moveMode": "bewegen"
},
"motionHeatmapLabel": "Bewegungs-Heatmap",
"dialog": {

View File

@ -16,7 +16,8 @@
"globalConfig": "Grundeinstellungen - Frigate",
"cameraConfig": "Kameraeinstellungen - Frigate",
"maintenance": "Wartung - Frigate",
"profiles": "Profile - Frigate"
"profiles": "Profile - Frigate",
"detectorsAndModel": "Sensoren und Modell Frigate"
},
"menu": {
"ui": "Benutzeroberfläche",
@ -31,7 +32,7 @@
"enrichments": "Erkennungsfunktionen",
"triggers": "Auslöser",
"roles": "Rollen",
"cameraManagement": "Verwaltung",
"cameraManagement": "Kamera Verwaltung",
"cameraReview": "Überprüfung",
"system": "System",
"general": "allgemein",
@ -92,7 +93,8 @@
"uiSettings": "Benutzeroberfläche Einstellung",
"profiles": "Profile",
"systemGo2rtcStreams": "go2rtc-streams",
"maintenance": "Wartung"
"maintenance": "Wartung",
"systemDetectorsAndModel": "Detektoren und Modell"
},
"dialog": {
"unsavedChanges": {
@ -728,7 +730,8 @@
"notificationUnavailable": {
"title": "Benachrichtigungen nicht verfügbar",
"desc": "Web Push Benachrichtigungen erfordern einen sicheren Kontext (<code>https://…</code>). Das ist eine Vorgabe des Browsers. Greife auf Frigate gesichert zu um Benachrichtigungen zu nutzen.",
"documentation": "Dokumentation lesen"
"documentation": "Dokumentation lesen",
"descPwa": "Unter iOS sind Web-Push-Benachrichtigungen nur verfügbar, wenn Frigate auf Ihrem Startbildschirm installiert ist. Öffnen Sie das Menü <strong>Teilen</strong>, wählen Sie <strong>Zum Startbildschirm hinzufügen</strong> und öffnen Sie Frigate über das neue Symbol, um dieses Gerät für Benachrichtigungen zu registrieren."
},
"cameras": {
"desc": "Wähle aus für welche Kameras Benachrichtigungen aktiviert werden sollen.",
@ -800,7 +803,7 @@
"cameras": "Kameras",
"loading": "Lade Model Informationen…",
"error": "Model Informationen laden fehlgeschlagen",
"availableModels": "Verfügbare Modelle",
"availableModels": "Verfügbare Frigate+ Modelle",
"loadingAvailableModels": "Lade verfügbare Modelle…",
"baseModel": "Basis Model",
"title": "Model Informationen",
@ -825,7 +828,8 @@
"currentModel": "Aktuelles Modell",
"otherModels": "Anderes Modell",
"configuration": "Konfiguration"
}
},
"changeInDetectorsAndModel": "Modell wechseln"
},
"enrichments": {
"birdClassification": {
@ -1133,7 +1137,7 @@
"brands": {
"reolink-rtsp": "Reolink RTSP wird nicht empfohlen. Es wird empfohlen, http in den Kameraeinstellungen zu aktivieren und den Kamera-Assistenten neu zu starten."
},
"customUrlRtspRequired": "Benutzerdefinierte URLs müssen mit „rtsp://“ beginnen. Für Nicht-RTSP-Kamerastreams ist eine manuelle Konfiguration erforderlich."
"customUrlRtspRequired": "Benutzerdefinierte URLs müssen mit „rtsp://“ oder \"rtsps://\" beginnen. Für Nicht-RTSP-Kamerastreams ist eine manuelle Konfiguration erforderlich."
},
"docs": {
"reolink": "https://docs.frigate.video/configuration/camera_specific.html#reolink-cameras"
@ -1353,19 +1357,41 @@
"selectCamera": "Wähle eine Kamera",
"backToSettings": "Zurück zu Kameraeinstellungen",
"streams": {
"title": "Kameras aktivieren / deaktivieren",
"title": "Kamerastatus und Details",
"desc": "Deaktiviere eine Kamera vorübergehend, bis Frigate neu gestartet wird. Deaktivierung einer Kamera stoppt die Verarbeitung der Streams dieser Kamera durch Frigate vollständig. Erkennung, Aufzeichnung und Debugging sind dann nicht mehr verfügbar. <br /> <em>Hinweis: Dies deaktiviert nicht die go2rtc restreams.</em>",
"enableLabel": "Aktivierte Kameras",
"enableDesc": "</em>Eine aktivierte Kamera vorübergehend deaktivieren, bis Frigate neu gestartet wird. Durch das Deaktivieren einer Kamera wird die Verarbeitung der Streams dieser Kamera durch Frigate vollständig unterbrochen. Erkennung, Aufzeichnung und Fehlerbehebung stehen dann nicht mehr zur Verfügung.<br /><em> Hinweis: go2rtc-Restreams werden dadurch nicht deaktiviert.</em>",
"disableLabel": "Deaktivierte Kameras",
"disableDesc": "Aktivieren Sie eine Kamera, die derzeit in der Benutzeroberfläche nicht sichtbar und in der Konfiguration deaktiviert ist. Nach der Aktivierung ist ein Neustart von Frigate erforderlich.",
"enableSuccess": "{{cameraName}} wurde in der Konfiguration aktiviert. Starte Frigate neu, um die Änderungen zu übernehmen.",
"enableSuccess": "{{cameraName}} wurde aktiviert. Starte Frigate neu, um die Änderung zu übernehmen.",
"friendlyName": {
"edit": "Anzeigenamen der Kamera bearbeiten",
"title": "Anzeigenamen bearbeiten",
"description": "Legen Sie den Anzeigenamen fest, der für diese Kamera in der gesamten Benutzeroberfläche von „Frigate“ angezeigt wird. Lassen Sie das Feld leer, um die Kamera-ID zu verwenden.",
"rename": "Umbenennen"
}
},
"reorderHandle": "Zum Neuanordnen ziehen",
"saving": "Speichern…",
"saved": "gespeichert",
"details": {
"edit": "Kameradaten bearbeiten",
"title": "Kameradaten bearbeiten",
"description": "Aktualisieren Sie den Anzeigenamen und die externe URL, die für diese Kamera in der gesamten Frigate-Benutzeroberfläche verwendet werden.",
"friendlyNameLabel": "Display Name",
"friendlyNameHelp": "Der in der Benutzeroberfläche von „Frigate“ für diese Kamera angezeigte Spitzname. Lassen Sie das Feld leer, um die Kamera-ID zu verwenden.",
"webuiUrlLabel": "URL der Web-Benutzeroberfläche",
"webuiUrlHelp": "URL, um die Web-Benutzeroberfläche der Kamera direkt aus der Debug-Ansicht aufzurufen. Lassen Sie das Feld leer, um den Link zu deaktivieren.",
"webuiUrlInvalid": "Es muss sich um eine gültige URL handeln (z. B. https://example.com)."
},
"label": "Kamerazustand",
"description": "Legen Sie den Betriebszustand für jede Kamera fest.<br /><br /><strong>Ein</strong>: Streams werden normal verarbeitet.<br /><strong>Aus</strong>: Die Verarbeitung wird vorübergehend angehalten. Diese Einstellung bleibt bei einem Neustart von Frigate nicht erhalten.<br /><strong>Deaktiviert</strong>: Die Verarbeitung wird beendet und die Änderung in Ihrer Konfiguration gespeichert. Um eine deaktivierte Kamera wieder zu aktivieren, ist ein Neustart erforderlich.<br /><br /><em>Hinweis: Die Deaktivierung hat keine Auswirkungen auf go2rtc-Restreams.</em><br /><br />Ziehen Sie den Griff, um die Reihenfolge der aktiven Kameras in der Benutzeroberfläche anzupassen, einschließlich des Live-Dashboards und der Dropdown-Menüs zur Kameraauswahl.",
"disabledSubheading": "In der Konfiguration deaktiviert",
"status": {
"on": "Eingeschaltet",
"off": "Ausgeschaltet",
"disabled": "Deaktiviert"
},
"disableSuccess": "{{cameraName}} wurde deaktiviert und in der Konfiguration gespeichert."
},
"cameraConfig": {
"add": "Kamera hinzufügen",
@ -1411,20 +1437,107 @@
"profiles": {
"title": "Profilkameraumschaltungen",
"selectLabel": "Profil auswählen",
"description": "Legen Sie fest, welche Kameras bei der Aktivierung eines Profils aktiviert oder deaktiviert werden sollen. Kameras, für die „Übernehmen“ eingestellt ist, behalten ihren ursprünglichen Aktivierungsstatus bei.",
"description": "Legen Sie fest, welche Kameras bei der Aktivierung eines Profils ein- oder ausgeschaltet werden. Kameras, die auf „Übernehmen“ eingestellt sind, behalten ihren Standardzustand bei.",
"inherit": "Erben",
"enabled": "Aktiviert",
"disabled": "Deaktiviert"
"disabled": "Deaktiviert",
"on": "Eingeschaltet",
"off": "Ausgeschaltet"
},
"cameraType": {
"title": "Kamerytyp",
"label": "Kameratyp",
"title": "Kamera Art",
"label": "Kamera Art",
"description": "Legen Sie den Kameratyp für jede Kamera fest. Spezielle LPR-Kameras sind Kameras mit leistungsstarkem optischen Zoom, um Kennzeichen von weit entfernten Fahrzeugen zu erfassen. Für die meisten Kameras sollte der normale Kameratyp verwendet werden, es sei denn, die Kamera ist speziell für LPR vorgesehen und verfügt über einen stark fokussierten Blickwinkel auf die Kennzeichen.",
"normal": "Normal",
"dedicatedLpr": "Spezielles LPR-System",
"saveSuccess": "Der Kameratyp für {{cameraName}} wurde aktualisiert. Starte Frigate neu, um die Änderungen zu übernehmen."
},
"description": "Fügen Sie Kameras hinzu, bearbeiten und löschen Sie sie, legen Sie fest, welche Kameras aktiviert sind, und konfigurieren Sie profil- und kameratypabhängige Übersteuerungen. Um Streams, Erkennung, Bewegung und andere kameraspezifische Einstellungen zu konfigurieren, wählen Sie den entsprechenden Abschnitt unter „Kamerakonfiguration“ aus."
"description": "Fügen Sie Kameras hinzu, bearbeiten und löschen Sie sie, steuern Sie den Status jeder einzelnen Kamera und konfigurieren Sie profil- und kameratypabhängige Übersteuerungen. Um Streams, Erkennung, Bewegung und andere kameraspezifische Einstellungen zu konfigurieren, wählen Sie den entsprechenden Abschnitt unter „Kamerakonfiguration“ aus.",
"clone": {
"sectionTitle": "Einstellungen klonen",
"sectionDescription": "Konfiguration von einer Kamera auf eine andere oder eine neue Kamera kopieren.",
"button": "Einstellungen klonen",
"title": "Kameraeinstellungen kopieren",
"description": "Kopieren Sie die Konfiguration einer Kamera auf eine oder mehrere andere Kameras oder auf eine neue Kamera. Die Identitätsdaten (Name, Anzeigename, URL der Web-Benutzeroberfläche, Anzeigereihenfolge) werden dabei nicht kopiert.",
"source": {
"label": "Quellkamera",
"placeholder": "Wählen Sie eine Quellkamera aus",
"required": "Wählen Sie eine Quellkamera aus"
},
"target": {
"legend": "Ziel",
"newRadio": "Neue Kamera",
"newNameLabel": "Kamera Name",
"newNamePlaceholder": "z. B. back_door oder Back Door",
"newNameRequired": "Kamera Name ist erforderlich",
"newNameInvalid": "ungültiger Kamera Name",
"newNameCollision": "Eine Kamera mit diesem Namen gibt es bereits",
"newStreamsForced": "Streams werden bei einer neuen Kamera immer kopiert.",
"existingCamerasRadio": "Vorhandene Kameras",
"allCameras": "Alle Kameras",
"existingPlaceholder": "Wählen Sie mindestens eine Kamera aus",
"existingDisabled": "Es gibt keine weiteren Kameras, auf die kopiert werden kann"
},
"categories": {
"legend": "Zu klonende Einstellungen",
"description": "Wählen Sie aus, welche Einstellungen von der Quellkamera kopiert werden sollen.",
"selectAll": "Alle auswählen",
"selectNone": "Keine auswählen",
"resetDefaults": "Auf Standardwerte zurücksetzen",
"general": "Allgemeines",
"spatial": "Räumliche Rahmenbedingungen",
"streams": "Streams",
"spatialWarningTitle": "Auflösungsdiskrepanz",
"spatialWarning": "Die Quellkamera {{srcCamera}} hat eine andere Auflösung ({{srcWidth}}×{{srcHeight}}) als: {{cameras}}. Die Polygone sind möglicherweise nicht auf diese Kameras ausgerichtet. Diese Standardeinstellungen sind deaktiviert; aktivieren Sie sie, um die Daten unverändert zu kopieren.",
"restartHint": "Neustart erforderlich",
"items": {
"record": "Aufnahme",
"snapshots": "Momentaufnahmen",
"motion": "Bewegungserkennung",
"objects": "Objekte",
"audio": "Tonerkennung",
"audio_transcription": "Audio-Transkription",
"notifications": "Benachrichtigungen",
"birdseye": "Birdseye",
"mqtt": "MQTT",
"timestamp_style": "Format für Zeitstempel",
"onvif": "ONVIF",
"lpr": "Kennzeichenerkennung",
"face_recognition": "Gesichtserkennung",
"semantic_search": "Semantische Suche",
"genai": "Generative AI",
"type": "Kameratyp (Standard / speziell für Kennzeichenerkennung)",
"profiles": "Profile",
"detect": "Abmessungen ermitteln",
"zones": "Zonen",
"motion_mask": "Bewegungsmaske",
"object_masks": "Objektmaske",
"ffmpeg_live": "Stream-URLs und Rollen",
"review": "Rezension"
}
},
"footer": {
"restartNeeded": "Für einige Änderungen ist ein Neustart erforderlich.",
"liveOnly": "Alle Änderungen werden sofort wirksam, ohne dass ein Neustart erforderlich ist.",
"submit": "Klon",
"submitting": "Klonen…",
"changeCount_one": "Die Änderung von {{count}} wird übernommen",
"changeCount_other": "Die Änderungen von {{count}} werden übernommen"
},
"toast": {
"success": "Einstellungen wurden auf {{cameraName}} kopiert",
"successWithRestart": "Die Einstellungen wurden auf {{cameraName}} kopiert. Starte Frigate neu, um alle Änderungen zu übernehmen.",
"successMulti_one": "Einstellungen wurden auf {{count}} Kamera kopiert",
"successMulti_other": "Einstellungen wurden auf {{count}} Kameras kopiert",
"successMultiWithRestart_one": "Die Einstellungen wurden auf die Kamera {{count}} kopiert. Starte Frigate neu, um alle Änderungen zu übernehmen.",
"successMultiWithRestart_other": "Die Einstellungen wurden auf {{count}} Kameras kopiert. Starten Sie Frigate neu, um alle Änderungen zu übernehmen.",
"partialFailure": "{{successCount}} Abschnitte wurden angewendet; '{{failedSection}}' ist fehlgeschlagen: {{errorMessage}}",
"partialFailureMulti": "{{successCount}} Kamera(s) wurden kopiert; bei {{failed}} ist ein Fehler aufgetreten: {{errorMessage}}",
"newCameraPartialFailure": "Die Kamera {{cameraName}} wurde erstellt, einige Einstellungen konnten jedoch nicht kopiert werden: {{errorMessage}}",
"sourceMissing": "Die Quellkamera existiert nicht mehr",
"submitError": "Das Klonen der Kamera ist fehlgeschlagen: {{errorMessage}}"
}
}
},
"cameraReview": {
"title": "Kamera-Einstellungen überprüfen",
@ -1773,9 +1886,39 @@
"platePlaceholder": "Kennzeichen oder regulärer Ausdruck"
},
"genaiModel": {
"placeholder": "Modell auswählen…",
"search": "Modell suchen…",
"noModels": "Keine Modelle verfügbar"
"placeholder": "Modell auswählen oder eingeben…",
"search": "Modell suchen oder eingeben…",
"noModels": "Keine Modelle verfügbar",
"available": "Verfügbare Modelle",
"useCustom": "Verwende „{{value}}“",
"refresh": "Modelle aktualisieren",
"probeFailed": "Das Abrufen der Modelle ist fehlgeschlagen",
"fetchedModels": "Modellliste erfolgreich abgerufen"
},
"semanticSearchModelSize": {
"notApplicable": "Gilt nicht für GenAI-Anbieter"
},
"liveStreams": {
"streamNameLabel": "Streamname",
"streamNamePlaceholder": "z. B. Haupt-HD-Stream",
"go2rtcStreamLabel": "go2rtc stream",
"go2rtcStreamPlaceholder": "Wählen Sie einen go2rtc-Stream aus",
"go2rtcStreamSearch": "Suchen Sie nach einem Streamnamen oder geben Sie ihn ein…",
"noGo2rtcStreams": "Es sind keine go2rtc-Streams konfiguriert",
"availableStreams": "Verfügbare Streams",
"useCustom": "Verwende „{{value}}“",
"addStream": "Stream hinzufügen"
},
"ptzPresets": {
"placeholder": "Wählen Sie eine Voreinstellung aus oder geben Sie eine ein...",
"search": "Suchen oder eine Voreinstellung eingeben...",
"noPresets": "Es sind keine Voreinstellungen verfügbar",
"available": "Kamera-Voreinstellungen",
"useCustom": "Verwende „{{value}}“"
},
"defaultRole": {
"admin": "Admin",
"viewer": "Betrachter"
}
},
"globalConfig": {
@ -1809,7 +1952,9 @@
"saveAllSuccess_other": "Alle {{count}} Abschnitte wurden erfolgreich gespeichert.",
"saveAllPartial_one": "{{successCount}} von {{totalCount}} Abschnitt wurden gespeichert. {{failCount}} sind fehlgeschlagen.",
"saveAllPartial_other": "{{successCount}} von {{totalCount}} Abschnitten wurden gespeichert. {{failCount}} sind fehlgeschlagen.",
"saveAllFailure": "Es konnten nicht alle Abschnitte gespeichert werden."
"saveAllFailure": "Es konnten nicht alle Abschnitte gespeichert werden.",
"saveAllSuccessRestartRequired_one": "Der Abschnitt {{count}} wurde erfolgreich gespeichert. Starte Frigate neu, um die Änderungen zu übernehmen.",
"saveAllSuccessRestartRequired_other": "Alle {{count}} Abschnitte wurden erfolgreich gespeichert. Starte Frigate neu, um die Änderungen zu übernehmen."
},
"profiles": {
"title": "Profile",
@ -1896,8 +2041,18 @@
"audioMp3": "Transcode zu MP3",
"audioExclude": "Ausschließen",
"hardwareNone": "Keine Hardwarebeschleunigung",
"hardwareAuto": "Automatische Hardwarebeschleunigung"
}
"hardwareAuto": "Automatisch (empfohlen)",
"hardwareVaapi": "VAAPI",
"hardwareCuda": "CUDA",
"hardwareV4l2m2m": "V4L2 M2M",
"hardwareDxva2": "DXVA2",
"hardwareVideotoolbox": "VideoToolbox",
"addVideoCodec": "Videocodec hinzufügen",
"addAudioCodec": "Audio-Codec hinzufügen",
"removeCodec": "Codec entfernen"
},
"streamNumber": "Stream {{index}}",
"sourceNumber": "Quelle {{index}}"
},
"onvif": {
"profileAuto": "Auto",
@ -1925,7 +2080,9 @@
},
"detect": {
"fpsGreaterThanFive": "Es wird nicht empfohlen, den Wert für die FPS-Erkennung auf mehr als 5 zu setzen. Höhere Werte können zu Leistungseinbußen führen und bieten keinerlei Vorteile.",
"disabled": "Die Objekterkennung ist deaktiviert. Momentaufnahmen, Überprüfungselemente und Erweiterungsfunktionen wie Gesichtserkennung, Kennzeichenerkennung und generative KI funktionieren nicht."
"disabled": "Die Objekterkennung ist deaktiviert. Momentaufnahmen, Überprüfungselemente und Erweiterungsfunktionen wie Gesichtserkennung, Kennzeichenerkennung und generative KI funktionieren nicht.",
"resolutionShouldBeMultipleOfFour": "Um optimale Ergebnisse zu erzielen, sollten Breite und Höhe ein Vielfaches von 4 sein. Andere gerade Werte können zu visuellen Artefakten oder leichten Verzerrungen im Erkennungsstrom führen.",
"aspectRatioMismatch": "Die von Ihnen eingegebene Breite und Höhe stimmen nicht mit dem Seitenverhältnis Ihrer aktuell erkannten Auflösung überein. Dies kann zu einem gestreckten oder verzerrten Bild führen."
},
"faceRecognition": {
"globalDisabled": "Die Gesichtserkennungserweiterung muss aktiviert sein, damit die Gesichtserkennungsfunktionen bei dieser Kamera funktionieren.",
@ -1955,6 +2112,9 @@
},
"semanticSearch": {
"jinav2SmallModelSize": "Die „kleine“ Variante des Jina V2-Modells verursacht hohe RAM- und Inferenzkosten. Es wird das „große“ Modell mit einer dedizierten GPU empfohlen."
},
"onvif": {
"autotrackingNoZones": "Für die automatische Verfolgung ist mindestens eine Zone erforderlich. Definieren Sie unter „Masken / Zonen“ eine Zone für diese Kamera und legen Sie diese anschließend unten als erforderliche Zone fest."
}
},
"birdseye": {
@ -1962,6 +2122,13 @@
"objects": "Objekte",
"motion": "Bewegung",
"continuous": "Fortlaufend"
},
"cameraOrder": {
"label": "Kamerabestellung",
"description": "Ziehe die Kameras per Drag & Drop, um ihre Reihenfolge im Birdseye-Layout festzulegen.",
"reorderHandle": "Zum Neuanordnen ziehen",
"saving": "Wird gespeichert…",
"saved": "gespeichert"
}
},
"retainMode": {
@ -2011,5 +2178,35 @@
"modelSize": {
"small": "klein",
"large": "groß"
},
"menuDot": {
"overrideGlobal": "Dieser Abschnitt überschreibt die globale Konfiguration",
"overrideProfile": "Dieser Abschnitt wird durch das Profil {{profile}} überschrieben",
"unsaved": "Dieser Abschnitt enthält ungespeicherte Änderungen"
},
"detectorsAndModel": {
"title": "Detektoren und Modell",
"description": "Konfigurieren Sie das Detektor-Backend, das die Objekterkennung ausführt, sowie das dafür verwendete Modell. Änderungen werden gemeinsam gespeichert, sodass Detektor und Modell synchron bleiben.",
"cardTitles": {
"detector": "Detektor-Hardware",
"model": "Erkennungsmodell"
},
"tabs": {
"plus": "Frigate+",
"custom": "Benutzerdefiniertes Modell"
},
"mismatch": {
"warning": "Das aktuelle Frigate+-Modell „{{model}}“ erfordert den {{required}}-Detektor. Wählen Sie unten ein kompatibles Modell aus oder wechseln Sie vor dem Speichern zu „Benutzerdefiniertes Modell“."
},
"plusModel": {
"requiresDetector": "Voraussetzung: {{detector}}",
"noModelSelected": "Wählen Sie ein Modell der Frigate+ aus"
},
"toast": {
"saveSuccess": "Detektoren und Modelleinstellungen wurden gespeichert. Starten Sie Frigate neu, um die Änderungen zu übernehmen.",
"saveError": "Das Speichern der Detektor- und Modelleinstellungen ist fehlgeschlagen"
},
"unsavedChanges": "Nicht gespeicherte Änderungen an Detektor und Modell",
"restartRequired": "Neustart erforderlich (Detektor oder Modell geändert)"
}
}

View File

@ -682,7 +682,7 @@
},
"timestamp_style": {
"label": "Timestamp style",
"description": "Styling options for in-feed timestamps applied to recordings and snapshots.",
"description": "Styling options for timestamps applied to snapshots and Debug view.",
"position": {
"label": "Timestamp position",
"description": "Position of the timestamp on the image (tl/tr/bl/br)."

View File

@ -212,7 +212,7 @@
},
"default_role": {
"label": "Default role",
"description": "Default role assigned to proxy-authenticated users when no role mapping applies (admin or viewer)."
"description": "Default role assigned to proxy-authenticated users when no role mapping applies."
},
"separator": {
"label": "Separator character",
@ -270,14 +270,6 @@
"label": "Time format",
"description": "Time format to use in the UI (browser, 12hour, or 24hour)."
},
"date_style": {
"label": "Date style",
"description": "Date style to use in the UI (full, long, medium, short)."
},
"time_style": {
"label": "Time style",
"description": "Time style to use in the UI (full, long, medium, short)."
},
"unit_system": {
"label": "Unit system",
"description": "Unit system for display (metric or imperial) used in the UI and MQTT."

View File

@ -8,6 +8,7 @@
"searchCancelled": "Search cancelled",
"cancelSearch": "Cancel",
"searching": "Search in progress.",
"scanning": "Scanning {{time}}",
"searchComplete": "Search complete",
"noResultsYet": "Run a search to find motion changes in the selected region",
"noChangesFound": "No pixel changes detected in the selected region",
@ -42,13 +43,11 @@
"settings": {
"title": "Search Settings",
"parallelMode": "Parallel mode",
"parallelModeDesc": "Scan multiple recording segments at the same time (faster, but significantly more CPU intensive)",
"parallelModeDesc": "Scan multiple recording ranges at the same time (faster; uses more decoding resources)",
"threshold": "Sensitivity Threshold",
"thresholdDesc": "Lower values detect smaller changes (1-255)",
"minArea": "Minimum Change Area",
"minAreaDesc": "Minimum percentage of the region of interest that must change to be considered significant",
"frameSkip": "Frame Skip",
"frameSkipDesc": "Process every Nth frame. Set this to your camera's frame rate to process one frame per second (e.g. 5 for a 5 FPS camera, 30 for a 30 FPS camera). Higher values will be faster, but may miss short motion events.",
"minAreaDesc": "Minimum size of a single moving region, as a percentage of the region of interest",
"maxResults": "Maximum Results",
"maxResultsDesc": "Stop after this many matching timestamps"
},
@ -72,6 +71,8 @@
"framesDecoded": "Frames decoded",
"wallTime": "Search time",
"segmentErrors": "Segment errors",
"seconds": "{{seconds}}s"
"seconds": "{{seconds}}s",
"minutesSeconds": "{{minutes}}m {{seconds}}s",
"scanSummary": "{{segments}} segments · {{time}}"
}
}

View File

@ -1154,7 +1154,8 @@
},
"notificationUnavailable": {
"title": "Notifications Unavailable",
"desc": "Web push notifications require a secure context (<code>https://…</code>). This is a browser limitation. Access Frigate securely to use notifications."
"desc": "Web push notifications require a secure context (<code>https://…</code>). This is a browser limitation. Access Frigate securely to use notifications.",
"descPwa": "On iOS, web push notifications are only available when Frigate is installed to your Home Screen. Open the <strong>Share</strong> menu, choose <strong>Add to Home Screen</strong>, then open Frigate from the new icon to register this device for notifications."
},
"globalSettings": {
"title": "Global Settings",
@ -1674,6 +1675,17 @@
"refresh": "Refresh models",
"probeFailed": "Failed to probe models",
"fetchedModels": "Successfully fetched model list"
},
"ptzPresets": {
"placeholder": "Select or enter a preset...",
"search": "Search or enter a preset...",
"noPresets": "No presets available",
"available": "Camera presets",
"useCustom": "Use \"{{value}}\""
},
"defaultRole": {
"admin": "Admin",
"viewer": "Viewer"
}
},
"globalConfig": {
@ -1763,7 +1775,7 @@
"addStream": "Add stream",
"addStreamDesc": "Enter a name for the new stream. This name will be used to reference the stream in your camera configuration.",
"addUrl": "Add URL",
"streamNumber": "Stream {{index}}",
"sourceNumber": "Source {{index}}",
"streamName": "Stream name",
"streamNamePlaceholder": "e.g., front_door",
"streamUrlPlaceholder": "e.g., rtsp://user:pass@192.168.1.100/stream",
@ -1840,12 +1852,6 @@
"12hour": "12 hour",
"24hour": "24 hour"
},
"TimeOrDateStyle": {
"full": "Full",
"long": "Long",
"medium": "Medium",
"short": "Short"
},
"unitSystem": {
"metric": "Metric",
"imperial": "Imperial"
@ -1928,6 +1934,9 @@
},
"semanticSearch": {
"jinav2SmallModelSize": "The 'small' size with the Jina V2 model has high RAM and inference cost. The 'large' model with a discrete GPU is recommended."
},
"onvif": {
"autotrackingNoZones": "Autotracking requires at least one zone. Define a zone for this camera in Masks / Zones, then set it as a required zone below."
}
}
}

View File

@ -155,7 +155,8 @@
"id": "Bahasa Indonesia (Indonesio)",
"ur": "اردو (Urdu)",
"hr": "Hrvatski (Croata)",
"bs": "Bosanski (Bosnio)"
"bs": "Bosanski (Bosnio)",
"zhHant": "繁體中文 (Chino Tradicional)"
},
"appearance": "Apariencia",
"darkMode": {
@ -333,5 +334,8 @@
"internalID": "La ID interna que usa Frigate en la configuración y en la base de datos"
},
"no_items": "No hay elementos",
"validation_errors": "Errores de validación"
"validation_errors": "Errores de validación",
"credentialField": {
"savedPlaceholder": "Guardado — déjalo en blanco para mantener el actual"
}
}

View File

@ -48,5 +48,6 @@
}
},
"livePlayerRequiredIOSVersion": "Se requiere iOS 17.1 o superior para este tipo de transmisión en vivo.",
"noRecordingsFoundForThisTime": "No se encontraron grabaciones para este momento"
"noRecordingsFoundForThisTime": "No se encontraron grabaciones para este momento",
"cameraOff": "La cámara está apagada"
}

View File

@ -896,7 +896,7 @@
},
"timestamp_style": {
"label": "Estilo de marca de tiempo",
"description": "Opciones de estilo para marcas de tiempo integradas aplicadas a grabaciones e instantáneas.",
"description": "Opciones de estilo para las marcas de tiempo aplicadas a las instantáneas y a la vista de depuración.",
"position": {
"label": "Posición de marca de tiempo",
"description": "Posición de la marca de tiempo en la imagen (tl/tr/bl/br)."

View File

@ -610,7 +610,7 @@
"description": "Carácter usado para separar varios valores proporcionados en las cabeceras del proxy."
},
"default_role": {
"description": "Rol predeterminado asignado a los usuarios autenticados por proxy cuando no se aplica ningún mapeo de roles (administrador o espectador).",
"description": "Rol predeterminado asignado a los usuarios autenticados mediante proxy cuando no se aplica ninguna asignación de roles.",
"label": "Rol predeterminado"
},
"description": "Configuración para integrar Frigate detrás de un proxy inverso que transmite encabezados de usuario autenticados.",

View File

@ -28,5 +28,8 @@
"header_map": {
"roleHeaderRequired": "Se requiere el encabezado de rol cuando hay mapeos de roles configurados."
}
},
"detect": {
"dimensionMustBeEven": "Debe ser un número par."
}
}

View File

@ -65,5 +65,8 @@
"active": "Razonando…",
"show": "Mostrar razonamiento",
"hide": "Ocultar razonamiento"
},
"thinking": {
"toggle": "Alternar razonamiento"
}
}

View File

@ -57,7 +57,9 @@
},
"camera": {
"enable": "Habilitar cámara",
"disable": "Deshabilitar cámara"
"disable": "Deshabilitar cámara",
"turnOn": "Encender cámara",
"turnOff": "Apagar cámara"
},
"muteCameras": {
"enable": "Silenciar todas las cámaras",
@ -151,7 +153,8 @@
"snapshots": "Capturas de pantalla",
"autotracking": "Seguimiento automático",
"cameraEnabled": "Cámara habilitada",
"transcription": "Transcripción de Audio"
"transcription": "Transcripción de Audio",
"camera": "Cámara"
},
"history": {
"label": "Mostrar grabaciones históricas"

View File

@ -26,7 +26,9 @@
"points_many": "{{count}} puntos",
"points_other": "{{count}} puntos",
"undo": "Deshacer el último punto",
"reset": "Restablecer polígono"
"reset": "Restablecer polígono",
"drawMode": "Dibujar",
"moveMode": "Mover"
},
"motionHeatmapLabel": "Mapa de calor de movimiento",
"dialog": {

View File

@ -32,7 +32,7 @@
"enrichments": "Análisis avanzado",
"triggers": "Disparadores",
"roles": "Rols",
"cameraManagement": "Administración",
"cameraManagement": "Gestión de cámaras",
"cameraReview": "Revisar",
"general": "General",
"globalConfig": "Configuración Global",
@ -727,7 +727,8 @@
"notificationUnavailable": {
"title": "Notificaciones no disponibles",
"documentation": "Leer la documentación",
"desc": "Las notificaciones push web requieren un contexto seguro (<code>https://…</code>). Esto es una limitación del navegador. Accede a Frigate de forma segura para usar las notificaciones."
"desc": "Las notificaciones push web requieren un contexto seguro (<code>https://…</code>). Esto es una limitación del navegador. Accede a Frigate de forma segura para usar las notificaciones.",
"descPwa": "En iOS, las notificaciones push web solo están disponibles cuando Frigate está instalado en la pantalla de inicio. Abre el menú <strong>Compartir</strong>, selecciona <strong>Añadir a la pantalla de inicio</strong> y, a continuación, abre Frigate desde el nuevo icono para registrar este dispositivo para las notificaciones."
},
"globalSettings": {
"title": "Configuración global",
@ -1091,7 +1092,7 @@
"nameLength": "El nombre de la cámara debe tener 64 caracteres o menos",
"invalidCharacters": "El nombre de la cámara contiene caracteres no válidos",
"nameExists": "El nombre de la cámara ya existe",
"customUrlRtspRequired": "Las URL personalizadas deben comenzar con \"rtsp://\". Se requiere configuración manual para transmisiones de cámara sin RTSP.",
"customUrlRtspRequired": "Las URL personalizadas deben comenzar por “rtsp://” o “rtsps://”. Se requiere configuración manual para flujos de cámara que no sean RTSP.",
"brandOrCustomUrlRequired": "Seleccione una marca de cámara con host/IP o elija \"Otro\" con una URL personalizada"
},
"description": "Ingrese los detalles de su cámara y elija probar la cámara o seleccionar manualmente la marca.",
@ -1281,13 +1282,13 @@
"selectCamera": "Seleccione una cámara",
"backToSettings": "Volver a configuración de la cámara",
"streams": {
"title": "Habilitar/deshabilitar cámaras",
"title": "Estado y detalles de la cámara",
"desc": "Desactiva temporalmente una cámara hasta que Frigate se reinicie. Desactivar una cámara detiene por completo el procesamiento de las transmisiones de Frigate. La detección, la grabación y la depuración no estarán disponibles.<br /> <em>Nota: Esto no desactiva las retransmisiones de go2rtc.</em>",
"enableDesc": "Deshabilita temporalmente una cámara habilitada hasta que Frigate se reinicie. Deshabilitar una cámara detiene completamente el procesamiento de los flujos de esa 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.Arrastra el controlador para reordenar las cámaras tal y como aparecen en la interfaz. El orden de las cámaras habilitadas se reflejará en toda la interfaz, incluido el panel en directo y los menús desplegables de selección de cámaras.",
"enableLabel": "Cámaras habilitadas",
"disableLabel": "Cámaras deshabilitadas",
"disableDesc": "Habilita una cámara que actualmente no está visible en la interfaz y está deshabilitada en la configuración. Es necesario reiniciar Frigate después de habilitarla.",
"enableSuccess": "{{cameraName}} se ha habilitado en la configuración. Reinicia Frigate para aplicar los cambios.",
"enableSuccess": "{{cameraName}} habilitada. Reinicia Frigate para aplicar los cambios.",
"friendlyName": {
"edit": "Editar nombre visible de la cámara",
"title": "Editar nombre visible",
@ -1296,7 +1297,26 @@
},
"reorderHandle": "Arrastrar para reordenar",
"saving": "Guardando…",
"saved": "Guardado"
"saved": "Guardado",
"details": {
"edit": "Editar detalles de la cámara",
"title": "Editar detalles de la cámara",
"description": "Actualiza el nombre visible y la URL externa usados para esta cámara en toda la interfaz de Frigate.",
"friendlyNameLabel": "Nombre visible",
"friendlyNameHelp": "Nombre descriptivo que se muestra para esta cámara en toda la interfaz de Frigate. Déjalo en blanco para usar el ID de la cámara.",
"webuiUrlLabel": "URL de la interfaz web de la cámara",
"webuiUrlHelp": "URL para acceder directamente a la interfaz web de la cámara desde la vista de depuración. Déjala en blanco para deshabilitar el enlace.",
"webuiUrlInvalid": "Debe ser una URL válida (p. ej., https://ejemplo.com)."
},
"label": "Estado de la cámara",
"description": "Set the operating state for each camera. <br /><br /><strong>On</strong>: las transmisiones se procesan con normalidad.<br /><strong>Off</strong>: pausa temporalmente el procesamiento. No persiste tras reinicios de Frigate.<br /><strong>Disabled</strong>: detiene el procesamiento y guarda el cambio en tu configuración. Es necesario reiniciar para volver a activar una cámara desactivada.<br /><br /><em>Note: Desactivar no afecta a las retransmisiones de go2rtc.</em><br /><br />Arrastra el asa para reordenar las cámaras activas tal como aparecen en toda la interfaz, incluido el panel de Live y los menús desplegables de selección de cámara.",
"disabledSubheading": "Deshabilitado en la configuración",
"status": {
"on": "On",
"off": "Off",
"disabled": "Deshabilitado"
},
"disableSuccess": "{{cameraName}} deshabilitada y guardada en la configuración."
},
"cameraConfig": {
"add": "Añadir cámara",
@ -1342,10 +1362,12 @@
"profiles": {
"title": "Sobrescrituras de cámaras del perfil",
"selectLabel": "Seleccionar perfil",
"description": "Configura qué cámaras se habilitan o deshabilitan cuando se activa un perfil. Las cámaras configuradas como \"Heredar\" conservan su estado base habilitado.",
"description": "Configura qué cámaras se activan o desactivan cuando se activa un perfil. Las cámaras configuradas como “Heredar” conservan su estado predeterminado.",
"inherit": "Heredar",
"enabled": "Habilitado",
"disabled": "Deshabilitado"
"disabled": "Deshabilitado",
"on": "Encendido",
"off": "Apagado"
},
"cameraType": {
"title": "Tipo de cámara",
@ -1355,7 +1377,95 @@
"dedicatedLpr": "LPR dedicada",
"saveSuccess": "Se ha actualizado el tipo de cámara de {{cameraName}}. Reinicia Frigate para aplicar los cambios."
},
"description": "Añade, edita y elimina cámaras, controla qué cámaras están habilitadas y configura sobrescrituras por perfil y tipo de cámara. Para configurar flujos, detección, movimiento y otros ajustes específicos de cámara, selecciona la sección correspondiente dentro de Configuración de cámara."
"description": "Añade, edita y elimina cámaras, controla el estado de cada cámara y configura sobrescrituras por perfil y tipo de cámara. Para configurar flujos, detección, movimiento y otros ajustes específicos de cámara, selecciona la sección correspondiente dentro de Configuración de cámara.",
"clone": {
"sectionTitle": "Clonar configuración",
"sectionDescription": "Copia la configuración de una cámara a otra cámara o a una nueva.",
"button": "Clonar configuración",
"title": "Clonar configuración de la cámara",
"description": "Copia la configuración de una cámara a una o varias cámaras existentes o a una cámara nueva. La identidad de la cámara (nombre, nombre visible, URL de la interfaz web y orden de visualización) nunca se copia.",
"source": {
"label": "Cámara de origen",
"placeholder": "Selecciona una cámara de origen",
"required": "Selecciona una cámara de origen"
},
"target": {
"legend": "Destino",
"newRadio": "Nueva cámara",
"newNameLabel": "Nombre de la cámara",
"newNamePlaceholder": "p. ej., puerta_trasera o Puerta trasera",
"newNameRequired": "El nombre de la cámara es obligatorio",
"newNameInvalid": "Nombre de cámara no válido",
"newNameCollision": "Ya existe una cámara con este nombre",
"newStreamsForced": "Los flujos siempre se copian al crear una cámara nueva.",
"existingCamerasRadio": "Cámaras existentes",
"allCameras": "Todas las cámaras",
"existingPlaceholder": "Selecciona al menos una cámara",
"existingDisabled": "No hay otras cámaras a las que copiar la configuración"
},
"categories": {
"legend": "Configuración para clonar",
"description": "Elige qué ajustes copiar desde la cámara de origen.",
"selectAll": "Seleccionar todo",
"selectNone": "No seleccionar ninguno",
"resetDefaults": "Restablecer valores predeterminados",
"general": "General",
"spatial": "Configuración espacial",
"streams": "Flujos",
"spatialWarningTitle": "Resolución no coincidente",
"spatialWarning": "La resolución de detección de la cámara de origen {{srcCamera}} ({{srcWidth}}×{{srcHeight}}) es diferente de la de: {{cameras}}. Es posible que los polígonos no se alineen correctamente en esas cámaras. Estas opciones están desactivadas de forma predeterminada; actívalas para copiarlas tal cual.",
"restartHint": "Reinicio necesario",
"items": {
"record": "Grabación",
"snapshots": "Instantáneas",
"review": "Revisión",
"motion": "Detección de movimiento",
"objects": "Objetos",
"audio": "Detección de audio",
"audio_transcription": "Transcripción de audio",
"notifications": "Notificaciones",
"birdseye": "Birdseye",
"mqtt": "MQTT",
"timestamp_style": "Estilo de marca de tiempo",
"onvif": "ONVIF",
"lpr": "Reconocimiento de matrículas",
"face_recognition": "Reconocimiento facial",
"semantic_search": "Búsqueda semántica",
"genai": "IA generativa",
"type": "Tipo de cámara (normal / LPR dedicada)",
"profiles": "Perfiles",
"detect": "Dimensiones de detección",
"zones": "Zonas",
"motion_mask": "Máscaras de movimiento",
"object_masks": "Máscaras de objetos",
"ffmpeg_live": "URL y roles de los flujos"
}
},
"footer": {
"changeCount_one": "Se aplicará {{count}} cambio",
"changeCount_many": "Se aplicarán {{count}} cambios",
"changeCount_other": "Se aplicarán {{count}} cambios",
"restartNeeded": "Será necesario reiniciar para aplicar algunos cambios.",
"liveOnly": "Todos los cambios se aplicarán en tiempo real sin necesidad de reiniciar.",
"submit": "Clonar",
"submitting": "Clonando…"
},
"toast": {
"success": "Configuración copiada a {{cameraName}}",
"successWithRestart": "Configuración copiada a {{cameraName}}. Reinicia Frigate para aplicar todos los cambios.",
"successMulti_one": "Configuración copiada a {{count}} cámara",
"successMulti_many": "Configuración copiada a {{count}} cámaras",
"successMulti_other": "Configuración copiada a {{count}} cámaras",
"successMultiWithRestart_one": "Configuración copiada a {{count}} cámara. Reinicia Frigate para aplicar todos los cambios.",
"successMultiWithRestart_many": "Configuración copiada a {{count}} cámaras. Reinicia Frigate para aplicar todos los cambios.",
"successMultiWithRestart_other": "Configuración copiada a {{count}} cámaras. Reinicia Frigate para aplicar todos los cambios.",
"partialFailure": "Se aplicaron {{successCount}} secciones; {{failedSection}} falló: {{errorMessage}}",
"partialFailureMulti": "Copiado a {{successCount}} cámara(s); error en {{failed}}: {{errorMessage}}",
"newCameraPartialFailure": "La cámara {{cameraName}} se creó, pero no se pudieron copiar algunos ajustes: {{errorMessage}}",
"sourceMissing": "La cámara de origen ya no existe",
"submitError": "No se pudo clonar la cámara: {{errorMessage}}"
}
}
},
"cameraReview": {
"title": "Configuración de revisión de la cámara",
@ -1502,8 +1612,13 @@
},
"genaiModel": {
"noModels": "No hay modelos disponibles",
"placeholder": "Seleccionar modelo…",
"search": "Buscar modelos…"
"placeholder": "Selecciona o introduce un modelo…",
"search": "Busca o introduce un modelo…",
"available": "Modelos disponibles",
"useCustom": "Usar “{{value}}”",
"refresh": "Actualizar modelos",
"probeFailed": "No se pudieron detectar los modelos",
"fetchedModels": "La lista de modelos se ha obtenido correctamente"
},
"global": {
"description": "Estos ajustes se aplican a todas las cámaras, a menos que se anulen en los ajustes específicos de cada cámara.",
@ -1686,7 +1801,32 @@
"title": "Ajustes de marcas de tiempo"
},
"searchPlaceholder": "Buscar...",
"addCustomLabel": "Añadir etiqueta personalizada..."
"addCustomLabel": "Añadir etiqueta personalizada...",
"semanticSearchModelSize": {
"notApplicable": "No aplicable a proveedores GenAI"
},
"liveStreams": {
"streamNameLabel": "Nombre del flujo",
"streamNamePlaceholder": "p. ej., Flujo principal HD",
"go2rtcStreamLabel": "Flujo go2rtc",
"go2rtcStreamPlaceholder": "Selecciona un flujo go2rtc",
"go2rtcStreamSearch": "Busca o introduce un nombre de flujo…",
"noGo2rtcStreams": "No hay flujos go2rtc configurados",
"availableStreams": "Flujos disponibles",
"useCustom": "Usar “{{value}}”",
"addStream": "Añadir flujo"
},
"ptzPresets": {
"placeholder": "Selecciona o introduce un preajuste…",
"search": "Busca o introduce un preajuste…",
"noPresets": "No hay preajustes disponibles",
"available": "Preajustes de cámara",
"useCustom": "Usar “{{value}}”"
},
"defaultRole": {
"admin": "Admin",
"viewer": "Visualizador"
}
},
"globalConfig": {
"title": "Configuración global",
@ -1818,7 +1958,8 @@
"addAudioCodec": "Añadir códec de audio",
"removeCodec": "Eliminar códec"
},
"streamNumber": "Flujo {{index}}"
"streamNumber": "Flujo {{index}}",
"sourceNumber": "Origen {{index}}"
},
"configMessages": {
"birdseye": {
@ -1855,7 +1996,9 @@
},
"detect": {
"fpsGreaterThanFive": "No se recomienda establecer los FPS de detección por encima de 5. Valores más altos pueden causar problemas de rendimiento y no aportarán ningún beneficio.",
"disabled": "La detección de objetos está deshabilitada. Las instantáneas, los elementos de revisión y enriquecimientos como el reconocimiento facial, el reconocimiento de matrículas y la IA generativa no funcionarán."
"disabled": "La detección de objetos está deshabilitada. Las instantáneas, los elementos de revisión y enriquecimientos como el reconocimiento facial, el reconocimiento de matrículas y la IA generativa no funcionarán.",
"resolutionShouldBeMultipleOfFour": "Para obtener mejores resultados, la anchura y la altura de detección deberían ser múltiplos de 4. Otros valores pares pueden producir artefactos visuales o una ligera distorsión en el flujo de detección.",
"aspectRatioMismatch": "La anchura y la altura que has introducido no coinciden con la relación de aspecto de la resolución de detección actual. Esto puede producir una imagen estirada o distorsionada."
},
"objects": {
"genaiNoDescriptionsProvider": "Debes configurar un proveedor GenAI con el rol 'descriptions' para que se generen descripciones."
@ -1864,7 +2007,11 @@
"noRecordRole": "Ningún flujo tiene definido el rol de grabación. La grabación no funcionará."
},
"semanticSearch": {
"jinav2SmallModelSize": "El tamaño 'small' con el modelo Jina V2 tiene un alto consumo de RAM y coste de inferencia. Se recomienda el modelo 'large' con una GPU dedicada."
"jinav2SmallModelSize": "El tamaño 'small' con el modelo Jina V2 tiene un alto consumo de RAM y coste de inferencia. Se recomienda el modelo 'large' con una GPU dedicada.",
"modelSizeIgnoredForProvider": "El tamaño del modelo solo se aplica a los modelos Jina integrados. Este valor se ignorará al usar un proveedor de embeddings GenAI."
},
"onvif": {
"autotrackingNoZones": "El seguimiento automático requiere al menos una zona. Define una zona para esta cámara en Máscaras / Zonas y, a continuación, establécela como zona obligatoria a continuación."
}
},
"resetToDefaultDescription": "Esto restablecerá todos los ajustes de esta sección a sus valores predeterminados. Esta acción no se puede deshacer.",

View File

@ -141,7 +141,8 @@
"id": "Bahasa Indonesia (indoneesia keel)",
"ur": "اردو (urdu keel)",
"hr": "Hrvatski (horvaadi keel)",
"bs": "Bosanski (bosnia keel)"
"bs": "Bosanski (bosnia keel)",
"zhHant": "繁體中文 (hiina keel traditsiooniliste hieroglüüfidega)"
},
"system": "Süsteem",
"systemMetrics": "Süsteemi meetrika",
@ -316,5 +317,8 @@
"pixels": "{{area}} px"
},
"no_items": "Objekte pole",
"validation_errors": "Valideerimise vead"
"validation_errors": "Valideerimise vead",
"credentialField": {
"savedPlaceholder": "Salvestatud - senise kasutamiseks jäta tühjaks"
}
}

View File

@ -48,5 +48,6 @@
"error": {
"submitFrigatePlusFailed": "Kaadri saatmine Frigate+ teenusesse ei õnnestunud"
}
}
},
"cameraOff": "Kaamera on lülitatud välja"
}

View File

@ -18,5 +18,22 @@
"mode": {
"label": "Jälgimisrežiim"
}
},
"label": "Kaameraseadistus",
"semantic_search": {
"triggers": {
"threshold": {
"description": "Minimaalne sarnasuse punktiskoor (0-1), mis on vajalik selle päästiku käivitamiseks."
}
}
},
"lpr": {
"label": "Sõidukite numbrimärkide tuvastus",
"description": "Sõidukite numbrimärkide tuvastuse seadistus sisaldab tuvastuse lävendeid, vormindust ja teadaolevaid numbrimärke."
},
"review": {
"genai": {
"description": "Kontrollib generatiivse tehisaru kasutamist kirjelduste ja kokkuvõtete koostamiseks ülevaatamisele kuuluvate objektide jaoks."
}
}
}

View File

@ -6,5 +6,51 @@
"mode": {
"label": "Jälgimisrežiim"
}
},
"version": {
"label": "Praegune seadistuse versioon",
"description": "Aktiivse seadistuse numbriline või tekstiline versioon, mis aitab tuvastada vormingumuudatusi."
},
"classification": {
"bird": {
"threshold": {
"label": "Minimaalne punktiskoor",
"description": "Objekti määratlemiseks linnina vajalik mlassifitseerimise minimaalne punktiskoor."
}
},
"custom": {
"threshold": {
"label": "Punktiskoori lävend",
"description": "Punktiskoori lävend, mida kasutatakse klassifitseerimise oleku muutmiseks."
}
}
},
"semantic_search": {
"triggers": {
"threshold": {
"description": "Minimaalne sarnasuse punktiskoor (0-1), mis on vajalik selle päästiku käivitamiseks."
}
}
},
"face_recognition": {
"unknown_score": {
"label": "Tundmatu punktiskoori lävend"
}
},
"lpr": {
"label": "Sõidukite numbrimärkide tuvastus",
"description": "Sõidukite numbrimärkide tuvastuse seadistus sisaldab tuvastuse lävendeid, vormindust ja teadaolevaid numbrimärke.",
"enabled": {
"description": "Lülita sõidukite numbrimärkide tuvastus kõikide kaamerate jaoks sisse; seda saad kaamerakohaselt ka sürjutada."
}
},
"genai": {
"label": "Generatiivse tehisaru seadistus",
"description": "Seadistsued generatiivse tehisaru teenusepakkujate kasutamisel kirjelduste ja kokkuvõtete loomiseks ülevaatamisele kuuluvate objektide jaoks."
},
"review": {
"genai": {
"description": "Kontrollib generatiivse tehisaru kasutamist kirjelduste ja kokkuvõtete koostamiseks ülevaatamisele kuuluvate objektide jaoks."
}
}
}

View File

@ -28,5 +28,8 @@
"detectRequired": "„Tuvasta“ rollile pead määrama vähemalt ühe sisendvoo.",
"hwaccelDetectOnly": "Vaid „Tuvasta“ rolliga sisendvoog võib määratleda raudvaralise kiirenduse argumente."
}
},
"detect": {
"dimensionMustBeEven": "Peab olema paarisarv."
}
}

View File

@ -5,5 +5,6 @@
"placeholder": "Küsi mida iganes…",
"error": "Midagi läks valesti. Palun proovi uuesti.",
"processing": "Töötlen…",
"toolsUsed": "Kasutatud: {{tools}}"
"toolsUsed": "Kasutatud: {{tools}}",
"similarity_score": "Sarnasus"
}

View File

@ -7,7 +7,7 @@
},
"documentTitle": "Klassifitseerimise mudelid - Frigate",
"details": {
"scoreInfo": "Skoor näitab selle objekti kõigi tuvastuste keskmist klassifitseerimise usaldusväärsust.",
"scoreInfo": "Punktiskoor näitab selle objekti kõigi tuvastuste keskmist klassifitseerimise usaldusväärsust.",
"none": "Puudub",
"unknown": "Pole teada"
},

View File

@ -35,7 +35,9 @@
"zones": "Tsoonid",
"ratio": "Suhtarv",
"area": "Ala",
"score": "Punktiskoor"
"score": "Punktiskoor",
"computedScore": "Arvutatud punktiskoor",
"topScore": "Suuremad punktiskoorid"
},
"external": "{{label}} on tuvastatud",
"heard": "{{label}} on kuuldud",
@ -79,13 +81,34 @@
"mismatch_other": "Tuvastasin {{count}} võõrast objekti ja need on lisatud ülevaatamiseks. Need objektid kas ei ole piisavad häire või tuvastamise jaoks, aga ka võivad juba olla eemaldatud või kustutatud."
},
"title": "Vaata objekti üksikasju",
"desc": "Vaata objekti üksikasju"
"desc": "Vaata objekti üksikasju",
"toast": {
"success": {
"updatedLPR": "Sõiduki numbrimärgi uuendamine õnnestus."
},
"error": {
"updatedLPRFailed": "Sõiduki numbrimärgi uuendamine ei õnnestunud: {{errorMessage}}"
}
}
},
"snapshotScore": {
"label": "Hetkvõttete punktiskoor"
"label": "Hetkvõtete punktiskoor"
},
"regenerateFromSnapshot": "Loo uuesti hetkvõttest",
"timestamp": "Ajatampel"
"timestamp": "Ajatampel",
"score": {
"label": "Punktiskoor"
},
"scoreInfo": "Punktiskoori teave",
"editLPR": {
"title": "Muuda sõiduki numbrimärki",
"desc": "Sisesta sõiduki numbrimärgi uus väärtus: {{label}}",
"descNoLabel": "Sisesta sõiduki numbrimärgi uus väärtus selle jälgitava objekti jaoks"
},
"recognizedLicensePlate": "Tuvastatud sõiduki numbrimärk",
"description": {
"aiTips": "Frigate ei küsi sinu generatiivse tehisaru teenusepakkujalt kirjeldust enne, kui jälgitava objekti elutsükkel on lõppenud."
}
},
"trackedObjectDetails": "Jälgitava objekti üksikasjad"
}

View File

@ -18,14 +18,16 @@
},
"toast": {
"error": {
"addFaceLibraryFailed": "Näo sidumine nimega ei õnnestunud: {{errorMessage}}"
"addFaceLibraryFailed": "Näo sidumine nimega ei õnnestunud: {{errorMessage}}",
"updateFaceScoreFailed": "Näo punktiskoori uuendamine ei õnnestunud: {{errorMessage}}"
},
"success": {
"addFaceLibrary": "Lisamine Näoteeki õnnestus: {{name}}!",
"deletedFace_one": "{{count}} näo kustutamine õnnestus.",
"deletedFace_other": "{{count}} näo kustutamine õnnestus.",
"deletedName_one": "{{count}} näo kustutamine õnnestus.",
"deletedName_other": "{{count}} näo kustutamine õnnestus."
"deletedName_other": "{{count}} näo kustutamine õnnestus.",
"updatedFaceScore": "Näo punktiskoori uuendamine õnnestus: {{name}} ({{score}})."
}
},
"deleteFaceAttempts": {
@ -35,7 +37,7 @@
"details": {
"timestamp": "Ajatampel",
"unknown": "Pole teada",
"scoreInfo": "Skoor on kõigi nägude hindete kaalutud keskmine, kus kaalukoefitsiendiks on iga pildi näo suurus."
"scoreInfo": "Punktiskoor on kõigi nägude hinnete kaalutud keskmine, kus kaalukoefitsiendiks on iga pildi näo suurus."
},
"uploadFaceImage": {
"title": "Laadi näopilt üles",

View File

@ -12,7 +12,8 @@
"transcription": "Heli üleskirjutus",
"snapshots": "Hetkvõtted",
"autotracking": "Automaatne jälgimine",
"recording": "Salvestus"
"recording": "Salvestus",
"camera": "Kaamera"
},
"documentTitle": {
"default": "Frigate reaalajas"
@ -73,7 +74,9 @@
},
"camera": {
"enable": "Lülita kaamera sisse",
"disable": "Lülita kaamera välja"
"disable": "Lülita kaamera välja",
"turnOn": "Lülita kaamera sisse",
"turnOff": "Lülita kaamera välja"
},
"detect": {
"enable": "Lülita tuvastamine sisse",

View File

@ -1 +1,4 @@
{}
{
"documentTitle": "Liikumise tuvastus - Frigate",
"title": "Liikumise otsing"
}

View File

@ -13,5 +13,6 @@
"starting": "Käivitan kordust…",
"startLabel": "Algus",
"endLabel": "Lõpp"
}
},
"title": "Kordus veaotsinguks"
}

View File

@ -23,7 +23,13 @@
"search_type": "Otsingutüüp",
"time_range": "Ajavahemik",
"before": "Enne",
"after": "Pärast"
"after": "Pärast",
"min_score": "Minimaalne punktiskoor",
"max_score": "Maksimaalne punktiskoor",
"min_speed": "Miinimumkiirus",
"max_speed": "Maksimumkiirus",
"recognized_license_plate": "Tuvastatud sõiduki numbrimärk",
"has_clip": "Klipp on olemas"
},
"searchType": {
"thumbnail": "Pisipilt",
@ -32,9 +38,36 @@
"toast": {
"error": {
"beforeDateBeLaterAfter": "„Enne“ kuupäev peab olema varasem, kui „Pärast“ kuupäev.",
"afterDatebeEarlierBefore": "„Pärast“ kuupäev peab olema hilisem, kui „Enne“ kuupäev."
"afterDatebeEarlierBefore": "„Pärast“ kuupäev peab olema hilisem, kui „Enne“ kuupäev.",
"minScoreMustBeLessOrEqualMaxScore": "Minimaalne punktiskoor peab olema väiksem või võrdne kui maksimaalne punktiskoor.",
"maxScoreMustBeGreaterOrEqualMinScore": "Maksimaalne punktiskoor peab olema suurem või võrdne kui minimaalne punktiskoor.",
"minSpeedMustBeLessOrEqualMaxSpeed": "Minimaalne kiirus peab olema väiksem või võrdne kui maksimaalne kiirus.",
"maxSpeedMustBeGreaterOrEqualMinSpeed": "Maksimaalne kiirus peab olema suurem või võrdne kui minimaalne kiirus."
}
},
"tips": {
"title": "Kuidas saad kasutada tekstifiltreid",
"desc": {
"text": "Filtrid aitavad sul otsingutulemusi kitsendada. Siin on juhised nende kasutamiseks sisestusväljal:",
"step1": "Sisesta filtri nimi, millele järgnev koolon (nt, „cameras:“).",
"step2": "Vali soovitatud väärtus või sisesta enda oma.",
"step3": "Kasuta mitmeid filtreid lisades neid üksteise järgi ning eraldades tühikuga.",
"step4": "Kuupäevafiltrid (before: ja after:) kasutavad {{DateFormat}} vormingut.",
"step5": "Ajavahemiku filter kasutab {{exampleTime}} vormingut.",
"step6": "Filtreid saad eemaldada klõpsates nende kõrval leiduvad märget „x“.",
"exampleLabel": "Näide:"
}
},
"header": {
"currentFilterType": "Filtri väärtused",
"noFilters": "Filtrid",
"activeFilters": "Aktiivsed filtrid"
}
},
"trackedObjectId": "Jälgitava objekti tunnus"
"trackedObjectId": "Jälgitava objekti tunnus",
"similaritySearch": {
"title": "Sarnaste objektide otsing",
"active": "Sarnaste objektide otsing on aktiivne",
"clear": "Eemalda sarnaste objektide otsing"
}
}

View File

@ -115,11 +115,13 @@
"placeholder": "Sisesta oma senine salasõna"
},
"user": {
"title": "Kasutajanimi"
"title": "Kasutajanimi",
"desc": "Lubatud on vaid tähed, numbrid, punktid ja alakriipsud."
}
},
"createUser": {
"confirmPassword": "Palun kinnita oma uus salasõna"
"confirmPassword": "Palun kinnita oma uus salasõna",
"usernameOnlyInclude": "Kasutajanimes võivad olla vaid tähed, numbrid, punkt (.) või alakriips (_)"
},
"passwordSetting": {
"cannotBeEmpty": "Salasõna ei või jääda tühjaks",
@ -213,6 +215,14 @@
"pathPlaceholder": "rtsp://...",
"roles": "Rollid"
}
},
"clone": {
"categories": {
"items": {
"lpr": "Sõidukite numbrimärkide tuvastus",
"genai": "Generatiivne tehisaru"
}
}
}
},
"notification": {
@ -315,6 +325,10 @@
"form": {
"cameras": {
"title": "Kaamerad"
},
"role": {
"desc": "Lubatud on vaid tähed, numbrid, punktid ja alakriipsud.",
"roleOnlyInclude": "Rolli nimes võivad olla vaid tähed, numbrid, punkt (.) või alakriips (_)"
}
}
}
@ -330,7 +344,36 @@
"notifications": "Teavitused",
"frigateplus": "Frigate+",
"cameraReview": "Ülevaatamine",
"profiles": "Profiilid"
"profiles": "Profiilid",
"integrationLpr": "Sõidukite numbrimärkide tuvastus",
"cameraLpr": "Sõidukite numbrimärkide tuvastus",
"uiSettings": "Kasutajaliidese seadistused",
"globalDetect": "Objektide tuvastamine",
"globalRecording": "Salvestamine",
"globalSnapshots": "Hetkvõtted",
"globalFfmpeg": "FFmpeg",
"globalMotion": "Liikumise tuvastus",
"globalObjects": "Objektid",
"globalReview": "Ülevaatamine",
"globalAudioEvents": "Heli tuvastus",
"globalLivePlayback": "Reaalajas sisu taasesitus",
"globalTimestampStyle": "Ajatempli stiil",
"systemDatabase": "Andmebaas",
"systemTls": "TLS",
"systemAuthentication": "Autentimine",
"systemNetworking": "Võrgundus",
"systemProxy": "Proksiserver",
"systemUi": "Kasutajaliides",
"systemLogging": "Logimine",
"systemEnvironmentVariables": "Keskkonnamuutujad",
"systemTelemetry": "Telemeetria",
"systemBirdseye": "Vaade linnulennult",
"systemFfmpeg": "FFmpeg",
"systemDetectorsAndModel": "Tuvastamine ja mudelid",
"systemMqtt": "MQTT",
"systemGo2rtcStreams": "go2rtc voogedastus",
"integrationSemanticSearch": "Semantiline otsing",
"integrationGenerativeAi": "Generatiivne tehisaru"
},
"dialog": {
"unsavedChanges": {
@ -370,6 +413,9 @@
},
"birdClassification": {
"title": "Lindude klassifikatsioon"
},
"licensePlateRecognition": {
"title": "Sõidukite numbrimärkide tuvastus"
}
},
"cameraReview": {
@ -377,6 +423,13 @@
"title": "Ülevaatamine",
"alerts": "Hoiatused ",
"detections": "Tuvastamise tulemused "
},
"object_descriptions": {
"title": "Generatiivse tehisaru objektikirjeldused",
"desc": "Luba/keela ajutiselt selle kaamera jaoks generatiivse tehisaru objektikirjeldused kuni Frigate'i taaskäivitamiseni. Kui see on keelatud, ei küsita selle kaamera jälgitavate objektide kohta tehisintellekti poolt loodud kirjeldusi."
},
"review_descriptions": {
"title": "Generatiivne tehisaru ülevaatamisele kuuluva sisu kirjedlused"
}
},
"motionDetectionTuner": {
@ -404,7 +457,10 @@
"dialog": {
"form": {
"name": {
"title": "Nimi"
"title": "Nimi",
"error": {
"invalidCharacters": "Välja nimes võivad olla vaid tähed, numbrid, alakriipsud (_) või sidekriipsud (-)."
}
},
"type": {
"title": "Tüüp"
@ -420,5 +476,26 @@
}
}
}
},
"profiles": {
"nameInvalid": "Lubatud on vaid väiketähed, numbrid ja alakriipsud"
},
"go2rtcStreams": {
"validation": {
"nameInvalid": "Voogedastuse nimes on lubatud vaid tähed, numbrid alakriipsud ja sidekriipsud"
}
},
"configForm": {
"sections": {
"lpr": "Sõidukite numbrimärkide tuvastus"
}
},
"configMessages": {
"detect": {
"disabled": "Objektide tuvastamine on lülitatud välja. Hetkepildid, läbivaatamisele kuuluvad objektid ja täiendavad funktsioonid, nagu näotuvastus, sõidukite numbrimärkide tuvastus ja generatiivne tehisintellekt, ei tööta."
},
"lpr": {
"vehicleNotTracked": "Sõidukite numbrimärkide tuvastus eeldab, et auto või mootorratas on jälgitav. Lülita menüüst Objektid sell kaamera jaoks sisse valikud „auto“ või „mootorratas“."
}
}
}

View File

@ -10,7 +10,30 @@
},
"copy": {
"label": "Kopeeri lõikelauale",
"success": "Logid on kopeeritud lõikelauale"
"success": "Logid on kopeeritud lõikelauale",
"error": "Logide kopeerimine lõikelauale ei õnnestunud"
},
"websocket": {
"filter": {
"cameras_count_one": "{{count}} kaamera",
"cameras_count_other": "{{count}} kaamerat"
},
"empty": "Ühtegi sõnumit pole veel hõivatud",
"count_one": "{{count}} sõnum",
"count_other": "{{count}} sõnumit"
},
"type": {
"label": "Tüüp",
"timestamp": "Ajatempel",
"tag": "Silt",
"message": "Sõnum"
},
"tips": "Logid on serverist voogedastamisel",
"toast": {
"error": {
"fetchingLogsFailed": "Viga logide laadimisel: {{errorMessage}}",
"whileStreamingLogs": "Viga logide voogedastamisel: {{errorMessage}}"
}
}
},
"title": "Süsteem"

View File

@ -188,7 +188,8 @@
"gl": "Galego (Galicien)",
"id": "Bahasa Indonesia (Indonésien)",
"ur": "اردو (Ourdou)",
"hr": "Hrvatski (Croate)"
"hr": "Hrvatski (Croate)",
"bs": "Bosanski (Bosnien)"
},
"appearance": "Apparence",
"darkMode": {
@ -332,5 +333,8 @@
"separatorWithSpace": ", "
},
"no_items": "Aucun élément",
"validation_errors": "Erreurs de validation"
"validation_errors": "Erreurs de validation",
"credentialField": {
"savedPlaceholder": "Enregistré — laissez vide pour conserver la version actuelle"
}
}

View File

@ -67,7 +67,8 @@
"noVaildTimeSelected": "La plage horaire sélectionnée n'est pas valide."
},
"success": "Exportation démarrée avec succès. Consultez le fichier sur la page des exportations.",
"view": "Vue"
"view": "Vue",
"queued": "Exportation en attente. Consultez la progression sur la page des exportations."
},
"select": "Sélectionner",
"name": {
@ -112,7 +113,7 @@
"title_one": "Export {{count}} revue",
"title_many": "Export {{count}} revues",
"title_other": "Export {{count}} revues",
"description": "Export chaque revue sélectionnée. Tous les exports sont regroupés sous un cas unique.",
"description": "Exporter chaque revue sélectionnée. Tous les exports sont regroupés sous un cas unique.",
"descriptionNoCase": "Exporter chaque revue sélectionnée.",
"caseNamePlaceholder": "Vérification de l'export {{date}}",
"exportButton_one": "Exporter {{count}} revue",
@ -120,12 +121,14 @@
"exportButton_other": "Exporter {{count}} revues",
"exportingButton": "Exportation...",
"toast": {
"started_one": "Un export a démarré. Ouverture du dossier en cours",
"started_many": "{{count}} exports ont démarré. Ouverture du dossier en cours",
"started_other": "",
"started_one": "Un export a démarré. Ouverture du dossier en cours.",
"started_many": "{{count}} exports ont démarré. Ouverture du dossier en cours.",
"started_other": "{{count}} exports ont démarré. Ouverture du dossier en cours.",
"startedNoCase_one": "Un export a démarré.",
"startedNoCase_many": "{{count}} exports ont démarré.",
"startedNoCase_other": "{{count}} exports ont démarré."
"startedNoCase_other": "{{count}} exports ont démarré.",
"partial": "{{successful}} exportations sur {{total}} lancées. Échecs : {{failedItems}}",
"failed": "Échec du démarrage des exports {{total}}. Échec : {{failedItems}}"
}
}
},

View File

@ -1377,6 +1377,54 @@
"inherit": "Hériter",
"enabled": "Activé",
"disabled": "Désactivé"
},
"clone": {
"target": {
"newNameLabel": "Nom de la caméra",
"newNamePlaceholder": "p.ex., porte_arriere ou Porte arrière",
"newNameRequired": "Le nom de la caméra est requis",
"newNameInvalid": "Nom de caméra invalide",
"newNameCollision": "Une caméra avec ce nom existe déjà",
"newStreamsForced": "Les flux sont toujours copiés pour une nouvelle caméra.",
"existingCamerasRadio": "Caméras existantes",
"allCameras": "Toutes les caméras",
"existingPlaceholder": "Sélectionnez au moins une caméra",
"existingDisabled": "Aucune autre caméra à copier vers"
},
"categories": {
"legend": "Paramètres à cloner",
"description": "Choisissez quels paramètres copier depuis la caméra source.",
"selectAll": "Sélectionner tout",
"selectNone": "Sélectionner aucun",
"resetDefaults": "Rétablir à la configuration d'usine",
"general": "Général",
"spatial": "Paramètres spatiaux",
"streams": "Flux",
"spatialWarning": "La résolution détectée ({{srcWidth}}x{{srcHeight}}) de la caméra source {{srcCamera}} diffère de : {{cameras}}. Les polygones peuvent ne pas être alignés sur ces caméras. Ces paramètres sont désactivés; activer pour copier tel quel.",
"restartHint": "Redémarrage requis",
"items": {
"record": "En cours d'enregistrement",
"objects": "Objets",
"audio": "Détection audio",
"audio_transcription": "Transcription audio",
"notifications": "Notifications",
"mqtt": "MQTT",
"onvif": "ONVIF",
"face_recognition": "Reconnaissance faciale",
"semantic_search": "Recherche sémantique"
}
},
"footer": {
"submit": "Cloner",
"submitting": "Clonage…"
},
"toast": {
"success": "Paramètres copiés vers {{cameraName}}",
"successWithRestart": "Paramètres copiés vers {{cameraName}}. Redémarrez Frigate afin d'appliquer tous les changements.",
"successMulti_one": "Paramètres copiés vers {{count}} caméra",
"successMulti_many": "Paramètres copiés vers {{count}} caméras",
"successMulti_other": "Paramètres copiés vers {{count}} caméras"
}
}
},
"cameraReview": {

View File

@ -1,98 +1,503 @@
{
"yell": "Teriakan",
"speech": "Percakapan",
"babbling": "Ocehan",
"bellow": "Di bawah",
"whoop": "Teriakan",
"whispering": "Bisikan",
"snicker": "Tertawa",
"yell": "Berteriak",
"speech": "Ucapan",
"babbling": "Mengoceh (berekah)",
"bellow": "Begadang / Meraung",
"whoop": "Tertawa lepas (whoop)",
"whispering": "Berbisik",
"snicker": "Tertawa cekikikan",
"crying": "Menangis",
"sigh": "Mendesah",
"choir": "Paduan Suara",
"yodeling": "Bernyanyi Yodel",
"chant": "Nyanyian",
"sigh": "Menghela napas",
"choir": "Paduan suara",
"yodeling": "Yodel",
"chant": "Berzikir / Menyanyi berulang",
"child_singing": "Anak bernyanyi",
"rapping": "Mengetuk",
"humming": "Bersenandung",
"groan": "Mengerang",
"rapping": "Rap",
"humming": "Berdengung",
"groan": "Menggerung",
"grunt": "Mendengus",
"breathing": "Bernafas",
"breathing": "Bernapas",
"laughter": "Tertawa",
"singing": "Nyanyian",
"singing": "Bernyanyi",
"mantra": "Mantra",
"synthetic_singing": "Nyanyian sintesis",
"whistling": "Siulan",
"synthetic_singing": "Bernyanyi buatan (sintetis)",
"whistling": "Mendengung (mencicit / bersiul)",
"car": "Mobil",
"motorcycle": "Motor",
"motorcycle": "Sepeda motor",
"bicycle": "Sepeda",
"bus": "Bis",
"bus": "Bus",
"train": "Kereta",
"boat": "Kapal",
"boat": "Perahu",
"sneeze": "Bersin",
"run": "Lari",
"run": "Berlari",
"footsteps": "Langkah kaki",
"chewing": "Mengunyah",
"biting": "Menggigit",
"stomach_rumble": "Perut Keroncongan",
"stomach_rumble": "Suara perut bergerak",
"burping": "Sendawa",
"hiccup": "Cegukan",
"hiccup": "Cegukan (hikap)",
"fart": "Kentut",
"hands": "Tangan",
"heartbeat": "Detak Jantung",
"applause": "Tepuk Tangan",
"chatter": "Obrolan",
"children_playing": "Anak-Anak Bermain",
"animal": "Binatang",
"pets": "Peliharaan",
"heartbeat": "Detak jantung",
"applause": "Tepuk tangan massa",
"chatter": "Mengobrol",
"children_playing": "Anakanak bermain",
"animal": "Hewan",
"pets": "Hewan peliharaan",
"dog": "Anjing",
"bark": "Gonggongan",
"howl": "Melolong",
"bark": "Kulit kayu",
"howl": "Mengaung",
"cat": "Kucing",
"meow": "Meong",
"livestock": "Hewan Ternak",
"meow": "Mengeong",
"livestock": "Hewan ternak",
"horse": "Kuda",
"cattle": "Sapi",
"pig": "Babi",
"goat": "Kambing",
"sheep": "Domba",
"chicken": "Ayam",
"cluck": "Berkokok",
"cock_a_doodle_doo": "Kukuruyuk",
"cluck": "Menguk / \"cluck\"",
"cock_a_doodle_doo": "Berkokok (\"cockadoodledoo\")",
"turkey": "Kalkun",
"duck": "Bebek",
"quack": "Kwek",
"quack": "Menggock (\"quack\")",
"goose": "Angsa",
"wild_animals": "Hewan Liar",
"wild_animals": "Hewan liar",
"bird": "Burung",
"pigeon": "Merpati",
"crow": "Gagak",
"owl": "Burung Hantu",
"flapping_wings": "Kepakan Sayap",
"dogs": "Anjing",
"owl": "Burung hantu",
"flapping_wings": "Sayap berkibar",
"dogs": "Anjinganjing",
"insect": "Serangga",
"cricket": "Jangkrik",
"cricket": "Kerik / Kriket",
"mosquito": "Nyamuk",
"fly": "Lalat",
"frog": "Katak",
"frog": "Kodok",
"snake": "Ular",
"music": "Musik",
"musical_instrument": "Alat Musik",
"musical_instrument": "Instrumen musik",
"guitar": "Gitar",
"electric_guitar": "Gitar Elektrik",
"acoustic_guitar": "Gitar Akustik",
"strum": "Genjreng",
"electric_guitar": "Gitar listrik",
"acoustic_guitar": "Gitar akustik",
"strum": "Mengstrum",
"banjo": "Banjo",
"snoring": "Ngorok",
"snoring": "Mendengkur",
"cough": "Batuk",
"clapping": "Tepukan",
"clapping": "Tepuk tangan",
"camera": "Kamera",
"wheeze": "Nafas",
"gasp": "Tersedak",
"sound_effect": "Efek Suara",
"environmental_noise": "Suara Lingkungan",
"static": "Statis",
"white_noise": "Suara Derau",
"wheeze": "Mengi",
"gasp": "Menggigil / Tarik napas tajam",
"sound_effect": "Efek suara (sound effect)",
"environmental_noise": "Kebisingan lingkungan",
"static": "Suara statis",
"white_noise": "White noise",
"television": "Televisi",
"radio": "Radio",
"scream": "Teriakan"
"scream": "Teriakan",
"pant": "Terengah-engah",
"snort": "Mendengus (melalui hidung)",
"throat_clearing": "Membersihkan tenggorokan",
"sniff": "Mengendus",
"shuffle": "Menyeret kaki",
"gargling": "Gargling",
"finger_snapping": "Mengklik jari",
"heart_murmur": "Murmur jantung",
"cheering": "Bersorak",
"crowd": "Kerumunan orang",
"yip": "Menggonggong pendek / ringkik",
"bow_wow": "Gonggongan \"bow wow\" khas",
"growling": "Menggeram",
"whimper_dog": "Rintihan anjing",
"purr": "Mendengkur",
"hiss": "Mendesis",
"caterwaul": "Mengeong nyaring (melolong)",
"clip_clop": "Suara kuda berlari (\"clipclop\")",
"neigh": "Meringkik",
"moo": "Mengamuk / \"Moo\"",
"cowbell": "Bel sapi",
"oink": "Menggonggong \"oink\"",
"bleat": "Mengebik",
"fowl": "Unggas",
"gobble": "Menggobleg",
"honk": "Bebek / \"honk\"",
"roaring_cats": "Kucing besar mengaung",
"roar": "Mengaung (raungan predator)",
"chirp": "Cicit / bernyanyi burung kecil",
"squawk": "Mengkokok / mendengung keras",
"coo": "Mengkuk \"coo\"",
"caw": "Menggagak / \"caw\"",
"hoot": "Menghoo / \"hoot\"",
"rats": "Tikus",
"mouse": "Mouse",
"patter": "Peluit kaki kecil",
"buzz": "Menggema / \"buzz\"",
"croak": "Kokok / \"croak\"",
"rattle": "Bersuara \"rattle\"",
"whale_vocalization": "Suara vokalisasi paus",
"plucked_string_instrument": "Instrumen senar dipetik",
"bass_guitar": "Bass gitar",
"steel_guitar": "Steel gitar",
"tapping": "Mengetuk",
"sitar": "Sitar",
"mandolin": "Mandolin",
"zither": "Zither",
"ukulele": "Ukulele",
"keyboard": "Keyboard",
"piano": "Piano",
"electric_piano": "Piano elektrik",
"organ": "Organ",
"electronic_organ": "Organ elektronik",
"hammond_organ": "Organ Hammond",
"synthesizer": "Synthesizer",
"sampler": "Sampler",
"harpsichord": "Harpsichord",
"percussion": "Percussion",
"drum_kit": "Kotak drum (drum kit)",
"drum_machine": "Mesin drum (drum machine)",
"drum": "Drum",
"snare_drum": "Snare drum",
"rimshot": "Rimshot",
"drum_roll": "Roll drum",
"bass_drum": "Bass drum",
"timpani": "Timpani",
"tabla": "Tabla",
"cymbal": "Cymbal",
"hi_hat": "Hihat",
"wood_block": "Wood block",
"tambourine": "Tambourine",
"maraca": "Maraca",
"gong": "Gong",
"tubular_bells": "Tubular bells",
"mallet_percussion": "Percussion palu (mallet)",
"marimba": "Marimba",
"glockenspiel": "Glockenspiel",
"vibraphone": "Vibraphone",
"steelpan": "Steelpan",
"orchestra": "Orchestra",
"brass_instrument": "Instrumen tiup logam (brass)",
"french_horn": "French horn",
"trumpet": "Trumpet",
"trombone": "Trombone",
"bowed_string_instrument": "Instrumen senar digesek (bowed string)",
"string_section": "Seksi biola (string section)",
"violin": "Biola (violin)",
"pizzicato": "Pizzicato",
"cello": "Violoncello (cello)",
"double_bass": "Double bass",
"wind_instrument": "Instrumen tiup (wind)",
"flute": "Flute",
"saxophone": "Saxophone",
"clarinet": "Clarinet",
"harp": "Harp",
"bell": "Bel (lonceng)",
"church_bell": "Lonceng gereja",
"jingle_bell": "Jingle bell",
"bicycle_bell": "Bel sepeda",
"tuning_fork": "Tuning fork",
"chime": "Chime",
"wind_chime": "Wind chime",
"harmonica": "Harmonika",
"accordion": "Akordian",
"bagpipes": "Bagpipes",
"didgeridoo": "Didgeridoo",
"theremin": "Theremin",
"singing_bowl": "Singing bowl",
"scratching": "Scratching (DJ scratching)",
"pop_music": "Musik pop",
"hip_hop_music": "Musik hiphop",
"beatboxing": "Beatboxing",
"rock_music": "Musik rock",
"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",
"reggae": "Reggae",
"country": "Country",
"swing_music": "Swing",
"bluegrass": "Bluegrass",
"funk": "Funk",
"folk_music": "Folk",
"middle_eastern_music": "Musik Timur Tengah",
"jazz": "Jazz",
"disco": "Disco",
"classical_music": "Musik klasik",
"opera": "Opera",
"electronic_music": "Musik elektronik",
"house_music": "House music",
"techno": "Tekno",
"dubstep": "Dubstep",
"drum_and_bass": "Drum and bass",
"electronica": "Electronica",
"electronic_dance_music": "Electronic dance music (EDM)",
"ambient_music": "Musik ambient",
"trance_music": "Trance",
"music_of_latin_america": "Musik Amerika Latin",
"salsa_music": "Salsa",
"flamenco": "Flamenco",
"blues": "Blues",
"music_for_children": "Musik anakanak",
"new-age_music": "Musik new age",
"vocal_music": "Musik vokal",
"a_capella": "A cappella",
"music_of_africa": "Musik Afrika",
"afrobeat": "Afrobeat",
"christian_music": "Musik krisitan / Kristen",
"gospel_music": "Musik gospel",
"music_of_asia": "Musik Asia",
"carnatic_music": "Carnatic music",
"music_of_bollywood": "Musik Bollywood",
"ska": "Ska",
"traditional_music": "Musik tradisional",
"independent_music": "Independent music",
"song": "Lagu",
"background_music": "Background music",
"theme_music": "Theme music",
"jingle": "Jingle (lagu iklan singkat)",
"soundtrack_music": "Musik soundtrack",
"lullaby": "Lullaby",
"video_game_music": "Musik video game",
"christmas_music": "Musik Natal",
"dance_music": "Musik dansa",
"wedding_music": "Musik pernikahan",
"happy_music": "Musik bahagia",
"sad_music": "Musik sedih",
"tender_music": "Musik lembut / romantis",
"exciting_music": "Musik mendebarkan",
"angry_music": "Musik marah",
"scary_music": "Musik menakutkan",
"wind": "Angin",
"rustling_leaves": "Daun bergesekan",
"wind_noise": "Suara angin",
"thunderstorm": "Badai petir",
"thunder": "Kilat / guruh (guntur)",
"water": "Air",
"rain": "Hujan",
"raindrop": "Tetesan hujan",
"rain_on_surface": "Hujan jatuh ke permukaan",
"stream": "Aliran sungai kecil",
"waterfall": "Air terjun",
"ocean": "Laut",
"waves": "Ombak",
"steam": "Uap",
"gurgling": "Menggulung / bergolak (gurgling)",
"fire": "Api",
"crackle": "Mercekik / berderak (crackle)",
"vehicle": "Kendaraan",
"sailboat": "Perahu layar",
"rowboat": "Perahu dayung",
"motorboat": "Perahu bermotor",
"ship": "Kapal besar",
"motor_vehicle": "Kendaraan bermotor",
"toot": "Bunyi klakson kecil",
"car_alarm": "Alarm mobil",
"power_windows": "Jendela bergerak dengan tenaga listrik",
"skidding": "Selipan roda",
"tire_squeal": "Roda tergelincir / berdecit",
"car_passing_by": "Mobil melintas",
"race_car": "Mobil balap",
"truck": "Truk",
"air_brake": "Rem udara",
"air_horn": "Horn udara",
"reversing_beeps": "Bunyi beeper mundur",
"ice_cream_truck": "Mobil es krim",
"emergency_vehicle": "Kendaraan darurat",
"police_car": "Mobil patroli polisi",
"ambulance": "Ambulans",
"fire_engine": "Mobil pemadam kebakaran",
"traffic_noise": "Kebisingan lalu lintas",
"rail_transport": "Transportasi rel",
"train_whistle": "Pelecut kereta",
"train_horn": "Klakson kereta api",
"railroad_car": "Gerigit kereta api",
"train_wheels_squealing": "Rel kereta berdecit",
"subway": "Kereta bawah tanah (subway)",
"aircraft": "Pesawat udara",
"aircraft_engine": "Mesin pesawat",
"jet_engine": "Mesin jet",
"propeller": "Propeller",
"helicopter": "Helikopter",
"fixed-wing_aircraft": "Pesawat sayap tetap",
"skateboard": "Papan luncur",
"engine": "Mesin",
"light_engine": "Mesin ringan",
"dental_drill's_drill": "Bor gigi",
"lawn_mower": "Mesin pemotong rumput",
"chainsaw": "Gergaji mesin / chainsaw",
"medium_engine": "Mesin menengah",
"heavy_engine": "Mesin berat",
"engine_knocking": "Mesin berdecit",
"engine_starting": "Mesin dihidupkan",
"idling": "Mesin diam tetap hidup (idling)",
"accelerating": "Percepatan (accelerating)",
"door": "Pintu",
"doorbell": "Bel pintu",
"ding-dong": "Dingdong (bunyi bel pintu khas)",
"sliding_door": "Pintu geser",
"slam": "Menjekat (bunyi pintu ditutup keras)",
"knock": "Ketukan",
"tap": "Mengetuk",
"squeak": "Berderit",
"cupboard_open_or_close": "Kupmar terbuka atau tertutup",
"drawer_open_or_close": "Laci terbuka atau tertutup",
"dishes": "Piring",
"cutlery": "Sendok garpu",
"chopping": "Mengiris",
"frying": "Menggoreng",
"microwave_oven": "Oven microwave",
"blender": "Blender",
"water_tap": "Kran air",
"sink": "Wastafel",
"bathtub": "Bak mandi",
"hair_dryer": "Pengering rambut",
"toilet_flush": "Siraman toilet",
"toothbrush": "Sikat gigi",
"electric_toothbrush": "Sikat gigi elektrik",
"vacuum_cleaner": "Vacuum cleaner",
"zipper": "Ritsleting",
"keys_jangling": "Kunci berdering",
"coin": "Koin",
"scissors": "Gunting",
"electric_shaver": "Alat cukur listrik",
"shuffling_cards": "Mengacaukan kartu",
"typing": "Ketikan",
"typewriter": "Mesin tik",
"computer_keyboard": "Keyboard komputer",
"writing": "Menulis",
"alarm": "Alarm",
"telephone": "Telepon",
"telephone_bell_ringing": "Bel telepon berdering",
"ringtone": "Nada dering",
"telephone_dialing": "Menelepon dengan dial",
"dial_tone": "Nada tunggu (dial tone)",
"busy_signal": "Suara sibuk",
"alarm_clock": "Alarm jam",
"siren": "Sirine",
"civil_defense_siren": "Sirine perlindungan sipil",
"buzzer": "Buzzer",
"smoke_detector": "Detektor asap",
"fire_alarm": "Alarm kebakaran",
"foghorn": "Foghorn (bunyi peluit kabut laut)",
"whistle": "Peluit",
"steam_whistle": "Peluit uap",
"mechanisms": "Mekanisme",
"ratchet": "Ratchet",
"clock": "Jam",
"tick": "Detak (tick)",
"tick-tock": "Ticktock",
"gears": "Roda gigi (gears)",
"pulleys": "Katrol",
"sewing_machine": "Mesin jahit",
"mechanical_fan": "Kipas balingbaling mekanik",
"air_conditioning": "Pendingin ruangan / AC",
"cash_register": "Mesin kasir",
"printer": "Printer",
"single-lens_reflex_camera": "Kamera singlelens reflex",
"tools": "Perkakas",
"hammer": "Palu",
"jackhammer": "Jackhammer",
"sawing": "Menggergaji",
"filing": "Mengasah",
"sanding": "Mengampelas",
"power_tool": "Power tool (perkakas bermotor)",
"drill": "Bor",
"explosion": "Ledakan",
"gunshot": "Tembakan senjata api",
"machine_gun": "Senapan mesin",
"fusillade": "Fusillade (banyak tembakan sekaligus)",
"artillery_fire": "Tembakan artileri",
"cap_gun": "Senapan mainan (cap gun)",
"fireworks": "Kembang api",
"firecracker": "Petasan kembang api",
"burst": "Ledakan pecah (burst)",
"eruption": "Letusan (eruption)",
"boom": "Boom (bunyi ledakan berat)",
"wood": "Kayu",
"chop": "Menebang (chop)",
"splinter": "Bercerai (splinter)",
"crack": "Retak / pecah (crack)",
"glass": "Kaca",
"chink": "Bunyi kaca berdenting (chink)",
"shatter": "Hancur / pecah (shatter)",
"silence": "Diam / tidak ada suara (silence)",
"pink_noise": "Pink noise",
"field_recording": "Rekaman lapangan (field recording)",
"sodeling": "Menangis tertahan",
"chird": "Derit / suara aneh",
"change_ringing": "Lantunan lonceng bergantian (change ringing)",
"shofar": "Shofar",
"liquid": "Cairan",
"splash": "Cipratan (splash)",
"slosh": "Slosh (suara cairan bergoyang)",
"squish": "Squish (bunyi renyah basah)",
"drip": "Tetes (drip)",
"pour": "Tuang (pour)",
"trickle": "Menetes (trickle)",
"gush": "Mengalir deras (gush)",
"fill": "Mengisi (fill)",
"spray": "Semprot (spray)",
"pump": "Pompa",
"stir": "Aduk (stir)",
"boiling": "Mendidih",
"sonar": "Sonar",
"arrow": "Panah",
"whoosh": "Whoosh (bunyi melesat cepat)",
"thump": "Thump (bantingan)",
"thunk": "Thunk (bunyi tebal tumpul)",
"electronic_tuner": "Tuner elektronik",
"effects_unit": "Effects unit (efek audio)",
"chorus_effect": "Efek chorus",
"basketball_bounce": "Pantulan bola basket",
"bang": "Benturan keras (bang)",
"slap": "Plak (pukulan telapak)",
"whack": "Whack (pukulan keras)",
"smash": "Smash (hancurkan keras)",
"breaking": "Memecahkan",
"bouncing": "Memantul",
"whip": "Cambuk",
"flap": "Flap (sayap / lembaran berkibar)",
"scratch": "Gores (scratch)",
"scrape": "Gesekan kasar (scrape)",
"rub": "Menggosok (rub)",
"roll": "Gulung (roll)",
"crushing": "Menghancurkan (crushing)",
"crumpling": "Menggumpalkan (crumpling)",
"tearing": "Merosak (tearing)",
"beep": "Beep",
"ping": "Ping",
"ding": "Ding",
"clang": "Clang",
"squeal": "Squeal (mengerang)",
"creak": "Creak (berderit pelan)",
"rustle": "Rustle (menggerut)",
"whir": "Whir (menderu putaran cepat)",
"clatter": "Kerincing / benturan berantai (clatter)",
"sizzle": "Sizzle (menggoreng / bersiul)",
"clicking": "Clicking (bunyi kunci)",
"clickety_clack": "Clickety clack (bunyi kaki atau rel)",
"rumble": "Rumble (gempuran / gemuruh)",
"plop": "Plop (bunyi jatuh lembut ke air)",
"hum": "Hum (mendengung)",
"zing": "Zing (bunyi gesek tipis cepat)",
"boing": "Boing (bunyi pegas)",
"crunch": "Crunch (remas keras)",
"sine_wave": "Gelombang sinus (sine wave)",
"harmonic": "Harmonik",
"chirp_tone": "Tone chirp",
"pulse": "Pulse (detak / pulsa)",
"inside": "Di dalam ruangan",
"outside": "Di luar ruangan",
"reverberation": "Gema ruang (reverberation)",
"echo": "Gema (echo)",
"noise": "Kebisingan",
"mains_hum": "Mains hum (dengungan listrik arus utama)",
"distortion": "Distorsi",
"sidetone": "Sidetone (suara sendiri saat menelepon)",
"cacophony": "Kecemasan suara (cacophony)",
"throbbing": "Berdebar / gemuruh (throbbing)",
"vibration": "Vibrasi"
}

View File

@ -1,17 +1,17 @@
{
"time": {
"untilForRestart": "Hingga Frigate memulai ulang.",
"untilRestart": "Sampai memulai ulang",
"ago": "{{timeAgo}} Lalu",
"justNow": "Sekarang",
"untilForRestart": "Sampai Frigate dimulai ulang.",
"untilRestart": "Sampai dimulai ulang",
"ago": "{{timeAgo}} yang lalu",
"justNow": "Baru saja",
"today": "Hari ini",
"yesterday": "Kemarin",
"untilForTime": "Sampai",
"untilForTime": "Sampai {{time}}",
"last7": "7 hari terakhir",
"last14": "14 hari terakhir",
"last30": "30 hari terakhir",
"thisWeek": "Minggu Ini",
"never": "Tidak Pernah",
"never": "Tidak pernah",
"lastWeek": "Minggu Lalu",
"thisMonth": "Bulan Ini",
"lastMonth": "Bulan Lalu",
@ -21,11 +21,296 @@
"1hour": "1 jam",
"12hours": "12 jam",
"24hours": "24 jam",
"pm": "pm",
"am": "am",
"yr": "{{time}} tahun",
"pm": "PM",
"am": "AM",
"yr": "{{time}} th",
"year_other": "{{time}} tahun",
"mo": "{{time}} bulan"
"mo": "{{time}} bln",
"month_other": "{{time}} bulan",
"d": "{{time}} hr",
"day_other": "{{time}} hari",
"h": "{{time}} jam",
"hour_other": "{{time}} jam",
"m": "{{time}} mnt",
"minute_other": "{{time}} menit",
"s": "{{time}} dtk",
"second_other": "{{time}} detik",
"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"
},
"inProgress": "Sedang berlangsung",
"invalidStartTime": "Waktu mulai tidak valid",
"invalidEndTime": "Waktu selesai tidak valid"
},
"readTheDocumentation": "Baca dokumentasi"
"readTheDocumentation": "Baca dokumentasi",
"menu": {
"system": "Sistem",
"profiles": "Profil",
"systemMetrics": "Metrik sistem",
"configuration": "Konfigurasi",
"systemLogs": "Log sistem",
"settings": "Pengaturan",
"configurationEditor": "Editor Konfigurasi",
"languages": "Bahasa",
"language": {
"en": "English (Inggris)",
"es": "Español (Spanyol)",
"zhCN": "简体中文 (Tionghoa Sederhana)",
"hi": "हिन्दी (Hindi)",
"fr": "Français (Prancis)",
"ar": "العربية (Arab)",
"pt": "Português (Portugis)",
"ptBR": "Português brasileiro (Portugis Brasil)",
"ru": "Русский (Rusia)",
"de": "Deutsch (Jerman)",
"ja": "日本語 (Jepang)",
"tr": "Türkçe (Turki)",
"it": "Italiano (Italia)",
"nl": "Nederlands (Belanda)",
"sv": "Svenska (Swedia)",
"cs": "Čeština (Ceko)",
"nb": "Norsk Bokmål (Norwegia Bokmål)",
"ko": "한국어 (Korea)",
"vi": "Tiếng Việt (Vietnam)",
"fa": "فارسی (Persia)",
"pl": "Polski (Polandia)",
"uk": "Українська (Ukraina)",
"he": "עברית (Ibrani)",
"el": "Ελληνικά (Yunani)",
"ro": "Română (Rumania)",
"hu": "Magyar (Hungaria)",
"fi": "Suomi (Finlandia)",
"da": "Dansk (Denmark)",
"sk": "Slovenčina (Slovakia)",
"yue": "粵語 (Kanton)",
"th": "ไทย (Thai)",
"ca": "Català (Katalan)",
"hr": "Hrvatski (Kroasia)",
"bs": "Bosanski (Bosnia)",
"sr": "Српски (Serbia)",
"sl": "Slovenščina (Slovenia)",
"lt": "Lietuvių (Lituania)",
"bg": "Български (Bulgaria)",
"gl": "Galego (Galisia)",
"id": "Bahasa Indonesia (Indonesia)",
"ur": "اردو (Urdu)",
"withSystem": {
"label": "Gunakan pengaturan sistem untuk bahasa"
}
},
"appearance": "Tampilan",
"darkMode": {
"label": "Mode Gelap",
"light": "Terang",
"dark": "Gelap",
"withSystem": {
"label": "Gunakan pengaturan sistem untuk mode terang atau gelap"
}
},
"withSystem": "Sistem",
"theme": {
"label": "Tema",
"blue": "Biru",
"green": "Hijau",
"nord": "Nord",
"red": "Merah",
"highcontrast": "Kontras Tinggi",
"default": "Default"
},
"help": "Bantuan",
"documentation": {
"title": "Dokumentasi",
"label": "Dokumentasi Frigate"
},
"restart": "Mulai Ulang Frigate",
"live": {
"title": "Live",
"allCameras": "Semua Kamera",
"cameras": {
"title": "Kamera",
"count_other": "{{count}} Kamera"
}
},
"review": "Tinjauan",
"explore": "Jelajah",
"export": "Ekspor",
"actions": "Tindakan",
"uiPlayground": "UI Playground",
"features": "Fitur",
"faceLibrary": "Pustaka Wajah",
"classification": "Klasifikasi",
"chat": "Chat",
"user": {
"title": "Pengguna",
"account": "Akun",
"current": "Pengguna Saat Ini: {{user}}",
"anonymous": "anonim",
"logout": "Keluar",
"setPassword": "Atur Kata Sandi"
}
},
"unit": {
"speed": {
"mph": "mph",
"kph": "kph"
},
"length": {
"feet": "kaki",
"meters": "meter"
},
"data": {
"kbps": "kB/dtk",
"mbps": "MB/dtk",
"gbps": "GB/dtk",
"kbph": "kB/jam",
"mbph": "MB/jam",
"gbph": "GB/jam"
}
},
"label": {
"back": "Kembali",
"hide": "Sembunyikan {{item}}",
"show": "Tampilkan {{item}}",
"ID": "ID",
"none": "Tidak ada",
"all": "Semua",
"other": "Lainnya"
},
"list": {
"two": "{{0}} dan {{1}}",
"many": "{{items}}, dan {{last}}",
"separatorWithSpace": ", "
},
"field": {
"optional": "Opsional",
"internalID": "ID Internal yang digunakan Frigate dalam konfigurasi dan basis data"
},
"button": {
"add": "Tambah",
"apply": "Terapkan",
"applying": "Menerapkan…",
"reset": "Atur Ulang",
"undo": "Urungkan",
"done": "Selesai",
"enabled": "Diaktifkan",
"enable": "Aktifkan",
"disabled": "Dinonaktifkan",
"disable": "Nonaktifkan",
"save": "Simpan",
"saving": "Menyimpan…",
"cancel": "Batal",
"close": "Tutup",
"copy": "Salin",
"copiedToClipboard": "Disalin ke papan klip",
"back": "Kembali",
"history": "Riwayat",
"fullscreen": "Layar Penuh",
"exitFullscreen": "Keluar dari Layar Penuh",
"pictureInPicture": "Gambar dalam Gambar",
"twoWayTalk": "Audio Dua Arah",
"cameraAudio": "Audio Kamera",
"on": "AKTIF",
"off": "NONAKTIF",
"edit": "Edit",
"copyCoordinates": "Salin koordinat",
"delete": "Hapus",
"yes": "Ya",
"no": "Tidak",
"download": "Unduh",
"info": "Info",
"suspended": "Ditangguhkan",
"unsuspended": "Batalkan penangguhan",
"play": "Putar",
"unselect": "Batalkan pilihan",
"export": "Ekspor",
"deleteNow": "Hapus Sekarang",
"next": "Berikutnya",
"continue": "Lanjutkan",
"modified": "Diubah",
"overridden": "Ditimpa",
"resetToGlobal": "Atur Ulang ke Global",
"resetToDefault": "Atur Ulang ke Default",
"saveAll": "Simpan Semua",
"savingAll": "Menyimpan Semua…",
"undoAll": "Urungkan Semua",
"retry": "Coba Lagi"
},
"toast": {
"copyUrlToClipboard": "URL disalin ke papan klip.",
"save": {
"title": "Simpan",
"error": {
"title": "Gagal menyimpan perubahan konfigurasi: {{errorMessage}}",
"noMessage": "Gagal menyimpan perubahan konfigurasi"
},
"success": "Berhasil menyimpan perubahan konfigurasi."
}
},
"role": {
"title": "Peran",
"admin": "Admin",
"viewer": "Penampil",
"desc": "Admin memiliki akses penuh ke semua fitur di UI Frigate. Penampil terbatas hanya untuk melihat kamera, item tinjauan, dan rekaman historis di UI."
},
"pagination": {
"label": "paginasi",
"previous": {
"title": "Sebelumnya",
"label": "Buka halaman sebelumnya"
},
"next": {
"title": "Berikutnya",
"label": "Buka halaman berikutnya"
},
"more": "Halaman lainnya"
},
"accessDenied": {
"documentTitle": "Akses Ditolak - Frigate",
"title": "Akses Ditolak",
"desc": "Anda tidak memiliki izin untuk melihat halaman ini."
},
"notFound": {
"documentTitle": "Tidak Ditemukan - Frigate",
"title": "404",
"desc": "Halaman tidak ditemukan"
},
"selectItem": "Pilih {{item}}",
"information": {
"pixels": "{{area}}px"
},
"no_items": "Tidak ada item",
"validation_errors": "Kesalahan Validasi",
"credentialField": {
"savedPlaceholder": "Tersimpan — biarkan kosong untuk mempertahankan yang saat ini"
}
}

View File

@ -1,3 +1,62 @@
{
"label": "Pengaturan Kamera"
"label": "Pengaturan Kamera",
"name": {
"label": "Nama Kamera",
"description": "Nama Kamera diwajibkan"
},
"friendly_name": {
"label": "Nama Singkat",
"description": "Nama Singkat kamera digunakan pada tampilan UI Frigate"
},
"audio": {
"label": "Deteksi Suara",
"description": "Pengaturan untuk Deteksi Kejadian berdasarkan Suara pada kamera ini.",
"enabled": {
"label": "Nyalakan Deteksi Suara",
"description": "Nyalakan atau matikan deteksi kejadian suara pada kamera ini."
},
"filters": {
"threshold": {
"label": "Keyakinan-Suara Minimum"
}
},
"min_volume": {
"label": "Volume-Suara Minimum"
}
},
"audio_transcription": {
"label": "Transkripsi Suara",
"enabled": {
"label": "Nyalakan Transkripsi"
},
"live_enabled": {
"label": "Transkripsi Langsung (Live)"
}
},
"detect": {
"label": "Deteksi Objek",
"enabled": {
"label": "Nyalakan Deteksi Objek"
},
"stationary": {
"classifier": {
"label": "Nyalakan Klasifikasi-Visual",
"description": "Menggunakan pengklasifikasi visual untuk membedakan objek-objek diam (benar-benar tidak bergerak), meskipun bounding-box kurang stabil atau bergetar (jitter)."
}
},
"fps": {
"label": "Kecepatan (FPS) Deteksi",
"description": "Kecepatan yang ditargetkan untuk menjalankan Deteksi Objek, dalam satuan frame per second (FPS); nilai lebih rendah mengurangi intensitas proses dan dapat meringangkan beban kerja CPU. Nilai 5 direkomendasikan, sedangakan nilai 10 dianggap sangat tinggi dan hanya digunakan untuk pelacakan (tracking) benda yang bergerak dengan benar-benar cepat."
}
},
"enabled": {
"label": "Dinyalakan",
"description": "Dinyalakan (Enabled)"
},
"birdseye": {
"enabled": {
"description": "Nyalakan atau matikan fitur Penglihatan Atas (Birdseye View).",
"label": "Nyalakan Birdseye"
}
}
}

View File

@ -1,5 +1,47 @@
{
"version": {
"label": "Versi konfigurasi"
},
"audio": {
"label": "Deteksi Suara",
"enabled": {
"label": "Nyalakan Deteksi Suara"
},
"filters": {
"threshold": {
"label": "Keyakinan-Suara Minimum"
}
},
"min_volume": {
"label": "Volume-Suara Minimum"
}
},
"audio_transcription": {
"label": "Transkripsi Suara",
"live_enabled": {
"label": "Transkripsi Langsung (Live)"
}
},
"detect": {
"label": "Deteksi Objek",
"enabled": {
"label": "Nyalakan Deteksi Objek"
},
"stationary": {
"classifier": {
"label": "Nyalakan Klasifikasi-Visual",
"description": "Menggunakan pengklasifikasi visual untuk membedakan objek-objek diam (benar-benar tidak bergerak), meskipun bounding-box kurang stabil atau bergetar (jitter)."
}
},
"fps": {
"label": "Kecepatan (FPS) Deteksi",
"description": "Kecepatan yang ditargetkan untuk menjalankan Deteksi Objek, dalam satuan frame per second (FPS); nilai lebih rendah mengurangi intensitas proses dan dapat meringangkan beban kerja CPU. Nilai 5 direkomendasikan, sedangakan nilai 10 dianggap sangat tinggi dan hanya digunakan untuk pelacakan (tracking) benda yang bergerak dengan benar-benar cepat."
}
},
"birdseye": {
"enabled": {
"description": "Nyalakan atau matikan fitur Penglihatan Atas (Birdseye View).",
"label": "Nyalakan Birdseye"
}
}
}

View File

@ -2,30 +2,128 @@
"person": "Orang",
"bicycle": "Sepeda",
"car": "Mobil",
"motorcycle": "Motor",
"motorcycle": "Sepeda motor",
"airplane": "Pesawat",
"bus": "Bis",
"bus": "Bus",
"train": "Kereta",
"boat": "Kapal",
"traffic_light": "Lampu Lalu Lintas",
"fire_hydrant": "Hidran Kebakaran",
"animal": "Binatang",
"boat": "Perahu",
"traffic_light": "Lampu lalu lintas",
"fire_hydrant": "Hidran kebakaran",
"animal": "Hewan",
"dog": "Anjing",
"bark": "Gonggongan",
"bark": "Kulit kayu",
"cat": "Kucing",
"horse": "Kuda",
"goat": "Kambing",
"sheep": "Domba",
"bird": "Burung",
"street_sign": "Rambu Jalan",
"stop_sign": "Tanda Stop",
"parking_meter": "Parkir Meter",
"bench": "Kursi",
"street_sign": "Rambu jalan",
"stop_sign": "Rambu berhenti",
"parking_meter": "Meter parkir",
"bench": "Bangku",
"cow": "Sapi",
"elephant": "Gajah",
"bear": "Beruang",
"zebra": "Zebra",
"giraffe": "Jerapah",
"hat": "Topi",
"backpack": "Tas"
"backpack": "Ransel",
"mouse": "Mouse",
"keyboard": "Keyboard",
"vehicle": "Kendaraan",
"skateboard": "Papan luncur",
"door": "Pintu",
"blender": "Blender",
"sink": "Wastafel",
"hair_dryer": "Pengering rambut",
"toothbrush": "Sikat gigi",
"scissors": "Gunting",
"clock": "Jam",
"umbrella": "Payung",
"shoe": "Sepatu",
"eye_glasses": "Kacamata",
"handbag": "Tas tangan",
"tie": "Dasi",
"suitcase": "Koper",
"frisbee": "Frisbee",
"skis": "Ski",
"snowboard": "Papan seluncur salju",
"sports_ball": "Bola olahraga",
"kite": "Layang-layang",
"baseball_bat": "Tongkat bisbol",
"baseball_glove": "Sarung tangan bisbol",
"surfboard": "Papan selancar",
"tennis_racket": "Raket tenis",
"bottle": "Botol",
"plate": "Piring",
"wine_glass": "Gelas anggur",
"cup": "Cangkir",
"fork": "Garpu",
"knife": "Pisau",
"spoon": "Sendok",
"bowl": "Mangkuk",
"banana": "Pisang",
"apple": "Apel",
"sandwich": "Sandwich",
"orange": "Jeruk",
"broccoli": "Brokoli",
"carrot": "Wortel",
"hot_dog": "Hot dog",
"pizza": "Pizza",
"donut": "Donat",
"cake": "Kue",
"chair": "Kursi",
"couch": "Sofa",
"potted_plant": "Tanaman dalam pot",
"bed": "Tempat tidur",
"mirror": "Cermin",
"dining_table": "Meja makan",
"window": "Jendela",
"desk": "Meja tulis",
"toilet": "Toilet",
"tv": "TV",
"laptop": "Laptop",
"remote": "Remote",
"cell_phone": "Ponsel",
"microwave": "Microwave",
"oven": "Oven",
"toaster": "Pemanggang roti",
"refrigerator": "Kulkas",
"book": "Buku",
"vase": "Vas",
"teddy_bear": "Boneka beruang",
"hair_brush": "Sikat rambut",
"squirrel": "Tupai",
"deer": "Rusa",
"fox": "Rubah",
"rabbit": "Kelinci",
"raccoon": "Rakuns",
"robot_lawnmower": "Mesin pemotong rumput robot",
"waste_bin": "Tempat sampah",
"on_demand": "Sesuai permintaan",
"face": "Wajah",
"license_plate": "Pelat nomor",
"package": "Paket",
"bbq_grill": "Panggangan BBQ",
"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",
"canada_post": "Canada Post",
"royal_mail": "Royal Mail",
"school_bus": "Bus sekolah",
"skunk": "Sigung",
"kangaroo": "Kanguru",
"baby": "Bayi",
"baby_stroller": "Kereta dorong bayi",
"rickshaw": "Becak",
"rodent": "Hewan pengerat"
}

View File

@ -16,7 +16,9 @@
}
},
"timeline.aria": "Pilih timeline",
"timeline": "Linimasa",
"timeline": {
"label": "Linimasa"
},
"zoomIn": "Perbesar",
"zoomOut": "Perkecil",
"events": {
@ -43,7 +45,9 @@
},
"documentTitle": "Tinjauan - Frigate",
"recordings": {
"documentTitle": "Rekaman - Frigate"
"documentTitle": "Rekaman - Frigate",
"invalidSharedLink": "Tidak dapat membuka tautan rekaman bertanda waktu karena kesalahan penguraian.",
"invalidSharedCamera": "Tidak dapat membuka tautan rekaman bertanda waktu karena kamera tidak dikenal atau tidak berwenang."
},
"calendarFilter": {
"last24Hours": "24 Jam Terakhir"
@ -54,10 +58,37 @@
"button": "Item Batu Untuk Ditinjau",
"label": "Lihat item ulasan baru"
},
"selected_one": "{{count}} terpilih",
"selected_other": "{{count}} terpilih",
"selected_one": "{{count}} dipilih",
"selected_other": "{{count}} dipilih",
"camera": "Kamera",
"detected": "terdeteksi",
"suspiciousActivity": "Aktivitas Mencurigakan",
"threateningActivity": "Aktivitas yang Mengancam"
"threateningActivity": "Aktivitas yang Mengancam",
"select_all": "Semua",
"normalActivity": "Normal",
"needsReview": "Perlu ditinjau",
"securityConcern": "Kendala keamanan",
"motionSearch": {
"menuItem": "Pencarian gerakan",
"openMenu": "Opsi kamera"
},
"motionPreviews": {
"menuItem": "Lihat pratinjau gerakan",
"title": "Pratinjau gerakan: {{camera}}",
"mobileSettingsTitle": "Setelan Pratinjau Gerakan",
"mobileSettingsDesc": "Sesuaikan kecepatan pemutaran dan peredupan, serta pilih tanggal untuk meninjau klip hanya gerakan.",
"dim": "Redup",
"dimAria": "Sesuaikan intensitas peredupan",
"dimDesc": "Tingkatkan peredupan untuk meningkatkan visibilitas area gerakan.",
"speed": "Kecepatan",
"speedAria": "Pilih kecepatan pemutaran pratinjau",
"speedDesc": "Pilih seberapa cepat klip pratinjau diputar.",
"back": "Kembali",
"empty": "Tidak ada pratinjau tersedia",
"noPreview": "Pratinjau tidak tersedia",
"seekAria": "Pindahkan {{camera}} pemain ke {{time}}",
"filter": "Filter",
"filterDesc": "Pilih area untuk hanya menampilkan klip dengan gerakan di wilayah tersebut.",
"filterClear": "Hapus"
}
}

View File

@ -2,45 +2,262 @@
"documentTitle": "Jelajahi - Frigate",
"generativeAI": "AI Generatif",
"exploreIsUnavailable": {
"title": "Penelusuran tidak tersedia",
"title": "Jelajah Tidak Tersedia",
"embeddingsReindexing": {
"context": "Jelajahi dapat digunakan setelah embedding objek yang dilacak selesai di-reindex.",
"context": "Jelajah dapat digunakan setelah embedding objek terlacak selesai diindeks ulang.",
"startingUp": "Sedang memulai…",
"estimatedTime": "Perkiraan waktu tersisa:",
"finishingShortly": "Selesai sesaat lagi",
"finishingShortly": "Segera selesai",
"step": {
"thumbnailsEmbedded": "Keluku dilampirkan ",
"descriptionsEmbedded": "Deskripsi terlampir: ",
"trackedObjectsProcessed": "Objek yang dilacak diproses: "
"thumbnailsEmbedded": "Thumbnail yang disematkan: ",
"descriptionsEmbedded": "Deskripsi yang disematkan: ",
"trackedObjectsProcessed": "Objek terlacak yang diproses: "
}
},
"downloadingModels": {
"context": "Frigate sedang mengunduh model embedding yang diperlukan untuk mendukung fitur Pencarian Semantik. Proses ini mungkin memakan waktu beberapa menit tergantung pada kecepatan koneksi jaringan Anda.",
"context": "Frigate sedang mengunduh model embedding yang diperlukan untuk mendukung fitur Pencarian Semantik. Ini mungkin memerlukan beberapa menit tergantung pada kecepatan koneksi jaringan Anda.",
"setup": {
"visionModel": "Model vision",
"visionModelFeatureExtractor": "Ekstraktor fitur model visi",
"visionModel": "Model visi",
"visionModelFeatureExtractor": "Pengekstrak fitur model visi",
"textModel": "Model teks",
"textTokenizer": "Teks tokenizer"
"textTokenizer": "Tokenizer teks"
},
"tips": {
"context": "Anda mungkin ingin mengindeks ulang embeddings dari objek yang Anda lacak setelah model-model tersebut diunduh."
"context": "Anda mungkin ingin mengindeks ulang embedding objek terlacak Anda setelah model selesai diunduh."
},
"error": "Terjadi eror. Periksa log Frigate."
"error": "Terjadi kesalahan. Periksa log Frigate."
}
},
"details": {
"timestamp": "Stempel waktu"
"timestamp": "Cap waktu",
"item": {
"title": "Detail Item Tinjauan",
"desc": "Detail item tinjauan",
"button": {
"share": "Bagikan item tinjauan ini",
"viewInExplore": "Lihat di Jelajah"
},
"tips": {
"mismatch_other": "{{count}} objek yang tidak tersedia terdeteksi dan disertakan dalam item tinjauan ini. Objek-objek tersebut tidak memenuhi syarat sebagai peringatan atau deteksi, atau sudah dibersihkan/dihapus.",
"hasMissingObjects": "Sesuaikan konfigurasi Anda jika Anda ingin Frigate menyimpan objek terlacak untuk label berikut: <em>{{objects}}</em>"
},
"toast": {
"success": {
"regenerate": "Deskripsi baru telah diminta dari {{provider}}. Tergantung pada kecepatan penyedia Anda, deskripsi baru mungkin memerlukan waktu untuk dibuat ulang.",
"updatedSublabel": "Berhasil memperbarui sublabel.",
"updatedLPR": "Berhasil memperbarui pelat nomor.",
"updatedAttributes": "Berhasil memperbarui atribut.",
"audioTranscription": "Berhasil meminta transkripsi audio. Tergantung pada kecepatan server Frigate Anda, transkripsi mungkin memerlukan waktu untuk selesai."
},
"error": {
"regenerate": "Gagal memanggil {{provider}} untuk deskripsi baru: {{errorMessage}}",
"updatedSublabelFailed": "Gagal memperbarui sublabel: {{errorMessage}}",
"updatedLPRFailed": "Gagal memperbarui pelat nomor: {{errorMessage}}",
"updatedAttributesFailed": "Gagal memperbarui atribut: {{errorMessage}}",
"audioTranscription": "Gagal meminta transkripsi audio: {{errorMessage}}"
}
}
},
"label": "Label",
"editSubLabel": {
"title": "Edit sublabel",
"desc": "Masukkan sublabel baru untuk {{label}} ini",
"descNoLabel": "Masukkan sublabel baru untuk objek terlacak ini"
},
"editLPR": {
"title": "Edit pelat nomor",
"desc": "Masukkan nilai pelat nomor baru untuk {{label}} ini",
"descNoLabel": "Masukkan nilai pelat nomor baru untuk objek terlacak ini"
},
"editAttributes": {
"title": "Edit atribut",
"desc": "Pilih atribut klasifikasi untuk {{label}} ini"
},
"snapshotScore": {
"label": "Skor Snapshot"
},
"topScore": {
"label": "Skor Tertinggi",
"info": "Skor tertinggi adalah skor median tertinggi untuk objek terlacak, jadi ini mungkin berbeda dari skor yang ditampilkan pada thumbnail hasil pencarian."
},
"score": {
"label": "Skor"
},
"recognizedLicensePlate": "Pelat Nomor yang Diakui",
"attributes": "Atribut Klasifikasi",
"estimatedSpeed": "Perkiraan Kecepatan",
"objects": "Objek",
"camera": "Kamera",
"zones": "Zona",
"button": {
"findSimilar": "Cari yang Serupa",
"regenerate": {
"title": "Buat Ulang",
"label": "Buat ulang deskripsi objek terlacak"
}
},
"description": {
"label": "Deskripsi",
"placeholder": "Deskripsi objek terlacak",
"aiTips": "Frigate tidak akan meminta deskripsi dari penyedia AI Generatif Anda sampai siklus hidup objek terlacak berakhir."
},
"expandRegenerationMenu": "Perluas menu pembuatan ulang",
"regenerateFromSnapshot": "Buat Ulang dari Snapshot",
"regenerateFromThumbnails": "Buat Ulang dari Thumbnail",
"tips": {
"descriptionSaved": "Berhasil menyimpan deskripsi",
"saveDescriptionFailed": "Gagal memperbarui deskripsi: {{errorMessage}}"
},
"title": {
"label": "Judul"
},
"scoreInfo": "Informasi Skor"
},
"exploreMore": "Eksplor lebih jauh objek-objek {{label}}",
"exploreMore": "Jelajahi lebih banyak objek {{label}}",
"trackedObjectDetails": "Detail Objek Terlacak",
"type": {
"details": "detail",
"snapshot": "tangkapan layar",
"snapshot": "snapshot",
"thumbnail": "thumbnail",
"video": "video",
"tracking_details": "detail pelacakan"
},
"trackingDetails": {
"title": "Detail Pelacakan"
"title": "Detail Pelacakan",
"noImageFound": "Tidak ada gambar yang ditemukan untuk cap waktu ini.",
"createObjectMask": "Buat Masker Objek",
"adjustAnnotationSettings": "Sesuaikan pengaturan anotasi",
"scrollViewTips": "Klik untuk melihat momen-momen penting dalam siklus hidup objek ini.",
"autoTrackingTips": "Posisi kotak pembatas tidak akan akurat untuk kamera dengan pelacakan otomatis.",
"count": "{{first}} dari {{second}}",
"trackedPoint": "Titik Terlacak",
"lifecycleItemDesc": {
"visible": "{{label}} terdeteksi",
"entered_zone": "{{label}} memasuki {{zones}}",
"active": "{{label}} menjadi aktif",
"stationary": "{{label}} menjadi diam",
"attribute": {
"faceOrLicense_plate": "{{attribute}} terdeteksi untuk {{label}}",
"other": "{{label}} dikenali sebagai {{attribute}}"
},
"gone": "{{label}} pergi",
"heard": "{{label}} terdengar",
"external": "{{label}} terdeteksi",
"header": {
"zones": "Zona",
"ratio": "Rasio",
"area": "Area",
"score": "Skor",
"computedScore": "Skor Terhitung",
"topScore": "Skor Tertinggi",
"toggleAdvancedScores": "Alihkan skor lanjutan"
}
},
"annotationSettings": {
"title": "Pengaturan Anotasi",
"showAllZones": {
"title": "Tampilkan Semua Zona",
"desc": "Selalu tampilkan zona pada frame tempat objek telah memasuki suatu zona."
},
"offset": {
"label": "Offset Anotasi",
"desc": "Data ini berasal dari feed deteksi kamera Anda tetapi ditumpangkan pada gambar dari feed rekaman. Sangat mungkin kedua stream tersebut tidak sinkron sepenuhnya. Akibatnya, kotak pembatas dan rekaman tidak akan sejajar dengan sempurna. Anda dapat menggunakan pengaturan ini untuk menggeser anotasi maju atau mundur dalam waktu agar lebih selaras dengan rekaman video.",
"millisecondsToOffset": "Milidetik untuk menggeser anotasi deteksi. <em>Default: 0</em>",
"tips": "Turunkan nilainya jika pemutaran video berada di depan kotak dan titik jalur, dan naikkan nilainya jika pemutaran video berada di belakangnya. Nilai ini bisa negatif.",
"toast": {
"success": "Offset anotasi untuk {{camera}} telah disimpan ke file konfigurasi."
}
}
},
"carousel": {
"previous": "Slide sebelumnya",
"next": "Slide berikutnya"
}
},
"itemMenu": {
"downloadVideo": {
"label": "Unduh video",
"aria": "Unduh video"
},
"downloadSnapshot": {
"label": "Unduh snapshot",
"aria": "Unduh snapshot"
},
"downloadCleanSnapshot": {
"label": "Unduh snapshot bersih",
"aria": "Unduh snapshot bersih"
},
"viewTrackingDetails": {
"label": "Lihat detail pelacakan",
"aria": "Tampilkan detail pelacakan"
},
"findSimilar": {
"label": "Cari yang serupa",
"aria": "Cari objek terlacak yang serupa"
},
"addTrigger": {
"label": "Tambahkan pemicu",
"aria": "Tambahkan pemicu untuk objek terlacak ini"
},
"audioTranscription": {
"label": "Transkripsikan",
"aria": "Minta transkripsi audio"
},
"submitToPlus": {
"label": "Kirim ke Frigate+",
"aria": "Kirim ke Frigate Plus"
},
"viewInHistory": {
"label": "Lihat di Riwayat",
"aria": "Lihat di Riwayat"
},
"deleteTrackedObject": {
"label": "Hapus objek terlacak ini"
},
"showObjectDetails": {
"label": "Tampilkan jalur objek"
},
"hideObjectDetails": {
"label": "Sembunyikan jalur objek"
},
"debugReplay": {
"label": "Pemutaran Ulang Debug",
"aria": "Lihat objek terlacak ini dalam tampilan pemutaran ulang debug"
},
"more": {
"aria": "Lainnya"
}
},
"dialog": {
"confirmDelete": {
"title": "Konfirmasi Hapus",
"desc": "Menghapus objek terlacak ini akan menghapus snapshot, embedding yang tersimpan, dan entri detail pelacakan terkait. Rekaman video dari objek terlacak ini di tampilan Riwayat <em>TIDAK</em> akan dihapus.<br /><br />Anda yakin ingin melanjutkan?"
},
"toast": {
"error": "Kesalahan saat menghapus objek terlacak ini: {{errorMessage}}"
}
},
"noTrackedObjects": "Tidak Ada Objek Terlacak Ditemukan",
"fetchingTrackedObjectsFailed": "Kesalahan saat mengambil objek terlacak: {{errorMessage}}",
"trackedObjectsCount_other": "{{count}} objek terlacak ",
"searchResult": {
"tooltip": "Cocok dengan {{type}} pada {{confidence}}%",
"previousTrackedObject": "Objek terlacak sebelumnya",
"nextTrackedObject": "Objek terlacak berikutnya",
"deleteTrackedObject": {
"toast": {
"success": "Objek terlacak berhasil dihapus.",
"error": "Gagal menghapus objek terlacak: {{errorMessage}}"
}
}
},
"aiAnalysis": {
"title": "Analisis AI"
},
"concerns": {
"label": "Kekhawatiran"
},
"objectLifecycle": {
"noImageFound": "Tidak ada gambar yang ditemukan untuk objek terlacak ini."
}
}

View File

@ -1,23 +1,128 @@
{
"documentTitle": "Expor - Frigate",
"search": "Cari",
"noExports": "Ekspor tidak ditemukan",
"deleteExport": "Hapus Ekspor",
"deleteExport.desc": "Apakah Anda yakin ingin menghapus {{exportName}}?",
"documentTitle": "Ekspor - Frigate",
"search": "Pencarian",
"noExports": "Tidak ada ekspor ditemukan",
"deleteExport": {
"label": "Hapus Ekspor"
},
"deleteExport.desc": "Anda yakin ingin menghapus {{exportName}}?",
"editExport": {
"title": "Ubah nama ekspor",
"title": "Ubah Nama Ekspor",
"desc": "Masukkan nama baru untuk ekspor ini.",
"saveExport": "Simpan Ekspor"
},
"toast": {
"error": {
"renameExportFailed": "Gagal mengganti nama ekspor: {{errorMessage}}"
"renameExportFailed": "Gagal mengubah nama ekspor: {{errorMessage}}",
"assignCaseFailed": "Gagal memperbarui penetapan kasus: {{errorMessage}}",
"caseSaveFailed": "Gagal menyimpan kasus: {{errorMessage}}",
"caseDeleteFailed": "Gagal menghapus kasus: {{errorMessage}}"
}
},
"tooltip": {
"shareExport": "Bagikan Ekspor",
"downloadVideo": "Unduh Video",
"shareExport": "Bagikan ekspor",
"downloadVideo": "Unduh video",
"editName": "Ubah nama",
"deleteExport": "Hapus ekspor"
"deleteExport": "Hapus ekspor",
"assignToCase": "Tambahkan ke kasus",
"removeFromCase": "Hapus dari kasus"
},
"headings": {
"cases": "Kasus",
"uncategorizedExports": "Ekspor Tanpa Kategori"
},
"toolbar": {
"newCase": "Kasus Baru",
"addExport": "Tambahkan Ekspor",
"editCase": "Edit Kasus",
"deleteCase": "Hapus Kasus"
},
"deleteCase": {
"label": "Hapus Kasus",
"desc": "Anda yakin ingin menghapus {{caseName}}?",
"descKeepExports": "Ekspor akan tetap tersedia sebagai ekspor tanpa kategori.",
"descDeleteExports": "Semua ekspor dalam kasus ini akan dihapus secara permanen.",
"deleteExports": "Hapus juga ekspor"
},
"caseDialog": {
"title": "Tambahkan ke kasus",
"description": "Pilih kasus yang sudah ada atau buat yang baru.",
"selectLabel": "Kasus",
"newCaseOption": "Buat kasus baru",
"nameLabel": "Nama kasus",
"descriptionLabel": "Deskripsi"
},
"caseCard": {
"emptyCase": "Belum ada ekspor"
},
"jobCard": {
"defaultName": "Ekspor {{camera}}",
"queued": "Dalam antrean",
"running": "Sedang berjalan",
"preparing": "Menyiapkan",
"copying": "Menyalin",
"encoding": "Menyandi",
"encodingRetry": "Menyandi (coba lagi)",
"finalizing": "Menyelesaikan"
},
"caseView": {
"noDescription": "Tidak ada deskripsi",
"createdAt": "Dibuat {{value}}",
"exportCount_one": "1 ekspor",
"exportCount_other": "{{count}} ekspor",
"cameraCount_one": "1 kamera",
"cameraCount_other": "{{count}} kamera",
"showMore": "Tampilkan lebih banyak",
"showLess": "Tampilkan lebih sedikit",
"emptyTitle": "Kasus ini kosong",
"emptyDescription": "Tambahkan ekspor tanpa kategori yang sudah ada agar kasus tetap terorganisasi.",
"emptyDescriptionNoExports": "Belum ada ekspor tanpa kategori yang tersedia untuk ditambahkan."
},
"caseEditor": {
"createTitle": "Buat Kasus",
"editTitle": "Edit Kasus",
"namePlaceholder": "Nama kasus",
"descriptionPlaceholder": "Tambahkan catatan atau konteks untuk kasus ini"
},
"addExportDialog": {
"title": "Tambahkan Ekspor ke {{caseName}}",
"searchPlaceholder": "Cari ekspor tanpa kategori",
"empty": "Tidak ada ekspor tanpa kategori yang cocok dengan pencarian ini.",
"addButton_one": "Tambahkan 1 Ekspor",
"addButton_other": "Tambahkan {{count}} Ekspor",
"adding": "Menambahkan..."
},
"selected_one": "{{count}} dipilih",
"selected_other": "{{count}} dipilih",
"bulkActions": {
"addToCase": "Tambahkan ke Kasus",
"moveToCase": "Pindahkan ke Kasus",
"removeFromCase": "Hapus dari Kasus",
"delete": "Hapus",
"deleteNow": "Hapus Sekarang"
},
"bulkDelete": {
"title": "Hapus Ekspor",
"desc_one": "Anda yakin ingin menghapus {{count}} ekspor?",
"desc_other": "Anda yakin ingin menghapus {{count}} ekspor?"
},
"bulkRemoveFromCase": {
"title": "Hapus dari Kasus",
"desc_one": "Hapus {{count}} ekspor dari kasus ini?",
"desc_other": "Hapus {{count}} ekspor dari kasus ini?",
"descKeepExports": "Ekspor akan dipindahkan ke tanpa kategori.",
"descDeleteExports": "Ekspor akan dihapus secara permanen.",
"deleteExports": "Hapus ekspor saja"
},
"bulkToast": {
"success": {
"delete": "Berhasil menghapus ekspor",
"reassign": "Berhasil memperbarui penetapan kasus",
"remove": "Berhasil menghapus ekspor dari kasus"
},
"error": {
"deleteFailed": "Gagal menghapus ekspor: {{errorMessage}}",
"reassignFailed": "Gagal memperbarui penetapan kasus: {{errorMessage}}"
}
}
}

View File

@ -9,7 +9,7 @@
"subLabelScore": "Skor Sub Label",
"face": "Detail Wajah",
"scoreInfo": "Skor sub label adalah nilai gabungan dari tingkat keyakinan sistem dalam mengenali wajah. Nilai ini bisa berbeda dengan skor yang terlihat pada gambar cuplikan.",
"timestamp": "Stempel waktu",
"timestamp": "Cap waktu",
"unknown": "Tidak diketahui",
"faceDesc": "Detail objek terlacak yang menghasilkan wajah ini"
},

View File

@ -1,56 +1,57 @@
{
"documentTitle.withCamera": "{{camera}} - Langsung - Frigate",
"documentTitle.withCamera": "{{camera}} - Live - Frigate",
"documentTitle": {
"default": "Siaran Langsung - Frigate"
"default": "Live - Frigate"
},
"lowBandwidthMode": "Mode Bandwith-Rendah",
"lowBandwidthMode": "Mode bandwidth rendah",
"twoWayTalk": {
"enable": "Nyalakan Komunikasi dua arah",
"disable": "Nonaktifkan Komunikasi Dua Arah"
"enable": "Aktifkan Audio Dua Arah",
"disable": "Nonaktifkan Audio Dua Arah"
},
"cameraAudio": {
"enable": "Nyalakan Audio Kamera",
"disable": "Matikan Audio Kamera"
"enable": "Aktifkan Audio Kamera",
"disable": "Nonaktifkan Audio Kamera"
},
"ptz": {
"move": {
"clickMove": {
"label": "Klik kotak ini untuk menengahkan kamera",
"enable": "Aktifkan klik untuk bergerak",
"disable": "Non-aktifkan klik untuk bergerak"
"label": "Klik pada frame untuk memusatkan kamera",
"enable": "Aktifkan klik untuk memindahkan",
"disable": "Nonaktifkan klik untuk memindahkan",
"enableWithZoom": "Aktifkan klik untuk memindahkan / seret untuk memperbesar"
},
"left": {
"label": "Geser kamera PTZ ke kiri"
"label": "Gerakkan kamera PTZ ke kiri"
},
"up": {
"label": "Geser kamera PTZ keatas"
"label": "Gerakkan kamera PTZ ke atas"
},
"down": {
"label": "Geser kamera PTZ kebawah"
"label": "Gerakkan kamera PTZ ke bawah"
},
"right": {
"label": "Geser kamera PTZ ke kanan"
"label": "Gerakkan kamera PTZ ke kanan"
}
},
"zoom": {
"in": {
"label": "Perbesar kamera PTZ"
"label": "Perbesar zoom kamera PTZ"
},
"out": {
"label": "Perkecil kamera PTZ"
"label": "Perkecil zoom kamera PTZ"
}
},
"focus": {
"in": {
"label": "Fokus kamera PTZ kedalam"
"label": "Fokuskan kamera PTZ ke dalam"
},
"out": {
"label": "Fokus kamera PTZ keluar"
"label": "Fokuskan kamera PTZ ke luar"
}
},
"frame": {
"center": {
"label": "Klik pada frame untuk menengahkan kamera PTZ"
"label": "Klik pada frame untuk memusatkan kamera PTZ"
}
},
"presets": "Preset kamera PTZ"
@ -61,10 +62,139 @@
},
"muteCameras": {
"enable": "Bisukan Semua Kamera",
"disable": "Bunyikan Semua Kamera"
"disable": "Suarakan Semua Kamera"
},
"detect": {
"enable": "Aktifkan Pendeteksi",
"disable": "Nonaktifkan Pendeteksi"
"enable": "Aktifkan Deteksi",
"disable": "Nonaktifkan Deteksi"
},
"recording": {
"enable": "Aktifkan Perekaman",
"disable": "Nonaktifkan Perekaman",
"disabledInConfig": "Perekaman harus terlebih dahulu diaktifkan di Pengaturan untuk kamera ini."
},
"snapshots": {
"enable": "Aktifkan Snapshot",
"disable": "Nonaktifkan Snapshot"
},
"snapshot": {
"takeSnapshot": "Unduh snapshot instan",
"noVideoSource": "Tidak ada sumber video yang tersedia untuk snapshot.",
"captureFailed": "Gagal mengambil snapshot.",
"downloadStarted": "Pengunduhan snapshot dimulai."
},
"audioDetect": {
"enable": "Aktifkan Deteksi Audio",
"disable": "Nonaktifkan Deteksi Audio"
},
"transcription": {
"enable": "Aktifkan Transkripsi Audio Langsung",
"disable": "Nonaktifkan Transkripsi Audio Langsung"
},
"autotracking": {
"enable": "Aktifkan Pelacakan Otomatis",
"disable": "Nonaktifkan Pelacakan Otomatis"
},
"streamStats": {
"enable": "Tampilkan Statistik Stream",
"disable": "Sembunyikan Statistik Stream"
},
"manualRecording": {
"title": "Sesuai Permintaan",
"tips": "Unduh snapshot instan atau mulai event manual berdasarkan pengaturan retensi rekaman kamera ini.",
"playInBackground": {
"label": "Putar di latar belakang",
"desc": "Aktifkan opsi ini untuk melanjutkan streaming saat pemutar disembunyikan."
},
"showStats": {
"label": "Tampilkan Statistik",
"desc": "Aktifkan opsi ini untuk menampilkan statistik stream sebagai overlay pada umpan kamera."
},
"debugView": "Tampilan Debug",
"start": "Mulai perekaman sesuai permintaan",
"started": "Perekaman manual sesuai permintaan dimulai.",
"failedToStart": "Gagal memulai perekaman manual sesuai permintaan.",
"recordDisabledTips": "Karena perekaman dinonaktifkan atau dibatasi dalam konfigurasi untuk kamera ini, hanya snapshot yang akan disimpan.",
"end": "Akhiri perekaman sesuai permintaan",
"ended": "Perekaman manual sesuai permintaan diakhiri.",
"failedToEnd": "Gagal mengakhiri perekaman manual sesuai permintaan."
},
"streamingSettings": "Pengaturan Streaming",
"notifications": "Notifikasi",
"audio": "Audio",
"suspend": {
"forTime": "Tangguhkan selama: "
},
"stream": {
"title": "Stream",
"audio": {
"tips": {
"title": "Audio harus dikeluarkan oleh kamera Anda dan dikonfigurasi di go2rtc untuk stream ini."
},
"available": "Audio tersedia untuk stream ini",
"unavailable": "Audio tidak tersedia untuk stream ini"
},
"debug": {
"picker": "Pemilihan stream tidak tersedia dalam mode debug. Tampilan debug selalu menggunakan stream yang ditetapkan ke peran detect."
},
"twoWayTalk": {
"tips": "Perangkat Anda harus mendukung fitur ini dan WebRTC harus dikonfigurasi untuk audio dua arah.",
"available": "Audio dua arah tersedia untuk stream ini",
"unavailable": "Audio dua arah tidak tersedia untuk stream ini"
},
"lowBandwidth": {
"tips": "Tampilan live berada dalam mode bandwidth rendah karena buffering atau kesalahan stream.",
"resetStream": "Atur ulang stream"
},
"playInBackground": {
"label": "Putar di latar belakang",
"tips": "Aktifkan opsi ini untuk melanjutkan streaming saat pemutar disembunyikan."
}
},
"cameraSettings": {
"title": "Pengaturan {{camera}}",
"cameraEnabled": "Kamera Diaktifkan",
"objectDetection": "Deteksi Objek",
"recording": "Perekaman",
"snapshots": "Snapshot",
"audioDetection": "Deteksi Audio",
"transcription": "Transkripsi Audio",
"autotracking": "Pelacakan Otomatis"
},
"history": {
"label": "Tampilkan rekaman historis"
},
"effectiveRetainMode": {
"modes": {
"all": "Semua",
"motion": "Gerakan",
"active_objects": "Objek Aktif"
}
},
"editLayout": {
"label": "Edit Tata Letak",
"group": {
"label": "Edit Grup Kamera"
},
"exitEdit": "Keluar dari Mode Edit"
},
"noCameras": {
"title": "Tidak Ada Kamera yang Dikonfigurasi",
"description": "Mulai dengan menghubungkan kamera ke Frigate.",
"buttonText": "Tambahkan Kamera",
"restricted": {
"title": "Tidak Ada Kamera yang Tersedia",
"description": "Anda tidak memiliki izin untuk melihat kamera apa pun di grup ini."
},
"default": {
"title": "Tidak Ada Kamera yang Dikonfigurasi",
"description": "Mulai dengan menghubungkan kamera ke Frigate.",
"buttonText": "Tambahkan Kamera"
},
"group": {
"title": "Tidak Ada Kamera dalam Grup",
"description": "Grup kamera ini tidak memiliki kamera yang ditetapkan atau diaktifkan.",
"buttonText": "Kelola Grup"
}
}
}

View File

@ -1 +1,73 @@
{}
{
"documentTitle": "Pencarian Gerakan - Frigate",
"title": "Pencarian Gerakan",
"description": "Gambar poligon untuk menentukan wilayah yang diminati, lalu tentukan rentang waktu untuk mencari perubahan gerakan di dalam wilayah tersebut.",
"selectCamera": "Pencarian Gerakan sedang dimuat",
"startSearch": "Mulai Pencarian",
"searchStarted": "Pencarian dimulai",
"searchCancelled": "Pencarian dibatalkan",
"cancelSearch": "Batal",
"searching": "Pencarian sedang berlangsung.",
"searchComplete": "Pencarian selesai",
"noResultsYet": "Jalankan pencarian untuk menemukan perubahan gerakan di wilayah yang dipilih",
"noChangesFound": "Tidak ada perubahan piksel yang terdeteksi di wilayah yang dipilih",
"changesFound_other": "Ditemukan {{count}} perubahan gerakan",
"framesProcessed": "{{count}} frame diproses",
"jumpToTime": "Lompat ke waktu ini",
"results": "Hasil",
"showSegmentHeatmap": "Peta panas",
"newSearch": "Pencarian Baru",
"clearResults": "Hapus Hasil",
"clearROI": "Hapus poligon",
"polygonControls": {
"points_other": "{{count}} titik",
"undo": "Urungkan titik terakhir",
"reset": "Atur ulang poligon"
},
"motionHeatmapLabel": "Peta Panas Gerakan",
"dialog": {
"title": "Pencarian Gerakan",
"cameraLabel": "Kamera",
"previewAlt": "Pratinjau kamera untuk {{camera}}"
},
"timeRange": {
"title": "Rentang Pencarian",
"start": "Waktu mulai",
"end": "Waktu selesai"
},
"settings": {
"title": "Pengaturan Pencarian",
"parallelMode": "Mode paralel",
"parallelModeDesc": "Pindai beberapa segmen rekaman secara bersamaan (lebih cepat, tetapi penggunaan CPU jauh lebih tinggi)",
"threshold": "Ambang Sensitivitas",
"thresholdDesc": "Nilai yang lebih rendah mendeteksi perubahan yang lebih kecil (1-255)",
"minArea": "Luas Perubahan Minimum",
"minAreaDesc": "Persentase minimum dari wilayah yang diminati yang harus berubah agar dianggap signifikan",
"frameSkip": "Lewati Frame",
"frameSkipDesc": "Proses setiap frame ke-N. Atur ini ke frame rate kamera Anda untuk memproses satu frame per detik (misalnya 5 untuk kamera 5 FPS, 30 untuk kamera 30 FPS). Nilai yang lebih tinggi akan lebih cepat, tetapi bisa melewatkan kejadian gerakan singkat.",
"maxResults": "Jumlah Hasil Maksimum",
"maxResultsDesc": "Berhenti setelah sebanyak ini cap waktu yang cocok"
},
"errors": {
"noCamera": "Silakan pilih kamera",
"noROI": "Silakan gambar wilayah yang diminati",
"noTimeRange": "Silakan pilih rentang waktu",
"invalidTimeRange": "Waktu selesai harus setelah waktu mulai",
"searchFailed": "Pencarian gagal: {{message}}",
"polygonTooSmall": "Poligon harus memiliki setidaknya 3 titik",
"unknown": "Kesalahan tidak diketahui"
},
"changePercentage": "{{percentage}}% berubah",
"metrics": {
"title": "Metrik Pencarian",
"segmentsScanned": "Segmen dipindai",
"segmentsProcessed": "Diproses",
"segmentsSkippedInactive": "Dilewati (tidak ada aktivitas)",
"segmentsSkippedHeatmap": "Dilewati (tidak ada tumpang tindih ROI)",
"fallbackFullRange": "Pemindaian rentang penuh cadangan",
"framesDecoded": "Frame didekode",
"wallTime": "Waktu pencarian",
"segmentErrors": "Kesalahan segmen",
"seconds": "{{seconds}} dtk"
}
}

View File

@ -1 +1,59 @@
{}
{
"title": "Pemutaran Ulang Debug",
"description": "Putar ulang rekaman kamera untuk debugging. Daftar objek menampilkan ringkasan objek terdeteksi yang tertunda waktu, dan tab Pesan menampilkan aliran pesan internal Frigate dari rekaman pemutaran ulang.",
"websocket_messages": "Pesan",
"dialog": {
"title": "Mulai Pemutaran Ulang Debug",
"description": "Buat kamera pemutaran ulang sementara yang memutar berulang rekaman historis untuk men-debug masalah deteksi dan pelacakan objek. Kamera pemutaran ulang akan memiliki konfigurasi deteksi yang sama dengan kamera sumber. Pilih rentang waktu untuk memulai.",
"camera": "Kamera Sumber",
"timeRange": "Rentang Waktu",
"preset": {
"1m": "1 Menit Terakhir",
"5m": "5 Menit Terakhir",
"timeline": "Dari Linimasa",
"custom": "Kustom"
},
"startButton": "Mulai Pemutaran Ulang",
"selectFromTimeline": "Pilih",
"starting": "Memulai pemutaran ulang...",
"startLabel": "Mulai",
"endLabel": "Selesai",
"toast": {
"error": "Gagal memulai pemutaran ulang debug: {{error}}",
"alreadyActive": "Sesi pemutaran ulang sudah aktif",
"stopError": "Gagal menghentikan pemutaran ulang debug: {{error}}",
"goToReplay": "Buka Pemutaran Ulang"
}
},
"page": {
"noSession": "Tidak Ada Sesi Pemutaran Ulang Debug Aktif",
"noSessionDesc": "Mulai Pemutaran Ulang Debug dari tampilan Riwayat dengan mengeklik tombol Aksi di bilah alat dan memilih Pemutaran Ulang Debug.",
"goToRecordings": "Buka Riwayat",
"preparingClip": "Menyiapkan klip…",
"preparingClipDesc": "Frigate sedang menggabungkan rekaman untuk rentang waktu yang dipilih. Ini dapat memakan waktu satu menit untuk rentang yang lebih panjang.",
"startingCamera": "Memulai Pemutaran Ulang Debug…",
"startError": {
"title": "Gagal memulai Pemutaran Ulang Debug",
"back": "Kembali ke Riwayat"
},
"sourceCamera": "Kamera Sumber",
"replayCamera": "Kamera Pemutaran Ulang",
"initializingReplay": "Menginisialisasi Pemutaran Ulang Debug...",
"stoppingReplay": "Menghentikan Pemutaran Ulang Debug...",
"stopReplay": "Hentikan Pemutaran Ulang",
"confirmStop": {
"title": "Hentikan Pemutaran Ulang Debug?",
"description": "Ini akan menghentikan sesi dan membersihkan semua data sementara. Anda yakin?",
"confirm": "Hentikan Pemutaran Ulang",
"cancel": "Batal"
},
"activity": "Aktivitas",
"objects": "Daftar Objek",
"audioDetections": "Deteksi Audio",
"noActivity": "Tidak ada aktivitas terdeteksi",
"activeTracking": "Pelacakan aktif",
"noActiveTracking": "Tidak ada pelacakan aktif",
"configuration": "Konfigurasi",
"configurationDesc": "Sesuaikan secara halus pengaturan deteksi gerakan dan pelacakan objek untuk kamera Pemutaran Ulang Debug. Tidak ada perubahan yang disimpan ke file konfigurasi Frigate Anda."
}
}

View File

@ -1,36 +1,73 @@
{
"search": "Cari",
"savedSearches": "Simpan Pencarian",
"search": "Pencarian",
"savedSearches": "Pencarian Tersimpan",
"searchFor": "Cari untuk {{inputValue}}",
"button": {
"clear": "Bersihkan pencarian",
"save": "Simpan Pencarian",
"clear": "Hapus pencarian",
"save": "Simpan pencarian",
"delete": "Hapus pencarian yang disimpan",
"filterInformation": "Saring Informasi",
"filterInformation": "Informasi filter",
"filterActive": "Filter aktif"
},
"trackedObjectId": "Tracked Object ID",
"trackedObjectId": "ID Objek yang Dilacak",
"filter": {
"label": {
"cameras": "Kamera",
"labels": "Label",
"zones": "Zona",
"sub_labels": "Sublabel",
"sub_labels": "Sub Label",
"attributes": "Atribut",
"search_type": "Tipe pencarian",
"search_type": "Jenis Pencarian",
"time_range": "Rentang Waktu",
"before": "Sebelum",
"after": "Sesudah",
"min_score": "Minimal Skor",
"max_score": "Maks Skor",
"min_speed": "Kecepatan Min",
"max_speed": "Kecepatan Maks",
"recognized_license_plate": "Plat Kendaraan Dikenali",
"has_clip": "Memiliki Klip",
"has_snapshot": "Memiliki tangkapan layar"
"min_score": "Skor Minimum",
"max_score": "Skor Maksimum",
"min_speed": "Kecepatan Minimum",
"max_speed": "Kecepatan Maksimum",
"recognized_license_plate": "Pelat Nomor yang Diakui",
"has_clip": "Memiliki Video Klip",
"has_snapshot": "Memiliki Snapshot"
},
"searchType": {
"thumbnail": "Tumbnail"
"thumbnail": "Gambar Mini",
"description": "Deskripsi"
},
"toast": {
"error": {
"beforeDateBeLaterAfter": "Tanggal 'before' harus lebih akhir daripada tanggal 'after'.",
"afterDatebeEarlierBefore": "Tanggal 'after' harus lebih awal daripada tanggal 'before'.",
"minScoreMustBeLessOrEqualMaxScore": "'min_score' harus lebih kecil dari atau sama dengan 'max_score'.",
"maxScoreMustBeGreaterOrEqualMinScore": "'max_score' harus lebih besar dari atau sama dengan 'min_score'.",
"minSpeedMustBeLessOrEqualMaxSpeed": "'min_speed' harus lebih kecil dari atau sama dengan 'max_speed'.",
"maxSpeedMustBeGreaterOrEqualMinSpeed": "'max_speed' harus lebih besar dari atau sama dengan 'min_speed'."
}
},
"tips": {
"title": "Cara menggunakan filter teks",
"desc": {
"text": "Filter membantu Anda mempersempit hasil pencarian. Berikut cara menggunakannya di kolom input:",
"step1": "Ketik nama kunci filter diikuti tanda titik dua (misalnya, \"cameras:\").",
"step2": "Pilih nilai dari saran atau ketik nilai Anda sendiri.",
"step3": "Gunakan beberapa filter dengan menambahkannya satu per satu dengan spasi di antaranya.",
"step4": "Filter tanggal (before: dan after:) menggunakan format {{DateFormat}}.",
"step5": "Filter rentang waktu menggunakan format {{exampleTime}}.",
"step6": "Hapus filter dengan mengklik tanda 'x' di sebelahnya.",
"exampleLabel": "Contoh:"
}
},
"header": {
"currentFilterType": "Nilai Filter",
"noFilters": "Filter",
"activeFilters": "Filter Aktif"
}
},
"similaritySearch": {
"title": "Pencarian Kemiripan",
"active": "Pencarian kemiripan aktif",
"clear": "Hapus pencarian kemiripan"
},
"placeholder": {
"search": "Pencarian…"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,14 @@
{
"documentTitle": {
"cameras": "Status kamera - Frigate",
"storage": "Status Penyimpanan - Frigate",
"general": "Status umum - Frigate",
"cameras": "Statistik Kamera - Frigate",
"storage": "Statistik Penyimpanan - Frigate",
"general": "Statistik Umum - Frigate",
"enrichments": "Statistik Enrichment - Frigate",
"logs": {
"frigate": "Log Frigate - Frigate",
"go2rtc": "Log Go2RTC - Frigate",
"nginx": "Log NGINX - Frigate"
"nginx": "Log Nginx - Frigate",
"websocket": "Log Pesan - Frigate"
}
},
"title": "Sistem",
@ -17,32 +18,242 @@
"label": "Unduh Log"
},
"copy": {
"label": "Salin ke Clipboard",
"success": "Log tersalin ke clipboard",
"error": "Tidak dapat menyalin ke clipboard"
"label": "Salin ke Papan Klip",
"success": "Log berhasil disalin ke papan klip",
"error": "Tidak dapat menyalin log ke papan klip"
},
"type": {
"label": "Tipe",
"timestamp": "Waktu",
"label": "Jenis",
"timestamp": "Stempel waktu",
"tag": "Tag",
"message": "Pesan"
},
"tips": "Logs sedang berjalan dari server",
"tips": "Log sedang dialirkan dari server",
"toast": {
"error": {
"fetchingLogsFailed": "Error saat mengambil log: {{errorMessage}}",
"whileStreamingLogs": "Eror saat streaming logs: {{errorMessage}}"
"fetchingLogsFailed": "Kesalahan saat mengambil log: {{errorMessage}}",
"whileStreamingLogs": "Kesalahan saat mengalirkan log: {{errorMessage}}"
}
},
"websocket": {
"label": "Pesan",
"pause": "Jeda",
"resume": "Lanjutkan",
"clear": "Bersihkan",
"filter": {
"all": "Semua topik",
"topics": "Topik",
"events": "Peristiwa",
"reviews": "Tinjauan",
"classification": "Klasifikasi",
"face_recognition": "Pengenalan Wajah",
"lpr": "LPR",
"camera_activity": "Aktivitas kamera",
"system": "Sistem",
"camera": "Kamera",
"all_cameras": "Semua kamera",
"cameras_count_one": "{{count}} Kamera",
"cameras_count_other": "{{count}} Kamera"
},
"empty": "Belum ada pesan yang ditangkap",
"count_one": "{{count}} pesan",
"count_other": "{{count}} pesan",
"expanded": {
"payload": "Payload"
}
}
},
"general": {
"title": "Umum",
"detector": {
"title": "Pendeteksi",
"inferenceSpeed": "Pendeteksi Kecepatan Inferensi",
"temperature": "Pendeteksi Suhu",
"cpuUsage": "Pendeteksi penggunaan CPU",
"cpuUsageInformation": "CPU yang digunakan dalam mempersiapkan data masukan dan keluaran ke/dari model deteksi. Nilai ini tidak mengukur penggunaan inferensi, bahkan jika menggunakan GPU atau akselerator."
"title": "Detektor",
"inferenceSpeed": "Kecepatan Inferensi Detektor",
"temperature": "Suhu Detektor",
"cpuUsage": "Penggunaan CPU Detektor",
"cpuUsageInformation": "CPU yang digunakan untuk menyiapkan data input dan output ke/dari model deteksi. Nilai ini tidak mengukur penggunaan inferensi, meskipun menggunakan GPU atau akselerator.",
"memoryUsage": "Penggunaan Memori Detektor"
},
"hardwareInfo": {
"title": "Info Perangkat Keras",
"gpuUsage": "Penggunaan GPU",
"gpuMemory": "Memori GPU",
"gpuEncoder": "Encoder GPU",
"gpuCompute": "Komputasi / Enkode GPU",
"gpuDecoder": "Decoder GPU",
"gpuTemperature": "Suhu GPU",
"gpuInfo": {
"vainfoOutput": {
"title": "Output Vainfo",
"returnCode": "Kode Pengembalian: {{code}}",
"processOutput": "Output Proses:",
"processError": "Kesalahan Proses:"
},
"nvidiaSMIOutput": {
"title": "Output Nvidia SMI",
"name": "Nama: {{name}}",
"driver": "Driver: {{driver}}",
"cudaComputerCapability": "Kemampuan Komputasi CUDA: {{cuda_compute}}",
"vbios": "Info VBios: {{vbios}}"
},
"closeInfo": {
"label": "Tutup info GPU"
},
"copyInfo": {
"label": "Salin info GPU"
},
"toast": {
"success": "Info GPU berhasil disalin ke papan klip"
}
},
"npuUsage": "Penggunaan NPU",
"npuMemory": "Memori NPU",
"npuTemperature": "Suhu NPU",
"intelGpuWarning": {
"title": "Peringatan Statistik GPU Intel",
"message": "Statistik GPU tidak tersedia",
"description": "Ini adalah bug yang sudah diketahui pada alat pelaporan statistik GPU Intel (intel_gpu_top) yang dapat rusak dan berulang kali mengembalikan penggunaan GPU sebesar 0% bahkan ketika akselerasi perangkat keras dan deteksi objek berjalan dengan benar pada (i)GPU. Ini bukan bug Frigate. Anda dapat memulai ulang host untuk memperbaiki masalah ini sementara dan memastikan GPU berfungsi dengan benar. Ini tidak memengaruhi kinerja."
}
},
"otherProcesses": {
"title": "Proses Lainnya",
"processCpuUsage": "Penggunaan CPU Proses",
"processMemoryUsage": "Penggunaan Memori Proses",
"series": {
"go2rtc": "go2rtc",
"recording": "perekaman",
"review_segment": "segmen tinjauan",
"embeddings": "embedding",
"audio_detector": "detektor audio"
}
}
},
"storage": {
"title": "Penyimpanan",
"overview": "Ringkasan",
"recordings": {
"title": "Rekaman",
"tips": "Nilai ini menunjukkan total penyimpanan yang digunakan oleh rekaman di basis data Frigate. Frigate tidak melacak penggunaan penyimpanan untuk semua file di disk Anda.",
"earliestRecording": "Rekaman paling awal yang tersedia:"
},
"shm": {
"title": "Alokasi SHM (memori bersama)",
"warning": "Ukuran SHM saat ini sebesar {{total}}MB terlalu kecil. Tingkatkan menjadi setidaknya {{min_shm}}MB.",
"frameLifetime": {
"title": "Masa hidup frame",
"description": "Setiap kamera memiliki {{frames}} slot frame di memori bersama. Pada laju frame kamera tercepat, setiap frame tersedia selama sekitar {{lifetime}} dtk sebelum ditimpa."
}
},
"cameraStorage": {
"title": "Penyimpanan Kamera",
"camera": "Kamera",
"unusedStorageInformation": "Informasi Penyimpanan Tidak Terpakai",
"storageUsed": "Penyimpanan",
"percentageOfTotalUsed": "Persentase dari Total",
"bandwidth": "Bandwidth",
"unused": {
"title": "Tidak Terpakai",
"tips": "Nilai ini mungkin tidak secara akurat merepresentasikan ruang kosong yang tersedia untuk Frigate jika Anda memiliki file lain yang disimpan di drive selain rekaman Frigate. Frigate tidak melacak penggunaan penyimpanan di luar rekamannya."
}
}
},
"cameras": {
"title": "Kamera",
"overview": "Ringkasan",
"info": {
"aspectRatio": "rasio aspek",
"cameraProbeInfo": "Info Probe Kamera {{camera}}",
"streamDataFromFFPROBE": "Data stream diperoleh dengan <code>ffprobe</code>.",
"fetching": "Mengambil Data Kamera",
"stream": "Stream {{idx}}",
"video": "Video:",
"codec": "Codec:",
"resolution": "Resolusi:",
"fps": "FPS:",
"unknown": "Tidak diketahui",
"audio": "Audio:",
"error": "Kesalahan: {{error}}",
"tips": {
"title": "Info Probe Kamera"
}
},
"framesAndDetections": "Frame / Deteksi",
"noCameras": {
"title": "Tidak Ada Kamera Ditemukan"
},
"label": {
"camera": "kamera",
"detect": "deteksi",
"skipped": "dilewati",
"ffmpeg": "FFmpeg",
"capture": "penangkapan",
"overallFramesPerSecond": "jumlah frame per detik keseluruhan",
"overallDetectionsPerSecond": "jumlah deteksi per detik keseluruhan",
"overallSkippedDetectionsPerSecond": "jumlah deteksi yang dilewati per detik keseluruhan",
"cameraFfmpeg": "FFmpeg {{camName}}",
"cameraCapture": "penangkapan {{camName}}",
"cameraDetect": "deteksi {{camName}}",
"cameraGpu": "GPU {{camName}}",
"cameraFramesPerSecond": "frame per detik {{camName}}",
"cameraDetectionsPerSecond": "deteksi per detik {{camName}}",
"cameraSkippedDetectionsPerSecond": "deteksi yang dilewati per detik {{camName}}"
},
"connectionQuality": {
"title": "Kualitas Koneksi",
"excellent": "Sangat Baik",
"fair": "Cukup",
"poor": "Buruk",
"unusable": "Tidak Dapat Digunakan",
"fps": "FPS",
"expectedFps": "FPS yang Diharapkan",
"reconnectsLastHour": "Penyambungan ulang (1 jam terakhir)",
"stallsLastHour": "Macet (1 jam terakhir)"
},
"toast": {
"success": {
"copyToClipboard": "Data probe berhasil disalin ke papan klip."
},
"error": {
"unableToProbeCamera": "Tidak dapat memeriksa kamera: {{errorMessage}}"
}
}
},
"lastRefreshed": "Terakhir diperbarui: ",
"stats": {
"ffmpegHighCpuUsage": "{{camera}} memiliki penggunaan CPU FFmpeg yang tinggi ({{ffmpegAvg}}%)",
"detectHighCpuUsage": "{{camera}} memiliki penggunaan CPU deteksi yang tinggi ({{detectAvg}}%)",
"healthy": "Sistem sehat",
"reindexingEmbeddings": "Mengindeks ulang embedding ({{processed}}% selesai)",
"cameraIsOffline": "{{camera}} sedang offline",
"detectIsSlow": "{{detect}} lambat ({{speed}} md)",
"detectIsVerySlow": "{{detect}} sangat lambat ({{speed}} md)",
"shmTooLow": "Alokasi /dev/shm ({{total}} MB) harus ditingkatkan menjadi setidaknya {{min}} MB.",
"debugReplayActive": "Sesi pemutaran ulang debug sedang aktif"
},
"enrichments": {
"title": "Enrichment",
"infPerSecond": "Inferensi Per Detik",
"averageInf": "Waktu Inferensi Rata-rata",
"embeddings": {
"image_embedding": "Embedding Gambar",
"text_embedding": "Embedding Teks",
"face_recognition": "Pengenalan Wajah",
"plate_recognition": "Pengenalan Plat",
"image_embedding_speed": "Kecepatan Embedding Gambar",
"face_embedding_speed": "Kecepatan Embedding Wajah",
"face_recognition_speed": "Kecepatan Pengenalan Wajah",
"plate_recognition_speed": "Kecepatan Pengenalan Plat",
"text_embedding_speed": "Kecepatan Embedding Teks",
"yolov9_plate_detection_speed": "Kecepatan Deteksi Plat YOLOv9",
"yolov9_plate_detection": "Deteksi Plat YOLOv9",
"review_description": "Deskripsi Tinjauan",
"review_description_speed": "Kecepatan Deskripsi Tinjauan",
"review_description_events_per_second": "Deskripsi Tinjauan",
"object_description": "Deskripsi Objek",
"object_description_speed": "Kecepatan Deskripsi Objek",
"object_description_events_per_second": "Deskripsi Objek",
"classification": "Klasifikasi {{name}}",
"classification_speed": "Kecepatan Klasifikasi {{name}}",
"classification_events_per_second": "Peristiwa Klasifikasi {{name}} Per Detik"
}
}
}

View File

@ -222,7 +222,8 @@
"id": "Bahasa Indonesia (Indonesiano)",
"ur": "اردو (Urdu)",
"hr": "Hrvatski (Croato)",
"bs": "Bosanski (Bosniaco)"
"bs": "Bosanski (Bosniaco)",
"zhHant": "繁體中文 (Cinese Tradizionale)"
},
"darkMode": {
"label": "Modalità scura",
@ -333,5 +334,8 @@
"internalID": "L'ID interno che Frigate utilizza nella configurazione e nel database"
},
"no_items": "Nessun elemento",
"validation_errors": "Errori di convalida"
"validation_errors": "Errori di convalida",
"credentialField": {
"savedPlaceholder": "Salvato — lascia vuoto per mantenere aggiornato"
}
}

View File

@ -48,5 +48,6 @@
"submitFrigatePlusFailed": "Impossibile inviare il fotogramma a Frigate+"
}
},
"cameraDisabled": "La telecamera è disabilita"
"cameraDisabled": "La telecamera è disabilita",
"cameraOff": "La telecamera è spenta"
}

View File

@ -5,8 +5,8 @@
"description": "Il nome della telecamera è obbligatorio"
},
"friendly_name": {
"description": "Nome amichevole della telecamera utilizzato nell'interfaccia utente di Frigate",
"label": "Nome amichevole"
"description": "Nome descrittivo della telecamera utilizzato nell'interfaccia utente di Frigate",
"label": "Nome descrittivo"
},
"enabled": {
"label": "Abilitata",
@ -169,6 +169,10 @@
"threshold": {
"label": "Soglia stazionaria",
"description": "Numero di fotogrammi senza cambio di posizione necessari per contrassegnare un oggetto come stazionario."
},
"max_frames": {
"label": "Fotogrammi massimi",
"description": "Limita la durata del tracciamento degli oggetti statici prima che vengano scartati."
}
}
},
@ -179,7 +183,8 @@
"label": "Revisiona"
},
"profiles": {
"label": "Profili"
"label": "Profili",
"description": "Profili di configurazione denominati con sovrascritture parziali che possono essere attivati in fase di esecuzione."
},
"record": {
"label": "Registrazione",
@ -248,7 +253,11 @@
"semantic_search": {
"label": "Ricerca semantica",
"triggers": {
"label": "Inneschi"
"label": "Inneschi",
"friendly_name": {
"label": "Nome descrittivo",
"description": "Nome descrittivo opzionale visualizzato nell'interfaccia utente per questo innesco."
}
}
},
"lpr": {
@ -269,7 +278,11 @@
"enabled": {
"label": "Abilitata"
},
"label": "Zone"
"label": "Zone",
"friendly_name": {
"label": "Nome zona",
"description": "Un nome intuitivo per la zona, visualizzato nell'interfaccia utente di Frigate. Se non specificato, verrà utilizzata una versione formattata del nome della zona."
}
},
"type": {
"description": "Tipo di telecamera",

View File

@ -89,11 +89,16 @@
"description": "Elenco degli indirizzi IP proxy attendibili utilizzati per determinare l'indirizzo IP del client ai fini della limitazione della velocità."
},
"roles": {
"label": "Mappatura dei ruoli"
"label": "Mappatura dei ruoli",
"description": "Associa i ruoli agli elenchi delle telecamere. Un elenco vuoto garantisce l'accesso a tutte le telecamere per quel ruolo."
},
"failed_login_rate_limit": {
"label": "Limiti di accesso non riusciti",
"description": "Regole di limitazione della frequenza per i tentativi di accesso non riusciti al fine di ridurre gli attacchi di forza bruta."
},
"hash_iterations": {
"description": "Numero di iterazioni PBKDF2-SHA256 da utilizzare per criptare le password utente.",
"label": "Iterazioni di crittografia"
}
},
"ffmpeg": {
@ -294,6 +299,10 @@
"threshold": {
"label": "Soglia stazionaria",
"description": "Numero di fotogrammi senza cambio di posizione necessari per contrassegnare un oggetto come stazionario."
},
"max_frames": {
"label": "Fotogrammi massimi",
"description": "Limita la durata del tracciamento degli oggetti statici prima che vengano scartati."
}
}
},
@ -343,7 +352,12 @@
"description": "Preferenze dell'interfaccia utente come fuso orario, formato di data/ora e unità di misura."
},
"profiles": {
"label": "Profili"
"label": "Profili",
"friendly_name": {
"label": "Nome descrittivo",
"description": "Nome visualizzato per questo profilo nell'interfaccia utente."
},
"description": "Definizioni di profili denominati con nomi descrittivi. I profili delle telecamere devono fare riferimento ai nomi definiti qui."
},
"record": {
"label": "Registrazione",
@ -462,7 +476,11 @@
"semantic_search": {
"label": "Ricerca semantica",
"triggers": {
"label": "Inneschi"
"label": "Inneschi",
"friendly_name": {
"label": "Nome descrittivo",
"description": "Nome descrittivo opzionale visualizzato nell'interfaccia utente per questo innesco."
}
},
"model_size": {
"label": "Dimensioni del modello"

View File

@ -28,5 +28,8 @@
"detectRequired": "Ad almeno un flusso di ingresso deve essere assegnato il ruolo di 'rilevamento'.",
"hwaccelDetectOnly": "Solo il flusso di ingresso con il ruolo di rilevamento può definire argomenti di accelerazione hardware."
}
},
"detect": {
"dimensionMustBeEven": "Deve essere un numero pari."
}
}

View File

@ -60,5 +60,13 @@
"stats": {
"context": "{{tokens}} token",
"tokens_per_second": "{{rate}} t/s"
},
"reasoning": {
"active": "Ragionamento…",
"show": "Mostra il ragionamento",
"hide": "Nascondi il ragionamento"
},
"thinking": {
"toggle": "Alterna ragionamento"
}
}

View File

@ -40,7 +40,8 @@
"objectDetection": "Rilevamento oggetti",
"recording": "Registrazione",
"audioDetection": "Rilevamento audio",
"transcription": "Trascrizione audio"
"transcription": "Trascrizione audio",
"camera": "Telecamera"
},
"history": {
"label": "Mostra filmati storici"
@ -98,7 +99,9 @@
},
"camera": {
"enable": "Abilita telecamera",
"disable": "Disabilita telecamera"
"disable": "Disabilita telecamera",
"turnOn": "Attiva la telecamera",
"turnOff": "Disattiva la telecamera"
},
"muteCameras": {
"enable": "Muta tutte le telecamere",

View File

@ -16,7 +16,8 @@
"globalConfig": "Configurazione globale - Frigate",
"cameraConfig": "Configurazione telecamera - Frigate",
"maintenance": "Manutenzione - Frigate",
"profiles": "Profili - Frigate"
"profiles": "Profili - Frigate",
"detectorsAndModel": "Rilevatori e modelli - Frigate"
},
"frigatePlus": {
"snapshotConfig": {
@ -45,7 +46,7 @@
"userModel": "Messa a punto fine",
"baseModel": "Modello base"
},
"availableModels": "Modelli disponibili",
"availableModels": "Modelli Frigate+ disponibili",
"loadingAvailableModels": "Caricamento dei modelli disponibili…",
"supportedDetectors": "Rilevatori supportati",
"error": "Impossibile caricare le informazioni sul modello",
@ -75,7 +76,8 @@
"currentModel": "Modello attuale",
"otherModels": "Altri modelli",
"configuration": "Configurazione"
}
},
"changeInDetectorsAndModel": "Cambia modello"
},
"debug": {
"timestamp": {
@ -169,7 +171,7 @@
"defaultName": "Maschera di movimento {{number}}",
"name": {
"title": "Nome",
"description": "Un nome amichevole opzionale per questa maschera di movimento.",
"description": "Un nome descrittivo opzionale per questa maschera di movimento.",
"placeholder": "Inserisci un nome..."
}
},
@ -341,7 +343,7 @@
"name": {
"title": "Nome",
"placeholder": "Inserisci un nome...",
"description": "Un nome amichevole facoltativo per questa maschera oggetto."
"description": "Un nome descrittivo facoltativo per questa maschera oggetto."
}
},
"restart_required": "Riavvio richiesto (maschere/zone modificate)",
@ -447,7 +449,7 @@
"enrichments": "Miglioramenti",
"triggers": "Inneschi",
"roles": "Ruoli",
"cameraManagement": "Gestione",
"cameraManagement": "Gestione della telecamera",
"cameraReview": "Revisiona",
"profiles": "Profili",
"general": "Generale",
@ -507,7 +509,8 @@
"mediaSync": "Sincronizzazione multimediale",
"cameraMqtt": "MQTT telecamera",
"maintenance": "Manutenzione",
"regionGrid": "Griglia di regioni"
"regionGrid": "Griglia di regioni",
"systemDetectorsAndModel": "Rilevatori e modelli"
},
"users": {
"dialog": {
@ -1401,19 +1404,41 @@
"selectCamera": "Seleziona una telecamera",
"backToSettings": "Torna alle impostazioni della telecamera",
"streams": {
"title": "Abilita/Disabilita telecamere",
"title": "Stato e dettagli della telecamera",
"desc": "Disattiva temporaneamente una telecamera fino al riavvio di Frigate. La disattivazione completa di una telecamera interrompe l'elaborazione dei flussi di questa telecamera da parte di Frigate. Rilevamento, registrazione e correzioni non saranno disponibili.<br /> <em>Nota: questa operazione non disattiva le ritrasmissioni di go2rtc.</em>",
"enableLabel": "Telecamere abilitate",
"enableDesc": "Disabilita temporaneamente una telecamera abilitata fino al riavvio di Frigate. La disabilitazione completa di una telecamera interrompe l'elaborazione dei flussi video di tale telecamera da parte di Frigate. Le funzioni di rilevamento, registrazione e correzioni non saranno disponibili.<br /> <em>Nota: questa operazione non disabilita le ritrasmissioni go2rtc.</em>",
"enableDesc": "Disabilita temporaneamente una telecamera abilitata fino al riavvio di Frigate. La disabilitazione completa di una telecamera interrompe l'elaborazione dei flussi video di tale telecamera da parte di Frigate. Le funzioni di rilevamento, registrazione e correzioni non saranno disponibili.<br /> <em>Nota: questa operazione non disabilita le ritrasmissioni go2rtc.</em><br /><br />Trascina le schede per riordinare le telecamere nell'interfaccia utente. L'ordine delle telecamere abilitate verrà visualizzato in tutta l'interfaccia utente inclusa la schermata Dal vivo e i menu a tendina di selezione delle telecamere.",
"disableLabel": "Telecamere disabilitate",
"disableDesc": "Abilita una telecamera attualmente non visibile nell'interfaccia utente e disabilitata nella configurazione. Dopo l'abilitazione è necessario riavviare Frigate.",
"enableSuccess": "{{cameraName}} abilitata nella configurazione. Riavvia Frigate per applicare le modifiche.",
"enableSuccess": "{{cameraName}} abilitata. Riavvia Frigate per applicare le modifiche.",
"friendlyName": {
"edit": "Modifica il nome visualizzato della telecamera",
"title": "Modifica il nome visualizzato",
"description": "Imposta il nome amichevole visualizzato per questa telecamera nell'interfaccia utente di Frigate. Lascia vuoto per utilizzare l'ID della telecamera.",
"rename": "Rinomina"
}
},
"reorderHandle": "Trascina per riordinare",
"saving": "Salvataggio…",
"saved": "Salvato",
"details": {
"edit": "Modifica i dettagli della telecamera",
"title": "Modifica i dettagli della telecamera",
"description": "Aggiorna il nome visualizzato e l'URL esterno utilizzati per questa telecamera nell'interfaccia utente di Frigate.",
"friendlyNameLabel": "Nome da visualizzare",
"friendlyNameHelp": "Nome descrittivo visualizzato per questa telecamera nell'interfaccia utente di Frigate. Lasciare vuoto per utilizzare l'ID della telecamera.",
"webuiUrlLabel": "URL dell'interfaccia web della telecamera",
"webuiUrlHelp": "URL per accedere direttamente all'interfaccia web della telecamera dalla vista Correzioni. Lasciare vuoto per disabilitare il collegamento.",
"webuiUrlInvalid": "Deve essere un URL valido (ad esempio, https://esempio.com)."
},
"label": "Stato della telecamera",
"description": "Imposta lo stato operativo per ciascuna telecamera.<br /><br /><strong>Accesa</strong>: i flussi vengono elaborati normalmente.<br /><strong>Spenta</strong>: mette temporaneamente in pausa l'elaborazione. Non viene mantenuta dopo il riavvio di Frigate.<br /><strong>Disabilitata</strong>: interrompe l'elaborazione e salva la modifica nella configurazione. È necessario riavviare Frigate per riattivare una telecamera disabilitata.<br /><br /><em>Nota: la disabilitazione non influisce sulle ritrasmissioni go2rtc.</em><br /><br />Trascina la maniglia per riordinare le telecamere attive nell'interfaccia utente, inclusi il pannello di controllo Dal vivo e i menu a tendina di selezione della telecamera.",
"disabledSubheading": "Disabilitata nella configurazione",
"status": {
"on": "Accesa",
"off": "Spenta",
"disabled": "Disabilitata"
},
"disableSuccess": "{{cameraName}} disabilitata e salvata nella configurazione."
},
"cameraConfig": {
"add": "Aggiungi telecamera",
@ -1448,11 +1473,13 @@
"enabled": "Abilitato",
"title": "Sovrascritture della telecamera del profilo",
"selectLabel": "Seleziona il profilo",
"description": "Configura quali telecamere vengono abilitate o disabilitate all'attivazione di un profilo. Le telecamere impostate su \"Eredita\" mantengono il loro stato di abilitazione predefinito.",
"description": "Configura quali telecamere vengono accese o spente all'attivazione di un profilo. Le telecamere impostate su \"Eredita\" mantengono il loro stato predefinito.",
"inherit": "Eredita",
"disabled": "Disabilitato"
"disabled": "Disabilitato",
"on": "Attivato",
"off": "Disattivato"
},
"description": "Aggiungi, modifica ed elimina le telecamere, controlla quali telecamere sono abilitate e configura le impostazioni personalizzate per profilo e tipo di telecamera. Per configurare flussi video, rilevamento, movimento e altre impostazioni specifiche per ciascuna telecamera, seleziona la sezione corrispondente in Configurazione telecamera.",
"description": "Aggiungi, modifica ed elimina le telecamere, controlla lo stato di ciascuna telecamera e configura le impostazioni personalizzate per profilo e tipo di telecamera. Per configurare flussi video, rilevamento, movimento e altre impostazioni specifiche per ciascuna telecamera, seleziona la sezione corrispondente in Configurazione telecamera.",
"deleteCamera": "Elimina telecamera",
"deleteCameraDialog": {
"title": "Elimina telecamera",
@ -1512,7 +1539,7 @@
"videoCopy": "Copia",
"hardware": "Accelerazione hardware",
"hardwareNone": "Nessuna accelerazione hardware",
"hardwareAuto": "Accelerazione hardware automatica",
"hardwareAuto": "Automatico (consigliato)",
"useFfmpegModule": "Utilizza la modalità di compatibilità (ffmpeg)",
"videoH264": "Transcodifica in H.264",
"videoH265": "Transcodifica in H.265",
@ -1523,7 +1550,15 @@
"audioPcma": "Transcodifica in PCM A-law",
"audioPcm": "Transcodifica in PCM",
"audioMp3": "Transcodifica in MP3",
"audioExclude": "Escludi"
"audioExclude": "Escludi",
"hardwareVaapi": "VAAPI",
"hardwareCuda": "CUDA",
"hardwareV4l2m2m": "V4L2 M2M",
"hardwareDxva2": "DXVA2",
"hardwareVideotoolbox": "VideoToolbox",
"addVideoCodec": "Aggiungi codec video",
"addAudioCodec": "Aggiungi codec audio",
"removeCodec": "Rimuovi codec"
},
"description": "Gestisci le configurazioni del flusso go2rtc per la ritrasmissione delle immagini della telecamera. Ogni flusso ha un nome e uno o più URL sorgente.",
"addStream": "Aggiungi flusso",
@ -1543,7 +1578,8 @@
},
"renameStream": "Rinomina flusso",
"renameStreamDesc": "Inserisci un nuovo nome per questo flusso. Rinominare un flusso potrebbe causare problemi alle telecamere o ad altri flussi che lo referenziano tramite il suo nome.",
"newStreamName": "Nuovo nome del flusso"
"newStreamName": "Nuovo nome del flusso",
"streamNumber": "Flusso {{index}}"
},
"configForm": {
"sections": {
@ -1652,7 +1688,7 @@
}
},
"cameraInputs": {
"itemTitle": "Stream {{index}}"
"itemTitle": "Flusso {{index}}"
},
"restartRequiredField": "Riavvio richiesto",
"restartRequiredFooter": "Configurazione modificata - Riavvio necessario",
@ -1713,9 +1749,14 @@
"genaiProviders": "Fornitori di GenAI"
},
"genaiModel": {
"placeholder": "Seleziona il modello…",
"search": "Ricerca modelli…",
"noModels": "Nessun modello disponibile"
"placeholder": "Seleziona o inserisci un modello…",
"search": "Cerca o inserisci un modello…",
"noModels": "Nessun modello disponibile",
"available": "Modelli disponibili",
"useCustom": "Utilizza \"{{value}}\"",
"refresh": "Aggiorna modelli",
"probeFailed": "Impossibile rilevare i modelli",
"fetchedModels": "Elenco dei modelli recuperato con successo"
},
"review": {
"title": "Impostazioni di revisione"
@ -1737,6 +1778,20 @@
},
"timezone": {
"defaultOption": "Utilizza il fuso orario del browser"
},
"semanticSearchModelSize": {
"notApplicable": "Non applicabile ai fornitori GenAI"
},
"liveStreams": {
"streamNameLabel": "Nome flusso",
"streamNamePlaceholder": "p.es., flusso HD principale",
"go2rtcStreamLabel": "flusso go2rtc",
"go2rtcStreamPlaceholder": "Seleziona un flusso go2rtc",
"go2rtcStreamSearch": "Cerca o inserisci il nome di un flusso…",
"noGo2rtcStreams": "Nessun flusso go2rtc configurato",
"availableStreams": "Flussi disponibili",
"useCustom": "Utilizza \"{{value}}\"",
"addStream": "Aggiungi flusso"
}
},
"globalConfig": {
@ -1886,6 +1941,13 @@
"motion": "Movimento",
"objects": "Oggetti",
"continuous": "Continuo"
},
"cameraOrder": {
"reorderHandle": "Trascina per riordinare",
"saving": "Salvataggio…",
"saved": "Salvato",
"label": "Ordine delle telecamere",
"description": "Trascina le telecamere per impostarne l'ordine nella visualizzazione Birdseye."
}
},
"toast": {
@ -1902,7 +1964,10 @@
"saveAllPartial_one": "{{successCount}} sezione su {{totalCount}} salvata. {{failCount}} errore.",
"saveAllPartial_many": "{{successCount}} sezioni su {{totalCount}} salvate. {{failCount}} errori.",
"saveAllPartial_other": "{{successCount}} sezioni su {{totalCount}} salvate. {{failCount}} errori.",
"saveAllFailure": "Impossibile salvare tutte le sezioni."
"saveAllFailure": "Impossibile salvare tutte le sezioni.",
"saveAllSuccessRestartRequired_one": "Salvata {{count}} sezione correttamente. Riavvia Frigate per applicare le modifiche.",
"saveAllSuccessRestartRequired_many": "Salvate {{count}} sezioni correttamente. Riavvia Frigate per applicare le modifiche.",
"saveAllSuccessRestartRequired_other": "Salvate {{count}} sezioni correttamente. Riavvia Frigate per applicare le modifiche."
},
"unsavedChanges": "Hai delle modifiche non salvate",
"confirmReset": "Conferma il ripristino",
@ -1977,7 +2042,9 @@
},
"detect": {
"fpsGreaterThanFive": "Impostare il valore di FPS rilevato su un valore superiore a 5 non è consigliabile. Valori più elevati potrebbero causare problemi di prestazioni e non apporteranno alcun vantaggio.",
"disabled": "Il rilevamento degli oggetti è disabilitato. Le istantanee, gli elementi di revisione e le funzionalità aggiuntive come il riconoscimento facciale, il riconoscimento delle targhe e l'intelligenza artificiale generativa non funzioneranno."
"disabled": "Il rilevamento degli oggetti è disabilitato. Le istantanee, gli elementi di revisione e le funzionalità aggiuntive come il riconoscimento facciale, il riconoscimento delle targhe e l'intelligenza artificiale generativa non funzioneranno.",
"resolutionShouldBeMultipleOfFour": "Per ottenere risultati ottimali, la larghezza e l'altezza di rilevamento dovrebbero essere multipli di 4. Altri valori pari potrebbero produrre artefatti visivi o una leggera distorsione nel flusso di rilevamento.",
"aspectRatioMismatch": "La larghezza e l'altezza inserite non corrispondono al rapporto d'aspetto della risoluzione di rilevamento corrente. Ciò potrebbe produrre un'immagine allungata o distorta."
},
"objects": {
"genaiNoDescriptionsProvider": "Per generare le descrizioni è necessario configurare un provider GenAI con il ruolo 'descrizioni'."
@ -2028,5 +2095,35 @@
"label": "Nuovo valore",
"reset": "Reimposta"
}
},
"menuDot": {
"overrideGlobal": "Questa sezione sovrascrive la configurazione globale",
"overrideProfile": "Questa sezione viene sovrascritta dal profilo {{profile}}",
"unsaved": "Questa sezione contiene modifiche non salvate"
},
"detectorsAndModel": {
"title": "Rilevatori e modelli",
"description": "Configura il backend del rilevatore che esegue il rilevamento degli oggetti e il modello che utilizza. Le modifiche vengono salvate insieme in modo che il rilevatore e il modello rimangano sincronizzati.",
"cardTitles": {
"detector": "Dispositivo di rilevamento",
"model": "Modello di rilevamento"
},
"tabs": {
"plus": "Frigate+",
"custom": "Modello personalizzato"
},
"mismatch": {
"warning": "Il modello Frigate+ attuale \"{{model}}\" richiede il rilevatore {{required}}. Seleziona un modello compatibile qui sotto oppure passa a Modello personalizzato prima di salvare."
},
"plusModel": {
"requiresDetector": "Richiede: {{detector}}",
"noModelSelected": "Seleziona un modello Frigate+"
},
"toast": {
"saveSuccess": "Rilevatori e impostazioni del modello salvati. Riavviare Frigate per applicare le modifiche.",
"saveError": "Impossibile salvare le impostazioni del rilevatore e del modello"
},
"unsavedChanges": "Modifiche al rilevatore e al modello non salvate",
"restartRequired": "Riavvio richiesto (rilevatore o modello modificato)"
}
}

View File

@ -222,7 +222,7 @@
"dubstep": "ダブステップ",
"drum_and_bass": "ドラムンベース",
"electronica": "エレクトロニカ",
"electronic_dance_music": "EDM",
"electronic_dance_music": "エレクトロニック・ダンス・ミュージック",
"ambient_music": "アンビエント",
"trance_music": "トランス",
"music_of_latin_america": "ラテン音楽",

View File

@ -136,11 +136,23 @@
"export": "エクスポート",
"deleteNow": "今すぐ削除",
"next": "次へ",
"continue": "続行"
"continue": "続行",
"add": "追加",
"applying": "適用中…",
"undo": "元に戻す",
"copiedToClipboard": "クリップボードにコピーしました",
"modified": "変更あり",
"overridden": "上書き済み",
"resetToGlobal": "グローバル設定にリセット",
"resetToDefault": "デフォルトにリセット",
"saveAll": "すべて保存",
"savingAll": "すべて保存中…",
"undoAll": "すべて元に戻す",
"retry": "再試行"
},
"menu": {
"system": "システム",
"systemMetrics": "システムモニター",
"systemMetrics": "システムメトリクス",
"configuration": "設定",
"systemLogs": "システムログ",
"settings": "設定",
@ -235,10 +247,15 @@
"withSystem": {
"label": "システム設定に従う"
},
"hr": "Hrvatski (クロアチア語)"
"hr": "Hrvatski (クロアチア語)",
"bs": "Bosanski (ボスニア語)",
"zhHant": "繁體中文 (繁体字中国語)"
},
"classification": "分類",
"profiles": "プロファイル"
"profiles": "プロファイル",
"actions": "操作",
"features": "機能",
"chat": "チャット"
},
"toast": {
"copyUrlToClipboard": "URLをクリップボードにコピーしました。",
@ -247,7 +264,8 @@
"error": {
"title": "設定変更の保存に失敗しました: {{errorMessage}}",
"noMessage": "設定変更の保存に失敗しました"
}
},
"success": "設定変更を保存しました。"
}
},
"role": {
@ -290,5 +308,10 @@
"field": {
"optional": "任意",
"internalID": "Frigate が設定で使用する内部 ID です"
},
"no_items": "項目がありません",
"validation_errors": "入力エラー",
"credentialField": {
"savedPlaceholder": "保存済み — 変更しない場合は空欄"
}
}

View File

@ -4,8 +4,8 @@
"password": "パスワード",
"login": "ログイン",
"errors": {
"usernameRequired": "ユーザー名が必要です",
"passwordRequired": "パスワードが必要です",
"usernameRequired": "ユーザー名は必須です",
"passwordRequired": "パスワードは必須です",
"rateLimit": "リクエスト制限を超えました。後でもう一度お試しください。",
"loginFailed": "ログインに失敗しました",
"unknownError": "不明なエラー。ログを確認してください。",

Some files were not shown because too many files have changed in this diff Show More