From c9b451b1e4810eadc654abb69d62dc033729e807 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Sun, 18 Oct 2026 17:42:41 -0400 Subject: [PATCH] i18n: complete non-English locale catalogs --- web/public/locales/ar.json | 1493 +++++++++++++++++++++++++++- web/public/locales/de.json | 1503 +++++++++++++++++++++++++++- web/public/locales/es.json | 1497 +++++++++++++++++++++++++++- web/public/locales/fil.json | 1525 ++++++++++++++++++++++++++++- web/public/locales/fr.json | 1503 +++++++++++++++++++++++++++- web/public/locales/it.json | 1501 +++++++++++++++++++++++++++- web/public/locales/ja.json | 1497 +++++++++++++++++++++++++++- web/public/locales/ko.json | 1493 +++++++++++++++++++++++++++- web/public/locales/nl.json | 1493 +++++++++++++++++++++++++++- web/public/locales/pl.json | 1499 +++++++++++++++++++++++++++- web/public/locales/pt-BR.json | 1298 +++++++++++++++++++++++- web/public/locales/pt-PT.json | 1497 +++++++++++++++++++++++++++- web/public/locales/ru.json | 1497 +++++++++++++++++++++++++++- web/public/locales/tr.json | 1497 +++++++++++++++++++++++++++- web/public/locales/uk.json | 1497 +++++++++++++++++++++++++++- web/public/locales/zh-TW.json | 1497 +++++++++++++++++++++++++++- web/public/locales/zh.json | 1497 +++++++++++++++++++++++++++- web/tests/locale-coverage.spec.js | 52 + 18 files changed, 25249 insertions(+), 87 deletions(-) create mode 100644 web/tests/locale-coverage.spec.js diff --git a/web/public/locales/ar.json b/web/public/locales/ar.json index 8018787f..9e29ea3f 100644 --- a/web/public/locales/ar.json +++ b/web/public/locales/ar.json @@ -819,7 +819,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "تأكد من أن light-object-detect يعمل على نقطة النهاية هذه", "streamsConfig.customApiEndpointUrl": "URL مخصص لنقطة نهاية API", "streamsConfig.useDefaultEndpoint": "استخدام نقطة النهاية الافتراضية", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "أدخل عنوان URL الكامل لنقطة نهاية API الاكتشاف المخصصة", "streamsConfig.overrideWithCustomEndpoint": "تجاوز باستخدام نقطة نهاية مخصصة", "streamsConfig.detectionThreshold": "عتبة الاكتشاف", @@ -1056,7 +1056,7 @@ "settings.detectionModelsPath": "مسار نماذج الاكتشاف", "settings.detectionModelsPathHelp": "الدليل الذي تُخزَّن فيه نماذج الاكتشاف", "settings.apiDetectionUrl": "URL اكتشاف API", - "settings.apiDetectionUrlHelp": "عنوان URL لنقطة نهاية API الخارجية لاكتشاف الكائنات", + "settings.apiDetectionUrlHelp": "نقطة نهاية light-object-detect، مثل http://localhost:8000/api/v1/detect. يتم رفع اللقطة كبيانات نموذج متعددة الأجزاء مع إضافة معاملات الاستعلام backend و confidence_threshold.", "settings.apiDetectionBackend": "واجهة API الخلفية للاكتشاف", "settings.apiDetectionBackendOnnx": "ONNX Runtime", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1156,5 +1156,1492 @@ "settings.discoveryIntervalSecondsRangeHelp": "عدد مرات فحص الكاميرات (من 30 إلى 3600 ثانية)", "settings.discoveryNetwork": "شبكة الاكتشاف", "settings.discoveryNetworkExamples": "أمثلة: 192.168.1.0/24، 10.0.0.0/16، auto", - "settings.saveSettings": "حفظ الإعدادات" + "settings.saveSettings": "حفظ الإعدادات", + "live.navigator.title": "المُتنقّل", + "live.navigator.subtitle": "المواقع، والتخطيطات، والنشاط", + "live.navigator.cameras": "الكاميرات", + "live.navigator.plans": "المخطط", + "live.navigator.views": "العروض", + "live.navigator.events": "الأحداث", + "live.navigator.search": "ابحث عن كاميرا…", + "live.navigator.allCameras": "جميع الكاميرات", + "live.navigator.unassigned": "غير مُسندة", + "live.navigator.noCameras": "لا توجد كاميرات مطابقة لهذا النطاق.", + "live.navigator.saveCurrent": "حفظ التخطيط الحالي", + "live.navigator.noLayouts": "لا توجد تخطيطات محفوظة بعد.", + "live.navigator.layoutNamePrompt": "أعطِ اسماً لهذا التخطيط المباشر", + "live.navigator.shareLayoutPrompt": "مشاركة هذا التخطيط مع المشغّلين الآخرين؟", + "live.navigator.layoutSaved": "تم حفظ {name}", + "live.navigator.layoutLoaded": "تم تحميل {name}", + "live.navigator.deleteLayoutConfirm": "حذف {name}؟", + "live.navigator.shared": "مُشترك", + "live.navigator.loadingEvents": "جارٍ تحميل الأحداث الأخيرة…", + "live.navigator.noRecentEvents": "لا توجد اكتشافات في الساعة الأخيرة.", + "live.navigator.expand": "توسيع المُتنقّل", + "live.navigator.collapse": "طيّ المُتنقّل", + "live.plan.navigatorHelp": "اختر مبنى أو طابقاً. تُفتح معاينات الكاميرا عند الطلب فقط.", + "live.plan.noPlans": "لا توجد مخططات مبانٍ بعد. أنشئ واحداً في مساحة عمل المخططات.", + "live.plan.emptyTitle": "إنشاء عرض مكاني للكاميرات", + "live.plan.emptyDescription": "يعرض المخطط مؤشرات الحالة للموقع بأكمله ويفتح الفيديو فقط عند طلب المشغّل. ارسم الغرف والجدران هنا مباشرة، أو ارفع مخطط أرضي ممسوحًا ضوئيًا أو رسمًا للموقع أو لقطة شاشة من برنامج NVR، ثم اربط الكاميرات بالغرف الفعلية.", + "live.plan.sketch.tools": "أدوات التخطيط", + "live.plan.sketch.tool.select": "تحديد", + "live.plan.sketch.tool.room": "غرفة", + "live.plan.sketch.tool.wall": "جدار", + "live.plan.sketch.tool.area": "منطقة", + "live.plan.sketch.tool.label": "تسمية", + "live.plan.sketch.undo": "تراجع عن الرسم", + "live.plan.sketch.redo": "إعادة الرسم", + "live.plan.sketch.snap": "محاذاة للشبكة", + "live.plan.sketch.hint.select": "اسحب الأشكال أو الكاميرات لتحريكها. انقر على شكل لتعديله؛ اضغط على Alt لتجاهل الشبكة.", + "live.plan.sketch.hint.room": "اسحب على المخطط لرسم حدود غرفة أو مبنى.", + "live.plan.sketch.hint.wall": "انقر لإضافة نقاط الجدار. انقر نقرًا مزدوجًا أو اضغط Enter للإنهاء، أو Escape للإلغاء.", + "live.plan.sketch.hint.area": "انقر لرسم حدود منطقة. انقر على النقطة الأولى أو اضغط Enter لإغلاقها.", + "live.plan.sketch.hint.label": "انقر على المخطط لوضع تسمية نصية.", + "live.plan.sketch.type.rect": "غرفة", + "live.plan.sketch.type.wall": "جدار", + "live.plan.sketch.type.area": "منطقة", + "live.plan.sketch.type.label": "تسمية", + "live.plan.sketch.pointCount": "{count} نقاط", + "live.plan.sketch.defaultLabel": "تسمية", + "live.plan.sketch.shapes": "أشكال التخطيط", + "live.plan.sketch.noShapes": "لم يتم الرسم بعد. اختر أداة من أعلى المخطط للبدء.", + "live.plan.sketch.tone": "اللون", + "live.plan.sketch.tone.slate": "رمادي داكن", + "live.plan.sketch.tone.blue": "أزرق", + "live.plan.sketch.tone.green": "أخضر", + "live.plan.sketch.tone.amber": "كهرماني", + "live.plan.sketch.tone.red": "أحمر", + "live.plan.sketch.tone.violet": "بنفسجي", + "live.plan.sketch.labelText": "التسمية", + "live.plan.sketch.text": "النص", + "live.plan.sketch.size": "الحجم", + "live.plan.sketch.size.sm": "صغير", + "live.plan.sketch.size.md": "متوسط", + "live.plan.sketch.size.lg": "كبير", + "live.plan.sketch.filled": "ملء الغرفة", + "live.plan.sketch.left": "اليسار %", + "live.plan.sketch.top": "الأعلى %", + "live.plan.sketch.width": "العرض %", + "live.plan.sketch.height": "الارتفاع %", + "live.plan.sketch.points": "النقاط", + "live.plan.sketch.point": "النقطة {index}", + "live.plan.sketch.delete": "حذف الشكل", + "live.plan.sketch.duplicate": "تكرار", + "live.plan.sketch.deselect": "تم", + "live.plan.sketch.emptyTitle": "لا يوجد شيء على هذا المخطط بعد", + "live.plan.sketch.emptyBody": "ارسم الغرف والجدران والتسميات هنا مباشرة، أو ارفع مخططًا ممسوحًا أو رسمًا موقعيًا أو تصدير PNG/JPEG (حتى 768 كيلوبايت).", + "live.plan.sketch.emptyBodyReadOnly": "يمكن للمسؤول رسم التخطيط أو رفع مخطط المبنى الفعلي.", + "live.plan.sketch.drawLayout": "رسم التخطيط", + "live.plan.sketch.uploadImage": "رفع صورة", + "live.plan.sketch.limitReached": "تم الوصول إلى الحد الأقصى للأشكال ({max})", + "live.plan.sketch.discardDrawing": "تم إلغاء الرسم", + "live.favorites": "المفضلة", + "live.favoritesOnly": "إظهار الكاميرات المفضلة فقط", + "live.addFavorite": "إضافة {stream} إلى المفضلة", + "live.removeFavorite": "إزالة {stream} من المفضلة", + "live.noFavorites": "لا توجد كاميرات مفضلة بعد. استخدم النجمة على بطاقة الكاميرا لإضافة واحدة.", + "live.favoriteUpdateError": "تعذّر تحديث المفضلة: {message}", + "live.resetZoom": "إعادة تعيين التكبير", + "live.audioPlaybackBlocked": "حظر المتصفح صوت الكاميرا. انقر على زر السماعة مرة أخرى لإعادة المحاولة.", + "live.fullscreenSubStreamFallback": "{stream}: لا توجد سعة نطاق كافية للبث بالدقة الكاملة في وضع ملء الشاشة — تم التبديل إلى البث الفرعي.", + "live.tileActions": "إجراءات الكاميرا", + "live.takeSnapshot": "التقاط لقطة", + "live.openStreamRecordings": "فتح التسجيلات لهذا البث", + "live.enterReorderMode": "إعادة ترتيب الكاميرات", + "live.pullToRefresh": "اسحب لتحديث البثوث", + "live.releaseToRefresh": "أفلت لتحديث البثوث", + "live.refreshingStreams": "جارٍ تحديث البثوث…", + "live.streamsRefreshed": "تم تحديث البثوث", + "live.refreshStreamsFailed": "تعذّر تحديث البثوث: {message}", + "live.tipDoubleTapFullscreen": "تلميح: انقر نقرًا مزدوجًا على البلاطة لفتحها بملء الشاشة.", + "live.dayNightControl": "وضع النهار/الليل", + "live.dayNightLoading": "جارٍ التحميل…", + "live.dayNightApplying": "جارٍ التطبيق…", + "live.dayNightMode_auto": "تلقائي", + "live.dayNightMode_day": "نهار", + "live.dayNightMode_night": "ليل", + "live.dayNightMode_unknown": "غير معروف", + "live.dayNightApplied": "تم ضبط وضع النهار/الليل إلى {mode}", + "live.dayNightApplyFailed": "تعذّر ضبط وضع النهار/الليل", + "live.dayNightLoadFailed": "تعذّر قراءة وضع النهار/الليل", + "live.playbackFallbackUsed": "البديل: {transport}", + "live.playbackTransportUnavailable": "{transport} معطّل على الخادم لهذا البث.", + "live.recordingMode.constant": "تسجيل مستمر", + "live.recordingMode.detection": "تسجيل عند الكشف", + "live.recordingMode.schedule": "تسجيل مجدول", + "live.recordingMode.none": "غير مسجّل", + "live.health.healthy": "البث سليم", + "live.health.degraded": "البث قيد التخزين المؤقت أو التعافي", + "live.health.offline": "البث غير متاح", + "live.enterPictureInPicture": "فتح صورة داخل صورة", + "live.exitPictureInPicture": "إغلاق صورة داخل صورة", + "live.pictureInPictureError": "فشل صورة داخل صورة: {message}", + "live.alwaysFullscreenOnTapEnable": "تفعيل ملء الشاشة عند النقر مرة واحدة على البلاطة", + "live.alwaysFullscreenOnTapDisable": "تعطيل ملء الشاشة عند النقر على بلاطة واحدة", + "live.displayMode": "وضع العرض", + "live.displayModeFit": "ملاءمة", + "live.displayModeFill": "ملء", + "live.displayModeFitDescription": "ملاءمة: عرض الإطار بالكامل مع أشرطة سوداء", + "live.displayModeFillDescription": "ملء: ملء البلاطة وقص حواف الإطار", + "live.slideshowStartCameras": "بدء عرض الشرائح: التنقل بين الكاميرات", + "live.slideshowStartPages": "بدء عرض الشرائح: التنقل بين صفحات الشبكة", + "live.slideshowStop": "إيقاف عرض الشرائح", + "live.slideshowInterval": "الفاصل بين شرائح العرض", + "live.slideshowSeconds": "{seconds} ث", + "live.plan.previewUnavailable": "معاينة الكاميرا غير متوفرة", + "live.plan.previewAlt": "العرض الحالي من {name}", + "live.plan.degreesValue": "{value} درجة", + "live.plan.inDegrees": "{label} بالدرجات", + "live.plan.imageDimensionsError": "تعذّر قراءة أبعاد الصورة", + "live.plan.loading": "جارٍ تحميل مخططات المبنى…", + "live.plan.created": "تم إنشاء {name}", + "live.plan.renamed": "تمت إعادة التسمية إلى {name}", + "live.plan.deleted": "تم حذف {name}", + "live.plan.backgroundType": "يجب أن تكون الخلفية صورة بصيغة PNG أو JPEG", + "live.plan.backgroundTooLarge": "صورة الخلفية كبيرة جدًا؛ الحد الأقصى 768 كيلوبايت", + "live.plan.backgroundAspect": "تم الرفع، لكن نسبة أبعاد الصورة لا تتناسب مع أي حجم لوحة صالح", + "live.plan.backgroundUpdatedSave": "تم تحديث الخلفية لـ {name}؛ احفظ التخطيط لتطبيق حجم اللوحة", + "live.plan.backgroundNotResized": "تم رفع الخلفية، لكن لم يتم تغيير حجم اللوحة: {error}", + "live.plan.backgroundUpdated": "تم تحديث الخلفية لـ {name}", + "live.plan.backgroundRemoved": "تمت إزالة الخلفية", + "live.plan.saved": "تم حفظ {name}", + "live.plan.createTitle": "إنشاء مخطط مبنى", + "live.plan.createDescription": "أعطِ هذا المبنى أو الطابق اسمًا واضحًا. ارسم التخطيط أو ارفع صورة مخطط الطابق، ثم ضع الكاميرات.", + "live.plan.nameLabel": "اسم المخطط", + "live.plan.namePlaceholder": "المبنى الرئيسي · الطابق الأول", + "live.plan.createConfirm": "إنشاء مخطط", + "live.plan.eyebrow": "مخطط المبنى", + "live.plan.placedSummary": "{placed} موضوعة · {live} مباشرة الآن", + "live.plan.zoomAndPan": "تكبير وتحريك المخطط", + "live.plan.panLeft": "تحريك لليسار", + "live.plan.panUp": "تحريك لأعلى", + "live.plan.panDown": "تحريك لأسفل", + "live.plan.panRight": "تحريك لليمين", + "live.plan.zoomOut": "تصغير", + "live.plan.zoomIn": "تكبير", + "live.plan.fitTitle": "ملاءمة المخطط", + "live.plan.fit": "ملاءمة", + "live.plan.backgroundMenu": "الخلفية…", + "live.plan.save": "حفظ المخطط", + "live.plan.uploadBackgroundTitle": "رفع صورة بصيغة PNG أو JPEG كخلفية للمخطط", + "live.plan.replaceBackground": "استبدال الخلفية", + "live.plan.uploadBackground": "رفع الخلفية", + "live.plan.removeBackground": "إزالة الخلفية", + "live.plan.rename": "إعادة تسمية", + "live.plan.newPlan": "مخطط جديد", + "live.plan.editLayout": "تعديل التخطيط", + "live.plan.placementHint": "انقر على المخطط لتحديد موقع {name}", + "live.plan.clusterLabel": "{count} كاميرات؛ قم بالتكبير", + "live.plan.markerLabel": "{name}؛ {availability}؛ تواجه {rotation}° بزاوية رؤية {fov}°", + "live.plan.cameraFallback": "كاميرا", + "live.plan.legendLive": "مباشر", + "live.plan.canvas": "لوحة المخطط", + "live.plan.width": "العرض", + "live.plan.height": "الارتفاع", + "live.plan.canvasHint": "رفع صورة خلفية يغيّر حجم اللوحة ليتناسب معها.", + "live.plan.canvasInvalid": "يجب أن يكون العرض بين 400–4000 والارتفاع بين 300–4000.", + "live.plan.openLive": "فتح الكاميرا المباشرة", + "live.plan.direction": "اتجاه الكاميرا", + "live.plan.fov": "مجال الرؤية", + "live.plan.coverageNote": "تُظهر القطاعات الاتجاه والزاوية فقط؛ المسافة على المخطط غير معايرة.", + "live.plan.removeCamera": "إزالة من المخطط", + "live.plan.selectCamera": "اختر كاميرا", + "live.plan.selectHintEditing": "اسحب العلامات المحددة لضبطها بدقة. افحص الحالة وافتح عرضًا مباشرًا عند الحاجة.", + "live.plan.selectHint": "افحص الحالة وافتح عرضًا مباشرًا عند الحاجة.", + "live.plan.cameras": "كاميرات المخطط", + "live.plan.findPlaceholder": "بحث في هذا المخطط…", + "live.plan.findLabel": "ابحث عن كاميرا في هذا المخطط", + "live.plan.unplaced": "كاميرات غير موضوعة", + "live.plan.unplacedHint": "حدد كاميرا، ثم انقر على موقعها في المخطط.", + "live.plan.renameTitle": "إعادة تسمية المخطط", + "live.plan.renameDescription": "المخططات مشتركة مع جميع المشغلين في هذا الموقع.", + "live.plan.deleteTitle": "حذف المخطط", + "live.plan.deleteMessage": "حذف \"{name}\" وخلفيته المرفوعة؟ سيتم إزالة مواضع الكاميرات في هذا المخطط؛ الكاميرات نفسها لن تتأثر.", + "setupWizard.welcomeTitle": "مرحبًا بك في LightNVR", + "setupWizard.welcomeIntro": "لنقم بإعداد جهاز NVR الخاص بك في خطوات سريعة. يمكنك دائمًا العودة إلى هذه الإعدادات لاحقًا من صفحة الإعدادات.", + "setupWizard.welcomeStorage": "مسار التخزين وحدود الحجم", + "setupWizard.welcomePerformance": "حدود الأداء لعدد الكاميرات", + "setupWizard.welcomeSecurity": "تسجيل دخول آمن للمسؤول", + "setupWizard.storageTitle": "التخزين وقاعدة البيانات", + "setupWizard.storageIntro": "أين يجب تخزين التسجيلات وقاعدة البيانات؟", + "setupWizard.storagePath": "مسار تخزين التسجيلات", + "setupWizard.storagePathHint": "المسار المطلق الذي تُكتب فيه ملفات الفيديو.", + "setupWizard.maxStorage": "الحد الأقصى لحجم التخزين (جيجابايت)", + "setupWizard.maxStorageHint": "0 = غير محدود.", + "setupWizard.dbPath": "مسار قاعدة البيانات", + "setupWizard.dbPathHint": "موقع ملف قاعدة بيانات SQLite.", + "setupWizard.performanceTitle": "الأداء", + "setupWizard.performanceIntro": "هذه الإعدادات تتحكم في السعة وليس في جودة الفيديو. يمكن لمعظم المستخدمين الإبقاء على القيم الافتراضية.", + "setupWizard.threadPool": "حجم مجموعة خيوط العمل", + "setupWizard.threadPoolInfo": "يؤثر على عمل الخادم/الويب في الخلفية. عادةً ما يكون الافتراضي الموصى به هو الأفضل ما لم تكن تضبط الأداء.", + "setupWizard.maxStreams": "الحد الأقصى للبث المتزامن", + "setupWizard.maxStreamsInfo": "هو الحد الأقصى لعدد الكاميرات لهذه النسخة العاملة. اضبطه على الأقل بعدد الكاميرات التي تخطط لإضافتها مع هامش إضافي بسيط.", + "setupWizard.important": "مهم:", + "setupWizard.restartWarning": "إذا غيّرت أيًا من الإعدادين، فسيتم حفظ القيمة الجديدة الآن لكنها لن تُطبَّق حتى يُعاد تشغيل LightNVR. على سبيل المثال، إذا كان حد البث الحالي 1 ورفعتَه إلى 32، يجب إعادة التشغيل قبل إضافة كاميرات تتجاوز الحد القديم.", + "setupWizard.threadPoolHintCores": "الموصى به: {recommended} (2× معالجك بـ {cores} نواة). يتحكم في خيوط عمل libuv في الخلفية. النطاق: 2–128.", + "setupWizard.threadPoolHint": "الموصى به: {recommended} (2× عدد أنوية معالجك). يتحكم في خيوط عمل libuv في الخلفية. النطاق: 2–128.", + "setupWizard.maxStreamsHint": "عدد الكاميرات التي يمكن لـ LightNVR إبقاؤها نشطة في وقت واحد. الافتراضي 32، الأقصى {max}. إذا كنت تتوقع 8 كاميرات، اختر 8 على الأقل. يتطلب إعادة تشغيل للتطبيق.", + "setupWizard.completeTitle": "اكتمل الإعداد!", + "setupWizard.saved": "تم حفظ إعداداتك بنجاح.", + "setupWizard.notSaved": "لم يتم تغيير أي إعدادات — سيتم استخدام القيم الافتراضية.", + "setupWizard.restartRequired": "إعادة تشغيل مطلوبة", + "setupWizard.restartRequiredInfo": "تم حفظ تغييرات حجم مجموعة الخيوط و/أو الحد الأقصى للبث، لكنها لن تُطبَّق حتى يُعاد تشغيل الخدمة. أعد التشغيل قبل إضافة كاميرات إضافية أو توقع سعة الحد الجديد.", + "setupWizard.saveFailed": "فشل حفظ الإعدادات: {error}", + "setupWizard.back": "رجوع", + "setupWizard.saving": "جارٍ الحفظ…", + "setupWizard.saveContinue": "حفظ ومتابعة", + "setupWizard.next": "التالي ←", + "setupWizard.finish": "الانتقال إلى لوحة التحكم", + "setupWizard.skip": "تخطي معالج الإعداد", + "live.eptzCanvasLabel": "عرض العين السمكة الإلكتروني للدوران والإمالة والتقريب", + "live.eptzCanvasHint": "اسحب للدوران والإمالة؛ عجلة الفأرة أو القرص للتكبير؛ زر Home لإعادة الضبط", + "live.eptzReset": "إعادة ضبط عرض ePTZ", + "live.autoShort": "تلقائي", + "live.webrtcShort": "WebRTC", + "nav.investigation": "التحقيق", + "availability.label": "توفر الكاميرات", + "availability.live": "مباشر الآن", + "availability.offline": "غير متصل (متصل سابقًا)", + "availability.neverConnected": "لم يتم الاتصال مطلقًا", + "availability.disabled": "معطّل", + "availability.all": "جميع الكاميرات", + "streams.inventory": "المخزون", + "streams.configuration": "الإعدادات", + "events.tab": "الأحداث", + "events.eyebrow": "تكاملات مبنية على الأحداث", + "events.title": "الأحداث والتوجيه", + "events.description": "حوّل أحداث الكاميرا والنظام إلى تدفقات MQTT دائمة لأتمتة العمليات وخدمات الإشعارات والمعالجة الخارجية. يوفّر LightNVR واجهة الأحداث، بينما تبقى عمليات تسليم البريد الإلكتروني والرسائل النصية في الخدمات اللاحقة.", + "events.routes": "المسارات", + "events.destinations": "الوجهات", + "events.catalog": "كتالوج الأحداث", + "events.enable": "تفعيل", + "events.loadError": "تعذّر تحميل إعدادات توجيه الأحداث", + "events.accessDenied": "تم رفض الوصول - صلاحيات غير كافية", + "events.summary.routes": "المسارات", + "events.summary.enabled": "{count} مفعّل", + "events.summary.destinations": "الوجهات", + "events.summary.managedActive": "{count} مُدارة ونشطة", + "events.summary.types": "الأنواع المسجّلة", + "events.summary.registry": "كتالوج أحداث مُصدَّر", + "events.summary.interface": "الواجهة", + "events.summary.interfaceHelp": "مخرجات أحداث دائمة", + "events.route.add": "إضافة مسار", + "events.route.addTitle": "إنشاء مسار أحداث", + "events.route.editTitle": "تعديل مسار أحداث", + "events.route.create": "إنشاء مسار", + "events.route.editorDescription": "اختر الأحداث المؤهلة، والكاميرات المشمولة، والوجهة، وكيفية التحكم في المصادر كثيفة الأحداث.", + "events.route.emptyTitle": "لم يتم تكوين مسارات أحداث", + "events.route.emptyDescription": "أنشئ مسارًا لتحديد أنواع الأحداث، ونطاق الكاميرات، والجدول الزمني، وسياسة القمع، ووجهة MQTT.", + "events.route.enabled": "المسار مُفعّل", + "events.route.enabledHelp": "يتم قبول الأحداث المطابقة للتسليم الدائم", + "events.route.destination": "الوجهة", + "events.route.destinationHelp": "يتم حفظ كل حدث مطابق مرة واحدة لكل وجهة فريدة.", + "events.route.eventTypes": "أنواع الأحداث", + "events.route.eventTypesHelp": "حدد عقدًا واحدًا أو أكثر من عقود الأحداث المُصدّرة من السجل.", + "events.route.detectionFilters": "تصفية اكتشافات الكائنات", + "events.route.detectionFiltersHelp": "يمكنك اختياريًا اشتراط تسميات أو مناطق أو حد أدنى من الثقة لأحداث اكتشاف الكائنات.", + "events.route.healthFilters": "تصفية أحداث صحة النظام", + "events.route.healthFiltersHelp": "يمكنك اختياريًا مطابقة رموز أو درجات خطورة حالات الصحة المسجلة. القيم المتاحة تأتي من هذا المسجّل.", + "events.route.healthConditions": "حالات الصحة (أي)", + "events.route.healthSeverities": "درجات الخطورة (أي)", + "events.route.healthRegistryUnavailable": "سجل حالات الصحة غير متاح. أعد التحميل قبل تكوين مرشحات الحالات.", + "events.route.labels": "التسميات (أي)", + "events.route.zones": "معرّفات المناطق (أي)", + "events.route.listHelp": "افصل بين القيم بفواصل.", + "events.route.minConfidence": "الحد الأدنى من الثقة", + "events.route.confidenceHelp": "قيمة من 0 إلى 1.", + "events.route.cameraScope": "نطاق الكاميرات", + "events.route.cameraScopeHelp": "أعد استخدام مواقع الأسطول أو الوسوم أو مجموعات السمات أو الكاميرات المحددة دون تحميل الأسطول بالكامل.", + "events.route.allCameras": "جميع الكاميرات", + "events.route.dynamicScope": "محدد الكاميرات الديناميكي", + "events.route.systemScopeHelp": "أحداث النظام ليست كاميرات. محددات الكاميرات غير متاحة عندما يتضمن هذا المسار أحداثًا بنطاق النظام.", + "events.route.schedule": "الجدول الزمني", + "events.route.scheduleHelp": "استخدم وقت وقوع الحدث في منطقة زمنية IANA؛ يتم دعم النوافذ الليلية.", + "events.route.restrictSchedule": "أثناء النوافذ المُهيّأة فقط", + "events.route.suppression": "سياسة الضوضاء والتسليم", + "events.route.suppressionHelp": "الصفر يعطّل عنصر التحكم. لا يتقدم القمع إلا بعد أن تقبل الوجهة الحدث الدائم.", + "events.route.debounce": "ثوانٍ التخميد", + "events.route.debounceHelp": "الملاحظات المتكررة تُطيل هذه الفترة الهادئة.", + "events.route.cooldown": "ثوانٍ التبريد", + "events.route.cooldownHelp": "الحد الأدنى للفاصل الزمني بعد حدث مقبول.", + "events.route.grouping": "ثوانٍ نافذة التجميع", + "events.route.groupingHelp": "يحتفظ بالحدث الأول ويجمع التكرارات.", + "events.route.rateLimit": "عدد الأحداث في الدقيقة", + "events.route.rateLimitHelp": "الحد الأقصى لنافذة ثابتة لكل مسار وكاميرا.", + "events.route.deliveryPolicy": "سياسة التسليم", + "events.route.suppressionActive": "عوامل تصفية الضوضاء نشطة", + "events.route.everyMatch": "كل تطابق", + "events.route.preview": "معاينة المسار", + "events.route.previewing": "جارٍ المعاينة…", + "events.route.previewResult": "معاينة المسار", + "events.route.cameraMatches": "تطابق {count} كاميرات", + "events.route.previewNoPublish": "تتحقق المعاينة من القاعدة الكاملة وتحدد عينة كاميرا؛ ولا تنشر أي حدث.", + "events.route.systemPreviewHelp": "تتجاوز أحداث النظام اختيار الكاميرا، لذلك تُظهر صفر كاميرات مطابقة في هذه المعاينة.", + "events.route.created": "تم إنشاء مسار الحدث", + "events.route.updated": "تم تحديث مسار الحدث", + "events.route.deleted": "تم حذف مسار الحدث", + "events.route.disabled": "تم تعطيل مسار الحدث", + "events.route.enabledMessage": "تم تفعيل مسار الحدث", + "events.route.deleteConfirm": "حذف مسار الحدث \"{name}\"؟", + "events.route.validation.name": "أدخل اسم المسار.", + "events.route.validation.destination": "اختر وجهة.", + "events.route.validation.event_types": "حدد نوع حدث واحدًا على الأقل.", + "events.route.validation.selector": "أكمل أو صحّح محدد الكاميرا.", + "events.route.validation.system_scope": "لا يمكن استخدام محددات الكاميرا مع أحداث نطاق النظام.", + "events.route.validation.detection_type": "عوامل تصفية الكشف تتطلب نوع حدث كشف الكائنات.", + "events.route.validation.detection_filter": "أضف تسمية كشف أو منطقة أو حدًا أدنى للثقة واحدًا على الأقل.", + "events.route.validation.confidence": "يجب أن تكون الحد الأدنى للثقة من 0 إلى 1.", + "events.route.validation.predicate_mix": "لا يمكن دمج عوامل تصفية الكشف والصحة في مسار واحد.", + "events.route.validation.health_type": "عوامل تصفية الصحة تتطلب فقط أنواع أحداث صحة النظام المسجلة.", + "events.route.validation.health_filter": "حدد حالة صحة أو مستوى خطورة مسجلة واحدة على الأقل.", + "events.route.validation.health_condition": "اختر فقط رموز الحالة التي يعيدها سجل الحالة في المسجّل.", + "events.route.validation.health_severity": "اختر فقط مستويات الخطورة المدعومة لأنواع أحداث الحالة المحددة.", + "events.route.validation.timezone": "أدخل منطقة زمنية IANA مثبتة مثل UTC أو America/New_York.", + "events.route.validation.schedule_window": "تحتاج كل نافذة جدولة إلى يوم واحد على الأقل وأوقات بداية ونهاية صالحة ومختلفة.", + "events.route.validation.suppression": "يجب أن تكون قيم الكبت أعدادًا صحيحة ضمن النطاقات المسموح بها.", + "events.schedule.timezone": "المنطقة الزمنية", + "events.schedule.timezoneHelp": "يجب أن تكون متوفرة في قاعدة بيانات المناطق الزمنية للمسجّل.", + "events.schedule.addWindow": "إضافة نافذة زمنية", + "events.schedule.windowNumber": "النافذة {number}", + "events.schedule.start": "البداية", + "events.schedule.end": "النهاية", + "events.schedule.sunday": "الأحد", + "events.schedule.monday": "الاثنين", + "events.schedule.tuesday": "الثلاثاء", + "events.schedule.wednesday": "الأربعاء", + "events.schedule.thursday": "الخميس", + "events.schedule.friday": "الجمعة", + "events.schedule.saturday": "السبت", + "events.destination.add": "إضافة وجهة", + "events.destination.addTitle": "إضافة وجهة MQTT", + "events.destination.editTitle": "تعديل وجهة MQTT", + "events.destination.create": "إنشاء وجهة", + "events.destination.editorDescription": "قم بتكوين مخرج أحداث دائم. تبقى بيانات الاعتماد للكتابة فقط ولا تُعاد أبدًا عبر واجهة API.", + "events.destination.default": "إعدادات MQTT الافتراضية", + "events.destination.settingsManaged": "إعدادات مُدارة", + "events.destination.defaultDescription": "تبقى إعدادات MQTT الحالية متاحة باسم mqtt:default وتُستخدم من قبل {count} مسارات.", + "events.destination.openSettings": "فتح إعدادات MQTT", + "events.destination.emptyTitle": "لا توجد وجهات مُدارة", + "events.destination.emptyDescription": "أضف وسيط MQTT آخر لتسليم الأحداث بشكل مستقل إلى موصل سحابي أو نظام أتمتة أو خدمة إشعارات.", + "events.destination.identity": "هوية الوجهة", + "events.destination.enabled": "الوجهة مفعّلة", + "events.destination.enabledHelp": "الاتصال وتفريغ قائمة انتظارها الدائمة", + "events.destination.active": "نشط", + "events.destination.paused": "متوقف مؤقتًا", + "events.destination.pause": "إيقاف مؤقت", + "events.destination.broker": "الوسيط", + "events.destination.host": "مضيف الوسيط", + "events.destination.hostHelp": "اسم المضيف أو عنوان IP فقط؛ لا تُضمّن مخطط URL.", + "events.destination.port": "المنفذ", + "events.destination.clientId": "معرّف العميل", + "events.destination.clientIdHelp": "يجب أن يكون فريدًا لهذا الاتصال بالوسيط.", + "events.destination.topic": "الموضوع", + "events.destination.topicTemplate": "قالب الموضوع", + "events.destination.topicHelp": "يجب أن يتضمن رموز نوع الحدث ومعرّف الموضوع؛ أحرف البدل في MQTT غير مسموح بها.", + "events.destination.keepalive": "ثوانٍ للنبض الحي", + "events.destination.statusTopicTemplate": "موضوع حالة التواجد", + "events.destination.statusTopicHelp": "اختياري. يجب أن يتضمن {installation_uuid}؛ {destination_uuid} متاح أيضًا. أحرف البدل في MQTT غير مسموح بها.", + "events.destination.statusTopicEnabled": "التواجد مُفعّل صراحةً لهذه الوجهة. لا يتم استنتاج الموضوع من موضوع الحدث.", + "events.destination.statusTopicDisabled": "التواجد معطّل لهذه الوجهة. اترك هذا الحقل فارغًا لإبقائه معطّلًا.", + "events.destination.qos": "جودة الخدمة", + "events.destination.qos0": "إرسال مرة واحدة", + "events.destination.qos1": "مرة واحدة على الأقل", + "events.destination.qos2": "مرة واحدة بالضبط", + "events.destination.authentication": "المصادقة", + "events.destination.passwordPreserved": "اتركه فارغًا للحفاظ على كلمة المرور المخزنة (حقل الكتابة فقط).", + "events.destination.passwordOptional": "اختياري عندما يسمح الوسيط للعملاء المجهولين.", + "events.destination.clearPassword": "مسح كلمة المرور المخزنة", + "events.destination.transportSecurity": "أمان النقل", + "events.destination.tlsMode": "وضع TLS", + "events.destination.tlsSystem": "مخزن الثقة الخاص بالنظام", + "events.destination.tlsCustomCa": "جهة شهادات مخصصة", + "events.destination.tlsMutual": "TLS متبادل", + "events.destination.tlsDisabled": "معطّل (نص عادي)", + "events.destination.tlsHelp.system": "تحقق من شهادة الوسيط مقابل مخزن الثقة الخاص بنظام التشغيل.", + "events.destination.tlsHelp.custom_ca": "تحقّق من الوسيط مقابل ملف جهة إصدار شهادات بصيغة PEM.", + "events.destination.tlsHelp.mutual": "تحقّق من الوسيط باستخدام جهة إصدار شهادات محددة وقدّم شهادة عميل ومفتاحًا.", + "events.destination.tlsHelp.disabled": "لا يوجد تشفير للنقل أو تحقّق من هوية الوسيط.", + "events.destination.caFile": "ملف جهة الإصدار", + "events.destination.certFile": "ملف شهادة العميل", + "events.destination.keyFile": "ملف مفتاح العميل", + "events.destination.absolutePathHelp": "استخدم مسارًا مطلقًا يمكن لخدمة LightNVR قراءته.", + "events.destination.plaintextWarning": "قد يعرّض MQTT غير المشفّر بيانات الأحداث الوصفية وبيانات الاعتماد للخطر. استخدمه فقط على شبكة موثوقة ومعزولة.", + "events.destination.security": "الأمان", + "events.destination.tls.system": "ثقة النظام", + "events.destination.tls.custom_ca": "جهة إصدار مخصصة", + "events.destination.tls.mutual": "TLS متبادل", + "events.destination.tls.disabled": "نص غير مشفّر", + "events.destination.routes": "المسارات", + "events.destination.presence": "موضوع الحضور", + "events.destination.deleteInUse": "أزل أو أعد توجيه المسارات قبل حذف هذه الوجهة.", + "events.destination.created": "تم إنشاء وجهة MQTT", + "events.destination.updated": "تم تحديث وجهة MQTT", + "events.destination.deleted": "تم حذف وجهة MQTT", + "events.destination.pausedMessage": "تم إيقاف وجهة MQTT مؤقتًا؛ تبقى الأحداث في قائمة الانتظار محفوظة حتى انتهاء صلاحيتها.", + "events.destination.enabledMessage": "تم تفعيل وجهة MQTT", + "events.destination.deleteConfirm": "حذف وجهة MQTT \"{name}\"؟", + "events.destination.validation.name": "أدخل اسم الوجهة.", + "events.destination.validation.host": "أدخل اسم مضيف الوسيط أو عنوان IP.", + "events.destination.validation.client_id": "أدخل معرّف عميل الوسيط.", + "events.destination.validation.topic": "يجب أن يتضمن الموضوع رموز نوع الحدث ومعرّف الموضوع وألا يحتوي على أحرف البدل في MQTT.", + "events.destination.validation.status_topic": "يجب أن يتضمن موضوع الحضور الاختياري رمز UUID للتثبيت، وأن يستخدم الرموز المدعومة فقط، وألا يحتوي على أحرف البدل في MQTT.", + "events.destination.validation.port": "يجب أن يكون المنفذ عددًا صحيحًا من 1 إلى 65535.", + "events.destination.validation.keepalive": "يجب أن تكون مدة الإبقاء على الاتصال عددًا صحيحًا من 5 إلى 3600 ثانية.", + "events.destination.validation.qos": "اختر جودة الخدمة MQTT 0 أو 1 أو 2.", + "events.destination.validation.username": "يتطلب تعيين كلمة مرور إدخال اسم مستخدم.", + "events.destination.validation.ca_file": "يتطلب وضع TLS هذا مسارًا مطلقًا لملف جهة الإصدار.", + "events.destination.validation.mutual_files": "يتطلب Mutual TLS مسارات مطلقة لـ CA وشهادة العميل ومفتاح العميل.", + "fleet.eyebrow": "عمليات الكاميرات", + "fleet.title": "جرد الكاميرات", + "fleet.description": "ابحث عن الكاميرات وقيّمها ونظّمها عبر عمليات النشر الكبيرة دون تحميل الجرد الكامل في المتصفح.", + "fleet.summary": "ملخص صحة الأسطول", + "fleet.totalCameras": "الكاميرات المطابقة", + "fleet.needsAttention": "متدهورة", + "fleet.searchLabel": "البحث عن كاميرات", + "fleet.searchPlaceholder": "ابحث بالاسم أو العنوان أو الموقع أو الوسم أو المورّد أو الطراز…", + "fleet.resultCount": "{count} كاميرا", + "fleet.filters": "عوامل التصفية", + "fleet.clearFilters": "مسح عوامل التصفية", + "fleet.filter.health": "الحالة", + "fleet.filter.enabled": "حالة الكاميرا", + "fleet.filter.anyState": "أي حالة", + "fleet.filter.recording": "وضع التسجيل", + "fleet.filter.location": "شجرة المواقع", + "fleet.filter.allLocations": "جميع المواقع", + "fleet.filter.tags": "الوسوم (مطابقة أي)", + "fleet.filter.collection": "مجموعة الكاميرات", + "fleet.health.unknown": "غير معروف", + "fleet.health.up": "متصل", + "fleet.health.degraded": "متدهورة", + "fleet.health.down": "غير متصل", + "fleet.health.disabled": "معطّل", + "fleet.recording.off": "إيقاف", + "fleet.recording.continuous": "مستمر", + "fleet.recording.detection": "الكشف", + "fleet.recordingActive": "جارٍ التسجيل", + "fleet.recordingInactive": "لا يوجد تسجيل", + "fleet.column.camera": "الكاميرا", + "fleet.column.health": "الحالة", + "fleet.column.location": "الموقع", + "fleet.column.tags": "الوسوم", + "fleet.column.recording": "التسجيل", + "fleet.viewLive": "مباشر", + "fleet.lastFrame": "آخر إطار", + "fleet.noAddress": "العنوان غير متاح", + "fleet.unassigned": "غير مُعيَّن", + "fleet.loading": "جارٍ تحميل أسطول الكاميرات…", + "fleet.refreshing": "جارٍ التحديث…", + "fleet.loadError": "تعذّر تحميل أسطول الكاميرات", + "fleet.emptyTitle": "لا توجد كاميرات مُهيَّأة", + "fleet.emptyDescription": "أضف تدفقًا لجعله متاحًا في مساحة عمل الأسطول.", + "fleet.emptyFilteredTitle": "لا توجد كاميرات مطابقة لهذا العرض", + "fleet.emptyFilteredDescription": "جرّب توسيع نطاق البحث أو مسح أحد المرشحات أو أكثر.", + "fleet.paginationSummary": "عرض {first}–{last} من {total}", + "fleet.perPage": "لكل صفحة", + "fleet.pageOf": "صفحة {page} من {pages}", + "fleet.selectPage": "تحديد جميع الكاميرات في هذه الصفحة", + "fleet.selectCamera": "تحديد {name}", + "fleet.selectedCount": "تم تحديد {count} كاميرات", + "fleet.organizeSelected": "تنظيم المحدد", + "fleet.clearSelection": "مسح التحديد", + "fleet.organization.manage": "إدارة التنظيم", + "fleet.organization.title": "تنظيم الكاميرات", + "fleet.organization.description": "حافظ على تسلسل هرمي قابل لإعادة الاستخدام للمواقع وقاموس وسوم موحَّد لأسطول الكاميرات.", + "fleet.organization.locations": "المواقع", + "fleet.organization.tags": "الوسوم", + "fleet.organization.locationsDescription": "نمذج المواقع والمباني والطبقات والمناطق التشغيلية كتسلسل هرمي قابل للتنقل.", + "fleet.organization.tagsDescription": "استخدم قاموس وسوم مُدار بدلاً من التسميات الحرة غير المتسقة.", + "fleet.organization.addRoot": "إضافة موقع رئيسي", + "fleet.organization.addLocation": "إضافة موقع", + "fleet.organization.editLocation": "تعديل الموقع", + "fleet.organization.addChild": "إضافة فرع", + "fleet.organization.type": "النوع", + "fleet.organization.parent": "الموقع الأب", + "fleet.organization.topLevel": "المستوى الأعلى", + "fleet.organization.sortOrder": "ترتيب الفرز", + "fleet.organization.contents": "المحتويات", + "fleet.organization.cameras": "الكاميرات", + "fleet.organization.system": "النظام", + "fleet.organization.contentCounts": "{cameras} كاميرا · {children} فرع", + "fleet.organization.locationNotEmpty": "انقل الكاميرات واحذف المواقع الفرعية أولاً", + "fleet.organization.noLocations": "لم يتم تكوين أي مواقع.", + "fleet.organization.locationCreated": "تم إنشاء الموقع", + "fleet.organization.locationUpdated": "تم تحديث الموقع", + "fleet.organization.locationDeleted": "تم حذف الموقع", + "fleet.organization.deleteLocationConfirm": "حذف الموقع “{name}”؟", + "fleet.organization.addTag": "إضافة وسم", + "fleet.organization.editTag": "تحرير الوسم", + "fleet.organization.tagLabel": "الوسم", + "fleet.organization.color": "اللون (#RRGGBB)", + "fleet.organization.tagDescription": "الوصف", + "fleet.organization.noTags": "لم يتم تكوين أي وسوم معيارية.", + "fleet.organization.tagCreated": "تم إنشاء الوسم", + "fleet.organization.tagUpdated": "تم تحديث الوسم", + "fleet.organization.tagDeleted": "تم حذف الوسم", + "fleet.organization.deleteTagConfirm": "حذف “{name}”؟ هو مُعيَّن حاليًا لـ {count} كاميرا.", + "fleet.organization.merge": "دمج", + "fleet.organization.mergeTagNamed": "دمج “{name}”", + "fleet.organization.mergeInto": "دمج في", + "fleet.organization.chooseTag": "اختر الوسم المراد الاحتفاظ به", + "fleet.organization.mergeWarning": "تنتقل جميع تعيينات الكاميرات إلى الوسم المحتفظ به، ثم يُحذف الوسم المصدر.", + "fleet.organization.tagsMerged": "تم دمج الوسوم", + "fleet.organization.saveError": "تعذّر الحفظ: {message}", + "fleet.organization.deleteError": "تعذّر الحذف: {message}", + "fleet.locationType.site": "موقع", + "fleet.locationType.building": "مبنى", + "fleet.locationType.floor": "طابق", + "fleet.locationType.area": "منطقة", + "fleet.locationType.zone": "قطاع", + "fleet.locationType.system": "نظام", + "fleet.bulk.title": "تنظيم الكاميرات المحددة", + "fleet.bulk.description": "تطبيق تغييرات الموقع والوسوم على {count} كاميرات مع تحديد عدد العمليات المتزامنة.", + "fleet.bulk.location": "تعيين الموقع", + "fleet.bulk.locationHelp": "سيتم نقل كل كاميرا محددة إلى الموقع المختار.", + "fleet.bulk.keepLocations": "الاحتفاظ بالمواقع الحالية", + "fleet.bulk.tags": "تعيين الوسوم", + "fleet.bulk.tagsHelp": "إضافة أو إزالة الوسوم دون التأثير على التعيينات الأخرى، أو استبدال مجموعة الوسوم بالكامل.", + "fleet.bulk.tagOperation.none": "إبقاء", + "fleet.bulk.tagOperation.add": "إضافة", + "fleet.bulk.tagOperation.remove": "إزالة", + "fleet.bulk.tagOperation.replace": "استبدال الكل", + "fleet.bulk.replaceWarning": "استبدال الكل يزيل جميع الوسوم الحالية قبل تطبيق هذا التحديد. التحديد الفارغ يمسح جميع الوسوم.", + "fleet.bulk.apply": "تطبيق التغييرات", + "fleet.bulk.working": "جارٍ تطبيق التغييرات…", + "fleet.bulk.success": "تم تحديث {count} كاميرات", + "fleet.bulk.partial": "تم تحديث {succeeded} كاميرات؛ فشل {failed}", + "fleet.bulk.error": "تعذّر تنظيم الكاميرات: {message}", + "fleet.bulk.failures": "الكاميرات التي تعذّر تحديثها", + "fleet.queues.degraded": "بثوط متدهورة", + "fleet.queues.offline": "كاميرات غير متصلة", + "fleet.queues.oldest": "الأقدم: {time}", + "fleet.queues.noneActive": "لا توجد حالات نشطة", + "fleet.views.title": "العروض المحفوظة", + "fleet.views.choose": "اختر عرضًا محفوظًا", + "fleet.views.none": "لا توجد عروض محفوظة بعد", + "collections.loadError": "تعذّر تحميل المجموعة: {message}", + "collections.cameras": "كاميرات", + "collections.visibility.shared": "مشتركة", + "collections.visibility.private": "خاصة", + "collections.selectorRedacted": "قواعد خاصة", + "collections.emptyTitle": "لا توجد مجموعات بعد", + "collections.emptyAdmin": "أنشئ مجموعة ثابتة أو عرضًا ذكيًا قائمًا على قواعد لإعادة استخدام اختيارات الكاميرات.", + "collections.emptyViewer": "لا توجد مجموعات مشتركة متاحة لنطاق الكاميرات الخاص بك.", + "collections.deleteConfirm": "حذف المجموعة \"{name}\"؟", + "collections.deleted": "تم حذف المجموعة", + "collections.deleteError": "تعذّر حذف المجموعة: {message}", + "collections.preview.title": "معاينة القواعد", + "collections.preview.matches": "{count} كاميرا مطابقة", + "collections.preview.action": "معاينة", + "collections.preview.hide": "إخفاء المعاينة", + "collections.preview.loading": "جارٍ التقييم…", + "collections.preview.empty": "لا توجد كاميرات مطابقة حاليًا.", + "collections.preview.sample": "عرض عينة من {count} كاميرا من أصل {total} مطابقة.", + "collections.preview.error": "تعذّر معاينة المجموعة: {message}", + "collections.members.title": "الأعضاء الثابتون", + "collections.members.selected": "تم تحديد {count} كاميرا عبر جميع الصفحات", + "collections.members.search": "ابحث عن كاميرات…", + "collections.members.selectPage": "تحديد هذه الصفحة", + "collections.members.empty": "لا توجد كاميرات مطابقة لهذا البحث.", + "collections.builder.title": "القواعد الذكية", + "collections.builder.description": "تُقيَّم القواعد بناءً على تنظيم الكاميرات الحالي وإعداداتها وقدراتها وحالتها.", + "collections.builder.match": "مطابقة", + "collections.builder.allRules": "جميع القواعد", + "collections.builder.anyRule": "أي قاعدة", + "collections.builder.addRule": "إضافة قاعدة", + "collections.builder.removeRule": "إزالة قاعدة", + "collections.builder.matchesAll": "بدون قواعد مكتملة، تطابق هذه المجموعة كل كاميرا ضمن النطاق المصرّح للمستخدم.", + "collections.builder.incompleteRule": "أكمل أو احذف كل قاعدة قبل الحفظ.", + "collections.builder.chooseLocation": "اختر شجرة مواقع فرعية", + "collections.builder.vendorPlaceholder": "أسماء الموردين، مفصولة بفواصل", + "collections.builder.modelPlaceholder": "أسماء الطرازات، مفصولة بفواصل", + "collections.builder.advancedMode": "JSON متقدم", + "collections.builder.visualMode": "المنشئ المرئي", + "collections.builder.cannotVisualize": "يحتوي هذا المحدد على منطق متداخل أو متقدم لا يمكن للمنشئ المرئي تمثيله بأمان.", + "collections.rule.location_subtree": "الموقع ضمن", + "collections.rule.camera_uuid": "كاميرات محددة", + "collections.rule.tag_any": "يحمل أي وسم", + "collections.rule.tag_all": "يحمل جميع الوسوم", + "collections.rule.tag_none": "لا يحمل أي وسم", + "collections.rule.health": "الحالة هي", + "collections.rule.enabled": "الكاميرا", + "collections.rule.recording_mode": "وضع التسجيل هو", + "collections.rule.capability_any": "يملك أي ميزة", + "collections.rule.capability_all": "يملك جميع الميزات", + "collections.rule.vendor": "المورد هو", + "collections.rule.model": "الطراز هو", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "قناة الصوت العكسية", + "streamHealth.observedFps": "FPS المرصود", + "streamHealth.expectedFps": "المتوقع", + "streamHealth.fpsHelp": "مرصود بواسطة LightNVR؛ المتوقع يأتي من بيانات البث الوصفية للكاميرا.", + "login.passwordChanged": "تم تغيير كلمة المرور بنجاح. سجّل الدخول بكلمة المرور الجديدة.", + "passwordChangeRequired.title": "تغيير كلمة المرور الافتراضية", + "passwordChangeRequired.description": "لا يزال هذا التثبيت يستخدم كلمة مرور المسؤول الافتراضية. استبدلها قبل المتابعة إلى LightNVR. عند تفعيل المصادقة متعددة العوامل، سيتم التحقق منها عند تسجيل الدخول التالي.", + "passwordChangeRequired.currentPassword": "كلمة المرور الحالية", + "passwordChangeRequired.newPassword": "كلمة المرور الجديدة", + "passwordChangeRequired.confirmPassword": "تأكيد كلمة المرور الجديدة", + "passwordChangeRequired.passwordHelp": "استخدم 8 أحرف على الأقل. لا يمكن أن تكون كلمة المرور admin.", + "passwordChangeRequired.submit": "تغيير كلمة المرور", + "passwordChangeRequired.saving": "جارٍ تغيير كلمة المرور...", + "passwordChangeRequired.error.currentRequired": "أدخل كلمة المرور الحالية.", + "passwordChangeRequired.error.tooShort": "يجب أن تتكون كلمة المرور الجديدة من 8 أحرف على الأقل.", + "passwordChangeRequired.error.defaultPassword": "لا يمكن أن تكون كلمة المرور الجديدة admin.", + "passwordChangeRequired.error.mismatch": "كلمتا المرور الجديدتان غير متطابقتين.", + "passwordChangeRequired.error.generic": "تعذّر تغيير كلمة المرور. حاول مرة أخرى.", + "settings.tab.health": "الحالة", + "settings.tab.workspaces": "مساحات العمل", + "settings.health.title": "حالة المضيف والأجهزة", + "settings.health.description": "قم بتكوين مراقبة نظام التشغيل والأجهزة ضمن حدود محددة دون الكشف عن مسارات الأجهزة أو الأسرار.", + "settings.health.enabled": "تمكين مراقبة الحالة", + "settings.health.enabledHelp": "اجمع إشارات المضيف والخدمات والتخزين والشبكة والأجهزة المدعومة.", + "settings.health.profile": "ملف تعريف السياسة", + "settings.health.profileHelp": "المتوازن هو الإعداد الافتراضي العادي؛ المتحفظ يتطلب أدلة أقوى قبل التنبيه.", + "settings.health.profile.balanced": "متوازن", + "settings.health.profile.conservative": "متحفظ", + "settings.health.hardwareProvider": "مزوّد الأجهزة", + "settings.health.provider.auto": "تلقائي (مزوّدات النواة)", + "settings.health.provider.smartctl": "smartctl (صريح)", + "settings.health.providerHelp.auto": "يستخدم فقط مزوّدات sysfs وNVMe والنواة ضمن حدود محددة؛ لا يتم استنتاج smartctl أبدًا.", + "settings.health.providerHelp.smartctl": "يُمكّن صراحةً مزوّد smartctl JSON الاختياري ضمن حدود محددة للأجهزة المكتشفة.", + "settings.health.providerHelp.disabled": "يعطّل مزوّدات الأجهزة الاختيارية مع إبقاء مراقبة الحالة المحمولة متاحة.", + "settings.health.writeProbe": "تمكين فحص الكتابة على التخزين", + "settings.health.writeProbeHelp": "يُجري دوريًا فحص هدف التسجيل المُهيّأ ضمن حدود محددة.", + "settings.health.cadences": "إيقاعات أخذ العينات", + "settings.health.cadencesHelp": "يجب أن تبقى الفترات مرتبة من السريع إلى فحص الأجهزة وضمن حدود الخادم.", + "settings.health.fastInterval": "الفاصل السريع", + "settings.health.normalInterval": "الفاصل العادي", + "settings.health.slowInterval": "الفاصل البطيء", + "settings.health.deviceInterval": "فاصل الأجهزة", + "settings.health.presenceInterval": "فاصل التواجد", + "settings.health.retention": "الاحتفاظ بالحوادث", + "settings.health.conditions": "تجاوزات الشروط", + "settings.health.conditionsHelp": "تجاوز أكواد الشروط والوحدات المُرجَعة من سجل السياسة الفعّالة فقط.", + "settings.health.conditionOverride": "تجاوز الشرط", + "settings.health.overrideMode": "وضع التجاوز", + "settings.health.overrideModeHelp": "ورث الملف الشخصي المحدد، أو اختر ملفًا آخر محدد الحدود، أو عطّل الشرط، أو عيّن عتبات مُتحقَّقًا منها.", + "settings.health.profileDefault": "استخدام الملف المحدد", + "settings.health.custom": "عتبات مخصصة", + "settings.health.warning": "عتبة التحذير", + "settings.health.critical": "عتبة الحرج", + "settings.health.recovery": "عتبة التعافي", + "settings.health.warning_for_seconds": "ثوانٍ البقاء في التحذير", + "settings.health.critical_for_seconds": "ثوانٍ البقاء في الحرج", + "settings.health.recovery_for_seconds": "ثوانٍ البقاء في التعافي", + "settings.health.clearOverrides": "مسح التجاوزات", + "settings.health.registryUnavailable": "لم يُرجِع الخادم سجل الشروط. أعد التحميل قبل تعديل التجاوزات.", + "settings.health.resetDefaults": "إعادة تعيين الإعدادات الافتراضية للصحة", + "settings.health.reloadGuidance": "الحفظ ذرّي. أعد التحميل بعد الحفظ الناجح لتأكيد السياسة الفعّالة؛ أعد التشغيل فقط عندما يطلب الخادم ذلك صراحةً.", + "settings.health.validation.profile": "اختر ملف صحة مدعومًا.", + "settings.health.validation.provider": "اختر مزوّد أجهزة مدعومًا.", + "settings.health.validation.healthFastIntervalSeconds": "يجب أن تكون الفترة السريعة عددًا صحيحًا من 5 إلى 60 ثانية.", + "settings.health.validation.healthNormalIntervalSeconds": "يجب أن تكون الفترة العادية عددًا صحيحًا من 15 إلى 600 ثانية.", + "settings.health.validation.healthSlowIntervalSeconds": "يجب أن تكون الفترة البطيئة عددًا صحيحًا من 60 إلى 3600 ثانية.", + "settings.health.validation.healthDeviceIntervalSeconds": "يجب أن تكون فترة الجهاز عددًا صحيحًا من 300 إلى 86400 ثانية.", + "settings.health.validation.healthPresenceIntervalSeconds": "يجب أن تكون فترة التواجد عددًا صحيحًا من 15 إلى 3600 ثانية.", + "settings.health.validation.healthIncidentRetentionDays": "يجب أن تكون مدة الاحتفاظ بالحوادث عددًا صحيحًا من 7 إلى 3650 يومًا.", + "settings.health.validation.ordered": "يجب أن تكون فترات أخذ العينات مرتبة: سريعة، ثم عادية، ثم بطيئة، ثم الجهاز.", + "settings.health.validation.overrides": "يجب أن تستخدم تجاوزات الشروط أكوادًا فريدة وملفات مدعومة من سجل الخادم.", + "settings.health.validation.thresholds": "يجب أن تكون العتبات المخصصة قيمًا محدودة ضمن حدود وحدة الشرط.", + "settings.health.validation.thresholdOrder": "يجب أن تحافظ عتبات التحذير والحرج والتعافي على اتجاه التنبيه والتخلفية للشرط.", + "settings.health.validation.dwell": "يجب أن تكون أوقات البقاء ثوانٍ صحيحة ضمن سبعة أيام؛ ولا يمكن أن يكون بقاء التحذير أو التعافي صفرًا.", + "workspaces.title": "مساحات عمل المشغّل", + "workspaces.description": "اختر مساحات العمل المتخصصة التي تظهر في التنقل وعناصر الصفحة.", + "workspaces.saved": "تم حفظ تفضيلات مساحات العمل", + "workspaces.saveError": "تعذّر حفظ تفضيلات مساحات العمل: {message}", + "workspaces.loadError": "تعذّر تحميل تفضيلات مساحات العمل.", + "workspaces.showWorkspace": "إظهار {name}", + "workspaces.authorizationNote": "هذا يتحكم في العرض فقط. روابط URL المباشرة والوصول عبر API لا تزال تخضع لسياسة التفويض الخاصة بك.", + "workspaces.liveNavigator": "المُتنقّل المحسّن", + "workspaces.liveNavigatorDescription": "شجرة المواقع، مرشحات التوفّر، التخطيطات المحفوظة، والأحداث الأخيرة.", + "workspaces.investigation": "التحقيق", + "workspaces.investigationDescription": "البحث، الربط، الحماية، وتصدير الأدلة المسجّلة.", + "settings.reduceMotion": "تقليل الحركة", + "settings.reduceMotionHelp": "يعطّل الرسوم المتحركة والانتقالات غير الضرورية. يتّبع تلقائيًا تفضيل نظام التشغيل.", + "settings.reduceMotionPreference": "تفضيل تقليل الحركة", + "settings.reduceMotionAuto": "تلقائي", + "settings.reduceMotionOn": "مُفعّل", + "settings.reduceMotionOff": "مُعطّل", + "settings.audioCompliance": "امتثال الصوت", + "settings.disableAudioGlobally": "تعطيل الصوت عبر هذه النسخة", + "settings.audioDisabled": "الصوت معطّل على مستوى النسخة", + "settings.audioComplianceHelp": "يمنع التنصّت المباشر، والتحدّث ثنائي الاتجاه، والصوت في التسجيلات الجديدة عبر هذه النسخة. الحفظ يعيد تشغيل جلسات الوسائط النشطة في go2rtc. التسجيلات الحالية لا تتأثر.", + "tokens.manage": "إدارة الوصول عبر API", + "tokens.title": "الوصول عبر API — {username}", + "tokens.description": "أنشئ بيانات اعتماد محدودة النطاق للتكاملات وألغِ كل واحدة منها بشكل مستقل.", + "tokens.recommendedTitle": "يُنصح باستخدام الرموز محدودة النطاق", + "tokens.recommendedDescription": "كل رمز ينتهي صلاحيته، وله إجراءات ونطاق كاميرا محدّدان، ولا يمكنه أبدًا تجاوز سياسة الوصول الحالية للمستخدم.", + "tokens.coverageNotice": "الأذونات المتاحة تعكس ما يفرضه هذا الخادم. الرمز لا يمكنه استخدام أذونات لا يملكها مستخدمه بالفعل.", + "tokens.createTitle": "إنشاء رمز محدّد النطاق", + "tokens.createDescription": "استخدم رمزًا واحدًا لكل تكامل حتى يمكن تحديد هويته وتدويره وإلغاؤه دون تعطيل أي شيء آخر.", + "tokens.name": "اسم التكامل", + "tokens.namePlaceholder": "مثال: جسر PTZ المرآب الشمالي", + "tokens.expiry": "ينتهي بعد", + "tokens.expiryDays": "{days} يوم", + "tokens.actions": "الإجراءات المسموح بها", + "tokens.actionsHelp": "اختر فقط ما تحتاجه هذه التكاملات. تستحق الإجراءات التدميرية رمزًا خاصًا بها.", + "tokens.destructive": "تدميرية", + "tokens.noEnforcedActions": "لا توجد إجراءات مدعومة بالرموز متاحة من إصدار الخادم هذا.", + "tokens.scope.label": "نطاق الكاميرا", + "tokens.scope.all": "أسطول الكاميرات بالكامل", + "tokens.scope.collection": "مجموعة مشتركة", + "tokens.scope.selector": "محدد مخصص", + "tokens.scope.chooseCollection": "مجموعة الكاميرات المشتركة", + "tokens.scope.allValue": "الأسطول بالكامل", + "tokens.scope.collectionValue": "المجموعة: {name}", + "tokens.scope.selectorValue": "محدد ديناميكي مخصص", + "tokens.create": "إنشاء رمز", + "tokens.creating": "جارٍ إنشاء الرمز…", + "tokens.createdSuccess": "تم إنشاء رمز API محدد النطاق", + "tokens.createError": "تعذّر إنشاء رمز API: {message}", + "tokens.invalidResponse": "أعاد الخادم استجابة بيانات اعتماد غير مكتملة.", + "tokens.existingTitle": "الرموز الموجودة", + "tokens.existingDescription": "تبقى البادئات والبيانات الوصفية متاحة فقط بعد الإنشاء.", + "tokens.emptyTitle": "لا توجد رموز نشطة", + "tokens.emptyDescription": "أنشئ رمزًا محدد النطاق لأول تكامل يحتاج إلى الوصول إلى API.", + "tokens.showInactive": "إظهار {count} غير نشط", + "tokens.status.active": "نشط", + "tokens.status.expired": "منتهي الصلاحية", + "tokens.status.revoked": "ملغى", + "tokens.expires": "ينتهي", + "tokens.expiresValue": "ينتهي {date}", + "tokens.created": "تم الإنشاء", + "tokens.lastUsed": "آخر استخدام", + "tokens.revoke": "إلغاء", + "tokens.revoking": "جارٍ الإلغاء…", + "tokens.revokeConfirm": "إلغاء \"{description}\"؟ ستتوقف الطلبات التي تستخدمه فورًا.", + "tokens.revokedSuccess": "تم إلغاء رمز API", + "tokens.revokeError": "تعذّر إلغاء رمز API: {message}", + "tokens.validation.missing_description": "أدخل اسم التكامل الذي سيستخدم هذا الرمز.", + "tokens.validation.description_too_long": "يجب ألا يتجاوز اسم التكامل 128 حرفًا.", + "tokens.validation.invalid_expiry": "اختر مدة صلاحية الرمز بين 1 و365 يومًا.", + "tokens.validation.missing_actions": "اختر إجراءً واحدًا مسموحًا به على الأقل.", + "tokens.validation.invalid_action": "واحد أو أكثر من الإجراءات المحددة غير مدعوم بالرموز على هذا الخادم.", + "tokens.validation.invalid_scope": "اختر نطاق كاميرا صالحًا.", + "tokens.validation.requires_all_scope": "الأذونات غير المتعلقة بالكاميرا تتطلب نطاق الأسطول الكامل للكاميرات. اختر هذا النطاق أو أزل تلك الأذونات.", + "tokens.validation.missing_collection": "اختر مجموعة مشتركة متاحة.", + "tokens.validation.invalid_selector": "أكمل أو صحّح محدد الكاميرا المخصص.", + "tokens.secret.oneTime": "يُعرض مرة واحدة", + "tokens.secret.scopedTitle": "احفظ هذا الرمز المحدد النطاق الآن", + "tokens.secret.legacyTitle": "احفظ مفتاح API القديم الآن", + "tokens.secret.scopedDescription": "يخزّن lightNVR بصمة هذا الرمز فقط. في حال فقدانه، ألغِ الرمز وأنشئ رمزًا آخر.", + "tokens.secret.legacyDescription": "يُعرض مفتاح التوافق هذا هنا مرة واحدة فقط. إنشاء مفتاح آخر سيُبطله.", + "tokens.secret.value": "بيانات اعتماد API", + "tokens.secret.copied": "تم النسخ", + "tokens.secret.copySuccess": "تم نسخ بيانات اعتماد API", + "tokens.secret.copyError": "تعذّر النسخ تلقائيًا؛ حدد بيانات الاعتماد وانسخها يدويًا.", + "tokens.secret.savedConfirm": "لقد حفظت بيانات الاعتماد بأمان", + "tokens.secret.savedHelp": "التأكيد يُغلق هذه النافذة. لا يمكن عرض القيمة الكاملة مرة أخرى.", + "tokens.legacy.title": "مفتاح التوافق القديم", + "tokens.legacy.description": "يتمتع المفتاح القديم بوصول كامل فعلي لهذا المستخدم، ولا ينتهي صلاحيته، ولا يمكن تحديده حسب الكاميرا أو الإجراء.", + "tokens.legacy.warning": "أنشئه فقط لتكامل قائم لم تهاجر نقاط نهايته إلى تطبيق الرموز المحددة النطاق. إنشاؤه يُبطل فورًا المفتاح القديم السابق.", + "tokens.legacy.generate": "إنشاء مفتاح قديم", + "tokens.legacy.confirm": "إنشاء مفتاح قديم جديد؟ هذا يُبطل فورًا المفتاح القديم الحالي للمستخدم.", + "tokens.legacy.createdSuccess": "تم إنشاء مفتاح API القديم", + "tokens.legacy.createError": "تعذّر إنشاء مفتاح API القديم: {message}", + "audit.manage": "سجل التدقيق", + "audit.title": "تدقيق الأمان والوصول", + "audit.description": "تتبّع نتائج تسجيل الدخول وقرارات الوصول وتغييرات السياسات الحساسة دون كشف بيانات الاعتماد.", + "audit.retention": "مدة الاحتفاظ", + "audit.retentionDescription": "يتم حاليًا الاحتفاظ بالأحداث لمدة {days} يومًا. تقليل هذه القيمة يحذف السجل الأقدم فورًا.", + "audit.retentionDays": "أيام", + "audit.retentionInvalid": "اختر مدة احتفاظ بين 1 و 3650 يومًا.", + "audit.retentionSaved": "تم حفظ مدة الاحتفاظ؛ تم حذف {count} حدثًا منتهي الصلاحية", + "audit.retentionError": "تعذّر حفظ مدة الاحتفاظ: {message}", + "audit.filters": "عوامل التصفية", + "audit.clearFilters": "مسح عوامل التصفية", + "audit.applyFilters": "تطبيق عوامل التصفية", + "audit.actor": "الفاعل", + "audit.unauthenticated": "غير مُصادَق", + "audit.outcome": "النتيجة", + "audit.action": "الإجراء الدقيق", + "audit.filterToAction": "تصفية حسب هذا الإجراء", + "audit.since": "من", + "audit.until": "إلى", + "audit.invalidDateRange": "يجب أن يكون تاريخ البداية أسبق من تاريخ النهاية.", + "audit.source": "عنوان المصدر", + "audit.target": "الهدف", + "audit.targetUuid": "معرّف UUID للهدف", + "audit.noTarget": "على مستوى النظام", + "audit.requestId": "معرّف الطلب", + "audit.apiToken": "معرّف الرمز المميز المحدد النطاق", + "audit.showDetails": "إظهار التفاصيل", + "audit.hideDetails": "إخفاء التفاصيل", + "audit.pageSize": "لكل صفحة", + "audit.resultRange": "عرض {start}–{end} من {total}", + "audit.empty": "لا توجد أحداث تدقيق مطابقة", + "audit.emptyDescription": "جرّب مسح أحد عوامل التصفية أو أكثر، أو انتظر نشاطًا أمنيًا جديدًا.", + "audit.exportPage": "تصدير هذه الصفحة", + "audit.exporting": "جارٍ التصدير…", + "audit.exported": "تم تصدير صفحة التدقيق", + "audit.exportError": "تعذّر تصدير أحداث التدقيق: {message}", + "audit.pagination": "صفحات سجل التدقيق", + "audit.page": "صفحة {page}", + "audit.modesTitle": "قرارات السماح", + "audit.modesDescription": "اختر كيفية تسجيل الوصول المسموح به للقراءة فقط لكل إجراء. تُسجَّل الطلبات التي تُحدث تغييرًا، والرفض، والأخطاء، وتسجيل الدخول دائمًا. يحتفظ خيار التلخيص بمدخل واحد لكل مستخدم وكاميرا وعميل كل {minutes} دقيقة مع عدّاد.", + "audit.mode.record": "تسجيل كل", + "audit.mode.summarize": "تلخيص", + "audit.mode.off": "إيقاف", + "audit.modeOffWarning": "لن يظهر الوصول المسموح به لهذا الإجراء في سجل التدقيق بعد الآن.", + "audit.modesSaved": "تم حفظ أوضاع قرارات التدقيق", + "audit.modesError": "تعذّر حفظ أوضاع قرارات التدقيق: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "نوع الحدث", + "audit.eventTypeSummary": "ملخصات", + "audit.eventTypeDecision": "قرارات فردية", + "access.cameraSearch": "البحث عن كاميرات", + "access.cameraSearchPlaceholder": "اكتب حرفين على الأقل للبحث…", + "access.cameraSearchHint": "ابحث باسم الكاميرا أو UUID أو العنوان أو الموقع أو الوسم أو الشركة المصنّعة أو الطراز.", + "access.cameraSelected": "محدد", + "access.cameraAdd": "إضافة", + "access.cameraLimit": "يمكن أن يحتوي المحدّد على 64 كاميرا محددة كحد أقصى. استخدم قاعدة موقع أو وسم للنطاقات الأكبر.", + "access.roles.manage": "إدارة الأدوار", + "access.roles.title": "أدوار التفويض", + "access.roles.description": "اجمع الإجراءات في أدوار قابلة لإعادة الاستخدام، ثم امنح تلك الأدوار على نطاقات الكاميرات.", + "access.roles.create": "إنشاء دور", + "access.roles.newRole": "دور جديد", + "access.roles.copyName": "نسخة {name}", + "access.roles.clone": "استنساخ", + "access.roles.builtin": "مدمج", + "access.roles.builtinHelp": "الأدوار المدمجة هي قوالب ثابتة آمنة أثناء الترقية. استنسخ أحدها لتخصيصه.", + "access.roles.actionCount": "{count} إجراءات", + "access.roles.destructive": "إجراء حساس", + "access.roles.notEnforced": "لم يتم تطبيقه بعد من قبل أي نقطة نهاية", + "access.roles.destructiveWarning": "يمكن لهذا الدور تغيير الإعدادات أو الأدلة. امنحه فقط في النطاقات التي تتطلب هذه الصلاحية.", + "access.roles.created": "تم إنشاء الدور", + "access.roles.updated": "تم تحديث الدور", + "access.roles.deleted": "تم حذف الدور", + "access.roles.saveError": "تعذّر حفظ الدور: {message}", + "access.roles.deleteError": "تعذّر حذف الدور: {message}", + "access.roles.deleteConfirm": "حذف الدور \"{name}\"؟ لا يمكن حذف الأدوار المرتبطة بمنح.", + "access.policy.manage": "إدارة الوصول", + "access.policy.column": "الوصول", + "access.policy.scopedShort": "مُقيَّد بنطاق", + "access.policy.title": "سياسة الوصول — {username}", + "access.policy.description": "إدارة منح الأدوار بالرفض الافتراضي ومعاينة نطاقات الكاميرات الخاصة بها.", + "access.policy.tab.grants": "المنح", + "access.policy.tab.test": "اختبار الوصول", + "access.policy.scopedWarning": "ستعمل فقط الإجراءات المسموح بها من خلال منح مطابق ونطاق كاميرا.", + "access.policy.grants": "منح الأدوار", + "access.policy.grantsDescription": "يجمع المنح بين دور واحد وأسطول الكاميرات بالكامل، أو مجموعة مشتركة، أو مُحدِّد كاميرات مخصص.", + "access.policy.addGrant": "إضافة منح", + "access.policy.noGrants": "لا توجد منح مُهيّأة", + "access.policy.noGrantsHelp": "أضف منحًا واحدًا على الأقل قبل تفعيل السياسة المُقيَّدة بنطاق، ما لم يكن هذا المستخدم يجب أن لا يملك أي وصول.", + "access.policy.role": "الدور", + "access.policy.chooseRole": "اختر دورًا", + "access.policy.scope": "نطاق الكاميرا", + "access.policy.allCameras": "أسطول الكاميرات بالكامل", + "access.policy.collectionScope": "مجموعة مشتركة", + "access.policy.collection": "مجموعة الكاميرات", + "access.policy.chooseCollection": "اختر مجموعة مشتركة", + "access.policy.collectionHelp": "يتتبّع الوصول المجموعة عند إضافة الكاميرات أو إزالتها أو مطابقتها بقواعدها.", + "access.policy.dynamicScope": "مُحدِّد ديناميكي", + "access.policy.activateConfirm": "تفعيل سياسة الرفض الافتراضي المُقيَّدة بنطاق لـ {username}؟ سيتم رفض الإجراءات التي لا يوجد لها منح مطابق.", + "access.policy.emptyConfirm": "تفعيل السياسة المُقيَّدة بنطاق لـ {username} بدون منح؟ هذا يزيل عمدًا جميع الوصولات التي تتحكم بها السياسة.", + "access.policy.saved": "تم حفظ سياسة الوصول", + "access.policy.saveError": "تعذّر حفظ سياسة الوصول: {message}", + "access.policy.version": "إصدار السياسة {version}", + "access.policy.unsaved": "تغييرات غير محفوظة", + "access.policy.validation.invalid_mode": "اختر وضع تقييم صالح.", + "access.policy.validation.missing_role": "يجب أن يشير كل منح إلى دور متاح.", + "access.policy.validation.invalid_scope": "يجب أن يستخدم كل منح نطاق الأسطول الكامل أو المجموعة المشتركة أو المحدّد.", + "access.policy.validation.invalid_selector": "أكمل أو صحّح كل محدّد كاميرا قبل الحفظ.", + "access.policy.validation.missing_collection": "اختر مجموعة مشتركة متاحة لكل منح مجموعة.", + "access.policy.validation.duplicate_grant": "أزل منح الأدوار والنطاقات المكرّرة قبل الحفظ.", + "access.test.title": "اختبار الوصول الفعلي", + "access.test.description": "قيّم إجراءً محفوظًا وكاميرا باسم {username} دون تنفيذه.", + "access.test.saveFirst": "احفظ أو تجاهل تغييرات المنح قبل الاختبار ليعكس النتيجة السياسة المعروضة هنا.", + "access.test.action": "الإجراء", + "access.test.camera": "الكاميرا", + "access.test.run": "اختبار الوصول", + "access.test.running": "جارٍ الاختبار…", + "access.test.allowed": "مسموح", + "access.test.denied": "مرفوض", + "access.test.version": "الإصدار {version}", + "access.test.source": "المصدر: {source} · الدور: {role}", + "recordings.pullToRefresh": "اسحب لتحديث التسجيلات", + "recordings.releaseToRefresh": "أفلت لتحديث التسجيلات", + "recordings.refreshing": "جارٍ تحديث التسجيلات…", + "recordings.refreshed": "تم تحديث التسجيلات", + "recordings.refreshFailed": "تعذّر تحديث التسجيلات: {message}", + "recordings.download": "تنزيل", + "recordings.tags": "الوسوم", + "recordings.selectRecording": "تحديد تسجيل", + "timeline.legend.recording": "تسجيل", + "timeline.legend.detection": "حدث كشف", + "timeline.detectionEvent": "حدث كشف", + "streams.showCredentials": "إظهار بيانات الاعتماد", + "streams.hideCredentials": "إخفاء بيانات الاعتماد", + "streams.streamSuccessfullyEnabled": "تم تفعيل البث بنجاح.", + "streams.errorEnablingStream": "خطأ في تفعيل البث: {message}", + "system.health.tab": "الحالة", + "system.health.operatorView": "الحالة التشغيلية", + "system.health.title": "حالة النظام", + "system.health.loading": "جارٍ تحميل حالة النظام…", + "system.health.loadError": "تعذّر تحميل حالة النظام.", + "system.health.refreshing": "جارٍ التحديث…", + "system.health.activeIncidentCount": "{count} حوادث نشطة", + "system.health.coverage": "التغطية", + "system.health.monitoringDisabled": "مراقبة الحالة معطّلة", + "system.health.lastRecordedValue": "آخر قيمة مسجّلة", + "system.health.monitoringDisabledHelp": "لا يتم حاليًا جمع بيانات الحالة. فعّل مراقبة الحالة في الإعدادات → الحالة؛ أعد التشغيل إذا طُلب منك ذلك بعد الحفظ. يعرض سجل الحوادث الأحداث السابقة وليس الاستخدام الحالي للموارد.", + "system.health.monitoringRestartRequired": "مراقبة الحالة مفعّلة في الإعدادات المحفوظة، لكن العيّان النشط لا يزال معطّلًا. أعد تشغيل LightNVR لتطبيق التغيير. يعرض سجل الحوادث الأحداث السابقة.", + "system.health.containerCoverage": "تغطية محدودة للمضيف", + "system.health.hostHardwareUnavailable": "يمكن لهذا التثبيت رؤية حالة الحاويات والموارد المربوطة، لكن أجهزة المضيف غير متاحة. القيم المفقودة للمضيف غير معروفة وليست سليمة.", + "system.health.coverageUnknown": "لا توجد لقطة حالة مكتملة متاحة بعد. تبقى القيم غير معروفة حتى يكتمل الجمع.", + "system.health.coverageComplete": "تم جمع جميع البيانات المرئية لهذا التثبيت بنجاح.", + "system.health.coveragePartial": "التغطية جزئية. {count} من الملاحظات أو فحوصات الجمع غير متاحة أو قديمة أو غير مكتملة.", + "system.health.effectiveScope": "النطاق الفعلي", + "system.health.activeIncidents": "الحوادث النشطة", + "system.health.noActiveIncidents": "لا توجد حوادث نشطة مُبلَّغ عنها للتغطية المرئية.", + "system.health.duration": "المدة", + "system.health.currentValue": "القيمة الحالية", + "system.health.thresholds": "الحد ومدة البقاء", + "system.health.thresholdSummary": "تحذير {warning}، حرج {critical}، استعادة {recovery} {unit}؛ مدة بقاء التحذير {seconds} ثانية", + "system.health.remediation": "الاستجابة المقترحة", + "system.health.facts": "بيانات الحالة", + "system.health.group.resources": "الموارد", + "system.health.group.storage": "التخزين", + "system.health.group.hardware": "الأجهزة", + "system.health.group.network": "الشبكة", + "system.health.group.clock": "الساعة", + "system.health.group.components": "المكوّنات", + "system.health.noFacts": "لا توجد بيانات مرئية في هذه المجموعة.", + "system.health.observationState": "الإمكانية وحداثة البيانات", + "system.health.valueUnavailable": "قيمة واحدة أو أكثر غير معروفة", + "system.health.componentStatus": "مكوّنات المراقبة", + "system.health.collectors": "جامعات البيانات", + "system.health.collectorSummary": "{total} مسجّل · {attention} تحتاج إلى انتباه", + "system.health.collectorsNeedingAttention": "جامعات بيانات تحتاج إلى انتباه", + "system.health.collectionFailures": "{count} إخفاق أو انتهاء مهلة", + "system.health.stale": "قديمة", + "system.health.eventDelivery": "تسليم الأحداث", + "system.health.degraded": "متدهور", + "system.health.circularDelivery": "هذا هو مسار التنبيه الوحيد المُهيّأ، لذا لا يمكنه الإبلاغ عن فشله بشكل مستقل.", + "system.health.incidentPersistence": "حفظ الحوادث", + "system.health.persistenceSummary": "{pending} قيد الانتظار · {failures} إخفاق · {retries} إعادة محاولة", + "system.health.recentSamples": "نشاط الجمع الأخير", + "system.health.recentSamplesHelp": "حتى {count} ملخصات توليد محدودة من جانب الخادم؛ هذا نشاط تغطية وليس مخطط قيم.", + "system.health.sampleSequence": "التوليد {sequence}", + "system.health.sampleCoverage": "{observations} ملاحظة · {dropped} مُسقط", + "system.health.noSamples": "لا توجد عمليات توليد جمع مكتملة متاحة.", + "system.health.incidentHistory": "سجل الحوادث", + "system.health.incidentHistoryHelp": "الأحدث أولاً. يتم تحميل السجل في صفحات محدودة.", + "system.health.loadingHistory": "جارٍ تحميل سجل الحوادث…", + "system.health.historyError": "تعذّر تحميل سجل الحوادث.", + "system.health.emptyHistory": "لم يتم تسجيل أي حوادث.", + "system.health.firstSeen": "أول ظهور", + "system.health.lastSeen": "آخر ظهور", + "system.health.deliveryState": "حالة التسليم", + "system.health.historyPagination": "صفحات سجل الحوادث", + "system.health.pageCount": "{count} حدث على هذه الصفحة", + "system.health.remediation.memory": "قلّل ضغط الذاكرة، وتحقق من حدود العمليات و cgroup، وراجع نشاط OOM الأخير.", + "system.health.remediation.cpu": "حدّد مستهلكي المعالج المستمرين وتحقق من إنتاجية الخدمة قبل تغيير الحدود.", + "system.health.remediation.io": "تحقق من زمن استجابة التخزين والكتّاب النشطين؛ واحفظ التسجيلات قبل الصيانة المعطِّلة.", + "system.health.remediation.filesystem": "تحقق من نظام الملفات المنطقي المحدد، والمساحة أو المؤشرات الحرة، وتأكد من بقائه قابلاً للكتابة.", + "system.health.remediation.thermal": "حسّن التبريد وقلّل الحمل؛ افحص المراوح والفتحات قبل وصول درجات الحرارة إلى حدود الإيقاف.", + "system.health.remediation.network": "تحقق من الواجهة المرئية، والرابط، والمُبدِّل، وعدّادات الأخطاء من مسار شبكة مستقل.", + "system.health.remediation.clock": "استعد مزامنة الوقت وتحقق من مصدر ساعة المضيف قبل الاعتماد على طوابع زمنية للأحداث.", + "system.health.remediation.process": "افحص حدود موارد LightNVR والسجلات، ثم قلّل الحمل أو ارفع الحدود المعتمدة.", + "system.health.remediation.storage": "انسخ لقطات مهمة احتياطياً وافحص جهاز التخزين المرتبط قبل الاستبدال أو الإصلاح.", + "system.health.remediation.hardware": "افحص الأجهزة المتأثرة وسجلات المنصة؛ وحدّد موعد صيانة إذا استمرت الحالة.", + "system.health.remediation.health": "استعد وصول جامع البيانات والصلاحيات لتقييم أدلة الصحة المفقودة.", + "system.health.remediation.system": "راجع التشغيل السابق وسجلات المضيف للتمييز بين إعادة تشغيل العملية وإعادة تشغيل المضيف.", + "system.health.remediation.event": "استخدم واجهة API المحلية أو عرض المقاييس، وأزل ضغط قائمة الانتظار الدائمة، واستعد وجهة تنبيه مستقلة.", + "system.health.remediation.default": "راجع المكوّن المتأثر والسجلات الأخيرة، ثم تحقق من التعافي في جيل صحة جديد.", + "system.capacityTarget": "هدف السعة", + "system.capacityTargetValue": "إبقاء {pct}% فارغ", + "system.fillRate": "معدل الامتلاء", + "system.fillRateValue": "{value} / يوم", + "system.projectedToTarget": "الوقت المتوقع للوصول إلى الهدف", + "system.projectedNow": "بلغ الهدف أو تجاوزه الآن", + "system.projectedDays": "~{count} يوم", + "system.projectedHours": "~{count} ساعة", + "system.projectedUnknown": "—", + "common.description": "الوصف", + "common.remove": "إزالة", + "streams.selectStream": "اختر {name}", + "streams.search": "ابحث عن تدفقات", + "streams.searchPlaceholder": "ابحث عن كاميرات أو مواقع أو وسوم", + "streams.noStreamsMatchFilters": "لا توجد تدفقات تطابق المرشحات الحالية.", + "streamHealth.sourceConnected": "المصدر متصل", + "streamHealth.videoAdvancing": "الفيديو يتقدم", + "streamHealth.recorderWriting": "كتابة المسجّل", + "streamHealth.detectorOperating": "الكاشف يعمل", + "streamHealth.lastSegment": "آخر مقطع مكتمل", + "streams.disablingStreamsProgress": "جارٍ تعطيل البثوث…", + "streams.onvifInvalidAddress": "عنوان IP لجهاز ONVIF مفقود أو غير صالح.", + "streams.warningFallingBackToHttp": "فشل اتصال HTTPS؛ إعادة المحاولة عبر HTTP. قد تُرسل بيانات الاعتماد بنص عادي.", + "streamsConfig.playbackTransport": "نقل التشغيل", + "streamsConfig.playbackTransportHelp": "اختر طريقة التشغيل في المتصفح لهذه الكاميرا، وترتيب التراجع عند اختيارها.", + "streamsConfig.playbackTransportUnavailable": "غير متاح على الخادم: {transports}. فعّل النقل عالميًا أو اختر ملفًا شخصيًا آخر.", + "streamsConfig.audioDisabledByPolicy": "الصوت معطّل بموجب سياسة النسخة", + "streamsConfig.audioDisabledByPolicyHelp": "التسجيل والاستماع المباشر والتحدث ثنائي الاتجاه غير متاحة أثناء تفعيل سياسة الامتثال الصوتي العامة.", + "streamsConfig.audioVoiceEnhancement": "تحسين الصوت (التسجيلات)", + "streamsConfig.customApiModel": "كشف API مخصص", + "streamsConfig.modelNotSupportedByBuild": "غير مدعوم في هذا الإصدار", + "streamsConfig.tierCriticalMultiplier": "مضاعف المستوى الحرج ×", + "streamsConfig.tierImportantMultiplier": "مضاعف المستوى المهم ×", + "streamsConfig.tierEphemeralMultiplier": "مضاعف المستوى المؤقت ×", + "streamsConfig.tierMultipliersHelp": "مضاعفات لكل مستوى على مدة الاحتفاظ الأساسية. تُحتفظ لقطات المستويات الأعلى لفترة أطول وتُحذف أخيرًا عند ضغط القرص.", + "streamsConfig.storagePriority": "أولوية التخزين (1-10)", + "streamsConfig.storagePriorityHelp": "الأهمية النسبية لقطات هذا البث عند استعادة المساحة؛ الأولوية الأعلى تُحفظ لفترة أطول.", + "streamsConfig.restream": "إعادة البث / النشر (RTMP)", + "streamsConfig.publishUrl": "رابط النشر (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "أعد بث هذه الكاميرا إلى خدمة مثل YouTube Live عبر go2rtc. الصق رابط الاستقبال الكامل لـ RTMP متضمنًا مفتاح البث (مثال: rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). لإعادة البث إلى عدة خدمات دفعة واحدة، افصل بين الروابط بفواصل. يتطلب YouTube فيديو H264 وصوت AAC؛ يقوم LightNVR الآن بالتحويل التلقائي (H264 للكاميرات غير H264، وAAC للصوت غير AAC) فتعمل معظم الكاميرات مباشرةً. ملاحظة: يتطلب YouTube أيضًا مسار صوتي — الكاميرا التي لا تملك صوتًا على الإطلاق ستظل مرفوضة. اتركه فارغًا للتعطيل.", + "streams.lastSeen": "آخر ظهور {time}", + "streams.claimed": "مُطالَب به", + "streams.duplicateSuspected": "تكرار محتمل", + "streams.duplicateSuspectedHelp": "تتعارض الهوية المستقرة أو أدلة نقطة النهاية مع سجل اكتشاف آخر.", + "streams.onvifClaimWarning": "تمت إضافة البث، لكن تعذّر وضع علامة مطالَبة على سجل اكتشافه: {message}", + "common.online": "متصل", + "common.offline": "غير متصل", + "settings.storageTargets.title": "أهداف تخزين التسجيلات", + "settings.storageTargets.description": "سجّل الأقراص المحلية وأنظمة ملفات NFS أو SMB التي يثبّتها المدير كوجهات تسجيل مستقلة المراقبة.", + "settings.storageTargets.foundationNotice": "يستخدم الالتقاط أهداف نظام الملفات. يمكن لأدلاء S3 وأهداف NFS/SAN المُثبَّتة احتفاظ بنسخ أرشيفية مُتحقَّق منها. يحافظ الضغط الساخن على التسجيلات المؤرشفة حتى انتهاء مدة الاحتفاظ المنطقية.", + "settings.storageTargets.add": "إضافة هدف تخزين", + "settings.storageTargets.edit": "تعديل هدف التخزين", + "settings.storageTargets.editorHelp": "يجب أن تكون الأهداف المُفعَّلة موجودة مسبقًا وأن تجتاز اختبارات الكتابة وfsync والتنظيف. احفظ نقطة تثبيت مستقبلية غير متاحة كغير مُفعَّلة، ثم فعّلها بعد التثبيت.", + "settings.storageTargets.name": "اسم الهدف", + "settings.storageTargets.root": "مسار الجذر المُثبَّت", + "settings.storageTargets.rootLocked": "يحتفظ الهدف الافتراضي أو غير الفارغ بجذر غير قابل للتغيير حتى لا تُصبح اللقطات الحالية يتيمة.", + "settings.storageTargets.class": "فئة الأداء", + "settings.storageTargets.hot": "ساخن — تسجيل نشط", + "settings.storageTargets.warm": "دافئ — أرشيف مُثبَّت", + "settings.storageTargets.cold": "بارد — وصول غير متكرر", + "settings.storageTargets.reserveGb": "هامش محجوز (GB)", + "settings.storageTargets.lowWatermark": "علامة مائية منخفضة (% مستخدم)", + "settings.storageTargets.highWatermark": "علامة مائية عالية (% مستخدم)", + "settings.storageTargets.migrationBandwidth": "نطاق ترددي لدورة الحياة (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 يعني غير محدود. يُلتقط الحد عند إنشاء مهمة نقل أو نسخ.", + "settings.storageTargets.archiveStart": "بداية نافذة الأرشفة", + "settings.storageTargets.archiveEnd": "نهاية نافذة الأرشفة", + "settings.storageTargets.archiveWindowHelp": "التوقيت المحلي. تساوي وقت البداية والنهاية يسمح بمهام دورة الحياة طوال اليوم؛ قد تمتد نافذة الليل عبر منتصف الليل.", + "settings.storageTargets.enabled": "مُفعَّل (قد تختار سياسات التوزيع هذا الهدف)", + "settings.storageTargets.notRouted": "لا توجد سياسة توزيع مُفعَّلة تُوجِّه الكاميرات إلى هنا. تستمر التسجيلات الجديدة في الذهاب إلى الهدف الافتراضي حتى تُسمّي سياسة هذا الهدف كهدف أساسي أو عضو مجموعة أو هدف أرشفة.", + "settings.storageTargets.degradedNotice": "فوق العلامة المائية العالية أو داخل الهامش المحجوز. تتخطى سياسات التوزيع هذا الهدف حتى يتم تحرير المساحة.", + "settings.storageTargets.probePassedIneligible": "اجتاز اختبار الكتابة، لكن الهدف {status}: لن تختاره سياسات التوزيع.", + "settings.storageTargets.mountRequired": "يتطلب نظام ملفات مُثبَّتًا", + "settings.storageTargets.mountRequiredHelp": "اربط هذا الهدف بنقطة التثبيت الحالية غير الجذرية. إذا اختفى تثبيت NFS أو SMB أو bind أو PVC، يتوقف التسجيل بدلاً من الكتابة في مجلد المضيف الأساسي.", + "settings.storageTargets.mountGuard": "تثبيت مطلوب", + "settings.storageTargets.mountPending": "سيتم اكتشافه عند تفعيل الهدف", + "settings.storageTargets.default": "افتراضي", + "settings.storageTargets.capacity": "السعة", + "settings.storageTargets.available": "متاح", + "settings.storageTargets.recordings": "تسجيلات مفهرسة", + "settings.storageTargets.replicas": "{count} نسخ مُتحقَّق منها · {bytes}", + "settings.storageTargets.reserve": "محجوز", + "settings.storageTargets.pressure.normal": "الضغط طبيعي", + "settings.storageTargets.pressure.high": "حد الضغط المرتفع", + "settings.storageTargets.pressure.reserve": "تجاوز الحجز", + "settings.storageTargets.pressure.unavailable": "الضغط غير متاح", + "settings.storageTargets.cleanupActive": "تنظيف النطاق نشط ويعمل على توفير {target} متاح دون حذف التسجيلات المخصصة لهدف آخر.", + "settings.storageTargets.test": "اختبار الهدف", + "settings.storageTargets.probing": "جارٍ الاختبار…", + "settings.storageTargets.probePassed": "نجح اختبار الكتابة على هدف التخزين", + "settings.storageTargets.duplicateFilesystem": "هذا الجذر يشارك نفس نظام الملفات الأساسي مع هدف آخر. يجب عدم احتساب السعة مرتين عند تفعيل التوزيع.", + "settings.storageTargets.deleteLocked": "لا يمكن حذف الأهداف الافتراضية أو غير الفارغة.", + "settings.storageTargets.deleteConfirm": "حذف هدف التخزين الفارغ «{name}»؟ لن تتم إزالة أي ملفات.", + "settings.storageTargets.created": "تم إنشاء هدف التخزين", + "settings.storageTargets.updated": "تم تحديث هدف التخزين", + "settings.storageTargets.deleted": "تم حذف هدف التخزين", + "settings.storageTargets.invalidThresholds": "تحقق من حدود الضغط والحجز وعرض النطاق الزمني للدورة الحياتية وأوقات نافذة الأرشفة.", + "settings.storageTargets.loadError": "تعذّر تحميل أهداف التخزين", + "settings.storagePools.title": "مجمعات التخزين", + "settings.storagePools.description": "تجميع الأهداف السليمة للتحويل التلقائي والنسخ على أهداف مختلفة.", + "settings.storagePools.add": "إضافة مجمع", + "settings.storagePools.strategy": "استراتيجية التخصيص", + "settings.storagePools.mostFree": "أكثر مساحة متاحة", + "settings.storagePools.roundRobin": "التناوب الدوري", + "settings.storagePools.priority": "أولوية صريحة", + "settings.storagePools.members": "الأهداف (ترتيب العرض هو أولوية التخصيص)", + "settings.storagePools.enabled": "المجمع مفعّل", + "settings.storagePools.active": "نشط", + "settings.storagePools.inactive": "معطّل", + "settings.storagePools.strategyValue.most_free": "أكثر مساحة متاحة", + "settings.storagePools.strategyValue.round_robin": "التناوب الدوري", + "settings.storagePools.strategyValue.priority": "ترتيب الأولوية", + "settings.storagePools.created": "تم إنشاء مجمع التخزين", + "settings.storagePools.updated": "تم تحديث مجموعة التخزين", + "settings.storagePools.deleted": "تم حذف مجموعة التخزين", + "settings.storagePools.deleteConfirm": "حذف مجموعة التخزين \"{name}\"؟", + "settings.storagePools.empty": "لا توجد مجموعات تخزين بعد.", + "settings.storageMigrations.title": "مهام ترحيل التسجيلات", + "settings.storageMigrations.description": "تنقل النسخ المحفوظة والنسخ الاحتياطية ضمن نافذة الأرشفة وحد النطاق الترددي لكل هدف، مع التحقق من SHA-256 والاسترداد الآمن بعد إعادة التشغيل.", + "settings.storageMigrations.empty": "لا توجد مهام ترحيل تسجيلات بعد.", + "settings.storageMigrations.loadError": "تعذّر تحميل مهام ترحيل التسجيلات", + "settings.storageMigrations.recording": "تسجيل #{id}", + "settings.storageMigrations.attempt": "المحاولة {current}/{max}", + "settings.storageMigrations.operation.move": "نقل", + "settings.storageMigrations.operation.copy": "نسخة محفوظة", + "settings.storageMigrations.cancelled": "تم قبول إلغاء الترحيل", + "settings.storageMigrations.cancelling": "جارٍ الإلغاء…", + "settings.storageMigrations.retried": "تمت إضافة الترحيل إلى قائمة إعادة المحاولة", + "settings.storageMigrations.state.queued": "في الانتظار", + "settings.storageMigrations.state.copying": "جارٍ النسخ", + "settings.storageMigrations.state.verifying": "جارٍ التحقق", + "settings.storageMigrations.state.committing": "جارٍ الإثبات", + "settings.storageMigrations.state.cleanup_pending": "جارٍ تنظيف المصدر", + "settings.storageMigrations.state.retry_wait": "بانتظار إعادة المحاولة", + "settings.storageMigrations.state.completed": "مكتمل", + "settings.storageMigrations.state.failed": "فشل", + "settings.storageMigrations.state.cancelled": "ملغى", + "settings.storagePolicies.title": "سياسات توزيع الكاميرات", + "settings.storagePolicies.description": "توجيه الكاميرات المطابقة إلى هدف التسجيل الأساسي حسب الأولوية. تستخدم الكاميرا أول سياسة مفعّلة مطابقة.", + "settings.storagePolicies.add": "إضافة سياسة توزيع", + "settings.storagePolicies.edit": "تعديل سياسة توزيع", + "settings.storagePolicies.editorHelp": "يُعاد تقييم السياسة للمقاطع الجديدة. لا تنقل التغييرات التسجيلات الموجودة مسبقًا.", + "settings.storagePolicies.priority": "الأولوية (الأعلى أولًا)", + "settings.storagePolicies.priorityValue": "الأولوية {priority}", + "settings.storagePolicies.primary": "الهدف الأساسي", + "settings.storagePolicies.updated": "تم تحديث سياسة التوزيع", + "settings.storagePolicies.deleted": "تم حذف سياسة التوزيع", + "settings.storagePolicies.deleteConfirm": "حذف سياسة التوزيع “{name}”؟ لن تتأثر التسجيلات الحالية.", + "settings.storagePolicies.active": "نشط", + "settings.storagePolicies.inactive": "معطّل", + "settings.storagePolicies.routesTo": "الهدف الأساسي: {target}", + "settings.storagePolicies.lifecycleSummary": "مدة الاحتفاظ الدنيا/المطلوبة/القصوى: {minimum}/{desired}/{maximum} يوم · {copies} نسخة موثّقة", + "settings.storagePolicies.fallsBackTo": "هدف الاحتياط: {target}", + "settings.storagePolicies.mode.default": "الاحتياط: الهدف الافتراضي", + "settings.storagePolicies.mode.pause": "الاحتياط: إيقاف التسجيل مؤقتًا", + "settings.storagePolicies.mode.fail": "الاحتياط: فشل بدء التسجيل", + "settings.storagePolicies.empty": "لا توجد سياسات توزيع. تستمر الكاميرات في استخدام الهدف الافتراضي؛ لا تستقبل الأهداف الأخرى أي شيء حتى تُوجّه سياسة الكاميرات إليها.", + "settings.storagePolicies.archiveNoTrigger": "تم تعيين هدف أرشفة لكن لا يوجد ما يُحفّز النقل. عيّن 'النقل بعد عمر (أيام)' أو عمر الأرشفة أو خيار الأرشفة؛ وإلا لن يتم نقل أي تسجيلات.", + "settings.storageCompliance.title": "الامتثال للسعة والسياسات", + "settings.storageCompliance.description": "تتنبأ المعدلات المرصودة على مدى 30 يومًا بضغط الهدف ومدة الاحتفاظ المحققة؛ تبقى انتهاكات دورة الحياة النشطة مرئية حتى يتم حلها.", + "settings.storageCompliance.loadError": "تعذّر تحميل امتثال التخزين", + "settings.storageCompliance.unknown": "غير معروف", + "settings.storageCompliance.days": "{days} يوم", + "settings.storageCompliance.day": "يوم", + "settings.storageCompliance.targetForecasts": "توقعات الأهداف", + "settings.storageCompliance.target": "الهدف", + "settings.storageCompliance.dailyRate": "المعدل المرصود", + "settings.storageCompliance.toHigh": "حتى العلامة العليا", + "settings.storageCompliance.expected": "مدة الاحتفاظ المتوقعة", + "settings.storageCompliance.confidence": "الثقة", + "settings.storageCompliance.policyCompliance": "الامتثال للسياسات", + "settings.storageCompliance.compliant": "لا توجد انتهاكات نشطة", + "settings.storageCompliance.violationCount": "{count} انتهاك", + "settings.storageCompliance.policyForecast": "المحقق {achieved}؛ المتوقع {expected}؛ المطلوب {desired} يوم.", + "settings.storageCompliance.copyDeficits": "{count} تسجيل يحتاج نسخة موثّقة إضافية.", + "settings.storageCompliance.activeViolations": "الانتهاكات النشطة", + "settings.storageCompliance.type.copy_count": "عدد النسخ", + "settings.storageCompliance.type.minimum_retention": "الحد الأدنى لسعة الاحتفاظ", + "settings.storageCompliance.type.target_unavailable": "الوجهة غير متاحة", + "settings.storageCompliance.type.migration_failed": "فشل مهمة دورة الحياة", + "settings.recordingDirectoryFormat": "تخطيط مجلد التسجيلات", + "settings.recordingDirectoryFormatHelp": "يقسّم تسجيلات MP4 الجديدة داخل مجلد كل كاميرا. لا يتم نقل التسجيلات الحالية.", + "settings.recordingDirectoryFlat": "مسطّح (مجلد الكاميرا فقط)", + "settings.recordingDirectoryMonth": "حسب الشهر (YYYY/MM)", + "settings.recordingDirectoryDay": "حسب اليوم (YYYY/MM/DD)", + "settings.minFreePct": "الحد الأدنى للمساحة الحرة (%)", + "settings.minFreePctHelp": "احتفظ بهذه النسبة المئوية على الأقل من مساحة القرص فارغة عن طريق حذف أقدم التسجيلات تلقائيًا، بغض النظر عن أيام الاحتفاظ. هذا يحدّ الاستخدام بحجم القرص — حدّده ولن تمتلئ القرص أبدًا. القيمة 0 تعطّل حد السعة.", + "settings.pressureThresholds": "عتبات ضغط القرص (%)", + "settings.pressureThresholdsHelp": "نطاقات المساحة الحرة التي تُصعّد التنظيف التلقائي. يجب أن تكون: طارئ < حرج < تحذير.", + "settings.pressureWarningPct": "تحذير أقل من (% حرة)", + "settings.pressureCriticalPct": "حرج أقل من (% حرة)", + "settings.pressureEmergencyPct": "طارئ أقل من (% حرة)", + "settings.databaseBackupVerify": "التحقق من النسخة الاحتياطية", + "settings.databaseBackupVerifyFull": "كامل (integrity_check، يتحقق من كل فهرس)", + "settings.databaseBackupVerifyQuick": "سريع (quick_check، هيكل الصفحات فقط)", + "settings.databaseBackupVerifyOff": "إيقاف (لا فحص بعد النسخ)", + "settings.databaseBackupVerifyHelp": "فحص يُطبَّق على كل نسخة احتياطية منسوخة قبل نشرها. الفحص الكامل قد يستغرق وقتًا أطول من النسخ نفسه على قاعدة بيانات كبيرة على قرص ميكانيكي وقد يبلغ حد الأمان البالغ 30 دقيقة فيتم تجاهل تلك النسخة؛ الفحص السريع يكتشف الصفحات التالفة أو المقطوعة بعدد أقل بكثير من عمليات البحث.", + "settings.viewMethodAuto": "تلقائي — تفضيل لكل كاميرا مع بديل", + "settings.resetWizardPending": "جارٍ بدء المعالج…", + "settings.apiDetectionFormat": "تنسيق طلب API", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (رفع صورة متعددة الأجزاء)", + "settings.apiDetectionFormatDoods2": "DOODS2 (نص JSON مع صورة base64)", + "settings.apiDetectionFormatHelp": "تنسيق الإرسال الذي يستخدمه LightNVR عند إرسال لقطات إلى واجهة الكشف. احتفظ بـ light-object-detect لـ light-object-detect أو أي خادم يطبّق عقده؛ اختر DOODS2 لخادم DOODS2.", + "settings.apiDetectionUrlHelpDoods2": "نقطة نهاية /detect لـ DOODS2، مثل http://localhost:8080/detect. يُرسل الطلب بصيغة JSON ولا تُضاف أي معاملات استعلام.", + "settings.apiDetectionDetectorName": "اسم كاشف DOODS2", + "settings.apiDetectionDetectorNameHelp": "يُرسل كـ detector_name في كل طلب. يجب أن يطابق كاشفًا مُدرجًا في GET /detectors الخاص بالخادم؛ \"default\" يستخدم الكاشف الافتراضي للخادم.", + "settings.defaultPlaybackTransport": "نقل التشغيل الافتراضي", + "settings.defaultPlaybackTransportHelp": "ملف التشغيل المطبَّق على البثوط الجديدة. تحتفظ البثوط الحالية باختيارها.", + "playbackTransport.auto": "تلقائي (موصى به)", + "playbackTransport.webrtcOnly": "WebRTC فقط", + "playbackTransport.mseOnly": "MSE فقط", + "playbackTransport.hlsOnly": "HLS فقط", + "playbackTransport.webrtcThenMse": "WebRTC، ثم MSE", + "playbackTransport.mseThenHls": "MSE، ثم HLS", + "investigation.experimental": "مساحة عمل تجريبية", + "investigation.title": "التحقيق", + "investigation.description": "راجع عدة كاميرات على مؤشر UTC مشترك واحد دون إخفاء الفجوات في التسجيلات.", + "investigation.query": "نافذة التحقيق", + "investigation.queryHelp": "اختر حتى 16 كاميرا. بحد أقصى أربعة مشغلات فيديو نشطة في وقت واحد.", + "investigation.cameras": "كاميرات", + "investigation.cameraSelection": "اختيار الكاميرا", + "investigation.start": "البداية", + "investigation.end": "النهاية", + "investigation.load": "تحميل التحقيق", + "investigation.applyWindow": "تطبيق النافذة الزمنية", + "investigation.loading": "جارٍ تحميل التحقيق…", + "investigation.eventType": "نوع الحدث", + "investigation.anyEventType": "أي نوع من الأحداث", + "investigation.eventType.detection": "كشف", + "investigation.eventType.motion": "حركة", + "investigation.location": "الموقع", + "investigation.anyLocation": "أي موقع", + "investigation.objectLabel": "تسمية الكائن", + "investigation.anyLabel": "أي تسمية", + "investigation.zone": "المنطقة", + "investigation.anyZone": "أي منطقة", + "investigation.source": "مصدر الكشف", + "investigation.anySource": "أي مصدر", + "investigation.captureMethod": "طريقة الالتقاط", + "investigation.anyCaptureMethod": "أي طريقة التقاط", + "investigation.recordingTag": "وسم التسجيل", + "investigation.anyRecordingTag": "أي وسم تسجيل", + "investigation.protection": "الحماية", + "investigation.anyProtection": "أي حالة حماية", + "investigation.protected": "محمي", + "investigation.unprotected": "غير محمي", + "investigation.minimumConfidence": "الحد الأدنى للثقة", + "investigation.confidenceError": "يجب أن يكون الحد الأدنى للثقة بين 0 و 1.", + "investigation.metadataRegionSearch": "البحث في منطقة البيانات الوصفية", + "investigation.regionSearchHelp": "اختر كاميرا رئيسية تحتوي على لقطات، ثم ارسم منطقة فوق الفيديو.", + "investigation.regionActive": "جارٍ البحث في الصناديق المخزنة من {camera}. عدم ظهور نتيجة لا يعني أن شيئًا لم يعبر المنطقة.", + "investigation.regionMatch": "مطابقة الصناديق", + "investigation.regionMatch.center": "المركز داخل", + "investigation.regionMatch.intersects": "أي تقاطع", + "investigation.regionMatch.minimumIntersection": "الحد الأدنى للتداخل", + "investigation.regionMinimumOverlap": "الحد الأدنى للتداخل (%)", + "investigation.regionLeft": "اليسار (%)", + "investigation.regionTop": "الأعلى (%)", + "investigation.regionWidth": "العرض (%)", + "investigation.regionHeight": "الارتفاع (%)", + "investigation.drawRegion": "رسم منطقة البحث", + "investigation.drawingRegion": "جارٍ رسم منطقة البحث…", + "investigation.clearRegion": "مسح المنطقة", + "investigation.useFullFrame": "استخدام الإطار الكامل", + "investigation.drawRegionPrompt": "اسحب فوق الفيديو لتحديد منطقة البحث", + "investigation.applyFilters": "تطبيق المرشحات", + "investigation.searching": "جارٍ البحث في الأحداث…", + "investigation.searchResults": "نتائج الأحداث", + "investigation.searchHelp": "حمّل تحقيقًا للبحث في بيانات الأحداث الوصفية المحفوظة.", + "investigation.resultCount": "{count} حدث مطابق", + "investigation.results": "نتائج", + "investigation.resultHistogram": "المدرج التكراري للأحداث", + "investigation.histogramHelp": "حدد عمودًا لتحريك المؤشر المشترك.", + "investigation.previousResult": "الحدث السابق", + "investigation.nextResult": "الحدث التالي", + "investigation.previousResultShortcut": "الحدث السابق ([)", + "investigation.nextResultShortcut": "الحدث التالي (])", + "investigation.noResults": "لا توجد أحداث محفوظة تطابق الكاميرا والفترة الزمنية والتصفية المحددة.", + "investigation.noThumbnail": "لا توجد صورة مصغّرة", + "investigation.exploreThumbnails": "استكشاف الصور المصغّرة", + "investigation.exploreSelectedThumbnails": "استكشاف حول الحدث", + "investigation.thumbnailDrilldown": "التنقّل التفصيلي للصور المصغّرة", + "investigation.thumbnailDrilldownHelp": "اختر أي لحظة، بما في ذلك الفجوات، لتحريك المؤشر المشترك وإعادة توليد مجموعة أضيق من العينات.", + "investigation.selectThumbnailSample": "فحص حول {time}", + "investigation.loadingThumbnail": "جارٍ تحميل الصورة المصغّرة…", + "investigation.thumbnailUnavailable": "الصورة المصغّرة غير متاحة", + "investigation.loadingSamples": "جارٍ تحميل عينات الصور المصغّرة…", + "investigation.thumbnailCoverageTruncated": "تحتوي هذه الفترة على تسجيلات أكثر مما يستطيع العيّان فحصه. ضيّق النافذة الزمنية للحصول على تغطية كاملة.", + "investigation.bookmarks.save": "حفظ إشارة مرجعية", + "investigation.bookmarks.open": "الإشارات المرجعية", + "investigation.bookmarks.saveTitle": "حفظ إشارة مرجعية للتحقيق", + "investigation.bookmarks.listTitle": "إشارات التحقيق المرجعية", + "investigation.bookmarks.notHold": "تُعيد الإشارة المرجعية هذا العرض، لكنها لا تحمي التسجيلات من الحذف أو الاحتفاظ العادي.", + "investigation.bookmarks.title": "اسم الإشارة المرجعية", + "investigation.bookmarks.note": "ملاحظة خاصة (اختياري)", + "investigation.bookmarks.titleRequired": "أدخل اسم الإشارة المرجعية.", + "investigation.bookmarks.empty": "لا توجد إشارات مرجعية محفوظة للتحقيق.", + "investigation.bookmarks.cameraCount": "{count} كاميرا", + "investigation.bookmarks.restore": "فتح", + "investigation.bookmarks.confirmDelete": "حذف الإشارة المرجعية؟", + "investigation.actions.open": "حماية / تنزيل", + "investigation.actions.title": "تسجيلات التحقيق", + "investigation.actions.notEvidenceExport": "الحماية تمنع الحذف العادي حسب سياسة الاحتفاظ. تنزيل ZIP هو تصدير للتسهيل وليس حزمة أدلة موثّقة.", + "investigation.actions.scope": "نطاق التسجيل", + "investigation.actions.selectedResult": "الحدث والكاميرا المحددان", + "investigation.actions.fullWindow": "جميع الكاميرات في نافذة التحقيق", + "investigation.actions.preview": "معاينة التسجيلات", + "investigation.actions.previewing": "جارٍ البحث عن التسجيلات المتداخلة…", + "investigation.actions.invalidRange": "اختر نطاقًا زمنيًا صالحًا بحيث تكون النهاية بعد البداية.", + "investigation.actions.recordingCount": "{count} تسجيل متداخل", + "investigation.actions.protectedCount": "{count} محمي بالفعل", + "investigation.actions.noRecordings": "لا توجد تسجيلات مكتملة تتداخل مع هذا الاختيار للكاميرا والوقت.", + "investigation.actions.protectDenied": "{count} تسجيل غير محمي خارج نطاق الحماية الخاص بك وتم استبعاده من هذا الإجراء.", + "investigation.actions.exportDenied": "صلاحية التصدير غير متوفرة لـ {count} تسجيل. التنزيلات تكون كاملة أو لا شيء، لذا لا يمكن تصدير هذا الاختيار.", + "investigation.actions.camera": "الكاميرا", + "investigation.actions.recording": "التسجيل", + "investigation.actions.size": "الحجم", + "investigation.actions.notPermitted": "غير مسموح", + "investigation.actions.protectButton": "حماية {count}", + "investigation.actions.protecting": "جارٍ الحماية…", + "investigation.actions.protectUnavailable": "لا توجد تسجيلات غير محمية مسموح لك بحمايتها.", + "investigation.actions.protectResult": "اكتملت الحماية: {success} نجحت، {failed} فشلت.", + "investigation.actions.downloadButton": "تنزيل {count}", + "investigation.actions.downloadUnavailable": "كل تسجيل يتطلب صلاحية تصدير قبل إنشاء ملف ZIP.", + "investigation.actions.buildingArchive": "جارٍ إنشاء ملف ZIP…", + "investigation.actions.downloadFailed": "فشل إنشاء ملف ZIP على الخادم.", + "investigation.actions.downloadTimedOut": "لم يكتمل إنشاء ملف ZIP خلال خمس دقائق. جرّب فترة زمنية أضيق.", + "investigation.actions.downloadStarted": "بدأ تنزيل ملف ZIP.", + "investigation.backOneLevel": "رجوع مستوى واحد", + "investigation.thumbnailMinimumWindow": "هذه أضيق فترة زمنية متاحة مدتها ثانية واحدة. انتقل المؤشر المشترك إلى اللحظة المحددة.", + "investigation.localSource": "محلي", + "investigation.mediaAvailable": "الوسائط متاحة", + "investigation.durationSeconds": "المدة {count} ثانية", + "investigation.pageNumber": "صفحة {count}", + "investigation.incompleteCoverage": "{count} صف أحداث قديم لم يمكن ربطه بهوية كاميرا ثابتة.", + "investigation.spatialCoverageGap": "{count} صف أحداث ضمن النطاق لم يكن له إطار إحاطة ولم يتم البحث فيه مكانيًا.", + "investigation.noSpatialMetadata": "لا توجد أحداث ضمن النطاق تحتوي على إطارات إحاطة لهذا البحث في البيانات الوصفية.", + "investigation.selectCameraError": "اختر كاميرا واحدة على الأقل.", + "investigation.selectRecordingError": "اختر تسجيلًا واحدًا على الأقل.", + "investigation.investigateSelectedCount": "التحقيق في {count} تسجيلًا محددًا", + "investigation.missingCameraIdentity": "لا يمكن التحقيق: {count} تسجيلًا محددًا لا يحتوي على هوية كاميرا.", + "investigation.recordingTimeError": "التسجيلات المحددة لا تحتوي على نطاق زمني صالح.", + "investigation.windowLimit": "التسجيلات المحددة تتجاوز حد التحقيق البالغ 31 يومًا.", + "investigation.timeRangeError": "يجب أن يكون وقت الانتهاء بعد وقت البدء.", + "investigation.cameraLimit": "يمكن أن يتضمن التحقيق {count} كاميرات كحد أقصى.", + "investigation.decoderLimit": "يمكن تشغيل {count} مشغلات كاميرات فقط في وقت واحد.", + "investigation.playbackControls": "أدوات التحكم في التشغيل المتزامن", + "investigation.play": "تشغيل", + "investigation.pause": "إيقاف مؤقت", + "investigation.mode": "وضع التشغيل", + "investigation.wallClock": "الساعة الفعلية", + "investigation.skipCommonGaps": "تخطي الفجوات المشتركة", + "investigation.speed": "السرعة", + "investigation.sharedCursor": "مؤشر UTC مشترك", + "investigation.activePlayers": "مشغلات نشطة", + "investigation.timeline": "الجدول الزمني المشترك", + "investigation.segments": "مقاطع", + "investigation.truncated": "مقتطع", + "investigation.gap": "لا يوجد تسجيل", + "investigation.players": "مشغلات كاميرات متزامنة", + "investigation.activateCamera": "فعّل صفًا واحدًا على الأقل في الجدول الزمني لتحميل الفيديو.", + "investigation.noFootage": "لا يوجد تسجيل", + "investigation.noFootageAtTime": "لا يوجد تسجيل في الوقت المشترك", + "investigation.primaryAudio": "الصوت الأساسي", + "investigation.makePrimary": "تعيين كأساسي", + "investigation.status.loading": "جارٍ تحميل الوسائط", + "investigation.status.synchronizing": "جارٍ المزامنة", + "investigation.status.ready": "متزامن", + "investigation.status.late": "متأخر — جارٍ الاستعادة", + "investigation.status.error": "الوسائط غير متاحة", + "investigation.status.paused-by-browser": "اختر التشغيل للسماح بالوسائط", + "streamsConfig.eptzTitle": "ePTZ للعين السمكية", + "streamsConfig.eptzEnable": "تفعيل ePTZ للعين السمكية من جهة المتصفح", + "streamsConfig.eptzHelp": "إزالة تشويه تدفق العين السمكية الأصلي في العرض المباشر وتشغيل الخط الزمني والتحقيق. لا يؤثر هذا على التسجيلات أو مخرجات الكاميرا.", + "streamsConfig.eptzModelHelp": "الإسقاط: عين سمكية دائرية متساوية البعد · التركيب: سقف. يستخدم المركز ونصف القطر إحداثيات صورة المصدر المُطبَّعة.", + "streamsConfig.eptzCenterX": "المركز البصري X", + "streamsConfig.eptzCenterY": "المركز البصري Y", + "streamsConfig.eptzRadius": "نصف قطر دائرة الصورة", + "streamsConfig.eptzLensFov": "مجال رؤية العدسة (بالدرجات)", + "streamsConfig.eptzRotation": "دوران العدسة (بالدرجات)", + "streamsConfig.eptzDefaultYaw": "التحريك الأفقي الافتراضي (بالدرجات)", + "streamsConfig.eptzDefaultTilt": "الميل الافتراضي (بالدرجات)", + "streamsConfig.eptzViewFov": "مجال الرؤية الافتراضي", + "streamsConfig.eptzCalibrationHelp": "اسحب للنظر حولك، واستخدم العجلة أو القرص للتكبير، واضغط Home لإعادة ضبط الكاميرا الافتراضية. اضبط المركز ونصف القطر بدقة إذا لم تتطابق حافة دائرة الصورة.", + "settings.archive.targetType": "نوع التخزين", + "settings.archive.filesystem": "نظام ملفات محلي أو مُثبَّت (NFS/SAN)", + "settings.archive.s3": "دلو أرشفة متوافق مع S3", + "settings.archive.endpoint": "نقطة نهاية HTTPS", + "settings.archive.region": "المنطقة", + "settings.archive.bucket": "دلو مخصص", + "settings.archive.credential_ref": "مرجع بيانات الاعتماد", + "settings.archive.budget": "ميزانية الأرشفة (GiB، 0 = غير محدودة)", + "settings.archive.connectionHelp": "استخدم دلوًا خاصًا بدون إصدارات وبدون قواعد انتهاء الصلاحية. يحدد مرجع بيانات الاعتماد ملفًا سريًا مُثبَّتًا على الخادم. أدخل الموقع المُدار بصيغة s3://bucket/instance-prefix.", + "settings.archive.policy": "سياسة الأرشفة الخارجية", + "settings.archive.archive_after_seconds": "الأرشفة بعد الالتقاط (بالثواني، -1 = معطّل)", + "settings.archive.hot_residency_seconds": "الاحتفاظ بنسخة ساخنة (بالثواني، -1 = النقل بعد الأرشفة)", + "settings.archive.archive_protected": "إعطاء الأولوية لأرشفة التسجيلات المحمية", + "settings.archive.archive_on_pressure": "الأرشفة المبكرة عند ضغط التخزين الساخن", + "settings.archive.policyHelp": "يعتمد توقيت الأرشفة على عمر الالتقاط ويتطلب تسجيلًا مكتملًا. -1 يعطّل الأرشفة المبنية على العمر أو يزيل الحد الأدنى للإقامة الساخنة؛ 0 يعني فورًا. تُطبَّق التعديلات على التسجيلات الجديدة. راجع التسجيلات الحالية لتطبيق المراجعة الجديدة عليها.", + "settings.archive.deletion_pending": "حذف قيد الانتظار", + "settings.archive.archived": "مؤرشف", + "settings.archive.hot": "ساخن", + "settings.archive.hot_and_archive": "ساخن + أرشيف", + "settings.archive.archiving": "الأرشفة", + "settings.archive.preparing": "جارٍ تجهيز التشغيل", + "settings.archive.unavailable": "غير متاح", + "settings.archive.operations": "عمليات الأرشيف", + "settings.archive.readOnly": "وضع الاسترداد: تم إيقاف نقل وحذف التسجيلات مؤقتًا.", + "settings.archive.disabledBuild": "دعم S3 معطّل في هذا الإصدار. أهداف نظام الملفات المتصلة تظل متاحة.", + "settings.archive.stored": "مُخزّن في الحاويات", + "settings.archive.backlog": "متأخرات النقل", + "settings.archive.cache": "ذاكرة التخزين المؤقت للاسترجاع", + "settings.archive.objectsRemaining": "كائنات متبقية", + "settings.archive.waitingForReaders": "في قائمة الانتظار، أو بانتظار القراء النشطين.", + "settings.archive.applied": "تم تطبيق مراجعة السياسة على التسجيلات الحالية", + "settings.archive.reviewExisting": "مراجعة التسجيلات الحالية", + "settings.archive.applySummary": "ستستخدم {count} تسجيلات ({bytes}) هذه المراجعة. {expired} تجاوزت بالفعل حد الاحتفاظ الخاص بها.", + "settings.archive.applyHelp": "تظل تجاوزات الحماية والتسجيل سارية. كما تنطبق قواعد الاحتفاظ للبث والنظام. يبدأ سريان توقيت الأرشيف والوجهة الجديدين في الفحص التالي لدورة الحياة.", + "settings.archive.applyBlocked": "أكمل أو حلّ عمليات النقل المرتبطة قبل تطبيق هذه المراجعة.", + "settings.archive.apply": "تطبيق على التسجيلات الحالية", + "common.fullscreenUnsupported": "وضع ملء الشاشة غير مدعوم في هذا المتصفح.", + "recordings.viewInTimelineTitle": "عرض هذا البث في هذه اللحظة في عرض الجدول الزمني", + "recordings.clickToRetry": "انقر لإعادة المحاولة", + "timeline.previousDay": "اليوم السابق", + "timeline.nextDay": "اليوم التالي", + "timeline.previousMonth": "الشهر السابق", + "timeline.nextMonth": "الشهر التالي", + "settings.searchLabel": "البحث في الإعدادات", + "settings.clearSearch": "مسح البحث", + "recordings.addTagPlaceholder": "إضافة وسم...", + "recordings.addNewTagPlaceholder": "إضافة وسم جديد...", + "fleet.views.shared": "مشترك", + "fleet.views.saveCurrent": "حفظ العرض الحالي", + "fleet.views.name": "اسم العرض", + "fleet.views.share": "مشاركة مع جميع المشغّلين", + "fleet.views.saved": "تم حفظ عرض الأسطول", + "fleet.views.saveError": "تعذّر حفظ العرض: {message}", + "fleet.views.deleted": "تم حذف عرض الأسطول", + "fleet.views.deleteConfirm": "حذف العرض المحفوظ «{name}»؟", + "fleet.views.deleteError": "تعذّر حذف العرض: {message}", + "fleet.views.unsupported": "لا يمكن تمثيل هذا المحدِّد المحفوظ باستخدام عناصر التصفية الحالية.", + "collections.manage": "المجموعات", + "collections.all": "جميع المجموعات", + "collections.filter": "المجموعة", + "collections.loadMembersError": "تعذّر تحميل كاميرات المجموعة: {message}", + "collections.title": "مجموعات الكاميرات", + "collections.subtitle": "أنشئ مجموعات كاميرات قابلة لإعادة الاستخدام للعمليات والعروض المحفوظة وسير العمل اللاحق.", + "collections.listDescription": "تحتفظ المجموعات الثابتة بعضوية صريحة؛ بينما تُقيّم المجموعات الذكية قواعد الأسطول باستمرار.", + "collections.create": "إنشاء مجموعة", + "collections.edit": "تعديل المجموعة", + "collections.editorDescription": "تستخدم تعريفات المجموعات معرّفات UUID ثابتة للكاميرات والمواقع والوسوم.", + "collections.backToList": "العودة إلى المجموعات", + "collections.type": "نوع المجموعة", + "collections.type.static": "ثابتة", + "collections.type.smart": "ذكية", + "collections.description": "الوصف", + "collections.shared": "مجموعة مشتركة", + "collections.sharedHelp": "السماح للمستخدمين المصرَّح لهم الآخرين برؤية هذه المجموعة؛ مع استمرار تطبيق قواعد الوصول إلى الكاميرات.", + "collections.typeChangeWarning": "تغيير نوع المجموعة يستبدل نموذج العضوية الخاص بها. لن تُطبَّق الأعضاء الثابتة أو القواعد الذكية من النوع السابق بعد الآن.", + "collections.selectorError": "المحدِّد غير صالح: {message}", + "collections.created": "تم إنشاء المجموعة", + "collections.updated": "تم تحديث المجموعة", + "collections.saveError": "تعذّر حفظ المجموعة: {message}", + "settings.storagePolicies.primaryPool": "مجموعة التوزيع (اختياري)", + "settings.storagePolicies.exactTarget": "استخدام الهدف الأساسي المحدد بدقة", + "settings.storagePolicies.fallback": "في حال عدم توفر الهدف الأساسي", + "settings.storagePolicies.fallbackDefault": "استخدام الهدف الافتراضي", + "settings.storagePolicies.fallbackTarget": "استخدام هدف بديل مُسمّى", + "settings.storagePolicies.fallbackPause": "إيقاف التسجيل مؤقتًا", + "settings.storagePolicies.fallbackFail": "فشل بدء التسجيل", + "settings.storagePolicies.namedFallback": "الهدف البديل", + "settings.storagePolicies.chooseTarget": "اختر هدفًا", + "settings.storagePolicies.choosePool": "اختر مجموعة", + "settings.storagePolicies.minimumDays": "الحد الأدنى لمدة الاحتفاظ (أيام)", + "settings.storagePolicies.desiredDays": "مدة الاحتفاظ المطلوبة (أيام)", + "settings.storagePolicies.maximumDays": "الحد الأقصى لمدة الاحتفاظ (أيام)", + "settings.storagePolicies.copyCount": "عدد النسخ المؤكدة المطلوبة", + "settings.storagePolicies.replicationPool": "مجموعة النسخ الاحتياطي", + "settings.storagePolicies.migrateAfter": "النقل بعد عمر (أيام)", + "settings.storagePolicies.migrationTarget": "هدف الأرشفة", + "settings.storagePolicies.pressurePriority": "أولوية الحذف عند الضغط (الأقل أولًا)", + "settings.storagePolicies.disabledTarget": "معطّل", + "settings.storagePolicies.enabled": "السياسة مفعّلة", + "settings.storagePolicies.selector": "الكاميرات المطابقة", + "settings.storagePolicies.preview": "معاينة الأولوية", + "settings.storagePolicies.previewing": "جارٍ التقييم…", + "settings.storagePolicies.previewRequired": "عاين المسودة الحالية قبل الحفظ لرؤية تداخل الكاميرات والسياسة الفعّالة.", + "settings.storagePolicies.previewSummary": "يطابق {matched} كاميرات؛ هذه المسودة فعّالة لـ {effective}.", + "settings.storagePolicies.previewShadowed": "تتفوّق سياسة ذات أولوية أعلى على {count} كاميرات مطابقة.", + "settings.storagePolicies.previewWins": "تتفوّق على «{policy}» (الأولوية {priority}) لـ {count} كاميرات.", + "settings.storagePolicies.previewLoses": "تخسر أمام «{policy}» (الأولوية {priority}) لـ {count} كاميرات.", + "settings.storagePolicies.previewNoMatches": "لا يطابق هذا المحدّد أي كاميرات حاليًا.", + "settings.storagePolicies.invalidPriority": "يجب أن تكون الأولوية عددًا صحيحًا بين -1,000,000 و 1,000,000.", + "settings.storagePolicies.invalidLifecycle": "تحقق من ترتيب الاحتفاظ، وعدد النسخ ومجموعة النسخ الاحتياطي، وعمر النقل والهدف.", + "settings.storagePolicies.created": "تم إنشاء سياسة التوزيع" } diff --git a/web/public/locales/de.json b/web/public/locales/de.json index 3f9ea95a..e6620b89 100644 --- a/web/public/locales/de.json +++ b/web/public/locales/de.json @@ -9,6 +9,84 @@ "nav.timeline": "Zeitleiste", "nav.health": "Verbindungsstatus", "nav.toggleMenu": "Menü umschalten", + "live.navigator.title": "Navigator", + "live.navigator.subtitle": "Standorte, Layouts und Aktivität", + "live.navigator.cameras": "Kameras", + "live.navigator.plans": "Plan", + "live.navigator.views": "Ansichten", + "live.navigator.events": "Ereignisse", + "live.navigator.search": "Kamera suchen…", + "live.navigator.allCameras": "Alle Kameras", + "live.navigator.unassigned": "Nicht zugewiesen", + "live.navigator.noCameras": "Keine Kameras entsprechen diesem Bereich.", + "live.navigator.saveCurrent": "Aktuelles Layout speichern", + "live.navigator.noLayouts": "Noch keine gespeicherten Layouts.", + "live.navigator.layoutNamePrompt": "Benennen Sie dieses Live-Layout", + "live.navigator.shareLayoutPrompt": "Dieses Layout mit anderen Bedienern teilen?", + "live.navigator.layoutSaved": "{name} gespeichert", + "live.navigator.layoutLoaded": "{name} geladen", + "live.navigator.deleteLayoutConfirm": "{name} löschen?", + "live.navigator.shared": "Geteilt", + "live.navigator.loadingEvents": "Neueste Ereignisse werden geladen…", + "live.navigator.noRecentEvents": "Keine Erkennungen in der letzten Stunde.", + "live.navigator.expand": "Navigator ausklappen", + "live.navigator.collapse": "Navigator einklappen", + "live.plan.navigatorHelp": "Wählen Sie ein Gebäude oder eine Etage. Kamera-Vorschauen öffnen sich nur auf Anfrage.", + "live.plan.noPlans": "Noch keine Gebäudepläne. Erstellen Sie einen im Plan-Arbeitsbereich.", + "live.plan.emptyTitle": "Räumliche Kameraansicht erstellen", + "live.plan.emptyDescription": "Ein Plan zeigt Statusmarker für das gesamte Gelände und öffnet Video nur auf Anfrage eines Bedieners. Zeichnen Sie Räume und Wände direkt hier oder laden Sie einen gescannten Plan, eine Geländeskizze oder einen Screenshot Ihrer NVR-Software hoch und ordnen Sie die Kameras dann den echten Räumen zu.", + "live.plan.sketch.tools": "Layout-Werkzeuge", + "live.plan.sketch.tool.select": "Auswählen", + "live.plan.sketch.tool.room": "Raum", + "live.plan.sketch.tool.wall": "Wand", + "live.plan.sketch.tool.area": "Bereich", + "live.plan.sketch.tool.label": "Beschriftung", + "live.plan.sketch.undo": "Zeichnung rückgängig machen", + "live.plan.sketch.redo": "Zeichnung wiederherstellen", + "live.plan.sketch.snap": "Am Raster ausrichten", + "live.plan.sketch.hint.select": "Ziehen Sie Formen oder Kameras, um sie zu verschieben. Klicken Sie auf eine Form, um sie zu bearbeiten; halten Sie Alt gedrückt, um das Raster zu überspringen.", + "live.plan.sketch.hint.room": "Ziehen Sie auf dem Plan, um einen Raum oder eine Gebäudekontur zu zeichnen.", + "live.plan.sketch.hint.wall": "Klicken Sie, um Wandpunkte hinzuzufügen. Doppelklicken oder Enter schließt ab, Escape bricht ab.", + "live.plan.sketch.hint.area": "Klicken Sie, um einen Bereich einzuzeichnen. Klicken Sie auf den ersten Punkt oder drücken Sie die Enter, um ihn zu schließen.", + "live.plan.sketch.hint.label": "Klicken Sie auf den Plan, um eine Textbeschriftung zu platzieren.", + "live.plan.sketch.type.rect": "Raum", + "live.plan.sketch.type.wall": "Wand", + "live.plan.sketch.type.area": "Bereich", + "live.plan.sketch.type.label": "Beschriftung", + "live.plan.sketch.pointCount": "{count} Punkte", + "live.plan.sketch.defaultLabel": "Beschriftung", + "live.plan.sketch.shapes": "Layout-Formen", + "live.plan.sketch.noShapes": "Noch nichts gezeichnet. Wählen Sie ein Werkzeug über dem Plan, um zu beginnen.", + "live.plan.sketch.tone": "Farbe", + "live.plan.sketch.tone.slate": "Schiefer", + "live.plan.sketch.tone.blue": "Blau", + "live.plan.sketch.tone.green": "Grün", + "live.plan.sketch.tone.amber": "Bernstein", + "live.plan.sketch.tone.red": "Rot", + "live.plan.sketch.tone.violet": "Violett", + "live.plan.sketch.labelText": "Beschriftung", + "live.plan.sketch.text": "Text", + "live.plan.sketch.size": "Größe", + "live.plan.sketch.size.sm": "Klein", + "live.plan.sketch.size.md": "Mittel", + "live.plan.sketch.size.lg": "Groß", + "live.plan.sketch.filled": "Raum füllen", + "live.plan.sketch.left": "Links %", + "live.plan.sketch.top": "Oben %", + "live.plan.sketch.width": "Breite %", + "live.plan.sketch.height": "Höhe %", + "live.plan.sketch.points": "Punkte", + "live.plan.sketch.point": "Punkt {index}", + "live.plan.sketch.delete": "Form löschen", + "live.plan.sketch.duplicate": "Duplizieren", + "live.plan.sketch.deselect": "Fertig", + "live.plan.sketch.emptyTitle": "Noch nichts auf diesem Plan", + "live.plan.sketch.emptyBody": "Zeichnen Sie Räume, Wände und Beschriftungen direkt hier oder laden Sie einen gescannten Plan, eine Geländeskizze oder einen PNG/JPEG-Export hoch (bis 768 KB).", + "live.plan.sketch.emptyBodyReadOnly": "Ein Administrator kann das Layout zeichnen oder einen Plan des echten Gebäudes hochladen.", + "live.plan.sketch.drawLayout": "Layout zeichnen", + "live.plan.sketch.uploadImage": "Bild hochladen", + "live.plan.sketch.limitReached": "Formlimit erreicht ({max})", + "live.plan.sketch.discardDrawing": "Zeichnung abgebrochen", "streamHealth.title": "Streamen Sie Gesundheit", "streamHealth.loading": "Gesundheitsdaten werden geladen...", "streamHealth.error": "Gesundheitsdaten konnten nicht geladen werden", @@ -325,14 +403,14 @@ "timeline.help.clickSegment": "Klicken Sie auf ein Segment (farbiger Balken), um diese Aufnahme abzuspielen", "timeline.help.arrowKeys": "Verwenden Sie die Pfeiltasten links und rechts, um zwischen Aufnahmen zu springen; klicken Sie auf das Video, damit die Pfeiltasten um 1 Sekunde suchen", "timeline.help.playFromCursor": "Verwenden Sie die grüne Wiedergabetaste, um die Wiedergabe an der aktuellen Cursorposition zu starten", - "timeline.help.zoomControls": "Verwenden Sie die Schaltflächen Anpassen, + und − oder Strg/Cmd + Mausrad, um die Zeitleiste zu zoomen", - "timeline.help.panControls": "Verschieben Sie die Ansicht auf der aktuellen Zoomstufe mit Umschalt + Mausrad oder einer horizontalen Trackpad-Geste nach links/rechts", + "timeline.help.zoomControls": "Verwenden Sie die Schaltflächen Anpassen, + und − oder Ctrl/Cmd + Mausrad, um die Zeitleiste zu zoomen", + "timeline.help.panControls": "Verschieben Sie die Ansicht auf der aktuellen Zoomstufe mit Shift + Mausrad oder einer horizontalen Trackpad-Geste nach links/rechts", "timeline.help.actions": "Verwenden Sie Schnappschuss, Herunterladen, Schützen oder Löschen für die aktuell abgespielte Aufnahme", "timeline.arrowKeysHelpTitle": "Klicken Sie auf das Video, damit die Pfeiltasten um 1 Sekunde suchen. Klicken Sie anderswo, um wieder zwischen Aufnahmen zu springen.", "timeline.arrowKeys": "Pfeiltasten", "timeline.seekOneSecond": "±1 Sek. suchen", "timeline.jumpRecordings": "zwischen Aufnahmen springen", - "timeline.inlineHint": "Klicken Sie auf das Video für 1-Sekunden-Suche mit den Pfeiltasten · Klicken Sie auf die Zeitleiste für Sprünge zwischen Aufnahmen · Umschalt+Rad verschiebt · Strg/Cmd+Rad zoomt", + "timeline.inlineHint": "Klicken Sie auf das Video für 1-Sekunden-Suche mit den Pfeiltasten · Klicken Sie auf die Zeitleiste für Sprünge zwischen Aufnahmen · Shift+Rad verschiebt · Ctrl/Cmd+Rad zoomt", "timeline.selectedRecordingsTimeline": "Zeitleiste ausgewählter Aufnahmen", "timeline.timelinePlayback": "Zeitleisten-Wiedergabe", "timeline.recordingsCount": "{count} Aufnahmen", @@ -405,6 +483,12 @@ "live.errorProcessingStreams": "Fehler bei der Verarbeitung von Streams: {message}", "live.couldNotEnableFullscreen": "Der Vollbildmodus konnte nicht aktiviert werden: {message}", "live.allTags": "Alle Tags", + "live.favorites": "Favoriten", + "live.favoritesOnly": "Nur bevorzugte Kameras anzeigen", + "live.addFavorite": "{stream} zu Favoriten hinzufügen", + "live.removeFavorite": "{stream} aus Favoriten entfernen", + "live.noFavorites": "Noch keine bevorzugten Kameras. Nutzen Sie den Stern auf einer Kamera-Kachel, um eine hinzuzufügen.", + "live.favoriteUpdateError": "Favoriten konnten nicht aktualisiert werden: {message}", "live.tags": "Tags", "live.stream": "Stream", "live.filterByTag": "Nach Tag filtern: {tag}", @@ -589,6 +673,7 @@ "live.forceRefreshWarning": "Dadurch wird die go2rtc-Verbindung kurzzeitig unterbrochen und die aktive Aufzeichnung unterbrochen. Die Aufnahme wird automatisch fortgesetzt.", "live.viewInTimeline": "In der Zeitleiste anzeigen", "live.toggleFullscreen": "Vollbild umschalten", + "live.resetZoom": "Zoom zurücksetzen", "live.streamStarting": "Stream wird gestartet...", "live.go2rtcNotRespondingRetry": "go2rtc ist aktiviert, reagiert aber nicht. Überprüfen Sie den Dienststatus von go2rtc. Klicken Sie auf „Wiederholen“, um es noch einmal zu versuchen.", "live.go2rtcHlsFailedRetry": "go2rtc HLS Stream fehlgeschlagen. Klicken Sie auf „Wiederholen“, um es noch einmal zu versuchen.", @@ -603,12 +688,14 @@ "live.failedToCreateMediaBuffer": "Fehler beim Erstellen des Medienpuffers", "live.webSocketConnectionError": "WebSocket-Verbindungsfehler", "live.webrtcAutoplayBlocked": "Zum Abspielen des Videos klicken (automatische Wiedergabe blockiert)", + "live.audioPlaybackBlocked": "Der Browser hat Kameraton blockiert. Klicken Sie erneut auf die Lautsprechertaste, um es erneut zu versuchen.", "live.webrtcConnectionLostRetry": "WebRTC Verbindung verloren. Klicken Sie auf „Wiederholen“, um die Verbindung wiederherzustellen.", "live.streamConnectedNoVideoDataRetry": "Stream verbunden, aber keine Videodaten. Klicken Sie auf „Wiederholen“, um die Verbindung wiederherzustellen.", "live.failedToLoadVideo": "Video konnte nicht geladen werden", "live.webrtcIceConnectionFailed": "WebRTC ICE Verbindung fehlgeschlagen", "live.webrtcConnectionLostPleaseRetry": "WebRTC Verbindung verloren. Bitte versuchen Sie es erneut.", "live.autoRetryingIn": "Erneuter Versuch in {seconds} s…", + "live.fullscreenSubStreamFallback": "{stream}: nicht genug Bandbreite für den Stream in voller Auflösung im Vollbild – auf den Sub-Stream umgeschaltet.", "live.connectionTimeoutCheckNetwork": "Verbindungszeitüberschreitung. Überprüfen Sie die Netzwerk-/Firewall-Einstellungen.", "live.failedToEstablishWebrtcConnection": "Es konnte keine WebRTC-Verbindung hergestellt werden", "live.cannotConnectToSource": "Keine Verbindung zur Kameraquelle möglich", @@ -622,6 +709,16 @@ "live.connectionQuality.bad": "Schlecht", "live.muteCameraAudio": "Kameraton stumm schalten", "live.unmuteCameraAudio": "Stummschaltung des Kameratons aufheben", + "live.tileActions": "Kamera-Aktionen", + "live.takeSnapshot": "Schnappschuss aufnehmen", + "live.openStreamRecordings": "Aufnahmen dieses Streams öffnen", + "live.enterReorderMode": "Kameras neu anordnen", + "live.pullToRefresh": "Ziehen, um Streams zu aktualisieren", + "live.releaseToRefresh": "Loslassen, um Streams zu aktualisieren", + "live.refreshingStreams": "Streams werden aktualisiert…", + "live.streamsRefreshed": "Streams aktualisiert", + "live.refreshStreamsFailed": "Streams konnten nicht aktualisiert werden: {message}", + "live.tipDoubleTapFullscreen": "Tipp: Doppeltippen auf eine Kachel öffnet sie im Vollbild.", "live.switchToToggleMode": "Wechseln Sie in den Toggle-Modus", "live.switchToPushToTalkMode": "Wechseln Sie zu Push-to-Talk", "live.releaseToStopTalking": "Lassen Sie los, um mit dem Reden aufzuhören", @@ -636,6 +733,40 @@ "live.pauseForPrivacyConfirm": "Diesen Stream aus Datenschutzgründen pausieren? Aufzeichnung und Live-Ansicht werden beendet, der Stream bleibt jedoch mit einem Datenschutz-Overlay auf dieser Seite sichtbar. Klicken Sie auf „Fortsetzen“, wenn Sie fertig sind.", "live.streamPausedForPrivacy": "Stream aus Datenschutzgründen pausiert", "live.resumeStream": "Stream fortsetzen", + "live.dayNightControl": "Tag/Nacht-Modus", + "live.dayNightLoading": "Lädt…", + "live.dayNightApplying": "Wird angewendet…", + "live.dayNightMode_auto": "Auto", + "live.dayNightMode_day": "Tag", + "live.dayNightMode_night": "Nacht", + "live.dayNightMode_unknown": "Unbekannt", + "live.dayNightApplied": "Tag/Nacht-Modus auf {mode} gesetzt", + "live.dayNightApplyFailed": "Tag/Nacht-Modus konnte nicht gesetzt werden", + "live.dayNightLoadFailed": "Tag/Nacht-Modus konnte nicht gelesen werden", + "live.playbackFallbackUsed": "Fallback: {transport}", + "live.playbackTransportUnavailable": "{transport} ist auf dem Server für diesen Stream deaktiviert.", + "live.recordingMode.constant": "Dauerhafte Aufnahme", + "live.recordingMode.detection": "Aufnahme bei Erkennung", + "live.recordingMode.schedule": "Geplante Aufnahme", + "live.recordingMode.none": "Keine Aufnahme", + "live.health.healthy": "Stream intakt", + "live.health.degraded": "Stream puffert oder erholt sich", + "live.health.offline": "Stream nicht verfügbar", + "live.enterPictureInPicture": "Bild-in-Bild öffnen", + "live.exitPictureInPicture": "Bild-in-Bild schließen", + "live.pictureInPictureError": "Bild-in-Bild fehlgeschlagen: {message}", + "live.alwaysFullscreenOnTapEnable": "Vollbild bei einmaligem Tippen auf eine Kachel aktivieren", + "live.alwaysFullscreenOnTapDisable": "Vollbild bei einmaligem Tippen auf eine Kachel deaktivieren", + "live.displayMode": "Anzeigemodus", + "live.displayModeFit": "Einpassen", + "live.displayModeFill": "Ausfüllen", + "live.displayModeFitDescription": "Einpassen: gesamtes Bild mit Letterboxbalken anzeigen", + "live.displayModeFillDescription": "Ausfüllen: Kachel füllen und Bildränder beschneiden", + "live.slideshowStartCameras": "Diashow starten: Kameras durchlaufen", + "live.slideshowStartPages": "Diashow starten: Rasterseiten durchlaufen", + "live.slideshowStop": "Diashow stoppen", + "live.slideshowInterval": "Diashow-Intervall", + "live.slideshowSeconds": "{seconds} s", "streams.toggleDisable": "Stream deaktivieren", "streams.toggleEnable": "Stream aktivieren", "streams.readOnlyInsufficientPermissions": "Schreibgeschützt (nicht ausreichende Berechtigungen zum Ändern)", @@ -759,9 +890,9 @@ "streamsConfig.streamNameImmutable": "Der Streamname kann nach der Erstellung nicht mehr geändert werden", "streamsConfig.streamNameAllowedChars": "Es sind nur Buchstaben, Ziffern, „.“, „-“ und „_“ zulässig (keine Leerzeichen).", "streamsConfig.streamUrl": "Stream-URL", - "streamsConfig.streamUrlPlaceholder": "rtsp://Benutzername:Passwort@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "Unterstream URL (optional)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://Benutzername:Passwort@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "Stream mit niedriger Auflösung URL für die Dashboard-Rasteransicht. Lassen Sie es leer, um den Hauptstrom überall zu nutzen. Der Substream wird nur für die Live-Vorschau im Rastermodus verwendet; Aufnahme und Vollbild verwenden immer den Hauptstream.", "streamsConfig.urlCredentialsHiddenTitle": "URL-Anmeldeinformationen sind im Demo-/Viewer-Modus ausgeblendet", "streamsConfig.urlCredentialsHidden": "URL Anmeldeinformationen aus Sicherheitsgründen ausgeblendet", @@ -819,7 +950,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "Stellen Sie sicher, dass Light-Object-Detect auf diesem Endpunkt ausgeführt wird", "streamsConfig.customApiEndpointUrl": "Benutzerdefinierter API Endpunkt URL", "streamsConfig.useDefaultEndpoint": "Verwenden Sie den Standardendpunkt", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "Geben Sie den vollständigen URL für Ihren benutzerdefinierten Erkennungsendpunkt API ein", "streamsConfig.overrideWithCustomEndpoint": "Mit benutzerdefiniertem Endpunkt überschreiben", "streamsConfig.detectionThreshold": "Erkennungsschwelle", @@ -1056,7 +1187,7 @@ "settings.detectionModelsPath": "Pfad der Erkennungsmodelle", "settings.detectionModelsPathHelp": "Verzeichnis, in dem Erkennungsmodelle gespeichert werden", "settings.apiDetectionUrl": "API Erkennung URL", - "settings.apiDetectionUrlHelp": "URL des externen Objekterkennungsendpunkts API.", + "settings.apiDetectionUrlHelp": "light-object-detect-Endpunkt, z. B. http://localhost:8000/api/v1/detect. Der Schnappschuss wird als Multipart-Form-Data hochgeladen, wobei die Abfrageparameter backend und confidence_threshold angehängt werden.", "settings.apiDetectionBackend": "API Erkennungs-Backend", "settings.apiDetectionBackendOnnx": "ONNX Laufzeit", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1156,5 +1287,1361 @@ "settings.discoveryIntervalSecondsRangeHelp": "Wie oft nach Kameras gesucht werden soll (30–3600 Sekunden)", "settings.discoveryNetwork": "Discovery-Netzwerk", "settings.discoveryNetworkExamples": "Beispiele: 192.168.1.0/24, 10.0.0.0/16, auto", - "settings.saveSettings": "Einstellungen speichern" + "settings.saveSettings": "Einstellungen speichern", + "live.plan.previewUnavailable": "Kamera-Vorschau nicht verfügbar", + "live.plan.previewAlt": "Aktuelle Ansicht von {name}", + "live.plan.degreesValue": "{value} Grad", + "live.plan.inDegrees": "{label} in Grad", + "live.plan.imageDimensionsError": "Bildmaße konnten nicht gelesen werden", + "live.plan.loading": "Gebäudepläne werden geladen…", + "live.plan.created": "{name} erstellt", + "live.plan.renamed": "Umbenannt in {name}", + "live.plan.deleted": "{name} gelöscht", + "live.plan.backgroundType": "Der Hintergrund muss ein PNG- oder JPEG-Bild sein", + "live.plan.backgroundTooLarge": "Hintergrundbild zu groß; Maximum sind 768 KB", + "live.plan.backgroundAspect": "Hochgeladen, aber das Seitenverhältnis des Bildes passt zu keiner gültigen Leinwandgröße", + "live.plan.backgroundUpdatedSave": "Hintergrund für {name} aktualisiert; speichern Sie das Layout, um seine Leinwandgröße anzuwenden", + "live.plan.backgroundNotResized": "Hintergrund hochgeladen, aber die Leinwand wurde nicht angepasst: {error}", + "live.plan.backgroundUpdated": "Hintergrund für {name} aktualisiert", + "live.plan.backgroundRemoved": "Hintergrund entfernt", + "live.plan.saved": "{name} gespeichert", + "live.plan.createTitle": "Gebäudeplan erstellen", + "live.plan.createDescription": "Geben Sie diesem Gebäude oder dieser Etage einen klaren Namen. Zeichnen Sie das Layout oder laden Sie ein Planbild hoch und platzieren Sie dann Kameras.", + "live.plan.nameLabel": "Planname", + "live.plan.namePlaceholder": "Hauptgebäude · Erdgeschoss", + "live.plan.createConfirm": "Plan erstellen", + "live.plan.eyebrow": "Gebäudeplan", + "live.plan.placedSummary": "{placed} platziert · {live} jetzt live", + "live.plan.zoomAndPan": "Plan-Zoom und Schwenken", + "live.plan.panLeft": "Nach links schwenken", + "live.plan.panUp": "Nach oben schwenken", + "live.plan.panDown": "Nach unten schwenken", + "live.plan.panRight": "Nach rechts schwenken", + "live.plan.zoomOut": "Herauszoomen", + "live.plan.zoomIn": "Hineinzoomen", + "live.plan.fitTitle": "Plan einpassen", + "live.plan.fit": "Einpassen", + "live.plan.backgroundMenu": "Hintergrund…", + "live.plan.save": "Plan speichern", + "live.plan.uploadBackgroundTitle": "PNG- oder JPEG-Bild als Planhintergrund hochladen", + "live.plan.replaceBackground": "Hintergrund ersetzen", + "live.plan.uploadBackground": "Hintergrund hochladen", + "live.plan.removeBackground": "Hintergrund entfernen", + "live.plan.rename": "Umbenennen", + "live.plan.newPlan": "Neuer Plan", + "live.plan.editLayout": "Layout bearbeiten", + "live.plan.placementHint": "Klicken Sie auf den Plan, um {name} zu positionieren", + "live.plan.clusterLabel": "{count} Kameras; hineinzoomen", + "live.plan.markerLabel": "{name}; {availability}; Blickrichtung {rotation}° mit einem Blickfeld von {fov}°", + "live.plan.cameraFallback": "Kamera", + "live.plan.legendLive": "Live", + "live.plan.canvas": "Planleinwand", + "live.plan.width": "Breite", + "live.plan.height": "Höhe", + "live.plan.canvasHint": "Beim Hochladen eines Hintergrundbilds wird die Leinwand an dessen Größe angepasst.", + "live.plan.canvasInvalid": "Die Breite muss 400–4000 und die Höhe 300–4000 sein.", + "live.plan.openLive": "Live-Kamera öffnen", + "live.plan.direction": "Kamerarichtung", + "live.plan.fov": "Blickfeld", + "live.plan.coverageNote": "Kreise zeigen nur Richtung und Winkel; die Entfernung im Plan ist nicht kalibriert.", + "live.plan.removeCamera": "Vom Plan entfernen", + "live.plan.selectCamera": "Kamera auswählen", + "live.plan.selectHintEditing": "Ziehen Sie platzierte Marker zum Feintuning. Prüfen Sie den Status und öffnen Sie bei Bedarf eine Liveansicht.", + "live.plan.selectHint": "Prüfen Sie den Status und öffnen Sie bei Bedarf eine Liveansicht.", + "live.plan.cameras": "Plan-Kameras", + "live.plan.findPlaceholder": "Auf diesem Plan suchen…", + "live.plan.findLabel": "Kamera auf diesem Plan suchen", + "live.plan.unplaced": "Nicht platzierte Kameras", + "live.plan.unplacedHint": "Wählen Sie eine Kamera und klicken Sie dann auf ihre Position im Plan.", + "live.plan.renameTitle": "Plan umbenennen", + "live.plan.renameDescription": "Pläne werden mit allen Bedienern dieser Anlage geteilt.", + "live.plan.deleteTitle": "Plan löschen", + "live.plan.deleteMessage": "„{name}“ und den hochgeladenen Hintergrund löschen? Kameraplatzierungen auf diesem Plan werden entfernt; die Kameras selbst bleiben unverändert.", + "setupWizard.welcomeTitle": "Willkommen bei LightNVR", + "setupWizard.welcomeIntro": "Lassen Sie uns Ihr NVR in wenigen Schritten konfigurieren. Diese Einstellungen können Sie später jederzeit über die Einstellungsseite erneut aufrufen.", + "setupWizard.welcomeStorage": "Speicherpfad und Größenlimits", + "setupWizard.welcomePerformance": "Leistungsgrenzen für Ihre Kamerazahl", + "setupWizard.welcomeSecurity": "Sichere Administrator-Anmeldung", + "setupWizard.storageTitle": "Speicher & Datenbank", + "setupWizard.storageIntro": "Wo sollen Aufnahmen und Datenbank gespeichert werden?", + "setupWizard.storagePath": "Speicherpfad für Aufnahmen", + "setupWizard.storagePathHint": "Absoluter Pfad, in den Videodateien geschrieben werden.", + "setupWizard.maxStorage": "Maximale Speichergröße (GB)", + "setupWizard.maxStorageHint": "0 = unbegrenzt.", + "setupWizard.dbPath": "Datenbankpfad", + "setupWizard.dbPathHint": "Speicherort der SQLite-Datenbankdatei.", + "setupWizard.performanceTitle": "Leistung", + "setupWizard.performanceIntro": "Diese Einstellungen steuern die Kapazität, nicht die Bildqualität. Die meisten Benutzer können die Standardwerte behalten.", + "setupWizard.threadPool": "Größe des Worker-Threadpools", + "setupWizard.threadPoolInfo": "betrifft Hintergrundarbeiten von Web/Server. Der empfohlene Standardwert ist meist optimal, es sei denn, Sie optimieren die Leistung.", + "setupWizard.maxStreams": "Maximale gleichzeitige Streams", + "setupWizard.maxStreamsInfo": "ist das Kamera-Kapazitätslimit dieser laufenden Instanz. Setzen Sie es mindestens auf die Zahl der Kameras, die Sie hinzufügen wollen, plus etwas Spielraum.", + "setupWizard.important": "Wichtig:", + "setupWizard.restartWarning": "wenn Sie eine der beiden Einstellungen ändern, wird der neue Wert jetzt gespeichert, aber erst nach einem Neustart von LightNVR verwendet. Wenn das aktuelle Streamlimit z. B. 1 ist und Sie es auf 32 erhöhen, müssen Sie neu starten, bevor Sie über das alte Limit hinaus Kameras hinzufügen.", + "setupWizard.threadPoolHintCores": "Empfohlen: {recommended} (2× Ihre {cores}-Kern-CPU). Dies steuert libuv-Hintergrund-Worker-Threads. Bereich: 2–128.", + "setupWizard.threadPoolHint": "Empfohlen: {recommended} (2× Ihre CPU-Kerne). Dies steuert libuv-Hintergrund-Worker-Threads. Bereich: 2–128.", + "setupWizard.maxStreamsHint": "Wie viele Kameras LightNVR gleichzeitig aktiv halten kann. Standard 32, maximal {max}. Wenn Sie mit 8 Kameras rechnen, wählen Sie mindestens 8. Neustart erforderlich, um wirksam zu werden.", + "setupWizard.completeTitle": "Einrichtung abgeschlossen!", + "setupWizard.saved": "Ihre Einstellungen wurden erfolgreich gespeichert.", + "setupWizard.notSaved": "Es wurden keine Einstellungen geändert – es werden die Standardwerte verwendet.", + "setupWizard.restartRequired": "Neustart erforderlich", + "setupWizard.restartRequiredInfo": "Änderungen an Threadpoolgröße und/oder maximaler Streamanzahl sind gespeichert, werden aber erst nach einem Neustart des Dienstes wirksam. Starten Sie neu, bevor Sie weitere Kameras hinzufügen oder das neue Kapazitätslimit erwarten.", + "setupWizard.saveFailed": "Einstellungen konnten nicht gespeichert werden: {error}", + "setupWizard.back": "Zurück", + "setupWizard.saving": "Wird gespeichert…", + "setupWizard.saveContinue": "Speichern & fortfahren", + "setupWizard.next": "Weiter →", + "setupWizard.finish": "Zum Dashboard", + "setupWizard.skip": "Einrichtungsassistent überspringen", + "live.eptzCanvasLabel": "Elektronische Schwenk-, Neige- und Zoomansicht für Fischaugenobjektive", + "live.eptzCanvasHint": "Ziehen zum Schwenken und Neigen; Mausrad oder Pinch zum Zoomen; Home setzt zurück", + "live.eptzReset": "ePTZ-Ansicht zurücksetzen", + "live.autoShort": "Auto", + "live.webrtcShort": "WebRTC", + "nav.investigation": "Ermittlung", + "availability.label": "Kamera-Verfügbarkeit", + "availability.live": "Jetzt live", + "availability.offline": "Offline (zuvor verbunden)", + "availability.neverConnected": "Nie verbunden", + "availability.disabled": "Deaktiviert", + "availability.all": "Alle Kameras", + "streams.inventory": "Inventar", + "streams.configuration": "Konfiguration", + "events.tab": "Ereignisse", + "events.eyebrow": "Ereignisgesteuerte Integrationen", + "events.title": "Ereignisse und Routing", + "events.description": "Wandeln Sie Kamera- und Systemereignisse in dauerhafte MQTT-Streams für Automatisierung, Benachrichtigungsdienste und externe Verarbeitung um. LightNVR stellt die Ereignisschnittstelle bereit; E-Mail- und SMS-Zustellung erfolgt über nachgelagerte Dienste.", + "events.routes": "Routen", + "events.destinations": "Ziele", + "events.catalog": "Ereigniskatalog", + "events.enable": "Aktivieren", + "events.loadError": "Ereignis-Routing-Konfiguration konnte nicht geladen werden", + "events.accessDenied": "Zugriff verweigert – unzureichende Berechtigungen", + "events.summary.routes": "Routen", + "events.summary.enabled": "{count} aktiviert", + "events.summary.destinations": "Ziele", + "events.summary.managedActive": "{count} verwaltet und aktiv", + "events.summary.types": "Registrierte Typen", + "events.summary.registry": "Versionierter Ereigniskatalog", + "events.summary.interface": "Schnittstelle", + "events.summary.interfaceHelp": "Dauerhafter Ereignisausgang", + "events.route.add": "Route hinzufügen", + "events.route.addTitle": "Ereignis-Route erstellen", + "events.route.editTitle": "Ereignis-Route bearbeiten", + "events.route.create": "Route erstellen", + "events.route.editorDescription": "Wählen Sie, welche Ereignisse qualifiziert sind, welche Kameras einbezogen werden, wohin sie geleitet werden und wie rauschende Quellen gesteuert werden.", + "events.route.emptyTitle": "Keine Ereignisrouten konfiguriert", + "events.route.emptyDescription": "Erstellen Sie eine Route, um Ereignistypen, Kamerabereich, Zeitplan, Unterdrückungsrichtlinie und MQTT-Ziel auszuwählen.", + "events.route.enabled": "Route aktiviert", + "events.route.enabledHelp": "Übereinstimmende Ereignisse werden zur dauerhaften Zustellung angenommen", + "events.route.destination": "Ziel", + "events.route.destinationHelp": "Ein übereinstimmendes Ereignis wird für jedes eindeutige Ziel einmal gespeichert.", + "events.route.eventTypes": "Ereignistypen", + "events.route.eventTypesHelp": "Wählen Sie einen oder mehrere versionierte Ereignisverträge aus dem Register.", + "events.route.detectionFilters": "Objekterkennungen filtern", + "events.route.detectionFiltersHelp": "Optional Bezeichnungen, Zonen oder eine Mindestkonfidenz für Objekterkennungsereignisse erforderlich.", + "events.route.healthFilters": "Systemzustandsereignisse filtern", + "events.route.healthFiltersHelp": "Optional registrierte Zustandsbedingungscodes oder Schweregrade abgleichen. Die verfügbaren Werte stammen von diesem Recorder.", + "events.route.healthConditions": "Zustandsbedingungen (beliebige)", + "events.route.healthSeverities": "Schweregrade (beliebige)", + "events.route.healthRegistryUnavailable": "Das Zustandsbedingungsregister ist nicht verfügbar. Bitte neu laden, bevor Sie Bedingungsfilter konfigurieren.", + "events.route.labels": "Bezeichnungen (beliebige)", + "events.route.zones": "Zonen-IDs (beliebige)", + "events.route.listHelp": "Werte durch Kommas trennen.", + "events.route.minConfidence": "Mindestkonfidenz", + "events.route.confidenceHelp": "Ein Wert von 0 bis 1.", + "events.route.cameraScope": "Kamerabereich", + "events.route.cameraScopeHelp": "Flottenstandorte, Tags, Attributsammlungen oder explizite Kameras wiederverwenden, ohne die gesamte Flotte zu laden.", + "events.route.allCameras": "Alle Kameras", + "events.route.dynamicScope": "Dynamische Kameraauswahl", + "events.route.systemScopeHelp": "Systemereignisse sind keine Kameras. Kameraauswahlen sind nicht verfügbar, wenn diese Route systembezogene Ereignisse enthält.", + "events.route.schedule": "Zeitplan", + "events.route.scheduleHelp": "Verwenden Sie die Ereigniszeit in einer IANA-Zeitzone; Nachtfenster werden unterstützt.", + "events.route.restrictSchedule": "Nur während konfigurierter Fenster", + "events.route.suppression": "Rausch- und Zustellungsrichtlinie", + "events.route.suppressionHelp": "Null deaktiviert eine Steuerung. Die Unterdrückung wird erst fortgesetzt, nachdem das Ziel das dauerhafte Ereignis akzeptiert hat.", + "events.route.debounce": "Entprellzeit in Sekunden", + "events.route.debounceHelp": "Wiederholte Beobachtungen verlängern dieses Ruheintervall.", + "events.route.cooldown": "Cooldown-Sekunden", + "events.route.cooldownHelp": "Mindestintervall nach einem akzeptierten Ereignis.", + "events.route.grouping": "Gruppierungsfenster in Sekunden", + "events.route.groupingHelp": "Erstes Ereignis beibehalten und Wiederholungen zusammenfassen.", + "events.route.rateLimit": "Ereignisse pro Minute", + "events.route.rateLimitHelp": "Fenstermaximum pro Route und Kamera.", + "events.route.deliveryPolicy": "Zustellungsrichtlinie", + "events.route.suppressionActive": "Rauschunterdrückung aktiv", + "events.route.everyMatch": "Jede Übereinstimmung", + "events.route.preview": "Route testen", + "events.route.previewing": "Vorschau läuft…", + "events.route.previewResult": "Route-Vorschau", + "events.route.cameraMatches": "{count} Kameras stimmen überein", + "events.route.previewNoPublish": "Die Vorschau validiert die vollständige Regel und löst eine Kameraauswahl auf; sie veröffentlicht niemals ein Ereignis.", + "events.route.systemPreviewHelp": "Systemereignisse umgehen die Kameraauswahl und melden daher null übereinstimmende Kameras in dieser Vorschau.", + "events.route.created": "Ereignisroute erstellt", + "events.route.updated": "Ereignisroute aktualisiert", + "events.route.deleted": "Ereignisroute gelöscht", + "events.route.disabled": "Ereignisroute deaktiviert", + "events.route.enabledMessage": "Ereignisroute aktiviert", + "events.route.deleteConfirm": "Ereignisroute „{name}“ löschen?", + "events.route.validation.name": "Routennamen eingeben.", + "events.route.validation.destination": "Ziel auswählen.", + "events.route.validation.event_types": "Mindestens einen Ereignistyp auswählen.", + "events.route.validation.selector": "Kameraauswahl vervollständigen oder korrigieren.", + "events.route.validation.system_scope": "Kameraauswahlen können nicht mit Systemereignissen verwendet werden.", + "events.route.validation.detection_type": "Erkennungsfilter erfordern den Ereignistyp Objekterkennung.", + "events.route.validation.detection_filter": "Mindestens ein Erkennungslabel, eine Zone oder einen Konfidenzschwellenwert hinzufügen.", + "events.route.validation.confidence": "Mindestkonfidenz muss zwischen 0 und 1 liegen.", + "events.route.validation.predicate_mix": "Erkennungs- und Zustandsfilter können nicht in einer Route kombiniert werden.", + "events.route.validation.health_type": "Zustandsfilter erfordern nur registrierte Systemzustands-Ereignistypen.", + "events.route.validation.health_filter": "Mindestens einen registrierten Zustands- oder Schweregradtyp auswählen.", + "events.route.validation.health_condition": "Wählen Sie nur Zustands-Codes aus, die von der Zustandsregistrierung des Recorders zurückgegeben werden.", + "events.route.validation.health_severity": "Wählen Sie nur Schweregrade aus, die von den ausgewählten Zustands-Ereignistypen unterstützt werden.", + "events.route.validation.timezone": "Geben Sie eine installierte IANA-Zeitzone wie UTC oder America/New_York ein.", + "events.route.validation.schedule_window": "Jedes Zeitfenster benötigt mindestens einen Tag sowie gültige, unterschiedliche Start- und Endzeiten.", + "events.route.validation.suppression": "Unterdrückungswerte müssen ganzzahlig und innerhalb der zulässigen Bereiche liegen.", + "events.schedule.timezone": "Zeitzone", + "events.schedule.timezoneHelp": "Muss in der Zeitzonen-Datenbank des Recorders vorhanden sein.", + "events.schedule.addWindow": "Zeitfenster hinzufügen", + "events.schedule.windowNumber": "Fenster {number}", + "events.schedule.start": "Start", + "events.schedule.end": "Ende", + "events.schedule.sunday": "So", + "events.schedule.monday": "Mo", + "events.schedule.tuesday": "Di", + "events.schedule.wednesday": "Mi", + "events.schedule.thursday": "Do", + "events.schedule.friday": "Fr", + "events.schedule.saturday": "Sa", + "events.destination.add": "Ziel hinzufügen", + "events.destination.addTitle": "MQTT-Ziel hinzufügen", + "events.destination.editTitle": "MQTT-Ziel bearbeiten", + "events.destination.create": "Ziel erstellen", + "events.destination.editorDescription": "Konfigurieren Sie einen persistenten Ereignisausgang. Zugangsdaten sind nur schreibbar und werden nie über die API zurückgegeben.", + "events.destination.default": "Standard-MQTT-Einstellungen", + "events.destination.settingsManaged": "Einstellungen verwaltet", + "events.destination.defaultDescription": "Die vorhandene MQTT-Konfiguration bleibt als mqtt:default verfügbar und wird von {count} Routen verwendet.", + "events.destination.openSettings": "MQTT-Einstellungen öffnen", + "events.destination.emptyTitle": "Keine verwalteten Ziele", + "events.destination.emptyDescription": "Fügen Sie einen weiteren MQTT-Broker für unabhängige Ereigniszustellung an einen Cloud-Connector, ein Automatisierungssystem oder einen Benachrichtigungsdienst hinzu.", + "events.destination.identity": "Zielidentität", + "events.destination.enabled": "Ziel aktiviert", + "events.destination.enabledHelp": "Verbinden und persistente Warteschlange abarbeiten", + "events.destination.active": "Aktiv", + "events.destination.paused": "Pausiert", + "events.destination.pause": "Pausieren", + "events.destination.broker": "Broker", + "events.destination.host": "Broker-Host", + "events.destination.hostHelp": "Nur Hostname oder IP-Adresse; kein URL-Schema angeben.", + "events.destination.port": "Port", + "events.destination.clientId": "Client-ID", + "events.destination.clientIdHelp": "Muss für diese Broker-Verbindung eindeutig sein.", + "events.destination.topic": "Topic", + "events.destination.topicTemplate": "Topic-Vorlage", + "events.destination.topicHelp": "Muss die Tokens für Ereignistyp und Subjekt-ID enthalten; MQTT-Wildcards sind nicht erlaubt.", + "events.destination.keepalive": "Keepalive-Sekunden", + "events.destination.statusTopicTemplate": "Präsenz-Status-Topic", + "events.destination.statusTopicHelp": "Optional. Muss {installation_uuid} enthalten; {destination_uuid} ist ebenfalls verfügbar. MQTT-Wildcards sind nicht erlaubt.", + "events.destination.statusTopicEnabled": "Präsenz ist für dieses Ziel explizit aktiviert. Das Topic wird nie aus dem Ereignis-Topic abgeleitet.", + "events.destination.statusTopicDisabled": "Präsenz ist für dieses Ziel deaktiviert. Dieses Feld leer lassen, um deaktiviert zu bleiben.", + "events.destination.qos": "Quality of Service", + "events.destination.qos0": "einmal senden", + "events.destination.qos1": "mindestens einmal", + "events.destination.qos2": "genau einmal", + "events.destination.authentication": "Authentifizierung", + "events.destination.passwordPreserved": "Leer lassen, um das gespeicherte, nur schreibbare Passwort beizubehalten.", + "events.destination.passwordOptional": "Optional, wenn der Broker anonyme Clients zulässt.", + "events.destination.clearPassword": "Gespeichertes Passwort löschen", + "events.destination.transportSecurity": "Transportsicherheit", + "events.destination.tlsMode": "TLS-Modus", + "events.destination.tlsSystem": "System-Truststore", + "events.destination.tlsCustomCa": "Eigene Zertifizierungsstelle", + "events.destination.tlsMutual": "Mutual TLS", + "events.destination.tlsDisabled": "Deaktiviert (Klartext)", + "events.destination.tlsHelp.system": "Broker-Zertifikat gegen den System-Truststore überprüfen.", + "events.destination.tlsHelp.custom_ca": "Broker anhand einer expliziten PEM-Zertifizierungsstellen-Datei überprüfen.", + "events.destination.tlsHelp.mutual": "Broker mit expliziter CA überprüfen und ein Client-Zertifikat sowie einen Schlüssel vorlegen.", + "events.destination.tlsHelp.disabled": "Keine Transportverschlüsselung oder Broker-Identitätsprüfung.", + "events.destination.caFile": "CA-Datei", + "events.destination.certFile": "Client-Zertifikatsdatei", + "events.destination.keyFile": "Client-Schlüsseldatei", + "events.destination.absolutePathHelp": "Absoluten Pfad verwenden, der für den LightNVR-Dienst lesbar ist.", + "events.destination.plaintextWarning": "Unverschlüsseltes MQTT kann Ereignis-Metadaten und Zugangsdaten offenlegen. Nur in einem vertrauenswürdigen, isolierten Netzwerk verwenden.", + "events.destination.security": "Sicherheit", + "events.destination.tls.system": "Systemzertifikate", + "events.destination.tls.custom_ca": "Eigene CA", + "events.destination.tls.mutual": "Gegenseitiges TLS", + "events.destination.tls.disabled": "Unverschlüsselt", + "events.destination.routes": "Routen", + "events.destination.presence": "Präsenz-Topic", + "events.destination.deleteInUse": "Routen entfernen oder umleiten, bevor dieses Ziel gelöscht wird.", + "events.destination.created": "MQTT-Ziel erstellt", + "events.destination.updated": "MQTT-Ziel aktualisiert", + "events.destination.deleted": "MQTT-Ziel gelöscht", + "events.destination.pausedMessage": "MQTT-Ziel pausiert; eingereihte Ereignisse bleiben bis zum Ablauf erhalten.", + "events.destination.enabledMessage": "MQTT-Ziel aktiviert", + "events.destination.deleteConfirm": "MQTT-Ziel „{name}“ löschen?", + "events.destination.validation.name": "Zielnamen eingeben.", + "events.destination.validation.host": "Broker-Hostname oder IP-Adresse eingeben.", + "events.destination.validation.client_id": "Broker-Client-ID eingeben.", + "events.destination.validation.topic": "Das Topic muss die Tokens für Ereignistyp und Subjekt-ID enthalten und darf keine MQTT-Wildcards enthalten.", + "events.destination.validation.status_topic": "Das optionale Präsenz-Topic muss das Installations-UUID-Token enthalten, nur unterstützte Tokens verwenden und darf keine MQTT-Wildcards enthalten.", + "events.destination.validation.port": "Port muss eine ganze Zahl zwischen 1 und 65535 sein.", + "events.destination.validation.keepalive": "Keepalive muss eine ganze Zahl zwischen 5 und 3600 Sekunden sein.", + "events.destination.validation.qos": "MQTT-QoS 0, 1 oder 2 wählen.", + "events.destination.validation.username": "Ein konfiguriertes Passwort erfordert einen Benutzernamen.", + "events.destination.validation.ca_file": "Dieser TLS-Modus erfordert einen absoluten CA-Dateipfad.", + "events.destination.validation.mutual_files": "Mutual TLS erfordert absolute Pfade für CA, Client-Zertifikat und Client-Schlüssel.", + "fleet.eyebrow": "Kamera-Betrieb", + "fleet.title": "Kamera-Inventar", + "fleet.description": "Kameras in großen Installationen finden, bewerten und organisieren, ohne das gesamte Inventar im Browser zu laden.", + "fleet.summary": "Übersicht zum Flottenstatus", + "fleet.totalCameras": "Übereinstimmende Kameras", + "fleet.needsAttention": "Eingeschränkt", + "fleet.searchLabel": "Kameras suchen", + "fleet.searchPlaceholder": "Name, Adresse, Standort, Tag, Hersteller oder Modell suchen…", + "fleet.resultCount": "{count} Kameras", + "fleet.filters": "Filter", + "fleet.clearFilters": "Filter zurücksetzen", + "fleet.filter.health": "Status", + "fleet.filter.enabled": "Kamerastatus", + "fleet.filter.anyState": "Alle Zustände", + "fleet.filter.recording": "Aufnahmemodus", + "fleet.filter.location": "Standort-Unterbaum", + "fleet.filter.allLocations": "Alle Standorte", + "fleet.filter.tags": "Tags (beliebige Übereinstimmung)", + "fleet.filter.collection": "Kamera-Sammlung", + "fleet.health.unknown": "Unbekannt", + "fleet.health.up": "Online", + "fleet.health.degraded": "Eingeschränkt", + "fleet.health.down": "Offline", + "fleet.health.disabled": "Deaktiviert", + "fleet.recording.off": "Aus", + "fleet.recording.continuous": "Kontinuierlich", + "fleet.recording.detection": "Erkennung", + "fleet.recordingActive": "Aufnahme aktiv", + "fleet.recordingInactive": "Keine Aufnahme", + "fleet.column.camera": "Kamera", + "fleet.column.health": "Status", + "fleet.column.location": "Standort", + "fleet.column.tags": "Tags", + "fleet.column.recording": "Aufnahme", + "fleet.viewLive": "Live", + "fleet.lastFrame": "Letztes Bild", + "fleet.noAddress": "Adresse nicht verfügbar", + "fleet.unassigned": "Nicht zugewiesen", + "fleet.loading": "Kameraflotte wird geladen…", + "fleet.refreshing": "Wird aktualisiert…", + "fleet.loadError": "Kameraflotte konnte nicht geladen werden", + "fleet.emptyTitle": "Keine Kameras konfiguriert", + "fleet.emptyDescription": "Fügen Sie einen Stream hinzu, um ihn im Flotten-Arbeitsbereich verfügbar zu machen.", + "fleet.emptyFilteredTitle": "Keine Kameras entsprechen dieser Ansicht", + "fleet.emptyFilteredDescription": "Erweitern Sie die Suche oder entfernen Sie einen oder mehrere Filter.", + "fleet.paginationSummary": "Zeige {first}–{last} von {total}", + "fleet.perPage": "Pro Seite", + "fleet.pageOf": "Seite {page} von {pages}", + "fleet.selectPage": "Alle Kameras auf dieser Seite auswählen", + "fleet.selectCamera": "{name} auswählen", + "fleet.selectedCount": "{count} Kameras ausgewählt", + "fleet.organizeSelected": "Auswahl organisieren", + "fleet.clearSelection": "Auswahl aufheben", + "fleet.organization.manage": "Organisation verwalten", + "fleet.organization.title": "Kameraorganisation", + "fleet.organization.description": "Verwalten Sie eine wiederverwendbare Standort-Hierarchie und ein normiertes Tag-Verzeichnis für die Kameraflotte.", + "fleet.organization.locations": "Standorte", + "fleet.organization.tags": "Tags", + "fleet.organization.locationsDescription": "Standorte, Gebäude, Etagen und Betriebsbereiche als navigierbare Hierarchie abbilden.", + "fleet.organization.tagsDescription": "Verwenden Sie ein verwaltetes Tag-Verzeichnis anstelle inkonsistenter Freitext-Bezeichnungen.", + "fleet.organization.addRoot": "Standort oberster Ebene hinzufügen", + "fleet.organization.addLocation": "Standort hinzufügen", + "fleet.organization.editLocation": "Standort bearbeiten", + "fleet.organization.addChild": "Untergeordneten Eintrag hinzufügen", + "fleet.organization.type": "Typ", + "fleet.organization.parent": "Übergeordneter Standort", + "fleet.organization.topLevel": "Oberste Ebene", + "fleet.organization.sortOrder": "Sortierreihenfolge", + "fleet.organization.contents": "Inhalte", + "fleet.organization.cameras": "Kameras", + "fleet.organization.system": "System", + "fleet.organization.contentCounts": "{cameras} Kameras · {children} untergeordnete Standorte", + "fleet.organization.locationNotEmpty": "Kameras verschieben und untergeordnete Standorte zuerst löschen", + "fleet.organization.noLocations": "Keine Standorte konfiguriert.", + "fleet.organization.locationCreated": "Standort erstellt", + "fleet.organization.locationUpdated": "Standort aktualisiert", + "fleet.organization.locationDeleted": "Standort gelöscht", + "fleet.organization.deleteLocationConfirm": "Standort „{name}“ löschen?", + "fleet.organization.addTag": "Tag hinzufügen", + "fleet.organization.editTag": "Tag bearbeiten", + "fleet.organization.tagLabel": "Tag", + "fleet.organization.color": "Farbe (#RRGGBB)", + "fleet.organization.tagDescription": "Beschreibung", + "fleet.organization.noTags": "Keine normalisierten Tags konfiguriert.", + "fleet.organization.tagCreated": "Tag erstellt", + "fleet.organization.tagUpdated": "Tag aktualisiert", + "fleet.organization.tagDeleted": "Tag gelöscht", + "fleet.organization.deleteTagConfirm": "„{name}“ löschen? Er ist derzeit {count} Kameras zugewiesen.", + "fleet.organization.merge": "Zusammenführen", + "fleet.organization.mergeTagNamed": "„{name}“ zusammenführen", + "fleet.organization.mergeInto": "Zusammenführen mit", + "fleet.organization.chooseTag": "Zu behaltendes Tag auswählen", + "fleet.organization.mergeWarning": "Alle Kamera-Zuweisungen werden auf das beibehaltene Tag übertragen; das Quell-Tag wird anschließend entfernt.", + "fleet.organization.tagsMerged": "Tags zusammengeführt", + "fleet.organization.saveError": "Speichern fehlgeschlagen: {message}", + "settings.health.retention": "Ereignis-Aufbewahrung", + "settings.health.conditions": "Bedingungsüberschreibungen", + "settings.health.conditionsHelp": "Überschreiben Sie nur Bedingungscodes und Einheiten, die von der Registry der wirksamen Richtlinien zurückgegeben werden.", + "settings.health.conditionOverride": "Bedingungsüberschreibung", + "settings.health.overrideMode": "Überschreibungsmodus", + "settings.health.overrideModeHelp": "Übernehmen Sie das ausgewählte Profil, wählen Sie ein anderes begrenztes Profil, deaktivieren Sie die Bedingung oder legen Sie validierte Schwellenwerte fest.", + "settings.health.profileDefault": "Ausgewähltes Profil verwenden", + "settings.health.custom": "Benutzerdefinierte Schwellenwerte", + "settings.health.warning": "Warnschwelle", + "settings.health.critical": "Kritische Schwelle", + "settings.health.recovery": "Erholungsschwelle", + "settings.health.warning_for_seconds": "Warnverweilzeit in Sekunden", + "settings.health.critical_for_seconds": "Kritische Verweilzeit in Sekunden", + "settings.health.recovery_for_seconds": "Erholungsverweilzeit in Sekunden", + "settings.health.clearOverrides": "Überschreibungen löschen", + "settings.health.registryUnavailable": "Der Server hat keine Bedingungs-Registry zurückgegeben. Bitte neu laden, bevor Überschreibungen bearbeitet werden.", + "settings.health.resetDefaults": "Standardwerte für Systemzustand zurücksetzen", + "settings.health.reloadGuidance": "Das Speichern erfolgt atomar. Nach erfolgreichem Speichern neu laden, um die wirksame Richtlinie zu bestätigen; Neustart nur, wenn der Server dies ausdrücklich anfordert.", + "settings.health.validation.profile": "Wählen Sie ein unterstütztes Systemzustandsprofil.", + "settings.health.validation.provider": "Wählen Sie einen unterstützten Hardware-Provider.", + "settings.health.validation.healthFastIntervalSeconds": "Das schnelle Intervall muss eine ganze Zahl zwischen 5 und 60 Sekunden sein.", + "settings.health.validation.healthNormalIntervalSeconds": "Das normale Intervall muss eine ganze Zahl zwischen 15 und 600 Sekunden sein.", + "settings.health.validation.healthSlowIntervalSeconds": "Das langsame Intervall muss eine ganze Zahl zwischen 60 und 3600 Sekunden sein.", + "settings.health.validation.healthDeviceIntervalSeconds": "Das Geräteintervall muss eine ganze Zahl zwischen 300 und 86400 Sekunden sein.", + "settings.health.validation.healthPresenceIntervalSeconds": "Das Präsenzintervall muss eine ganze Zahl zwischen 15 und 3600 Sekunden sein.", + "settings.health.validation.healthIncidentRetentionDays": "Die Ereignis-Aufbewahrung muss eine ganze Zahl zwischen 7 und 3650 Tagen sein.", + "settings.health.validation.ordered": "Die Abtastintervalle müssen in der Reihenfolge schnell, normal, langsam, dann Gerät angeordnet sein.", + "settings.health.validation.overrides": "Bedingungsüberschreibungen müssen eindeutige Codes und unterstützte Profile aus der Server-Registry verwenden.", + "settings.health.validation.thresholds": "Benutzerdefinierte Schwellenwerte müssen endliche Werte innerhalb der Einheitsgrenzen der Bedingung sein.", + "settings.health.validation.thresholdOrder": "Warn-, kritische und Erholungsschwellen müssen die Alarmrichtung und Hysterese der Bedingung beibehalten.", + "settings.health.validation.dwell": "Verweilzeiten müssen ganze Sekunden innerhalb von sieben Tagen sein; Warn- und Erholungsverweilzeit dürfen nicht null sein.", + "workspaces.title": "Operator-Arbeitsbereiche", + "tokens.actions": "Zulässige Aktionen", + "tokens.actionsHelp": "Wählen Sie nur, was diese Integration benötigt. Destruktive Aktionen verdienen ein eigenes Token.", + "tokens.destructive": "Destruktiv", + "tokens.noEnforcedActions": "In dieser Serverversion sind keine tokenfähigen Aktionen verfügbar.", + "tokens.scope.label": "Kamerabereich", + "tokens.scope.all": "Gesamter Kamerabestand", + "tokens.scope.collection": "Gemeinsame Sammlung", + "tokens.scope.selector": "Benutzerdefinierter Selektor", + "tokens.scope.chooseCollection": "Gemeinsame Kamerasammlung", + "tokens.scope.allValue": "Gesamter Bestand", + "tokens.scope.collectionValue": "Sammlung: {name}", + "tokens.scope.selectorValue": "Benutzerdefinierter dynamischer Selektor", + "tokens.create": "Token erstellen", + "tokens.creating": "Token wird erstellt…", + "tokens.createdSuccess": "Token mit Gültigkeitsbereich erstellt", + "tokens.createError": "API-Token konnte nicht erstellt werden: {message}", + "tokens.invalidResponse": "Der Server hat eine unvollständige Zugangsdaten-Antwort zurückgegeben.", + "tokens.existingTitle": "Vorhandene Tokens", + "tokens.existingDescription": "Nach der Erstellung sind nur noch Präfixe und Metadaten verfügbar.", + "tokens.emptyTitle": "Keine aktiven Tokens", + "tokens.emptyDescription": "Erstellen Sie ein Token mit Gültigkeitsbereich für die erste Integration, die API-Zugriff benötigt.", + "tokens.showInactive": "{count} inaktive anzeigen", + "tokens.status.active": "Aktiv", + "tokens.status.expired": "Abgelaufen", + "tokens.status.revoked": "Widerrufen", + "tokens.expires": "Gültig bis", + "tokens.expiresValue": "Gültig bis {date}", + "tokens.created": "Erstellt", + "tokens.lastUsed": "Zuletzt verwendet", + "tokens.revoke": "Widerrufen", + "tokens.revoking": "Wird widerrufen…", + "tokens.revokeConfirm": "„{description}“ widerrufen? Anfragen damit funktionieren sofort nicht mehr.", + "audit.retention": "Aufbewahrung", + "audit.retentionDescription": "Ereignisse werden derzeit {days} Tage lang aufbewahrt. Eine Verringerung dieses Werts löscht sofort ältere Einträge.", + "audit.retentionDays": "Tage", + "audit.retentionInvalid": "Wählen Sie einen Aufbewahrungszeitraum zwischen 1 und 3650 Tagen.", + "audit.retentionSaved": "Audit-Aufbewahrung gespeichert; {count} abgelaufene Ereignisse gelöscht", + "audit.retentionError": "Audit-Aufbewahrung konnte nicht gespeichert werden: {message}", + "audit.filters": "Filter", + "audit.clearFilters": "Filter zurücksetzen", + "audit.applyFilters": "Filter anwenden", + "audit.actor": "Akteur", + "audit.unauthenticated": "Nicht authentifiziert", + "audit.outcome": "Ergebnis", + "audit.action": "Genaue Aktion", + "audit.filterToAction": "Auf diese Aktion filtern", + "audit.since": "Von", + "audit.until": "Bis", + "audit.invalidDateRange": "Das Von-Datum muss vor dem Bis-Datum liegen.", + "audit.source": "Quelladresse", + "audit.target": "Ziel", + "audit.targetUuid": "Ziel-UUID", + "audit.noTarget": "Systemweit", + "audit.requestId": "Anfrage-ID", + "audit.apiToken": "Token-ID mit Gültigkeitsbereich", + "audit.showDetails": "Details anzeigen", + "audit.hideDetails": "Details ausblenden", + "audit.pageSize": "Pro Seite", + "audit.resultRange": "{start}–{end} von {total} angezeigt", + "audit.empty": "Keine passenden Audit-Ereignisse", + "audit.emptyDescription": "Versuchen Sie, einen oder mehrere Filter zurückzusetzen, oder warten Sie auf neue Sicherheitsaktivitäten.", + "audit.exportPage": "Diese Seite exportieren", + "audit.exporting": "Exportiere…", + "audit.exported": "Audit-Seite exportiert", + "fleet.organization.deleteError": "Löschen fehlgeschlagen: {message}", + "fleet.locationType.site": "Standort", + "fleet.locationType.building": "Gebäude", + "fleet.locationType.floor": "Etage", + "fleet.locationType.area": "Bereich", + "fleet.locationType.zone": "Zone", + "fleet.locationType.system": "System", + "fleet.bulk.title": "Ausgewählte Kameras organisieren", + "fleet.bulk.description": "Standort- und Tag-Änderungen an {count} Kameras mit begrenzter Parallelität anwenden.", + "fleet.bulk.location": "Standortzuweisung", + "fleet.bulk.locationHelp": "Alle ausgewählten Kameras werden an den gewählten Standort verschoben.", + "fleet.bulk.keepLocations": "Aktuelle Standorte beibehalten", + "fleet.bulk.tags": "Tag-Zuweisung", + "fleet.bulk.tagsHelp": "Tags hinzufügen oder entfernen, ohne andere Zuweisungen zu ändern, oder den vollständigen Tag-Satz explizit ersetzen.", + "fleet.bulk.tagOperation.none": "Beibehalten", + "fleet.bulk.tagOperation.add": "Hinzufügen", + "fleet.bulk.tagOperation.remove": "Entfernen", + "fleet.bulk.tagOperation.replace": "Alle ersetzen", + "fleet.bulk.replaceWarning": "Alle ersetzen entfernt alle aktuellen Tags, bevor diese Auswahl angewendet wird. Eine leere Auswahl löscht alle Tags.", + "fleet.bulk.apply": "Änderungen anwenden", + "fleet.bulk.working": "Änderungen werden angewendet…", + "fleet.bulk.success": "{count} Kameras aktualisiert", + "fleet.bulk.partial": "{succeeded} Kameras aktualisiert; {failed} fehlgeschlagen", + "fleet.bulk.error": "Kameras konnten nicht organisiert werden: {message}", + "fleet.bulk.failures": "Kameras, die nicht aktualisiert werden konnten", + "fleet.queues.degraded": "Eingeschränkte Streams", + "fleet.queues.offline": "Offline-Kameras", + "fleet.queues.oldest": "Ältester: {time}", + "fleet.queues.noneActive": "Keine aktiven Bedingungen", + "fleet.views.title": "Gespeicherte Ansichten", + "fleet.views.choose": "Gespeicherte Ansicht auswählen", + "fleet.views.none": "Noch keine gespeicherten Ansichten", + "fleet.views.shared": "Geteilt", + "fleet.views.saveCurrent": "Aktuelle Ansicht speichern", + "fleet.views.name": "Ansichtsname", + "fleet.views.share": "Mit allen Operatoren teilen", + "fleet.views.saved": "Flottenansicht gespeichert", + "fleet.views.saveError": "Ansicht konnte nicht gespeichert werden: {message}", + "fleet.views.deleted": "Flottenansicht gelöscht", + "fleet.views.deleteConfirm": "Gespeicherte Ansicht \"{name}\" löschen?", + "fleet.views.deleteError": "Ansicht konnte nicht gelöscht werden: {message}", + "fleet.views.unsupported": "Dieser gespeicherte Selektor kann nicht durch die aktuellen Filtersteuerungen dargestellt werden.", + "collections.manage": "Sammlungen", + "collections.all": "Alle Sammlungen", + "collections.filter": "Sammlung", + "collections.loadMembersError": "Kameras der Sammlung konnten nicht geladen werden: {message}", + "collections.title": "Kamera-Sammlungen", + "collections.subtitle": "Erstellen Sie wiederverwendbare Kameragruppen für Operationen, gespeicherte Ansichten und nachgelagerte Workflows.", + "collections.listDescription": "Statische Sammlungen behalten eine explizite Mitgliedschaft; intelligente Sammlungen bewerten kontinuierlich Flottenregeln.", + "collections.create": "Sammlung erstellen", + "collections.edit": "Sammlung bearbeiten", + "collections.editorDescription": "Sammlungsdefinitionen verwenden stabile Kamera-, Standort- und Tag-UUIDs.", + "collections.backToList": "Zurück zu den Sammlungen", + "collections.type": "Sammlungstyp", + "collections.type.static": "Statisch", + "collections.type.smart": "Intelligent", + "collections.description": "Beschreibung", + "collections.shared": "Gemeinsame Sammlung", + "collections.sharedHelp": "Anderen autorisierten Benutzern erlauben, diese Sammlung zu sehen; Kamera-Zugriffsregeln gelten weiterhin.", + "collections.typeChangeWarning": "Das Ändern des Sammlungstyps ersetzt das Mitgliedschaftsmodell. Statische Mitglieder oder intelligente Regeln des vorherigen Typs gelten nicht mehr.", + "collections.selectorError": "Selektor ist ungültig: {message}", + "collections.created": "Sammlung erstellt", + "collections.updated": "Sammlung aktualisiert", + "collections.saveError": "Sammlung konnte nicht gespeichert werden: {message}", + "collections.loadError": "Sammlung konnte nicht geladen werden: {message}", + "collections.cameras": "Kameras", + "collections.visibility.shared": "Gemeinsam", + "collections.visibility.private": "Privat", + "collections.selectorRedacted": "Regeln privat", + "collections.emptyTitle": "Noch keine Sammlungen", + "collections.emptyAdmin": "Erstellen Sie eine statische Gruppe oder eine regelbasierte Ansicht, um Kameraauswahlen wiederzuverwenden.", + "collections.emptyViewer": "Für Ihren Kamerabereich sind keine gemeinsamen Sammlungen verfügbar.", + "collections.deleteConfirm": "Sammlung „{name}\" löschen?", + "collections.deleted": "Sammlung gelöscht", + "collections.deleteError": "Sammlung konnte nicht gelöscht werden: {message}", + "collections.preview.title": "Regelvorschau", + "collections.preview.matches": "{count} passende Kameras", + "collections.preview.action": "Vorschau", + "collections.preview.hide": "Vorschau ausblenden", + "collections.preview.loading": "Wird ausgewertet…", + "collections.preview.empty": "Derzeit entsprechen keine Kameras den Kriterien.", + "collections.preview.sample": "Zeigt eine Auswahl von {count} Kameras aus {total} Treffern.", + "collections.preview.error": "Sammlungsvorschau fehlgeschlagen: {message}", + "collections.members.title": "Statische Mitglieder", + "collections.members.selected": "{count} Kameras über alle Seiten ausgewählt", + "collections.members.search": "Kameras suchen…", + "collections.members.selectPage": "Diese Seite auswählen", + "collections.members.empty": "Keine Kameras entsprechen dieser Suche.", + "collections.builder.title": "Intelligente Regeln", + "collections.builder.description": "Regeln werden anhand der aktuellen Kameraorganisation, -konfiguration, -fähigkeiten und des Zustands ausgewertet.", + "collections.builder.match": "Entspricht", + "collections.builder.allRules": "alle Regeln", + "collections.builder.anyRule": "eine Regel", + "collections.builder.addRule": "Regel hinzufügen", + "collections.builder.removeRule": "Regel entfernen", + "collections.builder.matchesAll": "Ohne vollständige Regeln entspricht diese Sammlung jeder Kamera im autorisierten Bereich des Benutzers.", + "collections.builder.incompleteRule": "Vervollständigen oder entfernen Sie jede Regel vor dem Speichern.", + "collections.builder.chooseLocation": "Standort-Unterbaum auswählen", + "collections.builder.vendorPlaceholder": "Anbieternamen, kommagetrennt", + "collections.builder.modelPlaceholder": "Modellnamen, kommagetrennt", + "collections.builder.advancedMode": "Erweitertes JSON", + "collections.builder.visualMode": "Visueller Builder", + "collections.builder.cannotVisualize": "Dieser Selektor enthält verschachtelte oder erweiterte Logik, die der visuelle Builder nicht sicher darstellen kann.", + "collections.rule.location_subtree": "Standort ist innerhalb", + "collections.rule.camera_uuid": "Bestimmte Kameras", + "collections.rule.tag_any": "Hat ein beliebiges Tag", + "collections.rule.tag_all": "Hat alle Tags", + "collections.rule.tag_none": "Hat keines der Tags", + "collections.rule.health": "Zustand ist", + "collections.rule.enabled": "Kamera ist", + "collections.rule.recording_mode": "Aufnahmemodus ist", + "collections.rule.capability_any": "Hat eine beliebige Funktion", + "collections.rule.capability_all": "Hat alle Funktionen", + "collections.rule.vendor": "Anbieter ist", + "collections.rule.model": "Modell ist", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Audio-Rückkanal", + "streamHealth.observedFps": "Beobachtete FPS", + "streamHealth.expectedFps": "Erwartet", + "streamHealth.fpsHelp": "Von LightNVR beobachtet; erwartet stammt aus den Metadaten des Kamerastreams.", + "login.passwordChanged": "Passwort erfolgreich geändert. Melden Sie sich mit Ihrem neuen Passwort an.", + "passwordChangeRequired.title": "Standardpasswort ändern", + "passwordChangeRequired.description": "Diese Installation verwendet noch das Standard-Passwort des Administrators. Ersetzen Sie es, bevor Sie mit LightNVR fortfahren. MFA wird, wenn aktiviert, bei Ihrer nächsten Anmeldung überprüft.", + "passwordChangeRequired.currentPassword": "Aktuelles Passwort", + "passwordChangeRequired.newPassword": "Neues Passwort", + "passwordChangeRequired.confirmPassword": "Neues Passwort bestätigen", + "passwordChangeRequired.passwordHelp": "Verwenden Sie mindestens 8 Zeichen. Das Passwort darf nicht „admin\" sein.", + "passwordChangeRequired.submit": "Passwort ändern", + "passwordChangeRequired.saving": "Passwort wird geändert…", + "passwordChangeRequired.error.currentRequired": "Aktuelles Passwort eingeben.", + "passwordChangeRequired.error.tooShort": "Das neue Passwort muss mindestens 8 Zeichen lang sein.", + "passwordChangeRequired.error.defaultPassword": "Das neue Passwort darf nicht „admin\" sein.", + "passwordChangeRequired.error.mismatch": "Die neuen Passwörter stimmen nicht überein.", + "passwordChangeRequired.error.generic": "Das Passwort konnte nicht geändert werden. Bitte erneut versuchen.", + "settings.tab.health": "Zustand", + "settings.tab.workspaces": "Arbeitsbereiche", + "settings.health.title": "Host- und Hardwarezustand", + "settings.health.description": "Betriebssystem- und Hardwareüberwachung mit begrenztem Umfang konfigurieren, ohne Gerätepfade oder Geheimnisse preiszugeben.", + "settings.health.enabled": "Zustandsüberwachung aktivieren", + "settings.health.enabledHelp": "Unterstützte Host-, Dienst-, Speicher-, Netzwerk- und Hardware-Signale erfassen.", + "settings.health.profile": "Richtlinienprofil", + "settings.health.profileHelp": "Ausgewogen ist die Standardoption; Konservativ erfordert stärkere Hinweise vor einer Warnung.", + "settings.health.profile.balanced": "Ausgewogen", + "settings.health.profile.conservative": "Konservativ", + "settings.health.hardwareProvider": "Hardware-Provider", + "settings.health.provider.auto": "Automatisch (Kernel-Provider)", + "settings.health.provider.smartctl": "smartctl (explizit)", + "settings.health.providerHelp.auto": "Verwendet nur begrenzte sysfs-, NVMe- und Kernel-Provider; smartctl wird nie automatisch erkannt.", + "settings.health.providerHelp.smartctl": "Aktiviert explizit den optionalen, begrenzten smartctl-JSON-Provider für erkannte Geräte.", + "settings.health.providerHelp.disabled": "Deaktiviert optionale Hardware-Provider, während die portable Zustandsüberwachung verfügbar bleibt.", + "settings.health.writeProbe": "Speicher-Schreibtest aktivieren", + "settings.health.writeProbeHelp": "Führt regelmäßig den konfigurierten, begrenzten Schreibtest auf dem Aufzeichnungsziel durch.", + "settings.health.cadences": "Abtastintervalle", + "settings.health.cadencesHelp": "Die Intervalle müssen von schnell bis Geräteabtastung geordnet und innerhalb der Servergrenzen liegen.", + "settings.health.fastInterval": "Schnelles Intervall", + "settings.health.normalInterval": "Normales Intervall", + "settings.health.slowInterval": "Langsames Intervall", + "settings.health.deviceInterval": "Geräteintervall", + "settings.health.presenceInterval": "Präsenzintervall", + "workspaces.description": "Wählen Sie aus, welche spezialisierten Arbeitsbereiche in Ihrer Navigation und im Seitenrahmen angezeigt werden.", + "workspaces.saved": "Arbeitsbereich-Einstellungen gespeichert", + "workspaces.saveError": "Arbeitsbereich-Einstellungen konnten nicht gespeichert werden: {message}", + "workspaces.loadError": "Arbeitsbereich-Einstellungen konnten nicht geladen werden.", + "workspaces.showWorkspace": "{name} anzeigen", + "workspaces.authorizationNote": "Dies steuert nur die Darstellung. Direkte URLs und API-Zugriff folgen weiterhin Ihrer Autorisierungsrichtlinie.", + "workspaces.liveNavigator": "Erweiterter Live-Navigator", + "workspaces.liveNavigatorDescription": "Standortbaum, Verfügbarkeitsfilter, gespeicherte Layouts und aktuelle Ereignisse.", + "workspaces.investigation": "Ermittlung", + "workspaces.investigationDescription": "Aufgezeichnete Beweismittel durchsuchen, korrelieren, schützen und exportieren.", + "settings.reduceMotion": "Bewegung reduzieren", + "settings.reduceMotionHelp": "Deaktiviert nicht wesentliche Animationen und Übergänge. „Auto\" folgt der Systemeinstellung Ihres Betriebssystems.", + "settings.reduceMotionPreference": "Einstellung zur Bewegungsreduzierung", + "settings.reduceMotionAuto": "Auto", + "settings.reduceMotionOn": "Ein", + "settings.reduceMotionOff": "Aus", + "settings.audioCompliance": "Audio-Compliance", + "settings.disableAudioGlobally": "Audio für diese Instanz deaktivieren", + "settings.audioDisabled": "Audio ist global deaktiviert", + "settings.audioComplianceHelp": "Verhindert Live-Hören, Gegensprechen und Audio in neuen Aufnahmen für diese Instanz. Beim Speichern werden aktive go2rtc-Medien-Sitzungen neu gestartet. Bestehende Aufnahmen werden nicht geändert.", + "tokens.manage": "API-Zugriff verwalten", + "tokens.title": "API-Zugriff — {username}", + "tokens.description": "Erstellen Sie eng umgrenzte Zugangsdaten für Integrationen und widerrufen Sie diese einzeln.", + "tokens.recommendedTitle": "Umgrenzte Tokens werden empfohlen", + "tokens.recommendedDescription": "Jedes Token läuft ab, hat explizite Aktionen und einen Kamera-Bereich und kann die aktuelle Zugriffsrichtlinie des Benutzers niemals überschreiten.", + "tokens.coverageNotice": "Verfügbare Berechtigungen entsprechen dem, was dieser Server durchsetzt. Ein Token kann nur Berechtigungen nutzen, die sein Benutzer bereits besitzt.", + "tokens.createTitle": "Umgrenztes Token erstellen", + "tokens.createDescription": "Verwenden Sie ein Token pro Integration, damit es identifiziert, rotiert und widerrufen werden kann, ohne andere zu beeinträchtigen.", + "tokens.name": "Integrationsname", + "tokens.namePlaceholder": "z. B. Nordgarage PTZ-Bridge", + "tokens.expiry": "Läuft ab nach", + "tokens.expiryDays": "{days} Tage", + "tokens.revokedSuccess": "API-Token widerrufen", + "tokens.revokeError": "API-Token konnte nicht widerrufen werden: {message}", + "tokens.validation.missing_description": "Benennen Sie die Integration, die dieses Token verwenden wird.", + "tokens.validation.description_too_long": "Der Integrationsname muss unter 128 Zeichen bleiben.", + "tokens.validation.invalid_expiry": "Wählen Sie eine Token-Gültigkeitsdauer zwischen 1 und 365 Tagen.", + "tokens.validation.missing_actions": "Wählen Sie mindestens eine erlaubte Aktion.", + "tokens.validation.invalid_action": "Eine oder mehrere ausgewählte Aktionen sind auf diesem Server nicht tokenfähig.", + "tokens.validation.invalid_scope": "Wählen Sie einen gültigen Kamera-Berechtigungsumfang.", + "tokens.validation.requires_all_scope": "Nicht-Kamera-Berechtigungen erfordern den Bereich „Gesamter Kamerabestand\". Wählen Sie diesen Bereich oder entfernen Sie diese Berechtigungen.", + "tokens.validation.missing_collection": "Wählen Sie eine verfügbare freigegebene Sammlung.", + "tokens.validation.invalid_selector": "Vervollständigen oder korrigieren Sie die benutzerdefinierte Kameraauswahl.", + "tokens.secret.oneTime": "Einmalig angezeigt", + "tokens.secret.scopedTitle": "Dieses Token mit Berechtigungsumfang jetzt speichern", + "tokens.secret.legacyTitle": "Diesen Legacy-API-Schlüssel jetzt speichern", + "tokens.secret.scopedDescription": "lightNVR speichert nur einen Hash dieses Tokens. Falls es verloren geht, widerrufen Sie es und erstellen Sie ein neues.", + "tokens.secret.legacyDescription": "Dieser Kompatibilitätsschlüssel wird hier nur einmal angezeigt. Die Generierung eines neuen Schlüssels macht ihn ungültig.", + "tokens.secret.value": "API-Zugangsdaten", + "tokens.secret.copied": "Kopiert", + "tokens.secret.copySuccess": "API-Zugangsdaten kopiert", + "tokens.secret.copyError": "Automatisches Kopieren fehlgeschlagen; wählen Sie die Zugangsdaten manuell aus und kopieren Sie sie.", + "tokens.secret.savedConfirm": "Ich habe diese Zugangsdaten sicher gespeichert", + "tokens.secret.savedHelp": "Bestätigen schließt diesen Dialog. Der vollständige Wert kann nicht erneut angezeigt werden.", + "tokens.legacy.title": "Legacy-Kompatibilitätsschlüssel", + "tokens.legacy.description": "Der Legacy-Schlüssel hat den vollständigen Zugriff dieses Benutzers, läuft nicht ab und kann nicht nach Kamera oder Aktion eingeschränkt werden.", + "tokens.legacy.warning": "Generieren Sie ihn nur für eine bestehende Integration, deren Endpunkte nicht auf die Durchsetzung berechtigter Tokens umgestellt wurden. Die Generierung macht den vorherigen Legacy-Schlüssel sofort ungültig.", + "tokens.legacy.generate": "Legacy-Schlüssel generieren", + "tokens.legacy.confirm": "Neuen Legacy-Schlüssel generieren? Dies macht den aktuellen Legacy-Schlüssel des Benutzers sofort ungültig.", + "tokens.legacy.createdSuccess": "Legacy-API-Schlüssel generiert", + "tokens.legacy.createError": "Legacy-API-Schlüssel konnte nicht generiert werden: {message}", + "audit.manage": "Audit-Verlauf", + "audit.title": "Sicherheits- und Zugriffsaudit", + "audit.description": "Verfolgen Sie Anmeldeergebnisse, Zugriffsentscheidungen und sensible Richtlinienänderungen, ohne Zugangsdaten preiszugeben.", + "audit.exportError": "Audit-Ereignisse konnten nicht exportiert werden: {message}", + "audit.pagination": "Seiten des Audit-Verlaufs", + "audit.page": "Seite {page}", + "audit.modesTitle": "Zugelassene Entscheidungen", + "audit.modesDescription": "Legen Sie fest, wie erlaubter Lesezugriff für jede Aktion protokolliert wird. Anfragende Änderungen, Ablehnungen, Fehler und Anmeldungen werden immer protokolliert. „Zusammenfassen\" erzeugt einen Eintrag pro Benutzer, Kamera und Client alle {minutes} Minuten mit Anzahl.", + "audit.mode.record": "Einzeln aufzeichnen", + "audit.mode.summarize": "Zusammenfassen", + "audit.mode.off": "Aus", + "audit.modeOffWarning": "Zugriffe auf diese Aktion werden nicht mehr im Audit-Verlauf angezeigt.", + "audit.modesSaved": "Audit-Entscheidungsmodi gespeichert", + "audit.modesError": "Audit-Entscheidungsmodi konnten nicht gespeichert werden: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Ereignistyp", + "audit.eventTypeSummary": "Zusammenfassungen", + "audit.eventTypeDecision": "Einzelne Entscheidungen", + "access.cameraSearch": "Kameras suchen", + "access.cameraSearchPlaceholder": "Mindestens zwei Zeichen eingeben, um zu suchen…", + "access.cameraSearchHint": "Suche nach Kameraname, UUID, Adresse, Standort, Tag, Hersteller oder Modell.", + "access.cameraSelected": "Ausgewählt", + "access.cameraAdd": "Hinzufügen", + "access.cameraLimit": "Ein Selektor kann maximal 64 explizite Kameras enthalten. Verwenden Sie eine Standort- oder Tag-Regel für größere Bereiche.", + "access.roles.manage": "Rollen verwalten", + "access.roles.title": "Autorisierungsrollen", + "access.roles.description": "Aktionen zu wiederverwendbaren Rollen bündeln und diese auf Kamerabereiche anwenden.", + "access.roles.create": "Rolle erstellen", + "access.roles.newRole": "Neue Rolle", + "access.roles.copyName": "{name} Kopie", + "access.roles.clone": "Klonen", + "access.roles.builtin": "Integriert", + "access.roles.builtinHelp": "Integrierte Rollen sind feste, upgrade-sichere Vorlagen. Klonen Sie eine, um sie anzupassen.", + "access.roles.actionCount": "{count} Aktionen", + "access.roles.destructive": "Sensible Aktion", + "access.roles.notEnforced": "Noch nicht durch einen Endpunkt durchgesetzt", + "access.roles.destructiveWarning": "Diese Rolle kann Konfiguration oder Beweismittel ändern. Gewähren Sie sie nur über die Bereiche, in denen diese Berechtigung erforderlich ist.", + "access.roles.created": "Rolle erstellt", + "access.roles.updated": "Rolle aktualisiert", + "access.roles.deleted": "Rolle gelöscht", + "access.roles.saveError": "Rolle konnte nicht gespeichert werden: {message}", + "access.roles.deleteError": "Rolle konnte nicht gelöscht werden: {message}", + "access.roles.deleteConfirm": "Rolle \"{name}\" löschen? Rollen, auf die durch Zuweisungen verwiesen wird, können nicht gelöscht werden.", + "access.policy.manage": "Zugriff verwalten", + "access.policy.column": "Zugriff", + "access.policy.scopedShort": "Bereichsbasiert", + "access.policy.title": "Zugriffsrichtlinie — {username}", + "access.policy.description": "Standardmäßig verweigernde Rollen-Zuweisungen verwalten und deren Kamera-Bereiche anzeigen.", + "access.policy.tab.grants": "Zuweisungen", + "access.policy.tab.test": "Zugriff testen", + "access.policy.scopedWarning": "Nur Aktionen, die durch eine passende Zuweisung und einen Kamera-Bereich erlaubt sind, funktionieren.", + "access.policy.grants": "Rollen-Zuweisungen", + "access.policy.grantsDescription": "Eine Zuweisung kombiniert eine Rolle mit der gesamten Kameraflotte, einer gemeinsamen Sammlung oder einem benutzerdefinierten Kamera-Selektor.", + "access.policy.addGrant": "Zuweisung hinzufügen", + "access.policy.noGrants": "Keine Zuweisungen konfiguriert", + "access.policy.noGrantsHelp": "Fügen Sie mindestens eine Zuweisung hinzu, bevor Sie die bereichsbasierte Richtlinie aktivieren, es sei denn, dieser Benutzer soll keinen Zugriff haben.", + "access.policy.role": "Rolle", + "access.policy.chooseRole": "Rolle auswählen", + "access.policy.scope": "Kamera-Bereich", + "access.policy.allCameras": "Gesamte Kameraflotte", + "access.policy.collectionScope": "Gemeinsame Sammlung", + "access.policy.collection": "Kamera-Sammlung", + "access.policy.chooseCollection": "Gemeinsame Sammlung auswählen", + "access.policy.collectionHelp": "Der Zugriff folgt der Sammlung, wenn Kameras hinzugefügt, entfernt oder durch deren Regeln zugeordnet werden.", + "access.policy.dynamicScope": "Dynamischer Selektor", + "access.policy.activateConfirm": "Standardmäßig verweigernde bereichsbasierte Richtlinie für {username} aktivieren? Aktionen ohne passende Zuweisung werden verweigert.", + "access.policy.emptyConfirm": "Bereichsbasierte Richtlinie für {username} ohne Zuweisungen aktivieren? Dies entfernt absichtlich alle richtlinienkontrollierten Zugriffe.", + "access.policy.saved": "Zugriffsrichtlinie gespeichert", + "access.policy.saveError": "Zugriffsrichtlinie konnte nicht gespeichert werden: {message}", + "access.policy.version": "Richtlinienversion {version}", + "access.policy.unsaved": "Ungespeicherte Änderungen", + "access.policy.validation.invalid_mode": "Gültigen Auswertungsmodus wählen.", + "access.policy.validation.missing_role": "Jede Berechtigung muss auf eine verfügbare Rolle verweisen.", + "access.policy.validation.invalid_scope": "Jede Berechtigung muss einen Flotten-, Sammlungs- oder Selektor-Bereich verwenden.", + "access.policy.validation.invalid_selector": "Jeden Kameraselektor vor dem Speichern vervollständigen oder korrigieren.", + "access.policy.validation.missing_collection": "Für jede Sammlungs-Berechtigung eine verfügbare gemeinsame Sammlung wählen.", + "access.policy.validation.duplicate_grant": "Doppelte Rollen- und Bereichsberechtigungen vor dem Speichern entfernen.", + "access.test.title": "Effektiven Zugriff testen", + "access.test.description": "Eine gespeicherte Aktion und Kamera als {username} bewerten, ohne sie auszuführen.", + "access.test.saveFirst": "Berechtigungsänderungen vor dem Test speichern oder verwerfen, damit das Ergebnis der hier angezeigten Richtlinie entspricht.", + "access.test.action": "Aktion", + "access.test.camera": "Kamera", + "access.test.run": "Zugriff testen", + "access.test.running": "Test läuft…", + "access.test.allowed": "Erlaubt", + "access.test.denied": "Verweigert", + "access.test.version": "Version {version}", + "access.test.source": "Quelle: {source} · Rolle: {role}", + "recordings.pullToRefresh": "Ziehen zum Aktualisieren der Aufnahmen", + "recordings.releaseToRefresh": "Loslassen zum Aktualisieren der Aufnahmen", + "recordings.refreshing": "Aufnahmen werden aktualisiert…", + "recordings.refreshed": "Aufnahmen aktualisiert", + "recordings.refreshFailed": "Aufnahmen konnten nicht aktualisiert werden: {message}", + "recordings.download": "Herunterladen", + "recordings.tags": "Tags", + "recordings.selectRecording": "Aufnahme auswählen", + "timeline.legend.recording": "Aufnahme", + "timeline.legend.detection": "Erkennungsereignis", + "timeline.detectionEvent": "Erkennungsereignis", + "streams.showCredentials": "Zugangsdaten anzeigen", + "streams.hideCredentials": "Zugangsdaten ausblenden", + "streams.streamSuccessfullyEnabled": "Stream erfolgreich aktiviert.", + "streams.errorEnablingStream": "Fehler beim Aktivieren des Streams: {message}", + "system.health.tab": "Zustand", + "system.health.operatorView": "Betriebszustand", + "system.health.title": "Systemzustand", + "system.health.loading": "Systemzustand wird geladen…", + "system.health.loadError": "Systemzustand konnte nicht geladen werden.", + "system.health.refreshing": "Wird aktualisiert…", + "system.health.activeIncidentCount": "{count} aktive Vorfälle", + "system.health.coverage": "Abdeckung", + "system.health.monitoringDisabled": "Zustandsüberwachung ist deaktiviert", + "system.health.lastRecordedValue": "Zuletzt erfasster Wert", + "system.health.monitoringDisabledHelp": "Aktuelle Zustandsdaten werden nicht erfasst. Aktivieren Sie die Zustandsüberwachung unter Einstellungen → Zustand; starten Sie nach dem Speichern ggf. neu. Die Vorfallshistorie zeigt vergangene Ereignisse, nicht die aktuelle Ressourcennutzung.", + "system.health.monitoringRestartRequired": "Die Zustandsüberwachung ist in der gespeicherten Konfiguration aktiviert, aber der laufende Erfasser ist noch deaktiviert. Starten Sie LightNVR neu, um die Änderung zu übernehmen. Die Vorfallshistorie zeigt vergangene Ereignisse.", + "system.health.containerCoverage": "Eingeschränkte Host-Abdeckung", + "system.health.hostHardwareUnavailable": "Diese Installation kann den Zustand von Containern und eingebundenen Ressourcen erkennen, aber die Host-Hardware ist nicht verfügbar. Fehlende Host-Werte sind unbekannt, nicht gesund.", + "system.health.coverageUnknown": "Noch keine abgeschlossene Zustands-Momentaufnahme verfügbar. Werte bleiben unbekannt, bis die Erfassung abgeschlossen ist.", + "system.health.coverageComplete": "Alle für diese Installation sichtbaren Daten wurden erfolgreich erfasst.", + "system.health.coveragePartial": "Die Abdeckung ist teilweise. {count} Beobachtungen oder Erfassungsprüfungen sind nicht verfügbar, veraltet oder unvollständig.", + "system.health.effectiveScope": "Effektiver Umfang", + "system.health.activeIncidents": "Aktive Vorfälle", + "system.health.noActiveIncidents": "Für die sichtbare Abdeckung werden keine aktiven Vorfälle gemeldet.", + "system.health.duration": "Dauer", + "system.health.currentValue": "Aktueller Wert", + "system.health.thresholds": "Schwellenwert und Verweildauer", + "system.health.thresholdSummary": "Warnung {warning}, kritisch {critical}, Erholung {recovery} {unit}; Warnungs-Verweildauer {seconds} s", + "system.health.remediation": "Empfohlene Maßnahme", + "system.health.facts": "Zustandsdaten", + "system.health.group.resources": "Ressourcen", + "system.health.group.storage": "Speicher", + "system.health.group.hardware": "Hardware", + "system.health.group.network": "Netzwerk", + "system.health.group.clock": "Uhr", + "system.health.group.components": "Komponenten", + "system.health.noFacts": "In dieser Gruppe sind keine Fakten sichtbar.", + "system.health.observationState": "Fähigkeiten und Aktualität", + "system.health.valueUnavailable": "Ein oder mehrere Werte sind unbekannt", + "system.health.componentStatus": "Überwachungskomponenten", + "system.health.collectors": "Sammler", + "system.health.collectorSummary": "{total} registriert · {attention} benötigen Aufmerksamkeit", + "system.health.collectorsNeedingAttention": "Sammler mit Handlungsbedarf", + "system.health.collectionFailures": "{count} Fehler oder Timeouts", + "system.health.stale": "veraltet", + "system.health.eventDelivery": "Ereignisübermittlung", + "system.health.degraded": "Eingeschränkt", + "system.health.circularDelivery": "Dies ist der einzige konfigurierte Alarmierungspfad, daher kann er seinen eigenen Ausfall nicht unabhängig melden.", + "system.health.incidentPersistence": "Vorfallspeicherung", + "system.health.persistenceSummary": "{pending} ausstehend · {failures} Fehler · {retries} Wiederholungen", + "system.health.recentSamples": "Aktuelle Sammlungsaktivität", + "system.health.recentSamplesHelp": "Bis zu {count} begrenzte serverseitige Generierungszusammenfassungen; dies ist Abdeckungsaktivität, kein Wertediagramm.", + "system.health.sampleSequence": "Generierung {sequence}", + "system.health.sampleCoverage": "{observations} Beobachtungen · {dropped} verworfen", + "system.health.noSamples": "Keine abgeschlossenen Sammlungs-Generierungen verfügbar.", + "system.health.incidentHistory": "Vorfallshistorie", + "system.health.incidentHistoryHelp": "Neueste Vorfälle zuerst. Die Historie wird in begrenzten Seiten geladen.", + "system.health.loadingHistory": "Vorfallshistorie wird geladen…", + "system.health.historyError": "Vorfallshistorie konnte nicht geladen werden.", + "system.health.emptyHistory": "Keine Vorfälle aufgezeichnet.", + "system.health.firstSeen": "Erstmals erkannt", + "system.health.lastSeen": "Zuletzt erkannt", + "system.health.deliveryState": "Übermittlungsstatus", + "system.health.historyPagination": "Vorfallshistorie-Seiten", + "system.health.pageCount": "{count} Vorfälle auf dieser Seite", + "system.health.remediation.memory": "Speicherdruck reduzieren, Prozess- und cgroup-Limits prüfen und kürzliche OOM-Aktivitäten überprüfen.", + "system.health.remediation.cpu": "Anhaltende CPU-Verbraucher identifizieren und den Service-Durchsatz prüfen, bevor Limits geändert werden.", + "system.health.remediation.io": "Speicherlatenz und aktive Schreibvorgänge prüfen; Aufnahmen vor störender Wartung sichern.", + "system.health.remediation.filesystem": "Das angegebene logische Dateisystem, freien Speicherplatz oder Inodes prüfen und sicherstellen, dass es beschreibbar bleibt.", + "system.health.remediation.thermal": "Kühlung verbessern und Last reduzieren; Lüfter und Belüftung prüfen, bevor Temperaturen die Abschaltlimits erreichen.", + "system.health.remediation.network": "Sichtbare Schnittstelle, Link, Switch und Fehlerzähler über einen unabhängigen Netzwerkpfad prüfen.", + "system.health.remediation.clock": "Zeitsynchronisation wiederherstellen und die Host-Uhrquelle prüfen, bevor Ereignis-Zeitstempel verwendet werden.", + "system.health.remediation.process": "LightNVR-Ressourcenlimits und Logs prüfen, dann Last reduzieren oder validierte Limits erhöhen.", + "system.health.remediation.storage": "Wichtige Aufnahmen sichern und das zugeordnete Speichergerät vor Austausch oder Reparatur prüfen.", + "system.health.remediation.hardware": "Betroffene Hardware und Plattform-Logs prüfen; Wartung planen, falls der Zustand bestehen bleibt.", + "system.health.remediation.health": "Collector-Zugriff und Berechtigungen wiederherstellen, damit fehlende Gesundheitsnachweise ausgewertet werden können.", + "system.health.remediation.system": "Vorherigen Lauf und Host-Logs prüfen, um einen Prozessneustart von einem Host-Neustart zu unterscheiden.", + "system.health.remediation.event": "Lokale API oder Metrikansicht verwenden, dauerhaften Queue-Druck abbauen und ein unabhängiges Alarmziel wiederherstellen.", + "system.health.remediation.default": "Betroffene Komponente und aktuelle Logs prüfen, dann die Wiederherstellung in einer neuen Gesundheitsgeneration verifizieren.", + "system.capacityTarget": "Kapazitätsziel", + "system.capacityTargetValue": "{pct}% frei halten", + "system.fillRate": "Füllrate", + "system.fillRateValue": "{value} / Tag", + "system.projectedToTarget": "Geschätzte Zeit bis zum Ziel", + "system.projectedNow": "Ziel erreicht/überschritten", + "system.projectedDays": "~{count} T", + "system.projectedHours": "~{count} Std.", + "system.projectedUnknown": "—", + "common.description": "Beschreibung", + "common.remove": "Entfernen", + "streams.selectStream": "{name} auswählen", + "streams.search": "Streams suchen", + "streams.searchPlaceholder": "Kameras, Standorte oder Tags suchen", + "streams.noStreamsMatchFilters": "Keine Streams entsprechen den aktuellen Filtern.", + "streamHealth.sourceConnected": "Quelle verbunden", + "streamHealth.videoAdvancing": "Video läuft", + "streamHealth.recorderWriting": "Recorder schreibt", + "streamHealth.detectorOperating": "Detektor aktiv", + "streamHealth.lastSegment": "Letztes abgeschlossenes Segment", + "streams.disablingStreamsProgress": "Streams werden deaktiviert…", + "streams.onvifInvalidAddress": "Die IP-Adresse des ONVIF-Geräts fehlt oder ist ungültig.", + "streams.warningFallingBackToHttp": "HTTPS-Verbindung fehlgeschlagen; erneuter Versuch über HTTP. Anmeldedaten könnten im Klartext übertragen werden.", + "streamsConfig.playbackTransport": "Wiedergabe-Transport", + "streamsConfig.playbackTransportHelp": "Wählen Sie die Browser-Wiedergabemethode für diese Kamera und ggf. deren Fallback-Reihenfolge.", + "streamsConfig.playbackTransportUnavailable": "Auf dem Server nicht verfügbar: {transports}. Aktivieren Sie den Transport global oder wählen Sie ein anderes Profil.", + "streamsConfig.audioDisabledByPolicy": "Audio ist durch die Instanzrichtlinie deaktiviert", + "streamsConfig.audioDisabledByPolicyHelp": "Aufnahme, Live-Hören und Gegensprechen sind nicht verfügbar, solange die globale Audio-Compliance-Richtlinie aktiviert ist.", + "streamsConfig.audioVoiceEnhancement": "Sprachverbesserung (Aufnahmen)", + "streamsConfig.customApiModel": "Benutzerdefinierte API-Erkennung", + "streamsConfig.modelNotSupportedByBuild": "von diesem Build nicht unterstützt", + "streamsConfig.tierCriticalMultiplier": "Kritische Stufe ×", + "streamsConfig.tierImportantMultiplier": "Wichtige Stufe ×", + "streamsConfig.tierEphemeralMultiplier": "Flüchtige Stufe ×", + "streamsConfig.tierMultipliersHelp": "Stufenweise Multiplikatoren auf die Basis-Aufbewahrungsdauer. Aufnahmen höherer Stufen werden länger behalten und bei Speicherdruck zuletzt gelöscht.", + "streamsConfig.storagePriority": "Speicher-Priorität (1–10)", + "streamsConfig.storagePriorityHelp": "Relative Bedeutung der Aufnahmen dieses Streams bei der Speicherfreigabe; höhere Priorität wird länger beibehalten.", + "streamsConfig.restream": "Restream / Veröffentlichen (RTMP)", + "streamsConfig.publishUrl": "Veröffentlichungs-URL (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "Diese Kamera über go2rtc an einen Dienst wie YouTube Live weiterleiten. Vollständige RTMP-Ingest-URL einschließlich Stream-Key einfügen (z. B. rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Um an mehrere Dienste gleichzeitig weiterzuleiten, die URLs durch Kommas trennen. YouTube erfordert H264-Video und AAC-Audio; LightNVR transkodiert automatisch (H264 für Nicht-H264-Kameras, AAC für Nicht-AAC-Audio), sodass die meisten Kameras ohne weitere Einrichtung funktionieren. Hinweis: YouTube erfordert ebenfalls eine Audiospur – eine Kamera ohne Audio wird weiterhin abgelehnt. Leer lassen zum Deaktivieren.", + "streams.lastSeen": "Zuletzt gesehen {time}", + "streams.claimed": "Zugeordnet", + "streams.duplicateSuspected": "Möglicherweise Duplikat", + "streams.duplicateSuspectedHelp": "Stabile Identitäts- oder Endpunkt-Nachweise stehen im Konflikt mit einem anderen Erkennungsdatensatz.", + "streams.onvifClaimWarning": "Der Stream wurde hinzugefügt, aber sein Erkennungsdatensatz konnte nicht als zugeordnet markiert werden: {message}", + "common.online": "Online", + "common.offline": "Offline", + "settings.storageTargets.title": "Aufnahmespeicher-Ziele", + "settings.storageTargets.description": "Lokale Datenträger und vom Administrator eingebundene NFS- oder SMB-Dateisysteme als unabhängig überwachte Aufnahmeziele registrieren.", + "settings.storageTargets.foundationNotice": "Aufnahme verwendet Dateisystemziele. S3-Buckets und eingebundene NFS/SAN-Ziele können verifizierte Archivkopien enthalten. Hot-Druck bewahrt archivierte Aufnahmen, bis ihre logische Aufbewahrungsdauer abläuft.", + "settings.storageTargets.add": "Speicherziel hinzufügen", + "settings.storageTargets.edit": "Speicherziel bearbeiten", + "settings.storageTargets.editorHelp": "Aktivierte Ziele müssen bereits vorhanden sein und einen Schreib-, fsync- und Bereinigungstest bestehen. Speichern Sie eine nicht verfügbare zukünftige Einbindung als deaktiviert und aktivieren Sie sie nach dem Einhängen.", + "settings.storageTargets.name": "Zielname", + "settings.storageTargets.root": "Eingebundener Stammpfad", + "settings.storageTargets.rootLocked": "Ein Standard- oder nicht leeres Ziel behält einen unveränderlichen Root, damit vorhandene Aufnahmen nicht verwaist werden.", + "settings.storageTargets.class": "Performanceklasse", + "settings.storageTargets.hot": "Hot — aktive Aufnahme", + "settings.storageTargets.warm": "Warm — eingebundenes Archiv", + "settings.storageTargets.cold": "Cold — seltener Zugriff", + "settings.storageTargets.reserveGb": "Reservierter Puffer (GB)", + "settings.storageTargets.lowWatermark": "Untere Warnschwelle (% belegt)", + "settings.storageTargets.highWatermark": "Obere Warnschwelle (% belegt)", + "settings.storageTargets.migrationBandwidth": "Lifecycle-Bandbreite (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 bedeutet unbegrenzt. Das Limit wird als Momentaufnahme gespeichert, wenn ein Verschiebe- oder Kopiervorgang erstellt wird.", + "settings.storageTargets.archiveStart": "Archivfenster beginnt", + "settings.storageTargets.archiveEnd": "Archivfenster endet", + "settings.storageTargets.archiveWindowHelp": "Ortszeit. Gleiche Start- und Endzeiten erlauben Lifecycle-Jobs den ganzen Tag; ein Nachtfenster kann Mitternacht überschreiten.", + "settings.storageTargets.enabled": "Aktiviert (Platzierungsrichtlinien können dieses Ziel auswählen)", + "settings.storageTargets.notRouted": "Keine aktivierte Platzierungsrichtlinie leitet Kameras hierher. Neue Aufnahmen gehen weiterhin an das Standardziel, bis eine Richtlinie dieses Ziel als primäres Ziel, Poolmitglied oder Archivziel festlegt.", + "settings.storageTargets.degradedNotice": "Über der oberen Warnschwelle oder innerhalb des reservierten Bereichs. Platzierungsrichtlinien überspringen dieses Ziel, bis Speicherplatz freigegeben wird.", + "settings.storageTargets.probePassedIneligible": "Schreibtest bestanden, aber das Ziel ist {status}: Platzierungsrichtlinien werden es nicht auswählen.", + "settings.storageTargets.mountRequired": "Eingebundenes Dateisystem erforderlich", + "settings.storageTargets.mountRequiredHelp": "Dieses Ziel an seinen aktuellen Nicht-Root-Mountpoint binden. Falls diese NFS-, SMB-, Bind- oder PVC-Einbindung verschwindet, pausiert die Aufnahme, statt in das darunterliegende Host-Verzeichnis zu schreiben.", + "settings.storageTargets.mountGuard": "Erforderliche Einbindung", + "settings.storageTargets.mountPending": "Wird erkannt, wenn das Ziel aktiviert wird", + "settings.storageTargets.default": "Standard", + "settings.storageTargets.capacity": "Kapazität", + "settings.storageTargets.available": "Verfügbar", + "settings.storageTargets.recordings": "Indexierte Aufnahmen", + "settings.storageTargets.replicas": "{count} verifizierte Kopien · {bytes}", + "settings.storageTargets.reserve": "Reserviert", + "settings.storageTargets.pressure.normal": "Druck normal", + "settings.storageTargets.pressure.high": "Hohe Marke", + "settings.storageTargets.pressure.reserve": "Reserve unterschritten", + "settings.storageTargets.pressure.unavailable": "Druck nicht verfügbar", + "settings.storageTargets.cleanupActive": "Zielbezogener Cleanup ist aktiv und strebt {target} verfügbar an, ohne Aufnahmen zu löschen, die einem anderen Ziel zugewiesen sind.", + "settings.storageTargets.test": "Ziel testen", + "settings.storageTargets.probing": "Test läuft…", + "settings.storageTargets.probePassed": "Schreibtest für Speicherziel bestanden", + "settings.storageTargets.duplicateFilesystem": "Dieser Root teilt sich dasselbe Dateisystem wie ein anderes Ziel. Die Kapazität darf bei aktivierter Platzierung nicht doppelt gezählt werden.", + "settings.storageTargets.deleteLocked": "Standard- und nicht leere Ziele können nicht gelöscht werden.", + "settings.storageTargets.deleteConfirm": "Leeres Speicherziel „{name}\" löschen? Es werden keine Dateien entfernt.", + "settings.storageTargets.created": "Speicherziel erstellt", + "settings.storageTargets.updated": "Speicherziel aktualisiert", + "settings.storageTargets.deleted": "Speicherziel gelöscht", + "settings.storageTargets.invalidThresholds": "Wassermarken, Reserve, Lifecycle-Bandbreite und Archivfenster-Zeiten prüfen.", + "settings.storageTargets.loadError": "Speicherziele konnten nicht geladen werden", + "settings.storagePools.title": "Speicherpools", + "settings.storagePools.description": "Gesunde Ziele für automatischen Überlauf und Replikation auf verschiedene Ziele gruppieren.", + "settings.storagePools.add": "Pool hinzufügen", + "settings.storagePools.strategy": "Zuweisungsstrategie", + "settings.storagePools.mostFree": "Meist freier Speicherplatz", + "settings.storagePools.roundRobin": "Round Robin", + "settings.storagePools.priority": "Explizite Priorität", + "settings.storagePools.members": "Ziele (Anzeigereihenfolge = Zuweisungspriorität)", + "settings.storagePools.enabled": "Pool aktiviert", + "settings.storagePools.active": "Aktiv", + "settings.storagePools.inactive": "Deaktiviert", + "settings.storagePools.strategyValue.most_free": "meist frei", + "settings.storagePools.strategyValue.round_robin": "Round Robin", + "settings.storagePools.strategyValue.priority": "Prioritätsreihenfolge", + "settings.storagePools.created": "Speicherpool erstellt", + "settings.storagePools.updated": "Speicherpool aktualisiert", + "settings.storagePools.deleted": "Speicherpool gelöscht", + "settings.storagePools.deleteConfirm": "Speicherpool „{name}\" löschen?", + "settings.storagePools.empty": "Noch keine Speicherpools.", + "settings.storageMigrations.title": "Aufnahmemigrationsaufträge", + "settings.storageMigrations.description": "Dauerhafte Verschiebungen und behaltene Kopien berücksichtigen das Archivierungsfenster und die Bandbreitenbegrenzung jedes Ziels, überprüfen SHA-256 und erholen sich sicher nach einem Neustart.", + "settings.storageMigrations.empty": "Noch keine Aufnahmemigrationsaufträge.", + "settings.storageMigrations.loadError": "Aufnahmemigrationsaufträge konnten nicht geladen werden", + "settings.storageMigrations.recording": "Aufnahme #{id}", + "settings.storageMigrations.attempt": "Versuch {current}/{max}", + "settings.storageMigrations.operation.move": "Verschieben", + "settings.storageMigrations.operation.copy": "Behaltene Kopie", + "settings.storageMigrations.cancelled": "Abbruch der Migration akzeptiert", + "settings.storageMigrations.cancelling": "Abbrechen…", + "settings.storageMigrations.retried": "Migration zur Wiederholung eingereiht", + "settings.storageMigrations.state.queued": "Eingereiht", + "settings.storageMigrations.state.copying": "Kopieren", + "settings.storageMigrations.state.verifying": "Überprüfen", + "settings.storageMigrations.state.committing": "Abschließen", + "settings.storageMigrations.state.cleanup_pending": "Quelle bereinigen", + "settings.storageMigrations.state.retry_wait": "Warten auf Wiederholung", + "settings.storageMigrations.state.completed": "Abgeschlossen", + "settings.storageMigrations.state.failed": "Fehlgeschlagen", + "settings.storageMigrations.state.cancelled": "Abgebrochen", + "settings.storagePolicies.title": "Kamera-Platzierungsrichtlinien", + "settings.storagePolicies.description": "Leiten Sie passende Kameras in Prioritätsreihenfolge an ein primäres Aufzeichnungsziel weiter. Eine Kamera verwendet die erste aktivierte Richtlinie, die übereinstimmt.", + "settings.storagePolicies.add": "Platzierungsrichtlinie hinzufügen", + "settings.storagePolicies.edit": "Platzierungsrichtlinie bearbeiten", + "settings.storagePolicies.editorHelp": "Die Richtlinie wird für neue Segmente neu bewertet. Änderungen verschieben keine bereits vorhandenen Aufnahmen.", + "settings.storagePolicies.priority": "Priorität (höhere zuerst)", + "settings.storagePolicies.priorityValue": "Priorität {priority}", + "settings.storagePolicies.primary": "Primäres Ziel", + "settings.storagePolicies.primaryPool": "Platzierungspool (optional)", + "settings.storagePolicies.exactTarget": "Exaktes primäres Ziel verwenden", + "settings.storagePolicies.fallback": "Wenn das primäre Ziel nicht verfügbar ist", + "settings.storagePolicies.fallbackDefault": "Standardziel verwenden", + "settings.storagePolicies.fallbackTarget": "Benanntes Ausweichziel verwenden", + "settings.storagePolicies.fallbackPause": "Aufnahme pausieren", + "settings.storagePolicies.fallbackFail": "Aufnahmestart fehlschlagen lassen", + "settings.storagePolicies.namedFallback": "Ausweichziel", + "settings.storagePolicies.chooseTarget": "Ziel auswählen", + "settings.storagePolicies.choosePool": "Pool auswählen", + "settings.storagePolicies.minimumDays": "Mindestaufbewahrung (Tage)", + "settings.storagePolicies.desiredDays": "Gewünschte Aufbewahrung (Tage)", + "settings.storagePolicies.maximumDays": "Maximale Aufbewahrung (Tage)", + "settings.storagePolicies.copyCount": "Erforderliche verifizierte Kopien", + "settings.storagePolicies.replicationPool": "Replikationspool", + "settings.storagePolicies.migrateAfter": "Verschieben nach Alter (Tage)", + "settings.storagePolicies.migrationTarget": "Archivziel", + "settings.storagePolicies.pressurePriority": "Löschpriorität bei Speicherdruck (niedrige zuerst)", + "settings.storagePolicies.disabledTarget": "deaktiviert", + "settings.storagePolicies.enabled": "Richtlinie aktiviert", + "settings.storagePolicies.selector": "Übereinstimmende Kameras", + "settings.storagePolicies.preview": "Vorschau-Priorität", + "settings.storagePolicies.previewing": "Wird ausgewertet…", + "settings.storagePolicies.previewRequired": "Vorschau des aktuellen Entwurfs vor dem Speichern anzeigen, um Kameraüberschneidungen und die wirksame Richtlinie zu sehen.", + "settings.storagePolicies.previewSummary": "Entspricht {matched} Kameras; dieser Entwurf ist wirksam für {effective}.", + "settings.storagePolicies.previewShadowed": "Eine Richtlinie mit höherer Priorität gewinnt bei {count} übereinstimmenden Kameras.", + "settings.storagePolicies.previewWins": "Gewinnt gegenüber „{policy}\" (Priorität {priority}) bei {count} Kameras.", + "settings.storagePolicies.previewLoses": "Unterliegt gegenüber „{policy}\" (Priorität {priority}) bei {count} Kameras.", + "settings.storagePolicies.previewNoMatches": "Dieser Selektor entspricht derzeit keinen Kameras.", + "settings.storagePolicies.invalidPriority": "Die Priorität muss eine ganze Zahl zwischen -1.000.000 und 1.000.000 sein.", + "settings.storagePolicies.invalidLifecycle": "Aufbewahrungsreihenfolge, Kopienanzahl und Replikationspool sowie Migrationsalter und Ziel prüfen.", + "settings.storagePolicies.created": "Platzierungsrichtlinie erstellt", + "settings.storagePolicies.updated": "Platzierungsrichtlinie aktualisiert", + "settings.storagePolicies.deleted": "Platzierungsrichtlinie gelöscht", + "settings.storagePolicies.deleteConfirm": "Platzierungsrichtlinie „{name}\" löschen? Bestehende Aufnahmen sind nicht betroffen.", + "settings.storagePolicies.active": "Aktiv", + "settings.storagePolicies.inactive": "Deaktiviert", + "settings.storagePolicies.routesTo": "Primäres Ziel: {target}", + "settings.storagePolicies.lifecycleSummary": "Aufbewahrung min./gewünscht/max.: {minimum}/{desired}/{maximum} Tage · {copies} verifizierte Kopie(n)", + "settings.storagePolicies.fallsBackTo": "Fallback-Ziel: {target}", + "settings.storagePolicies.mode.default": "Fallback: Standardziel", + "settings.storagePolicies.mode.pause": "Fallback: Aufnahme pausieren", + "settings.storagePolicies.mode.fail": "Fallback: Aufnahmestart fehlschlagen", + "settings.storagePolicies.empty": "Keine Platzierungsrichtlinien. Kameras verwenden weiterhin das Standardziel; andere Ziele erhalten nichts, bis eine Richtlinie Kameras an sie weiterleitet.", + "settings.storagePolicies.archiveNoTrigger": "Ein Archivziel ist festgelegt, aber nichts löst eine Verschiebung aus. Legen Sie „Nach Alter verschieben (Tage)\", ein Archivierungsalter oder eine Archivoption fest; andernfalls werden keine Aufnahmen verschoben.", + "settings.storageCompliance.title": "Kapazität und Richtlinienkonformität", + "settings.storageCompliance.description": "Beobachtete 30-Tage-Raten prognostizieren den Druck auf das Ziel und die erreichte Aufbewahrung; aktive Lifecycle-Verstöße bleiben sichtbar, bis sie behoben sind.", + "settings.storageCompliance.loadError": "Speicherkonformität konnte nicht geladen werden", + "settings.storageCompliance.unknown": "Unbekannt", + "settings.storageCompliance.days": "{days} Tage", + "settings.storageCompliance.day": "Tag", + "settings.storageCompliance.targetForecasts": "Zielprognosen", + "settings.storageCompliance.target": "Ziel", + "settings.storageCompliance.dailyRate": "Beobachtete Rate", + "settings.storageCompliance.toHigh": "Bis zur Hochwassermarke", + "settings.storageCompliance.expected": "Erwartete Aufbewahrung", + "settings.storageCompliance.confidence": "Konfidenz", + "settings.storageCompliance.policyCompliance": "Richtlinienkonformität", + "settings.storageCompliance.compliant": "Keine aktiven Verstöße", + "settings.storageCompliance.violationCount": "{count} Verstoß(e)", + "settings.storageCompliance.policyForecast": "Erreicht {achieved}; prognostiziert {expected}; gewünscht {desired} Tage.", + "settings.storageCompliance.copyDeficits": "{count} Aufnahme(n) benötigen eine weitere verifizierte Kopie.", + "settings.storageCompliance.activeViolations": "Aktive Verstöße", + "settings.storageCompliance.type.copy_count": "Anzahl der Kopien", + "settings.storageCompliance.type.minimum_retention": "Mindest-Aufbewahrungskapazität", + "settings.storageCompliance.type.target_unavailable": "Ziel nicht verfügbar", + "settings.storageCompliance.type.migration_failed": "Lifecycle-Job fehlgeschlagen", + "settings.recordingDirectoryFormat": "Aufnahme-Ordnerstruktur", + "settings.recordingDirectoryFormatHelp": "Neue MP4-Aufnahmen werden in Unterordnern unterhalb des jeweiligen Kameraordners angelegt. Bestehende Aufnahmen werden nicht verschoben.", + "settings.recordingDirectoryFlat": "Flach (nur Kameraordner)", + "settings.recordingDirectoryMonth": "Nach Monat (YYYY/MM)", + "settings.recordingDirectoryDay": "Nach Tag (YYYY/MM/DD)", + "settings.minFreePct": "Mindestfreiraum (%)", + "settings.minFreePctHelp": "Mindestens dieser Prozentsatz des Volumes bleibt frei, indem die ältesten Aufnahmen automatisch entfernt werden – unabhängig von den Aufbewahrungstagen. Damit wird die Nutzung an die Diskgröße gebunden — eingestellt, füllt sich die Disk nie. 0 deaktiviert die Kapazitätsgrenze.", + "settings.pressureThresholds": "Festplattenbelastungsschwellen (%)", + "settings.pressureThresholdsHelp": "Freiraumbereiche, die die automatische Bereinigung eskalieren. Es muss gelten: Notfall < Kritisch < Warnung.", + "settings.pressureWarningPct": "Warnung unter (% frei)", + "settings.pressureCriticalPct": "Kritisch unter (% frei)", + "settings.pressureEmergencyPct": "Notfall unter (% frei)", + "settings.databaseBackupVerify": "Backup-Überprüfung", + "settings.databaseBackupVerifyFull": "Vollständig (integrity_check, prüft jeden Index)", + "settings.databaseBackupVerifyQuick": "Schnell (quick_check, nur Seitenstruktur)", + "settings.databaseBackupVerifyOff": "Aus (kein Scan nach dem Kopieren)", + "settings.databaseBackupVerifyHelp": "Der Scan wird auf jede kopierte Sicherung angewendet, bevor sie veröffentlicht wird. Vollständig kann bei einer großen Datenbank auf einer mechanischen Festplatte länger dauern als der Kopiervorgang selbst und das 30-Minuten-Sicherheitslimit erreichen, wodurch die Sicherung verworfen wird. Schnell erkennt ebenfalls beschädigte oder abgeschnittene Seiten mit deutlich weniger Zugriffen.", + "settings.viewMethodAuto": "Auto — Kameraeinstellung mit Fallback", + "settings.resetWizardPending": "Assistent wird gestartet…", + "settings.apiDetectionFormat": "API-Anforderungsformat", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (Multipart-Bild-Upload)", + "settings.apiDetectionFormatDoods2": "DOODS2 (JSON-Body mit Base64-Bild)", + "settings.apiDetectionFormatHelp": "Drahtformat, das LightNVR beim Senden von Schnappschüssen an die Erkennungs-API verwendet. light-object-detect beibehalten für light-object-detect oder jeden Server, der dessen Vertrag implementiert; DOODS2 für einen DOODS2-Server wählen.", + "settings.apiDetectionUrlHelpDoods2": "DOODS2-/detect-Endpunkt, z. B. http://localhost:8080/detect. Die Anfrage wird als JSON gesendet, es werden keine Abfrageparameter hinzugefügt.", + "settings.apiDetectionDetectorName": "DOODS2-Detektorname", + "settings.apiDetectionDetectorNameHelp": "Wird als detector_name in jeder Anfrage gesendet. Muss mit einem vom Server über GET /detectors gelisteten Detektor übereinstimmen; „default\" verwendet den Standarddetektor des Servers.", + "settings.defaultPlaybackTransport": "Standard-Wiedergabetransport", + "settings.defaultPlaybackTransportHelp": "Wiedergabeprofil, das auf neu erstellte Streams angewendet wird. Bestehende Streams behalten ihre eigene Auswahl.", + "playbackTransport.auto": "Auto (empfohlen)", + "playbackTransport.webrtcOnly": "Nur WebRTC", + "playbackTransport.mseOnly": "Nur MSE", + "playbackTransport.hlsOnly": "Nur HLS", + "playbackTransport.webrtcThenMse": "WebRTC, dann MSE", + "playbackTransport.mseThenHls": "MSE, dann HLS", + "investigation.experimental": "Experimenteller Arbeitsbereich", + "investigation.title": "Untersuchung", + "investigation.description": "Mehrere Kameras anhand eines gemeinsamen UTC-Zeigers prüfen, ohne Lücken im Aufnahmematerial zu verbergen.", + "investigation.query": "Untersuchungsfenster", + "investigation.queryHelp": "Wählen Sie bis zu 16 Kameras aus. Es sind maximal vier Videoplayer gleichzeitig aktiv.", + "investigation.cameras": "Kameras", + "investigation.cameraSelection": "Kameraauswahl", + "investigation.start": "Start", + "investigation.end": "Ende", + "investigation.load": "Untersuchung laden", + "investigation.applyWindow": "Zeitfenster anwenden", + "investigation.loading": "Untersuchung wird geladen…", + "investigation.eventType": "Ereignistyp", + "investigation.anyEventType": "Alle Ereignistypen", + "investigation.eventType.detection": "Erkennung", + "investigation.eventType.motion": "Bewegung", + "investigation.location": "Standort", + "investigation.anyLocation": "Alle Standorte", + "investigation.objectLabel": "Objektbezeichnung", + "investigation.anyLabel": "Alle Bezeichnungen", + "investigation.zone": "Zone", + "investigation.anyZone": "Alle Zonen", + "investigation.source": "Erkennungsquelle", + "investigation.anySource": "Alle Quellen", + "investigation.captureMethod": "Aufnahmemethode", + "investigation.anyCaptureMethod": "Alle Aufnahmemethoden", + "investigation.recordingTag": "Aufnahme-Tag", + "investigation.anyRecordingTag": "Beliebiges Aufnahme-Tag", + "investigation.protection": "Schutz", + "investigation.anyProtection": "Beliebiger Schutz", + "investigation.protected": "Geschützt", + "investigation.unprotected": "Ungeschützt", + "investigation.minimumConfidence": "Mindestkonfidenz", + "investigation.confidenceError": "Die Mindestkonfidenz muss zwischen 0 und 1 liegen.", + "investigation.metadataRegionSearch": "Metadaten-Bereichssuche", + "investigation.regionSearchHelp": "Wählen Sie eine Hauptkamera mit Aufnahmen und zeichnen Sie einen Bereich über das Video.", + "investigation.regionActive": "Suche gespeicherte Boxen von {camera}. Ein fehlendes Ergebnis ist kein Beweis dafür, dass nichts den Bereich durchquert hat.", + "investigation.regionMatch": "Box-Abgleich", + "investigation.regionMatch.center": "Mittelpunkt innerhalb", + "investigation.regionMatch.intersects": "Beliebige Überlappung", + "investigation.regionMatch.minimumIntersection": "Mindestüberlappung", + "investigation.regionMinimumOverlap": "Mindestüberlappung (%)", + "investigation.regionLeft": "Links (%)", + "investigation.regionTop": "Oben (%)", + "investigation.regionWidth": "Breite (%)", + "investigation.regionHeight": "Höhe (%)", + "investigation.drawRegion": "Suchbereich zeichnen", + "investigation.drawingRegion": "Suchbereich wird gezeichnet…", + "investigation.clearRegion": "Bereich löschen", + "investigation.useFullFrame": "Gesamtes Bild verwenden", + "investigation.drawRegionPrompt": "Ziehen Sie über das Video, um den Suchbereich festzulegen", + "investigation.applyFilters": "Filter anwenden", + "investigation.searching": "Ereignisse werden durchsucht…", + "investigation.searchResults": "Ereignisergebnisse", + "investigation.searchHelp": "Laden Sie eine Untersuchung, um deren gespeicherte Ereignis-Metadaten zu durchsuchen.", + "investigation.resultCount": "{count} passende Ereignisse", + "investigation.results": "Ergebnisse", + "investigation.resultHistogram": "Ereignishistogramm", + "investigation.histogramHelp": "Wählen Sie einen Balken aus, um den gemeinsamen Cursor zu bewegen.", + "investigation.previousResult": "Vorheriges Ereignis", + "investigation.nextResult": "Nächstes Ereignis", + "investigation.previousResultShortcut": "Vorheriges Ereignis ([)", + "investigation.nextResultShortcut": "Nächstes Ereignis (])", + "investigation.noResults": "Keine gespeicherten Ereignisse entsprechen dieser Kamera-, Zeit- und Filterauswahl.", + "investigation.noThumbnail": "Kein Vorschaubild", + "investigation.exploreThumbnails": "Vorschaubilder durchsuchen", + "investigation.exploreSelectedThumbnails": "Um das Ereignis herum durchsuchen", + "investigation.thumbnailDrilldown": "Vorschaubild-Drilldown", + "investigation.thumbnailDrilldownHelp": "Wählen Sie einen beliebigen Zeitpunkt, auch eine Lücke, um den gemeinsamen Cursor zu verschieben und eine engere Auswahl an Stichproben zu generieren.", + "investigation.selectThumbnailSample": "Um {time} herum untersuchen", + "investigation.loadingThumbnail": "Vorschaubild wird geladen…", + "investigation.thumbnailUnavailable": "Vorschaubild nicht verfügbar", + "investigation.loadingSamples": "Vorschaubild-Stichproben werden geladen…", + "investigation.thumbnailCoverageTruncated": "Dieses Intervall enthält mehr Aufnahmen als vom Sampler geprüft werden konnten. Verkleinern Sie das Zeitfenster für eine vollständige Abdeckung.", + "investigation.bookmarks.save": "Lesezeichen speichern", + "investigation.bookmarks.open": "Lesezeichen", + "investigation.bookmarks.saveTitle": "Ermittlungs-Lesezeichen speichern", + "investigation.bookmarks.listTitle": "Ermittlungs-Lesezeichen", + "investigation.bookmarks.notHold": "Ein Lesezeichen stellt diese Ansicht wieder her, schützt Aufnahmen jedoch nicht vor automatischer Löschung gemäß Aufbewahrungsrichtlinie.", + "investigation.bookmarks.title": "Lesezeichenname", + "investigation.bookmarks.note": "Private Notiz (optional)", + "investigation.bookmarks.titleRequired": "Geben Sie einen Lesezeichennamen ein.", + "investigation.bookmarks.empty": "Sie haben keine gespeicherten Ermittlungs-Lesezeichen.", + "investigation.bookmarks.cameraCount": "{count} Kamera(s)", + "investigation.bookmarks.restore": "Öffnen", + "investigation.bookmarks.confirmDelete": "Lesezeichen löschen?", + "investigation.actions.open": "Schützen / Herunterladen", + "investigation.actions.title": "Ermittlungs-Aufnahmen", + "investigation.actions.notEvidenceExport": "Der Schutz verhindert die automatische Löschung gemäß Aufbewahrungsrichtlinie. Der ZIP-Download ist ein bequemer Export, kein verifiziertes Beweispaket.", + "investigation.actions.scope": "Aufnahmeumfang", + "investigation.actions.selectedResult": "Ausgewähltes Ereignis und Kamera", + "investigation.actions.fullWindow": "Alle Kameras im Untersuchungszeitraum", + "investigation.actions.preview": "Aufnahmen in der Vorschau", + "investigation.actions.previewing": "Überlappende Aufnahmen werden gesucht…", + "investigation.actions.invalidRange": "Bitte einen gültigen Zeitraum wählen, dessen Ende nach dem Start liegt.", + "investigation.actions.recordingCount": "{count} überlappende Aufnahme(n)", + "investigation.actions.protectedCount": "{count} bereits geschützt", + "investigation.actions.noRecordings": "Keine abgeschlossenen Aufnahmen überlappen diese Kamera- und Zeitauswahl.", + "investigation.actions.protectDenied": "{count} ungeschützte Aufnahme(n) liegen außerhalb Ihres Schutzumfangs und werden von dieser Aktion ausgeschlossen.", + "investigation.actions.exportDenied": "Exportberechtigung fehlt für {count} Aufnahme(n). Downloads sind alles-oder-nichts, daher kann diese Auswahl nicht exportiert werden.", + "investigation.actions.camera": "Kamera", + "investigation.actions.recording": "Aufnahme", + "investigation.actions.size": "Größe", + "investigation.actions.notPermitted": "Nicht erlaubt", + "investigation.actions.protectButton": "{count} schützen", + "investigation.actions.protecting": "Wird geschützt…", + "investigation.actions.protectUnavailable": "Es gibt keine ungeschützten Aufnahmen, die Sie schützen dürfen.", + "investigation.actions.protectResult": "Schutz abgeschlossen: {success} erfolgreich, {failed} fehlgeschlagen.", + "investigation.actions.downloadButton": "{count} herunterladen", + "investigation.actions.downloadUnavailable": "Jede Aufnahme erfordert eine Exportberechtigung, bevor ein ZIP erstellt werden kann.", + "investigation.actions.buildingArchive": "ZIP wird erstellt…", + "investigation.actions.downloadFailed": "ZIP-Erstellung auf dem Server fehlgeschlagen.", + "investigation.actions.downloadTimedOut": "ZIP-Erstellung wurde nicht innerhalb von fünf Minuten abgeschlossen. Versuchen Sie ein engeres Intervall.", + "investigation.actions.downloadStarted": "ZIP-Download gestartet.", + "investigation.backOneLevel": "Eine Ebene zurück", + "investigation.thumbnailMinimumWindow": "Dies ist das engste verfügbare Ein-Sekunden-Intervall. Der gemeinsame Cursor wurde dennoch auf den ausgewählten Zeitpunkt bewegt.", + "investigation.localSource": "lokal", + "investigation.mediaAvailable": "Medien verfügbar", + "investigation.durationSeconds": "{count} s Dauer", + "investigation.pageNumber": "Seite {count}", + "investigation.incompleteCoverage": "{count} Legacy-Ereigniszeilen konnten keiner unveränderlichen Kamera-Identität zugeordnet werden.", + "investigation.spatialCoverageGap": "{count} Ereigniszeilen im Geltungsbereich hatten keine Bounding Box und wurden nicht räumlich durchsucht.", + "investigation.noSpatialMetadata": "Keine Ereignisse im Geltungsbereich haben Bounding Boxes für diese Metadaten-Suche.", + "investigation.selectCameraError": "Mindestens eine Kamera auswählen.", + "investigation.selectRecordingError": "Mindestens eine Aufnahme auswählen.", + "investigation.investigateSelectedCount": "{count} ausgewählte Aufnahme(n) untersuchen", + "investigation.missingCameraIdentity": "Untersuchung nicht möglich: {count} ausgewählte Aufnahme(n) haben keine Kamera-Identität.", + "investigation.recordingTimeError": "Die ausgewählten Aufnahmen haben keinen gültigen Zeitraum.", + "investigation.windowLimit": "Die ausgewählten Aufnahmen überschreiten das Untersuchungslimit von 31 Tagen.", + "investigation.timeRangeError": "Die Endzeit muss nach der Startzeit liegen.", + "investigation.cameraLimit": "Eine Untersuchung kann maximal {count} Kameras umfassen.", + "investigation.decoderLimit": "Es können nur {count} Kamera-Player gleichzeitig aktiv sein.", + "investigation.playbackControls": "Synchronisierte Wiedergabesteuerung", + "investigation.play": "Wiedergabe", + "investigation.pause": "Pause", + "investigation.mode": "Wiedergabemodus", + "investigation.wallClock": "Echtzeit", + "investigation.skipCommonGaps": "Gemeinsame Lücken überspringen", + "investigation.speed": "Geschwindigkeit", + "investigation.sharedCursor": "Gemeinsamer UTC-Cursor", + "investigation.activePlayers": "aktive Player", + "investigation.timeline": "gemeinsame Zeitleiste", + "investigation.segments": "Segmente", + "investigation.truncated": "abgeschnitten", + "investigation.gap": "Kein Material", + "investigation.players": "Synchronisierte Kamera-Player", + "investigation.activateCamera": "Mindestens eine Zeitleistenzeile aktivieren, um Video zu laden.", + "investigation.noFootage": "Kein Material", + "investigation.noFootageAtTime": "Kein Material zur gemeinsamen Zeit", + "investigation.primaryAudio": "Primäres Audio", + "investigation.makePrimary": "Als primär festlegen", + "investigation.status.loading": "Medien werden geladen", + "investigation.status.synchronizing": "Synchronisierung", + "investigation.status.ready": "Synchronisiert", + "investigation.status.late": "Verzögert — Wiederherstellung", + "investigation.status.error": "Medien nicht verfügbar", + "investigation.status.paused-by-browser": "Wiedergabe auswählen, um Medien zuzulassen", + "streamsConfig.eptzTitle": "Fisheye-ePTZ", + "streamsConfig.eptzEnable": "Browserseitiges Fisheye-ePTZ aktivieren", + "streamsConfig.eptzHelp": "Entzerrt den unbearbeiteten Fisheye-Stream in Live-Ansicht, Timeline-Wiedergabe und Untersuchung. Dies ändert weder Aufnahmen noch Kameraausgabe.", + "streamsConfig.eptzModelHelp": "Projektion: äquidistante zirkulare Fisheye · Montage: Decke. Mittelpunkt und Radius verwenden normalisierte Quellbildkoordinaten.", + "streamsConfig.eptzCenterX": "Optischer Mittelpunkt X", + "streamsConfig.eptzCenterY": "Optischer Mittelpunkt Y", + "streamsConfig.eptzRadius": "Bildkreisradius", + "streamsConfig.eptzLensFov": "Objektiv-FOV (Grad)", + "streamsConfig.eptzRotation": "Objektivrotation (Grad)", + "streamsConfig.eptzDefaultYaw": "Standard-Schwenk (Grad)", + "streamsConfig.eptzDefaultTilt": "Standard-Neigung (Grad)", + "streamsConfig.eptzViewFov": "Standard-Sichtfeld", + "streamsConfig.eptzCalibrationHelp": "Ziehen zum Umschauen, Mausrad oder Pinch zum Zoomen, Home-Taste zum Zurücksetzen der virtuellen Kamera. Mittelpunkt und Radius feinjustieren, falls der Bildkreisrand nicht ausgerichtet ist.", + "settings.archive.targetType": "Speichertyp", + "settings.archive.filesystem": "Lokales oder gemountetes Dateisystem (NFS/SAN)", + "settings.archive.s3": "S3-kompatibler Archiv-Bucket", + "settings.archive.endpoint": "HTTPS-Endpunkt", + "settings.archive.region": "Region", + "settings.archive.bucket": "Dedizierter Bucket", + "settings.archive.credential_ref": "Zugangsdatenreferenz", + "settings.archive.budget": "Archivbudget (GiB, 0 = unbegrenzt)", + "settings.archive.connectionHelp": "Einen privaten, nicht versionierten Bucket ohne Lifecycle-Ablaufregeln verwenden. Die Zugangsdatenreferenz wählt eine auf dem Server gemountete Secret-Datei. Den verwalteten Speicherort als s3://bucket/instance-prefix eingeben.", + "settings.archive.policy": "Externe Archivrichtlinie", + "settings.archive.archive_after_seconds": "Archivierung nach Aufnahme (Sekunden, -1 = deaktiviert)", + "settings.archive.hot_residency_seconds": "Heißkopie behalten (Sekunden, -1 = nach Archivierung verschieben)", + "settings.archive.archive_protected": "Archivierung geschützter Aufnahmen priorisieren", + "settings.archive.archive_on_pressure": "Frühzeitig archivieren, wenn der Heißspeicher unter Druck steht", + "settings.archive.policyHelp": "Die Archivierungszeitsteuerung verwendet das Aufnahmealter und erfordert eine abgeschlossene Aufnahme. -1 deaktiviert die altersbasierte Archivierung oder entfernt die Mindestaufenthaltsdauer im Heißspeicher; 0 bedeutet sofort. Änderungen gelten für neue Aufnahmen. Bestehende Aufnahmen prüfen, um eine neue Revision anzuwenden.", + "settings.archive.deletion_pending": "Löschung ausstehend", + "settings.archive.archived": "Archiviert", + "settings.archive.hot": "Aktiv", + "settings.archive.hot_and_archive": "Aktiv + Archiv", + "settings.archive.archiving": "Archivierung", + "settings.archive.preparing": "Wiedergabe wird vorbereitet", + "settings.archive.unavailable": "Nicht verfügbar", + "settings.archive.operations": "Archivvorgänge", + "settings.archive.readOnly": "Wiederherstellungsmodus: Aufnahmemigration und Löschung sind pausiert.", + "settings.archive.disabledBuild": "S3-Unterstützung ist in diesem Build deaktiviert. Eingebundene Dateisystemziele bleiben verfügbar.", + "settings.archive.stored": "In Buckets gespeichert", + "settings.archive.backlog": "Übertragungsstau", + "settings.archive.cache": "Abruf-Cache", + "settings.archive.objectsRemaining": "Objekte verbleibend", + "settings.archive.waitingForReaders": "In Warteschlange oder wartend auf aktive Leser.", + "settings.archive.applied": "Richtlinienrevision auf vorhandene Aufnahmen angewendet", + "settings.archive.reviewExisting": "Vorhandene Aufnahmen prüfen", + "settings.archive.applySummary": "{count} Aufnahmen ({bytes}) verwenden diese Revision. {expired} haben bereits die Aufbewahrungsgrenze überschritten.", + "settings.archive.applyHelp": "Schutz- und Aufnahmeüberschreibungen gelten weiterhin. Stream- und Systemaufbewahrung gelten ebenfalls. Neues Archiv-Zeitfenster und -Ziel werden beim nächsten Lifecycle-Scan wirksam.", + "settings.archive.applyBlocked": "Zugehörige Übertragungen abschließen oder auflösen, bevor diese Revision angewendet wird.", + "settings.archive.apply": "Auf vorhandene Aufnahmen anwenden", + "common.fullscreenUnsupported": "Vollbildmodus wird in diesem Browser nicht unterstützt.", + "recordings.viewInTimelineTitle": "Diesen Stream zu diesem Zeitpunkt in der Timeline-Ansicht anzeigen", + "recordings.clickToRetry": "Klicken zum Wiederholen", + "timeline.previousDay": "Vorheriger Tag", + "timeline.nextDay": "Nächster Tag", + "timeline.previousMonth": "Vorheriger Monat", + "timeline.nextMonth": "Nächster Monat", + "settings.searchLabel": "Sucheinstellungen", + "settings.clearSearch": "Suche löschen", + "recordings.addTagPlaceholder": "Tag hinzufügen…", + "recordings.addNewTagPlaceholder": "Neues Tag hinzufügen…" } diff --git a/web/public/locales/es.json b/web/public/locales/es.json index 4f781257..a4879dd5 100644 --- a/web/public/locales/es.json +++ b/web/public/locales/es.json @@ -9,6 +9,84 @@ "nav.timeline": "Línea de tiempo", "nav.health": "Salud", "nav.toggleMenu": "Alternar menú", + "live.navigator.title": "Navegador", + "live.navigator.subtitle": "Ubicaciones, diseños y actividad", + "live.navigator.cameras": "Cámaras", + "live.navigator.plans": "Plano", + "live.navigator.views": "Vistas", + "live.navigator.events": "Eventos", + "live.navigator.search": "Buscar una cámara…", + "live.navigator.allCameras": "Todas las cámaras", + "live.navigator.unassigned": "Sin asignar", + "live.navigator.noCameras": "Ninguna cámara coincide con este ámbito.", + "live.navigator.saveCurrent": "Guardar el diseño actual", + "live.navigator.noLayouts": "Aún no hay diseños guardados.", + "live.navigator.layoutNamePrompt": "Nombre este diseño de vista en vivo", + "live.navigator.shareLayoutPrompt": "¿Compartir este diseño con otros operadores?", + "live.navigator.layoutSaved": "Guardado {name}", + "live.navigator.layoutLoaded": "Cargado {name}", + "live.navigator.deleteLayoutConfirm": "¿Eliminar {name}?", + "live.navigator.shared": "Compartido", + "live.navigator.loadingEvents": "Cargando eventos recientes…", + "live.navigator.noRecentEvents": "No hay detecciones en la última hora.", + "live.navigator.expand": "Expandir el navegador", + "live.navigator.collapse": "Contraer el navegador", + "live.plan.navigatorHelp": "Elige un edificio o una planta. Las vistas previas de las cámaras solo se abren cuando se solicitan.", + "live.plan.noPlans": "Aún no hay planos de edificios. Crea uno en el espacio de trabajo de planos.", + "live.plan.emptyTitle": "Crea una vista espacial de cámaras", + "live.plan.emptyDescription": "Un plano muestra marcadores de estado para todo el sitio y abre el video solo cuando un operador lo solicita. Dibuja las habitaciones y los muros aquí mismo, o sube un plano escaneado, un dibujo del sitio o una captura de tu software NVR, y luego asigna las cámaras a las habitaciones reales.", + "live.plan.sketch.tools": "Herramientas de diseño", + "live.plan.sketch.tool.select": "Seleccionar", + "live.plan.sketch.tool.room": "Habitación", + "live.plan.sketch.tool.wall": "Muro", + "live.plan.sketch.tool.area": "Área", + "live.plan.sketch.tool.label": "Etiqueta", + "live.plan.sketch.undo": "Deshacer el dibujo", + "live.plan.sketch.redo": "Rehacer el dibujo", + "live.plan.sketch.snap": "Ajustar a la cuadrícula", + "live.plan.sketch.hint.select": "Arrastra formas o cámaras para moverlas. Haz clic en una forma para editarla; mantén pulsado Alt para omitir la cuadrícula.", + "live.plan.sketch.hint.room": "Arrastra sobre el plano para dibujar una habitación o el contorno de un edificio.", + "live.plan.sketch.hint.wall": "Haz clic para añadir puntos de muro. Haz doble clic o pulsa Enter para terminar, Escape para cancelar.", + "live.plan.sketch.hint.area": "Haz clic para delimitar un área. Haz clic en el primer punto o pulsa Enter para cerrarla.", + "live.plan.sketch.hint.label": "Haz clic en el plano para colocar una etiqueta de texto.", + "live.plan.sketch.type.rect": "Habitación", + "live.plan.sketch.type.wall": "Muro", + "live.plan.sketch.type.area": "Área", + "live.plan.sketch.type.label": "Etiqueta", + "live.plan.sketch.pointCount": "{count} puntos", + "live.plan.sketch.defaultLabel": "Etiqueta", + "live.plan.sketch.shapes": "Formas del diseño", + "live.plan.sketch.noShapes": "Aún no hay nada dibujado. Elige una herramienta encima del plano para empezar.", + "live.plan.sketch.tone": "Color", + "live.plan.sketch.tone.slate": "Pizarra", + "live.plan.sketch.tone.blue": "Azul", + "live.plan.sketch.tone.green": "Verde", + "live.plan.sketch.tone.amber": "Ámbar", + "live.plan.sketch.tone.red": "Rojo", + "live.plan.sketch.tone.violet": "Violeta", + "live.plan.sketch.labelText": "Etiqueta", + "live.plan.sketch.text": "Texto", + "live.plan.sketch.size": "Tamaño", + "live.plan.sketch.size.sm": "Pequeño", + "live.plan.sketch.size.md": "Mediano", + "live.plan.sketch.size.lg": "Grande", + "live.plan.sketch.filled": "Rellenar la habitación", + "live.plan.sketch.left": "Izquierda %", + "live.plan.sketch.top": "Superior %", + "live.plan.sketch.width": "Ancho %", + "live.plan.sketch.height": "Alto %", + "live.plan.sketch.points": "Puntos", + "live.plan.sketch.point": "Punto {index}", + "live.plan.sketch.delete": "Eliminar la forma", + "live.plan.sketch.duplicate": "Duplicar", + "live.plan.sketch.deselect": "Listo", + "live.plan.sketch.emptyTitle": "Aún no hay nada en este plano", + "live.plan.sketch.emptyBody": "Dibuja habitaciones, muros y etiquetas aquí mismo, o sube un plano escaneado, un dibujo del sitio o una exportación PNG/JPEG (hasta 768 KB).", + "live.plan.sketch.emptyBodyReadOnly": "Un administrador puede dibujar el diseño o subir un plano del edificio real.", + "live.plan.sketch.drawLayout": "Dibujar el diseño", + "live.plan.sketch.uploadImage": "Subir imagen", + "live.plan.sketch.limitReached": "Límite de formas alcanzado ({max})", + "live.plan.sketch.discardDrawing": "Dibujo cancelado", "streamHealth.title": "Estado de la transmisión", "streamHealth.loading": "Cargando datos de salud...", "streamHealth.error": "No se pudieron cargar los datos de salud", @@ -405,6 +483,12 @@ "live.errorProcessingStreams": "Error al procesar los streams: {message}", "live.couldNotEnableFullscreen": "No se pudo activar el modo de pantalla completa: {message}", "live.allTags": "Todas las etiquetas", + "live.favorites": "Favoritos", + "live.favoritesOnly": "Mostrar solo cámaras favoritas", + "live.addFavorite": "Añadir {stream} a favoritos", + "live.removeFavorite": "Quitar {stream} de favoritos", + "live.noFavorites": "Aún no hay cámaras favoritas. Usa la estrella de un mosaico de cámara para añadir una.", + "live.favoriteUpdateError": "No se pudieron actualizar los favoritos: {message}", "live.tags": "Etiquetas", "live.stream": "Transmisión", "live.filterByTag": "Filtrar por etiqueta: {tag}", @@ -589,6 +673,7 @@ "live.forceRefreshWarning": "Esto interrumpirá brevemente la conexión de go2rtc y romperá la grabación activa. La grabación se reanudará automáticamente.", "live.viewInTimeline": "Ver en la línea de tiempo", "live.toggleFullscreen": "Alternar pantalla completa", + "live.resetZoom": "Restablecer el zoom", "live.streamStarting": "Iniciando transmisión...", "live.go2rtcNotRespondingRetry": "go2rtc está habilitado pero no responde. Comprueba el estado del servicio go2rtc. Haz clic en Reintentar para probar de nuevo.", "live.go2rtcHlsFailedRetry": "La transmisión HLS de go2rtc falló. Haz clic en Reintentar para volver a intentarlo.", @@ -603,12 +688,14 @@ "live.failedToCreateMediaBuffer": "No se pudo crear el búfer multimedia", "live.webSocketConnectionError": "Error de conexión WebSocket", "live.webrtcAutoplayBlocked": "Haz clic para reproducir el vídeo (reproducción automática bloqueada)", + "live.audioPlaybackBlocked": "El navegador bloqueó el audio de la cámara. Haz clic de nuevo en el botón del altavoz para reintentarlo.", "live.webrtcConnectionLostRetry": "Se perdió la conexión WebRTC. Haz clic en Reintentar para reconectar.", "live.streamConnectedNoVideoDataRetry": "La transmisión está conectada, pero no hay datos de vídeo. Haz clic en Reintentar para reconectar.", "live.failedToLoadVideo": "No se pudo cargar el vídeo", "live.webrtcIceConnectionFailed": "La conexión ICE de WebRTC falló", "live.webrtcConnectionLostPleaseRetry": "Se perdió la conexión WebRTC. Vuelve a intentarlo.", "live.autoRetryingIn": "Reintentando en {seconds} s…", + "live.fullscreenSubStreamFallback": "{stream}: no hay ancho de banda suficiente para la transmisión de resolución completa en pantalla completa; se cambió a la subtransmisión.", "live.connectionTimeoutCheckNetwork": "Tiempo de conexión agotado. Comprueba la configuración de red/firewall.", "live.failedToEstablishWebrtcConnection": "No se pudo establecer la conexión WebRTC", "live.cannotConnectToSource": "No se puede conectar a la fuente de cámara", @@ -622,6 +709,16 @@ "live.connectionQuality.bad": "Mala", "live.muteCameraAudio": "Silenciar audio de la cámara", "live.unmuteCameraAudio": "Activar audio de la cámara", + "live.tileActions": "Acciones de cámara", + "live.takeSnapshot": "Tomar una instantánea", + "live.openStreamRecordings": "Abrir las grabaciones de esta transmisión", + "live.enterReorderMode": "Reordenar cámaras", + "live.pullToRefresh": "Tira para actualizar las transmisiones", + "live.releaseToRefresh": "Suelta para actualizar las transmisiones", + "live.refreshingStreams": "Actualizando transmisiones…", + "live.streamsRefreshed": "Transmisiones actualizadas", + "live.refreshStreamsFailed": "No se pudieron actualizar las transmisiones: {message}", + "live.tipDoubleTapFullscreen": "Consejo: toca dos veces un mosaico para abrirlo en pantalla completa.", "live.switchToToggleMode": "Cambiar al modo conmutador", "live.switchToPushToTalkMode": "Cambiar a pulsar para hablar", "live.releaseToStopTalking": "Suelta para dejar de hablar", @@ -636,6 +733,40 @@ "live.pauseForPrivacyConfirm": "¿Pausar esta transmisión por motivos de privacidad? La grabación y la visualización en vivo se detendrán, pero la transmisión seguirá visible en esta página con una superposición de privacidad. Haz clic en Reanudar cuando termines.", "live.streamPausedForPrivacy": "Transmisión pausada por motivos de privacidad", "live.resumeStream": "Reanudar transmisión", + "live.dayNightControl": "Modo día/noche", + "live.dayNightLoading": "Cargando…", + "live.dayNightApplying": "Aplicando…", + "live.dayNightMode_auto": "Auto", + "live.dayNightMode_day": "Día", + "live.dayNightMode_night": "Noche", + "live.dayNightMode_unknown": "Desconocido", + "live.dayNightApplied": "Modo día/noche establecido en {mode}", + "live.dayNightApplyFailed": "No se pudo establecer el modo día/noche", + "live.dayNightLoadFailed": "No se pudo leer el modo día/noche", + "live.playbackFallbackUsed": "Respaldo: {transport}", + "live.playbackTransportUnavailable": "{transport} está deshabilitado en el servidor para esta transmisión.", + "live.recordingMode.constant": "Grabación constante", + "live.recordingMode.detection": "Grabación por detección", + "live.recordingMode.schedule": "Grabación programada", + "live.recordingMode.none": "Sin grabación", + "live.health.healthy": "Transmisión en buen estado", + "live.health.degraded": "Transmisión almacenando en búfer o recuperándose", + "live.health.offline": "Transmisión no disponible", + "live.enterPictureInPicture": "Abrir imagen en imagen", + "live.exitPictureInPicture": "Cerrar imagen en imagen", + "live.pictureInPictureError": "Falló la imagen en imagen: {message}", + "live.alwaysFullscreenOnTapEnable": "Habilitar pantalla completa con un solo toque en el mosaico", + "live.alwaysFullscreenOnTapDisable": "Deshabilitar pantalla completa con un solo toque en el mosaico", + "live.displayMode": "Modo de visualización", + "live.displayModeFit": "Ajustar", + "live.displayModeFill": "Rellenar", + "live.displayModeFitDescription": "Ajustar: mostrar el fotograma completo con barras negras", + "live.displayModeFillDescription": "Rellenar: llenar el mosaico y recortar los bordes del fotograma", + "live.slideshowStartCameras": "Iniciar presentación: recorrer las cámaras", + "live.slideshowStartPages": "Iniciar presentación: recorrer las páginas de la cuadrícula", + "live.slideshowStop": "Detener la presentación", + "live.slideshowInterval": "Intervalo de la presentación", + "live.slideshowSeconds": "{seconds} s", "streams.toggleDisable": "Deshabilitar transmisión", "streams.toggleEnable": "Habilitar transmisión", "streams.readOnlyInsufficientPermissions": "Sólo lectura (permisos insuficientes para modificar)", @@ -759,9 +890,9 @@ "streamsConfig.streamNameImmutable": "El nombre de la transmisión no se puede cambiar después de la creación", "streamsConfig.streamNameAllowedChars": "Sólo se permiten letras, dígitos, '.', '-' y '_' (sin espacios).", "streamsConfig.streamUrl": "URL de la transmisión", - "streamsConfig.streamUrlPlaceholder": "rtsp://nombre de usuario:contraseña@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "Subtransmisión URL (opcional)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://nombre de usuario:contraseña@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "URL de transmisión de baja resolución para la vista en cuadrícula del panel. Déjala vacía para usar la transmisión principal en todas partes. La subtransmisión solo se usa para la vista previa en vivo en modo cuadrícula; la grabación y la pantalla completa siempre usan la transmisión principal.", "streamsConfig.urlCredentialsHiddenTitle": "URL las credenciales están ocultas en el modo de demostración/visor", "streamsConfig.urlCredentialsHidden": "URL credenciales ocultas por seguridad", @@ -819,7 +950,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "Asegúrese de que Light-Object-Detect se esté ejecutando en este punto final", "streamsConfig.customApiEndpointUrl": "Personalizado API Punto final URL", "streamsConfig.useDefaultEndpoint": "Usar punto final predeterminado", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detectar", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "Ingresa la URL completa en tu endpoint de detección API personalizado", "streamsConfig.overrideWithCustomEndpoint": "Anular con punto final personalizado", "streamsConfig.detectionThreshold": "Umbral de detección", @@ -1056,7 +1187,7 @@ "settings.detectionModelsPath": "Ruta de los modelos de detección", "settings.detectionModelsPathHelp": "Directorio donde se almacenan los modelos de detección.", "settings.apiDetectionUrl": "API Detección URL", - "settings.apiDetectionUrlHelp": "URL del punto final de detección de objetos externos API", + "settings.apiDetectionUrlHelp": "Endpoint de light-object-detect, p. ej. http://localhost:8000/api/v1/detect. La instantánea se sube como datos de formulario multipart con los parámetros de consulta backend y confidence_threshold añadidos.", "settings.apiDetectionBackend": "API Detección de backend", "settings.apiDetectionBackendOnnx": "ONNX Tiempo de ejecución", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1156,5 +1287,1361 @@ "settings.discoveryIntervalSecondsRangeHelp": "Con qué frecuencia buscar cámaras (30 a 3600 segundos)", "settings.discoveryNetwork": "Red de descubrimiento", "settings.discoveryNetworkExamples": "Ejemplos: 192.168.1.0/24, 10.0.0.0/16, automático", - "settings.saveSettings": "Guardar configuración" + "settings.saveSettings": "Guardar configuración", + "live.plan.previewUnavailable": "Vista previa de cámara no disponible", + "live.plan.previewAlt": "Vista actual de {name}", + "live.plan.degreesValue": "{value} grados", + "live.plan.inDegrees": "{label} en grados", + "live.plan.imageDimensionsError": "No se pudieron leer las dimensiones de la imagen", + "live.plan.loading": "Cargando planos de edificios…", + "live.plan.created": "Creado {name}", + "live.plan.renamed": "Renombrado a {name}", + "live.plan.deleted": "Eliminado {name}", + "live.plan.backgroundType": "El fondo debe ser una imagen PNG o JPEG", + "live.plan.backgroundTooLarge": "La imagen de fondo es demasiado grande; el máximo es 768 KB", + "live.plan.backgroundAspect": "Se subió, pero la proporción de la imagen no coincide con ningún tamaño de lienzo válido", + "live.plan.backgroundUpdatedSave": "Fondo actualizado para {name}; guarda el diseño para aplicar su tamaño de lienzo", + "live.plan.backgroundNotResized": "Fondo subido, pero el lienzo no cambió de tamaño: {error}", + "live.plan.backgroundUpdated": "Fondo actualizado para {name}", + "live.plan.backgroundRemoved": "Fondo eliminado", + "live.plan.saved": "Guardado {name}", + "live.plan.createTitle": "Crear plano de edificio", + "live.plan.createDescription": "Ponle un nombre claro a este edificio o planta. Dibuja el diseño o sube una imagen de plano y luego coloca las cámaras.", + "live.plan.nameLabel": "Nombre del plano", + "live.plan.namePlaceholder": "Edificio principal · Primera planta", + "live.plan.createConfirm": "Crear plano", + "live.plan.eyebrow": "Plano de edificio", + "live.plan.placedSummary": "{placed} colocadas · {live} en vivo ahora", + "live.plan.zoomAndPan": "Zoom y desplazamiento del plano", + "live.plan.panLeft": "Desplazar a la izquierda", + "live.plan.panUp": "Desplazar hacia arriba", + "live.plan.panDown": "Desplazar hacia abajo", + "live.plan.panRight": "Desplazar a la derecha", + "live.plan.zoomOut": "Alejar", + "live.plan.zoomIn": "Acercar", + "live.plan.fitTitle": "Ajustar el plano", + "live.plan.fit": "Ajustar", + "live.plan.backgroundMenu": "Fondo…", + "live.plan.save": "Guardar el plano", + "live.plan.uploadBackgroundTitle": "Subir una imagen PNG o JPEG como fondo del plano", + "live.plan.replaceBackground": "Reemplazar el fondo", + "live.plan.uploadBackground": "Subir el fondo", + "live.plan.removeBackground": "Quitar el fondo", + "live.plan.rename": "Renombrar", + "live.plan.newPlan": "Nuevo plano", + "live.plan.editLayout": "Editar el diseño", + "live.plan.placementHint": "Haz clic en el plano para ubicar {name}", + "live.plan.clusterLabel": "{count} cámaras; amplía", + "live.plan.markerLabel": "{name}; {availability}; mirando a {rotation}° con una vista de {fov}°", + "live.plan.cameraFallback": "Cámara", + "live.plan.legendLive": "En vivo", + "live.plan.canvas": "Lienzo del plano", + "live.plan.width": "Ancho", + "live.plan.height": "Alto", + "live.plan.canvasHint": "Al subir una imagen de fondo, el lienzo se redimensiona para coincidir con ella.", + "live.plan.canvasInvalid": "El ancho debe ser 400–4000 y el alto 300–4000.", + "live.plan.openLive": "Abrir cámara en vivo", + "live.plan.direction": "Dirección de la cámara", + "live.plan.fov": "Campo de visión", + "live.plan.coverageNote": "Los sectores muestran solo la dirección y el ángulo; la distancia en el plano no está calibrada.", + "live.plan.removeCamera": "Quitar del plano", + "live.plan.selectCamera": "Selecciona una cámara", + "live.plan.selectHintEditing": "Arrastra los marcadores colocados para ajustar con precisión. Consulta el estado y abre una vista en vivo cuando la necesites.", + "live.plan.selectHint": "Consulta el estado y abre una vista en vivo cuando la necesites.", + "live.plan.cameras": "Cámaras del plano", + "live.plan.findPlaceholder": "Buscar en este plano…", + "live.plan.findLabel": "Buscar una cámara en este plano", + "live.plan.unplaced": "Cámaras sin colocar", + "live.plan.unplacedHint": "Selecciona una cámara y luego haz clic en su posición del plano.", + "live.plan.renameTitle": "Cambiar el nombre del plano", + "live.plan.renameDescription": "Los planos se comparten con todos los operadores de este sitio.", + "live.plan.deleteTitle": "Eliminar plano", + "live.plan.deleteMessage": "¿Eliminar “{name}” y su fondo subido? Las ubicaciones de cámaras de este plano se eliminan; las cámaras en sí no se modifican.", + "setupWizard.welcomeTitle": "Te damos la bienvenida a LightNVR", + "setupWizard.welcomeIntro": "Configura tu NVR en unos pasos rápidos. Siempre puedes volver a estos ajustes más tarde desde la página de Configuración.", + "setupWizard.welcomeStorage": "Ruta de almacenamiento y límites de tamaño", + "setupWizard.welcomePerformance": "Límites de rendimiento según el número de cámaras", + "setupWizard.welcomeSecurity": "Inicio de sesión seguro del administrador", + "setupWizard.storageTitle": "Almacenamiento y base de datos", + "setupWizard.storageIntro": "¿Dónde deben almacenarse las grabaciones y la base de datos?", + "setupWizard.storagePath": "Ruta de almacenamiento de grabaciones", + "setupWizard.storagePathHint": "Ruta absoluta donde se escriben los archivos de video.", + "setupWizard.maxStorage": "Tamaño máximo de almacenamiento (GB)", + "setupWizard.maxStorageHint": "0 = ilimitado.", + "setupWizard.dbPath": "Ruta de la base de datos", + "setupWizard.dbPathHint": "Ubicación del archivo de base de datos SQLite.", + "setupWizard.performanceTitle": "Rendimiento", + "setupWizard.performanceIntro": "Estos ajustes controlan la capacidad, no la calidad del video. La mayoría de los usuarios puede conservar los valores predeterminados.", + "setupWizard.threadPool": "Tamaño del grupo de subprocesos de trabajo", + "setupWizard.threadPoolInfo": "afecta al trabajo en segundo plano de web/servidor. El valor recomendado suele ser el mejor, salvo que estés ajustando el rendimiento.", + "setupWizard.maxStreams": "Máximo de transmisiones simultáneas", + "setupWizard.maxStreamsInfo": "es el límite de capacidad de cámaras para esta instancia en ejecución. Ponlo al menos en el número de cámaras que piensas añadir, más un pequeño margen.", + "setupWizard.important": "Importante:", + "setupWizard.restartWarning": "si cambias cualquiera de los dos ajustes, el nuevo valor se guarda ahora, pero no se usará hasta que LightNVR se reinicie. Por ejemplo, si el límite actual de transmisiones es 1 y lo subes a 32, debes reiniciar antes de añadir más cámaras que superen el límite anterior.", + "setupWizard.threadPoolHintCores": "Recomendado: {recommended} (2× tu CPU de {cores} núcleos). Esto controla los subprocesos de trabajo en segundo plano de libuv. Rango: 2–128.", + "setupWizard.threadPoolHint": "Recomendado: {recommended} (2× los núcleos de tu CPU). Esto controla los subprocesos de trabajo en segundo plano de libuv. Rango: 2–128.", + "setupWizard.maxStreamsHint": "Cuántas cámaras puede mantener activas LightNVR a la vez. Valor predeterminado 32, máximo {max}. Si esperas tener 8 cámaras, elige al menos 8. Requiere reiniciar para que surta efecto.", + "setupWizard.completeTitle": "¡Configuración completada!", + "setupWizard.saved": "Tus ajustes se han guardado correctamente.", + "setupWizard.notSaved": "No se cambió ningún ajuste; se usarán los valores predeterminados.", + "setupWizard.restartRequired": "Reinicio necesario", + "setupWizard.restartRequiredInfo": "los cambios del tamaño del grupo de subprocesos y/o del máximo de transmisiones se guardan, pero no surtirán efecto hasta que se reinicie el servicio. Reinicia antes de añadir más cámaras o de esperar que se aplique el nuevo límite de capacidad.", + "setupWizard.saveFailed": "No se pudieron guardar los ajustes: {error}", + "setupWizard.back": "Atrás", + "setupWizard.saving": "Guardando…", + "setupWizard.saveContinue": "Guardar y continuar", + "setupWizard.next": "Siguiente →", + "setupWizard.finish": "Ir al panel de control", + "setupWizard.skip": "Omitir el asistente de configuración", + "live.eptzCanvasLabel": "Vista de panorámica, inclinación y zoom electrónico con ojo de pez", + "live.eptzCanvasHint": "Arrastra para mover e inclinar; rueda o pellizco para el zoom; Home restablece", + "live.eptzReset": "Restablecer la vista ePTZ", + "live.autoShort": "Auto", + "live.webrtcShort": "WebRTC", + "nav.investigation": "Investigación", + "availability.label": "Disponibilidad de cámaras", + "availability.live": "En vivo ahora", + "availability.offline": "Sin conexión (conectada previamente)", + "availability.neverConnected": "Nunca conectada", + "availability.disabled": "Deshabilitada", + "availability.all": "Todas las cámaras", + "streams.inventory": "Inventario", + "streams.configuration": "Configuración", + "events.tab": "Eventos", + "events.eyebrow": "Integraciones basadas en eventos", + "events.title": "Eventos y enrutamiento", + "events.description": "Convierte eventos de cámara y sistema en flujos MQTT persistentes para automatización, servicios de notificación y procesamiento externo. LightNVR proporciona la interfaz de eventos; la entrega por correo y SMS se gestiona en servicios posteriores.", + "events.routes": "Rutas", + "events.destinations": "Destinos", + "events.catalog": "Catálogo de eventos", + "events.enable": "Habilitar", + "events.loadError": "No se pudo cargar la configuración de enrutamiento de eventos", + "events.accessDenied": "Acceso denegado - privilegios insuficientes", + "events.summary.routes": "Rutas", + "events.summary.enabled": "{count} habilitadas", + "events.summary.destinations": "Destinos", + "events.summary.managedActive": "{count} gestionadas y activas", + "events.summary.types": "Tipos registrados", + "events.summary.registry": "Catálogo de eventos versionado", + "events.summary.interface": "Interfaz", + "events.summary.interfaceHelp": "Salida de eventos persistente", + "events.route.add": "Añadir ruta", + "events.route.addTitle": "Crear ruta de eventos", + "events.route.editTitle": "Editar ruta de eventos", + "events.route.create": "Crear ruta", + "events.route.editorDescription": "Selecciona qué eventos califican, qué cámaras están en el alcance, a dónde se envían y cómo se controlan las fuentes ruidosas.", + "events.route.emptyTitle": "No hay rutas de eventos configuradas", + "events.route.emptyDescription": "Cree una ruta para seleccionar tipos de eventos, alcance de cámaras, horario, política de supresión y destino MQTT.", + "events.route.enabled": "Ruta habilitada", + "events.route.enabledHelp": "Los eventos coincidentes se aceptan para entrega persistente", + "events.route.destination": "Destino", + "events.route.destinationHelp": "Un evento coincidente se persiste una vez por cada destino único.", + "events.route.eventTypes": "Tipos de eventos", + "events.route.eventTypesHelp": "Seleccione uno o más contratos de eventos versionados del registro.", + "events.route.detectionFilters": "Filtrar detecciones de objetos", + "events.route.detectionFiltersHelp": "Opcionalmente, requiera etiquetas, zonas o una confianza mínima para eventos de detección de objetos.", + "events.route.healthFilters": "Filtrar eventos de salud del sistema", + "events.route.healthFiltersHelp": "Opcionalmente, coincida con códigos de condiciones de salud o severidades registrados. Los valores disponibles provienen de este grabador.", + "events.route.healthConditions": "Condiciones de salud (cualquiera)", + "events.route.healthSeverities": "Severidades (cualquiera)", + "events.route.healthRegistryUnavailable": "El registro de condiciones de salud no está disponible. Recargue antes de configurar filtros de condiciones.", + "events.route.labels": "Etiquetas (cualquiera)", + "events.route.zones": "IDs de zona (cualquiera)", + "events.route.listHelp": "Separe los valores con comas.", + "events.route.minConfidence": "Confianza mínima", + "events.route.confidenceHelp": "Un valor de 0 a 1.", + "events.route.cameraScope": "Alcance de cámaras", + "events.route.cameraScopeHelp": "Reutilice ubicaciones de flota, etiquetas, colecciones de atributos o cámaras explícitas sin cargar la flota completa.", + "events.route.allCameras": "Todas las cámaras", + "events.route.dynamicScope": "Selector dinámico de cámaras", + "events.route.systemScopeHelp": "Los eventos del sistema no son cámaras. Los selectores de cámaras no están disponibles cuando esta ruta incluye eventos de alcance del sistema.", + "events.route.schedule": "Horario", + "events.route.scheduleHelp": "Use la hora de ocurrencia del evento en una zona horaria IANA; se admiten ventanas nocturnas.", + "events.route.restrictSchedule": "Solo durante ventanas configuradas", + "events.route.suppression": "Política de ruido y entrega", + "events.route.suppressionHelp": "Cero deshabilita un control. La supresión avanza solo después de que ese destino acepte el evento persistente.", + "events.route.debounce": "Segundos de debounce", + "events.route.debounceHelp": "Las observaciones repetidas extienden este intervalo de silencio.", + "events.route.cooldown": "Segundos de enfriamiento", + "events.route.cooldownHelp": "Intervalo mínimo después de un evento aceptado.", + "events.route.grouping": "Segundos de ventana de agrupación", + "events.route.groupingHelp": "Conserva el primer evento y agrupa las repeticiones.", + "events.route.rateLimit": "Eventos por minuto", + "events.route.rateLimitHelp": "Máximo en ventana fija por ruta y cámara.", + "events.route.deliveryPolicy": "Política de entrega", + "events.route.suppressionActive": "Controles de ruido activos", + "events.route.everyMatch": "Cada coincidencia", + "events.route.preview": "Vista previa de ruta", + "events.route.previewing": "Vista previa…", + "events.route.previewResult": "Vista previa de ruta", + "events.route.cameraMatches": "{count} cámaras coinciden", + "events.route.previewNoPublish": "La vista previa valida la regla completa y resuelve una muestra de cámara; nunca publica un evento.", + "events.route.systemPreviewHelp": "Los eventos del sistema omiten la selección de cámara y por lo tanto reportan cero cámaras coincidentes en esta vista previa.", + "events.route.created": "Ruta de eventos creada", + "events.route.updated": "Ruta de eventos actualizada", + "events.route.deleted": "Ruta de eventos eliminada", + "events.route.disabled": "Ruta de eventos deshabilitada", + "events.route.enabledMessage": "Ruta de eventos habilitada", + "events.route.deleteConfirm": "¿Eliminar la ruta de eventos \"{name}\"?", + "events.route.validation.name": "Introduce un nombre de ruta.", + "events.route.validation.destination": "Elige un destino.", + "events.route.validation.event_types": "Selecciona al menos un tipo de evento.", + "events.route.validation.selector": "Completa o corrige el selector de cámara.", + "events.route.validation.system_scope": "Los selectores de cámara no se pueden usar con eventos de ámbito del sistema.", + "events.route.validation.detection_type": "Los filtros de detección requieren el tipo de evento de detección de objetos.", + "events.route.validation.detection_filter": "Añade al menos una etiqueta de detección, zona o umbral de confianza.", + "events.route.validation.confidence": "La confianza mínima debe estar entre 0 y 1.", + "events.route.validation.predicate_mix": "Los filtros de detección y de salud no se pueden combinar en una misma ruta.", + "events.route.validation.health_type": "Los filtros de salud requieren únicamente tipos de evento de salud del sistema registrados.", + "events.route.validation.health_filter": "Selecciona al menos una condición de salud o severidad registrada.", + "events.route.validation.health_condition": "Seleccione solo los códigos de condición devueltos por el registro de salud del grabador.", + "events.route.validation.health_severity": "Seleccione solo las severidades compatibles con los tipos de eventos de salud seleccionados.", + "events.route.validation.timezone": "Introduzca una zona horaria IANA instalada, como UTC o America/New_York.", + "events.route.validation.schedule_window": "Cada ventana de programación necesita al menos un día y horas de inicio y fin válidas y distintas.", + "events.route.validation.suppression": "Los valores de supresión deben ser números enteros dentro de sus rangos permitidos.", + "events.schedule.timezone": "Zona horaria", + "events.schedule.timezoneHelp": "Debe existir en la base de datos de zonas horarias del grabador.", + "events.schedule.addWindow": "Añadir ventana de tiempo", + "events.schedule.windowNumber": "Ventana {number}", + "events.schedule.start": "Inicio", + "events.schedule.end": "Fin", + "events.schedule.sunday": "Dom", + "events.schedule.monday": "Lun", + "events.schedule.tuesday": "Mar", + "events.schedule.wednesday": "Mié", + "events.schedule.thursday": "Jue", + "events.schedule.friday": "Vie", + "events.schedule.saturday": "Sáb", + "events.destination.add": "Añadir destino", + "events.destination.addTitle": "Añadir destino MQTT", + "events.destination.editTitle": "Editar destino MQTT", + "events.destination.create": "Crear destino", + "events.destination.editorDescription": "Configure una salida de eventos persistente. Las credenciales son de solo escritura y nunca se devuelven por la API.", + "events.destination.default": "Configuración MQTT predeterminada", + "events.destination.settingsManaged": "Configuración gestionada", + "events.destination.defaultDescription": "La configuración MQTT existente sigue disponible como mqtt:default y es utilizada por {count} rutas.", + "events.destination.openSettings": "Abrir configuración MQTT", + "events.destination.emptyTitle": "Sin destinos gestionados", + "events.destination.emptyDescription": "Añada otro broker MQTT para la entrega independiente de eventos a un conector en la nube, un sistema de automatización o un servicio de notificaciones.", + "events.destination.identity": "Identidad del destino", + "events.destination.enabled": "Destino habilitado", + "events.destination.enabledHelp": "Conectar y vaciar su cola persistente", + "events.destination.active": "Activo", + "events.destination.paused": "En pausa", + "events.destination.pause": "Pausar", + "events.destination.broker": "Broker", + "events.destination.host": "Host del broker", + "events.destination.hostHelp": "Solo nombre de host o dirección IP; no incluya un esquema de URL.", + "events.destination.port": "Puerto", + "events.destination.clientId": "ID de cliente", + "events.destination.clientIdHelp": "Debe ser único para esta conexión al broker.", + "events.destination.topic": "Tema", + "events.destination.topicTemplate": "Plantilla de tema", + "events.destination.topicHelp": "Debe incluir los tokens de tipo de evento y ID de sujeto; no se permiten comodines MQTT.", + "events.destination.keepalive": "Segundos de keepalive", + "events.destination.statusTopicTemplate": "Tema de estado de presencia", + "events.destination.statusTopicHelp": "Opcional. Debe incluir {installation_uuid}; {destination_uuid} también está disponible. No se permiten comodines MQTT.", + "events.destination.statusTopicEnabled": "La presencia está habilitada explícitamente para este destino. El tema nunca se infiere del tema de evento.", + "events.destination.statusTopicDisabled": "La presencia está deshabilitada para este destino. Deje este campo vacío para mantenerla deshabilitada.", + "events.destination.qos": "Calidad de servicio", + "events.destination.qos0": "enviar una vez", + "events.destination.qos1": "al menos una vez", + "events.destination.qos2": "exactamente una vez", + "events.destination.authentication": "Autenticación", + "events.destination.passwordPreserved": "Deje en blanco para conservar la contraseña de solo escritura almacenada.", + "events.destination.passwordOptional": "Opcional cuando el broker permite clientes anónimos.", + "events.destination.clearPassword": "Borrar la contraseña almacenada", + "events.destination.transportSecurity": "Seguridad de transporte", + "events.destination.tlsMode": "Modo TLS", + "events.destination.tlsSystem": "Almacén de confianza del sistema", + "events.destination.tlsCustomCa": "Autoridad de certificación personalizada", + "events.destination.tlsMutual": "TLS mutuo", + "events.destination.tlsDisabled": "Deshabilitado (texto plano)", + "events.destination.tlsHelp.system": "Verificar el certificado del broker contra el almacén de confianza del sistema operativo.", + "events.destination.tlsHelp.custom_ca": "Verificar el broker contra un archivo de autoridad de certificación PEM explícito.", + "events.destination.tlsHelp.mutual": "Verificar el broker con una CA explícita y presentar un certificado y clave de cliente.", + "events.destination.tlsHelp.disabled": "Sin cifrado de transporte ni verificación de identidad del broker.", + "events.destination.caFile": "Archivo CA", + "events.destination.certFile": "Archivo de certificado de cliente", + "events.destination.keyFile": "Archivo de clave de cliente", + "events.destination.absolutePathHelp": "Use una ruta absoluta legible por el servicio de LightNVR.", + "events.destination.plaintextWarning": "MQTT en texto plano puede exponer metadatos de eventos y credenciales. Úselo solo en una red de confianza y aislada.", + "events.destination.security": "Seguridad", + "events.destination.tls.system": "Confiar en el sistema", + "events.destination.tls.custom_ca": "CA personalizada", + "events.destination.tls.mutual": "TLS mutuo", + "events.destination.tls.disabled": "Texto plano", + "events.destination.routes": "Rutas", + "events.destination.presence": "Tema de presencia", + "events.destination.deleteInUse": "Elimine o redirija las rutas antes de eliminar este destino.", + "events.destination.created": "Destino MQTT creado", + "events.destination.updated": "Destino MQTT actualizado", + "events.destination.deleted": "Destino MQTT eliminado", + "events.destination.pausedMessage": "Destino MQTT pausado; los eventos en cola permanecen persistentes hasta su expiración.", + "events.destination.enabledMessage": "Destino MQTT habilitado", + "events.destination.deleteConfirm": "¿Eliminar el destino MQTT \"{name}\"?", + "events.destination.validation.name": "Introduzca un nombre de destino.", + "events.destination.validation.host": "Introduzca un nombre de host o dirección IP del broker.", + "events.destination.validation.client_id": "Introduzca un ID de cliente del broker.", + "events.destination.validation.topic": "El tema debe incluir los tokens de tipo de evento e ID de sujeto y no puede contener comodines MQTT.", + "events.destination.validation.status_topic": "El tema de presencia opcional debe incluir el token de UUID de instalación, usar solo tokens compatibles y no puede contener comodines MQTT.", + "events.destination.validation.port": "El puerto debe ser un número entero de 1 a 65535.", + "events.destination.validation.keepalive": "El keepalive debe ser un número entero de 5 a 3600 segundos.", + "events.destination.validation.qos": "Seleccione MQTT QoS 0, 1 o 2.", + "events.destination.validation.username": "Una contraseña configurada requiere un nombre de usuario.", + "events.destination.validation.ca_file": "Este modo TLS requiere una ruta absoluta al archivo CA.", + "events.destination.validation.mutual_files": "El TLS mutuo requiere rutas absolutas de CA, certificado de cliente y clave de cliente.", + "fleet.eyebrow": "Operaciones de cámara", + "fleet.title": "Inventario de cámaras", + "fleet.description": "Encuentra, evalúa y organiza cámaras en grandes despliegues sin cargar todo el inventario en el navegador.", + "fleet.summary": "Resumen de salud de la flota", + "fleet.totalCameras": "Cámaras coincidentes", + "fleet.needsAttention": "Degradada", + "fleet.searchLabel": "Buscar cámaras", + "fleet.searchPlaceholder": "Buscar por nombre, dirección, ubicación, etiqueta, fabricante o modelo…", + "fleet.resultCount": "{count} cámaras", + "fleet.filters": "Filtros", + "fleet.clearFilters": "Borrar filtros", + "fleet.filter.health": "Salud", + "fleet.filter.enabled": "Estado de la cámara", + "fleet.filter.anyState": "Cualquier estado", + "fleet.filter.recording": "Modo de grabación", + "fleet.filter.location": "Subárbol de ubicaciones", + "fleet.filter.allLocations": "Todas las ubicaciones", + "fleet.filter.tags": "Etiquetas (coincidencia cualquiera)", + "fleet.filter.collection": "Colección de cámaras", + "fleet.health.unknown": "Desconocido", + "fleet.health.up": "En línea", + "fleet.health.degraded": "Degradada", + "fleet.health.down": "Sin conexión", + "fleet.health.disabled": "Deshabilitada", + "fleet.recording.off": "Apagada", + "fleet.recording.continuous": "Continua", + "fleet.recording.detection": "Detección", + "fleet.recordingActive": "Grabando ahora", + "fleet.recordingInactive": "Sin grabar", + "fleet.column.camera": "Cámara", + "fleet.column.health": "Salud", + "fleet.column.location": "Ubicación", + "fleet.column.tags": "Etiquetas", + "fleet.column.recording": "Grabación", + "fleet.viewLive": "En vivo", + "fleet.lastFrame": "Último fotograma", + "fleet.noAddress": "Dirección no disponible", + "fleet.unassigned": "Sin asignar", + "fleet.loading": "Cargando flota de cámaras…", + "fleet.refreshing": "Actualizando…", + "fleet.loadError": "No se pudo cargar la flota de cámaras", + "fleet.emptyTitle": "No hay cámaras configuradas", + "fleet.emptyDescription": "Añade una transmisión para que esté disponible en el espacio de trabajo de la flota.", + "fleet.emptyFilteredTitle": "Ninguna cámara coincide con esta vista", + "fleet.emptyFilteredDescription": "Amplía la búsqueda o elimina uno o más filtros.", + "fleet.paginationSummary": "Mostrando {first}–{last} de {total}", + "fleet.perPage": "Por página", + "fleet.pageOf": "Página {page} de {pages}", + "fleet.selectPage": "Seleccionar todas las cámaras de esta página", + "fleet.selectCamera": "Seleccionar {name}", + "fleet.selectedCount": "{count} cámaras seleccionadas", + "fleet.organizeSelected": "Organizar seleccionadas", + "fleet.clearSelection": "Borrar selección", + "fleet.organization.manage": "Gestionar organización", + "fleet.organization.title": "Organización de cámaras", + "fleet.organization.description": "Mantén una jerarquía de ubicaciones reutilizable y un diccionario de etiquetas normalizado para la flota de cámaras.", + "fleet.organization.locations": "Ubicaciones", + "fleet.organization.tags": "Etiquetas", + "fleet.organization.locationsDescription": "Modela sitios, edificios, plantas y áreas operativas como una jerarquía navegable.", + "fleet.organization.tagsDescription": "Usa un diccionario de etiquetas controlado en lugar de etiquetas libres inconsistentes.", + "fleet.organization.addRoot": "Añadir ubicación de nivel superior", + "fleet.organization.addLocation": "Añadir ubicación", + "fleet.organization.editLocation": "Editar ubicación", + "fleet.organization.addChild": "Agregar sububicación", + "fleet.organization.type": "Tipo", + "fleet.organization.parent": "Ubicación principal", + "fleet.organization.topLevel": "Nivel superior", + "fleet.organization.sortOrder": "Orden de clasificación", + "fleet.organization.contents": "Contenido", + "fleet.organization.cameras": "Cámaras", + "fleet.organization.system": "Sistema", + "fleet.organization.contentCounts": "{cameras} cámaras · {children} sububicaciones", + "fleet.organization.locationNotEmpty": "Mueva las cámaras y elimine las sububicaciones primero", + "fleet.organization.noLocations": "No hay ubicaciones configuradas.", + "fleet.organization.locationCreated": "Ubicación creada", + "fleet.organization.locationUpdated": "Ubicación actualizada", + "fleet.organization.locationDeleted": "Ubicación eliminada", + "fleet.organization.deleteLocationConfirm": "¿Eliminar la ubicación \"{name}\"?", + "fleet.organization.addTag": "Agregar etiqueta", + "fleet.organization.editTag": "Editar etiqueta", + "fleet.organization.tagLabel": "Etiqueta", + "fleet.organization.color": "Color (#RRGGBB)", + "fleet.organization.tagDescription": "Descripción", + "fleet.organization.noTags": "No hay etiquetas normalizadas configuradas.", + "fleet.organization.tagCreated": "Etiqueta creada", + "fleet.organization.tagUpdated": "Etiqueta actualizada", + "fleet.organization.tagDeleted": "Etiqueta eliminada", + "fleet.organization.deleteTagConfirm": "¿Eliminar \"{name}\"? Está asignada actualmente a {count} cámaras.", + "fleet.organization.merge": "Combinar", + "fleet.organization.mergeTagNamed": "Combinar \"{name}\"", + "fleet.organization.mergeInto": "Combinar con", + "fleet.organization.chooseTag": "Elija la etiqueta a conservar", + "fleet.organization.mergeWarning": "Todas las asignaciones de cámaras se moverán a la etiqueta conservada; la etiqueta de origen se eliminará después.", + "fleet.organization.tagsMerged": "Etiquetas combinadas", + "fleet.organization.saveError": "No se pudo guardar: {message}", + "fleet.organization.deleteError": "No se pudo eliminar: {message}", + "fleet.locationType.site": "Sitio", + "fleet.locationType.building": "Edificio", + "fleet.locationType.floor": "Piso", + "fleet.locationType.area": "Área", + "fleet.locationType.zone": "Zona", + "fleet.locationType.system": "Sistema", + "fleet.bulk.title": "Organizar cámaras seleccionadas", + "fleet.bulk.description": "Aplicar cambios de ubicación y etiquetas a {count} cámaras con concurrencia limitada.", + "fleet.bulk.location": "Asignación de ubicación", + "fleet.bulk.locationHelp": "Todas las cámaras seleccionadas se moverán a la ubicación elegida.", + "fleet.bulk.keepLocations": "Mantener ubicaciones actuales", + "fleet.bulk.tags": "Asignación de etiquetas", + "fleet.bulk.tagsHelp": "Agregar o eliminar etiquetas sin afectar otras asignaciones, o reemplazar explícitamente el conjunto completo de etiquetas.", + "fleet.bulk.tagOperation.none": "Mantener", + "fleet.bulk.tagOperation.add": "Agregar", + "fleet.bulk.tagOperation.remove": "Eliminar", + "fleet.bulk.tagOperation.replace": "Reemplazar todo", + "fleet.bulk.replaceWarning": "Reemplazar todo elimina todas las etiquetas actuales antes de aplicar esta selección. Una selección vacía borra todas las etiquetas.", + "fleet.bulk.apply": "Aplicar cambios", + "fleet.bulk.working": "Aplicando cambios…", + "fleet.bulk.success": "{count} cámaras actualizadas", + "fleet.bulk.partial": "{succeeded} cámaras actualizadas; {failed} fallidas", + "fleet.bulk.error": "No se pudieron organizar las cámaras: {message}", + "fleet.bulk.failures": "Cámaras que no se pudieron actualizar", + "fleet.queues.degraded": "Flujos degradados", + "fleet.queues.offline": "Cámaras sin conexión", + "fleet.queues.oldest": "Más antiguo: {time}", + "fleet.queues.noneActive": "Sin condiciones activas", + "fleet.views.title": "Vistas guardadas", + "fleet.views.choose": "Elegir una vista guardada", + "fleet.views.none": "Aún no hay vistas guardadas", + "fleet.views.shared": "Compartida", + "fleet.views.saveCurrent": "Guardar vista actual", + "fleet.views.name": "Nombre de la vista", + "fleet.views.share": "Compartir con todos los operadores", + "fleet.views.saved": "Vista de flota guardada", + "fleet.views.saveError": "No se pudo guardar la vista: {message}", + "fleet.views.deleted": "Vista de flota eliminada", + "fleet.views.deleteConfirm": "¿Eliminar la vista guardada \"{name}\"?", + "fleet.views.deleteError": "No se pudo eliminar la vista: {message}", + "fleet.views.unsupported": "Este selector guardado no puede representarse con los controles de filtro actuales.", + "collections.manage": "Colecciones", + "collections.all": "Todas las colecciones", + "collections.filter": "Colección", + "collections.loadMembersError": "No se pudieron cargar las cámaras de la colección: {message}", + "collections.title": "Colecciones de cámaras", + "collections.subtitle": "Crea grupos de cámaras reutilizables para operaciones, vistas guardadas y flujos de trabajo posteriores.", + "collections.listDescription": "Las colecciones estáticas mantienen una pertenencia explícita; las colecciones inteligentes evalúan continuamente las reglas de flota.", + "collections.create": "Crear colección", + "collections.edit": "Editar colección", + "collections.editorDescription": "Las definiciones de colecciones utilizan UUIDs estables de cámaras, ubicaciones y etiquetas.", + "collections.backToList": "Volver a colecciones", + "collections.type": "Tipo de colección", + "collections.type.static": "Estática", + "collections.type.smart": "Inteligente", + "collections.description": "Descripción", + "collections.shared": "Colección compartida", + "collections.sharedHelp": "Permitir que otros usuarios autorizados vean esta colección; las reglas de acceso a cámaras siguen aplicándose.", + "collections.typeChangeWarning": "Cambiar el tipo de colección reemplaza su modelo de pertenencia. Los miembros estáticos o las reglas inteligentes del tipo anterior ya no se aplicarán.", + "collections.selectorError": "El selector no es válido: {message}", + "collections.created": "Colección creada", + "collections.updated": "Colección actualizada", + "collections.saveError": "No se pudo guardar la colección: {message}", + "collections.loadError": "No se pudo cargar la colección: {message}", + "collections.cameras": "cámaras", + "collections.visibility.shared": "Compartida", + "collections.visibility.private": "Privada", + "collections.selectorRedacted": "Reglas privadas", + "collections.emptyTitle": "Aún no hay colecciones", + "collections.emptyAdmin": "Crea un grupo estático o una vista inteligente basada en reglas para reutilizar selecciones de cámaras.", + "collections.emptyViewer": "No hay colecciones compartidas disponibles para tu alcance de cámaras.", + "collections.deleteConfirm": "¿Eliminar la colección \"{name}\"?", + "collections.deleted": "Colección eliminada", + "collections.deleteError": "No se pudo eliminar la colección: {message}", + "collections.preview.title": "Vista previa de reglas", + "collections.preview.matches": "{count} cámaras coincidentes", + "collections.preview.action": "Vista previa", + "collections.preview.hide": "Ocultar vista previa", + "collections.preview.loading": "Evaluando…", + "collections.preview.empty": "Ninguna cámara coincide actualmente.", + "collections.preview.sample": "Mostrando una muestra de {count} cámaras de {total} coincidencias.", + "collections.preview.error": "No se pudo previsualizar la colección: {message}", + "collections.members.title": "Miembros estáticos", + "collections.members.selected": "{count} cámaras seleccionadas en todas las páginas", + "collections.members.search": "Buscar cámaras…", + "collections.members.selectPage": "Seleccionar esta página", + "collections.members.empty": "Ninguna cámara coincide con esta búsqueda.", + "collections.builder.title": "Reglas inteligentes", + "collections.builder.description": "Las reglas se evalúan según la organización, configuración, capacidades y estado actual de las cámaras.", + "collections.builder.match": "Coincidir", + "collections.builder.allRules": "todas las reglas", + "collections.builder.anyRule": "cualquier regla", + "collections.builder.addRule": "Agregar regla", + "collections.builder.removeRule": "Eliminar regla", + "collections.builder.matchesAll": "Sin reglas completas, esta colección coincide con todas las cámaras en el alcance autorizado del usuario.", + "collections.builder.incompleteRule": "Complete o elimine todas las reglas antes de guardar.", + "collections.builder.chooseLocation": "Elija un subárbol de ubicación", + "collections.builder.vendorPlaceholder": "Nombres de fabricantes, separados por comas", + "collections.builder.modelPlaceholder": "Nombres de modelos, separados por comas", + "collections.builder.advancedMode": "JSON avanzado", + "collections.builder.visualMode": "Constructor visual", + "collections.builder.cannotVisualize": "Este selector contiene lógica anidada o avanzada que el constructor visual no puede representar de forma segura.", + "collections.rule.location_subtree": "La ubicación está dentro de", + "collections.rule.camera_uuid": "Cámaras específicas", + "collections.rule.tag_any": "Tiene alguna etiqueta", + "collections.rule.tag_all": "Tiene todas las etiquetas", + "collections.rule.tag_none": "No tiene ninguna de las etiquetas", + "collections.rule.health": "El estado de salud es", + "collections.rule.enabled": "La cámara está", + "collections.rule.recording_mode": "El modo de grabación es", + "collections.rule.capability_any": "Tiene alguna capacidad", + "collections.rule.capability_all": "Tiene todas las capacidades", + "collections.rule.vendor": "El fabricante es", + "collections.rule.model": "El modelo es", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Canal de retorno de audio", + "streamHealth.observedFps": "FPS observados", + "streamHealth.expectedFps": "Esperado", + "streamHealth.fpsHelp": "Observado por LightNVR; el valor esperado proviene de los metadatos del flujo de la cámara.", + "login.passwordChanged": "Contraseña cambiada correctamente. Inicie sesión con su nueva contraseña.", + "passwordChangeRequired.title": "Cambiar la contraseña predeterminada", + "passwordChangeRequired.description": "Esta instalación aún utiliza la contraseña de administrador predeterminada. Reemplácela antes de continuar a LightNVR. La MFA, cuando esté habilitada, se verificará en su próximo inicio de sesión.", + "passwordChangeRequired.currentPassword": "Contraseña actual", + "passwordChangeRequired.newPassword": "Nueva contraseña", + "passwordChangeRequired.confirmPassword": "Confirmar nueva contraseña", + "passwordChangeRequired.passwordHelp": "Use al menos 8 caracteres. La contraseña no puede ser admin.", + "passwordChangeRequired.submit": "Cambiar contraseña", + "passwordChangeRequired.saving": "Cambiando contraseña...", + "passwordChangeRequired.error.currentRequired": "Introduce tu contraseña actual.", + "passwordChangeRequired.error.tooShort": "La nueva contraseña debe tener al menos 8 caracteres.", + "passwordChangeRequired.error.defaultPassword": "La nueva contraseña no puede ser admin.", + "passwordChangeRequired.error.mismatch": "Las nuevas contraseñas no coinciden.", + "passwordChangeRequired.error.generic": "No se pudo cambiar la contraseña. Inténtalo de nuevo.", + "settings.tab.health": "Salud", + "settings.tab.workspaces": "Espacios de trabajo", + "settings.health.title": "Salud del host y del hardware", + "settings.health.description": "Configura la monitorización limitada del sistema operativo y del hardware sin exponer rutas de dispositivos ni secretos.", + "settings.health.enabled": "Habilitar monitorización de salud", + "settings.health.enabledHelp": "Recopila señales compatibles de host, servicios, almacenamiento, red y hardware.", + "settings.health.profile": "Perfil de política", + "settings.health.profileHelp": "Equilibrado es el valor predeterminado normal; conservador requiere evidencia más sólida antes de generar alertas.", + "settings.health.profile.balanced": "Equilibrado", + "settings.health.profile.conservative": "Conservador", + "settings.health.hardwareProvider": "Proveedor de hardware", + "settings.health.provider.auto": "Automático (proveedores del kernel)", + "settings.health.provider.smartctl": "smartctl (explícito)", + "settings.health.providerHelp.auto": "Utiliza únicamente proveedores limitados de sysfs, NVMe y kernel; smartctl nunca se infiere.", + "settings.health.providerHelp.smartctl": "Habilita explícitamente el proveedor JSON opcional y limitado de smartctl para los dispositivos detectados.", + "settings.health.providerHelp.disabled": "Deshabilita los proveedores de hardware opcionales manteniendo disponible la monitorización de salud portátil.", + "settings.health.writeProbe": "Habilitar prueba de escritura en almacenamiento", + "settings.health.writeProbeHelp": "Realiza periódicamente la prueba limitada del destino de grabación configurado.", + "settings.health.cadences": "Cadencias de muestreo", + "settings.health.cadencesHelp": "Los intervalos deben mantenerse ordenados desde el muestreo rápido hasta el de dispositivos y dentro de los límites del servidor.", + "settings.health.fastInterval": "Intervalo rápido", + "settings.health.normalInterval": "Intervalo normal", + "settings.health.slowInterval": "Intervalo lento", + "settings.health.deviceInterval": "Intervalo de dispositivo", + "settings.health.presenceInterval": "Intervalo de presencia", + "settings.health.retention": "Retención de incidentes", + "settings.health.conditions": "Anulaciones de condición", + "settings.health.conditionsHelp": "Anule solo los códigos de condición y unidades devueltos por el registro de política efectiva.", + "settings.health.conditionOverride": "anulación de condición", + "settings.health.overrideMode": "Modo de anulación", + "settings.health.overrideModeHelp": "Heredar el perfil seleccionado, elegir otro perfil delimitado, deshabilitar la condición o establecer umbrales validados.", + "settings.health.profileDefault": "Usar perfil seleccionado", + "settings.health.custom": "Umbrales personalizados", + "settings.health.warning": "Umbral de advertencia", + "settings.health.critical": "Umbral crítico", + "settings.health.recovery": "Umbral de recuperación", + "settings.health.warning_for_seconds": "Segundos de permanencia en advertencia", + "settings.health.critical_for_seconds": "Segundos de permanencia en crítico", + "settings.health.recovery_for_seconds": "Segundos de permanencia en recuperación", + "settings.health.clearOverrides": "Borrar anulaciones", + "settings.health.registryUnavailable": "El servidor no devolvió un registro de condiciones. Recargue antes de editar anulaciones.", + "settings.health.resetDefaults": "Restablecer valores predeterminados de salud", + "settings.health.reloadGuidance": "El guardado es atómico. Recargue tras un guardado exitoso para confirmar la política efectiva; reinicie solo cuando el servidor lo solicite explícitamente.", + "settings.health.validation.profile": "Elija un perfil de salud compatible.", + "settings.health.validation.provider": "Elija un proveedor de hardware compatible.", + "settings.health.validation.healthFastIntervalSeconds": "El intervalo rápido debe ser un número entero de 5 a 60 segundos.", + "settings.health.validation.healthNormalIntervalSeconds": "El intervalo normal debe ser un número entero de 15 a 600 segundos.", + "settings.health.validation.healthSlowIntervalSeconds": "El intervalo lento debe ser un número entero de 60 a 3600 segundos.", + "settings.health.validation.healthDeviceIntervalSeconds": "El intervalo de dispositivo debe ser un número entero de 300 a 86400 segundos.", + "settings.health.validation.healthPresenceIntervalSeconds": "El intervalo de presencia debe ser un número entero de 15 a 3600 segundos.", + "settings.health.validation.healthIncidentRetentionDays": "La retención de incidentes debe ser un número entero de 7 a 3650 días.", + "settings.health.validation.ordered": "Los intervalos de muestreo deben estar ordenados: rápido, normal, lento y luego dispositivo.", + "settings.health.validation.overrides": "Las anulaciones de condición deben usar códigos únicos y perfiles compatibles del registro del servidor.", + "settings.health.validation.thresholds": "Los umbrales personalizados deben ser valores finitos dentro de los límites de la unidad de la condición.", + "settings.health.validation.thresholdOrder": "Los umbrales de advertencia, crítico y recuperación deben preservar la dirección de alerta y la histéresis de la condición.", + "settings.health.validation.dwell": "Los tiempos de permanencia deben ser segundos enteros dentro de siete días; la permanencia en advertencia y recuperación no puede ser cero.", + "workspaces.title": "Espacios de trabajo del operador", + "workspaces.description": "Elija qué espacios de trabajo especializados aparecen en su navegación y elementos de la interfaz.", + "workspaces.saved": "Preferencias del espacio de trabajo guardadas", + "workspaces.saveError": "No se pudieron guardar las preferencias del espacio de trabajo: {message}", + "workspaces.loadError": "No se pudieron cargar las preferencias del espacio de trabajo.", + "workspaces.showWorkspace": "Mostrar {name}", + "workspaces.authorizationNote": "Esto solo controla la presentación. Las URLs directas y el acceso a la API siguen sujetas a su política de autorización.", + "workspaces.liveNavigator": "Navegador en vivo mejorado", + "workspaces.liveNavigatorDescription": "Árbol de ubicaciones, filtros de disponibilidad, diseños guardados y eventos recientes.", + "workspaces.investigation": "Investigación", + "workspaces.investigationDescription": "Buscar, correlacionar, proteger y exportar evidencia grabada.", + "settings.reduceMotion": "Reducir movimiento", + "settings.reduceMotionHelp": "Desactiva animaciones y transiciones no esenciales. Auto sigue la preferencia de su sistema operativo.", + "settings.reduceMotionPreference": "Preferencia de reducción de movimiento", + "settings.reduceMotionAuto": "Auto", + "settings.reduceMotionOn": "Activado", + "settings.reduceMotionOff": "Desactivado", + "settings.audioCompliance": "Cumplimiento de audio", + "settings.disableAudioGlobally": "Desactivar audio en toda esta instancia", + "settings.audioDisabled": "El audio está desactivado globalmente", + "settings.audioComplianceHelp": "Impide la escucha en vivo, la comunicación bidireccional y el audio en nuevas grabaciones en toda esta instancia. Al guardar se reinician las sesiones de medios activas de go2rtc. Las grabaciones existentes no se modifican.", + "tokens.manage": "Gestionar acceso a la API", + "tokens.title": "Acceso a la API — {username}", + "tokens.description": "Cree credenciales con alcance limitado para integraciones y revoque cada una de forma independiente.", + "tokens.recommendedTitle": "Se recomiendan tokens con alcance", + "tokens.recommendedDescription": "Cada token caduca, tiene acciones explícitas y un alcance de cámaras, y nunca puede exceder la política de acceso actual del usuario.", + "tokens.coverageNotice": "Los permisos disponibles reflejan lo que este servidor aplica. Un token solo puede usar permisos que su usuario ya posee.", + "tokens.createTitle": "Crear token con alcance", + "tokens.createDescription": "Use un token por integración para que pueda identificarse, rotarse y revocarse sin afectar nada más.", + "tokens.name": "Nombre de la integración", + "tokens.namePlaceholder": "p. ej. Puente PTZ del garaje norte", + "tokens.expiry": "Caduca después de", + "tokens.expiryDays": "{days} días", + "tokens.actions": "Acciones permitidas", + "tokens.actionsHelp": "Selecciona solo lo que esta integración necesita. Las acciones destructivas merecen su propio token.", + "tokens.destructive": "Destructiva", + "tokens.noEnforcedActions": "No hay acciones habilitadas para token disponibles en esta versión del servidor.", + "tokens.scope.label": "Alcance de cámaras", + "tokens.scope.all": "Flota completa de cámaras", + "tokens.scope.collection": "Colección compartida", + "tokens.scope.selector": "Selector personalizado", + "tokens.scope.chooseCollection": "Colección compartida de cámaras", + "tokens.scope.allValue": "Flota completa", + "tokens.scope.collectionValue": "Colección: {name}", + "tokens.scope.selectorValue": "Selector dinámico personalizado", + "tokens.create": "Crear token", + "tokens.creating": "Creando token…", + "tokens.createdSuccess": "Token de API con alcance creado", + "tokens.createError": "No se pudo crear el token de API: {message}", + "tokens.invalidResponse": "El servidor devolvió una respuesta de credenciales incompleta.", + "tokens.existingTitle": "Tokens existentes", + "tokens.existingDescription": "Solo los prefijos y metadatos quedan disponibles tras la creación.", + "tokens.emptyTitle": "No hay tokens activos", + "tokens.emptyDescription": "Crea un token con alcance para la primera integración que necesite acceso a la API.", + "tokens.showInactive": "Mostrar {count} inactivos", + "tokens.status.active": "Activo", + "tokens.status.expired": "Expirado", + "tokens.status.revoked": "Revocado", + "tokens.expires": "Expira", + "tokens.expiresValue": "Expira {date}", + "tokens.created": "Creado", + "tokens.lastUsed": "Último uso", + "tokens.revoke": "Revocar", + "tokens.revoking": "Revocando…", + "tokens.revokeConfirm": "¿Revocar \"{description}\"? Las solicitudes que lo usen dejarán de funcionar inmediatamente.", + "tokens.revokedSuccess": "Token de API revocado", + "tokens.revokeError": "No se pudo revocar el token de API: {message}", + "tokens.validation.missing_description": "Nombra la integración que usará este token.", + "tokens.validation.description_too_long": "Mantén el nombre de la integración en menos de 128 caracteres.", + "tokens.validation.invalid_expiry": "Elige una vigencia del token entre 1 y 365 días.", + "tokens.validation.missing_actions": "Elige al menos una acción permitida.", + "tokens.validation.invalid_action": "Una o más acciones seleccionadas no están habilitadas para tokens en este servidor.", + "tokens.validation.invalid_scope": "Elige un ámbito de cámara válido.", + "tokens.validation.requires_all_scope": "Los permisos que no son de cámara requieren el ámbito de flota completa de cámaras. Elige ese ámbito o elimina esos permisos.", + "tokens.validation.missing_collection": "Elige una colección compartida disponible.", + "tokens.validation.invalid_selector": "Completa o corrige el selector personalizado de cámaras.", + "tokens.secret.oneTime": "Mostrado una sola vez", + "tokens.secret.scopedTitle": "Guarda este token con ámbito ahora", + "tokens.secret.legacyTitle": "Guarda esta clave de API heredada ahora", + "tokens.secret.scopedDescription": "lightNVR solo almacena un hash de este token. Si se pierde, revócalo y crea otro.", + "tokens.secret.legacyDescription": "Esta clave de compatibilidad se muestra aquí solo una vez. Generar otra clave la invalidará.", + "tokens.secret.value": "Credencial de API", + "tokens.secret.copied": "Copiado", + "tokens.secret.copySuccess": "Credencial de API copiada", + "tokens.secret.copyError": "No se pudo copiar automáticamente; selecciona y copia la credencial manualmente.", + "tokens.secret.savedConfirm": "Guardé esta credencial de forma segura", + "tokens.secret.savedHelp": "Al confirmar se cierra este diálogo. El valor completo no se puede volver a mostrar.", + "tokens.legacy.title": "Clave de compatibilidad heredada", + "tokens.legacy.description": "La clave heredada tiene el acceso efectivo completo de este usuario, no caduca y no se puede limitar por cámara o acción.", + "tokens.legacy.warning": "Genera una solo para una integración existente cuyos endpoints no han migrado a la aplicación de tokens con ámbito. Generarla invalida inmediatamente la clave heredada anterior.", + "tokens.legacy.generate": "Generar clave heredada", + "tokens.legacy.confirm": "¿Generar una nueva clave heredada? Esto invalida inmediatamente la clave heredada actual del usuario.", + "tokens.legacy.createdSuccess": "Clave de API heredada generada", + "tokens.legacy.createError": "No se pudo generar la clave de API heredada: {message}", + "audit.manage": "Historial de auditoría", + "audit.title": "Auditoría de seguridad y acceso", + "audit.description": "Rastrea resultados de inicio de sesión, decisiones de acceso y cambios sensibles de políticas sin exponer credenciales.", + "audit.retention": "Retención", + "audit.retentionDescription": "Los eventos se retienen actualmente durante {days} días. Reducir este valor elimina inmediatamente el historial anterior.", + "audit.retentionDays": "Días", + "audit.retentionInvalid": "Elija un período de retención entre 1 y 3650 días.", + "audit.retentionSaved": "Retención de auditoría guardada; {count} eventos caducados eliminados", + "audit.retentionError": "No se pudo guardar la retención de auditoría: {message}", + "audit.filters": "Filtros", + "audit.clearFilters": "Borrar filtros", + "audit.applyFilters": "Aplicar filtros", + "audit.actor": "Actor", + "audit.unauthenticated": "No autenticado", + "audit.outcome": "Resultado", + "audit.action": "Acción exacta", + "audit.filterToAction": "Filtrar por esta acción", + "audit.since": "Desde", + "audit.until": "Hasta", + "audit.invalidDateRange": "La fecha de inicio debe ser anterior a la fecha de fin.", + "audit.source": "Dirección de origen", + "audit.target": "Destino", + "audit.targetUuid": "UUID de destino", + "audit.noTarget": "A nivel de sistema", + "audit.requestId": "ID de solicitud", + "audit.apiToken": "ID de token con alcance", + "audit.showDetails": "Mostrar detalles", + "audit.hideDetails": "Ocultar detalles", + "audit.pageSize": "Por página", + "audit.resultRange": "Mostrando {start}–{end} de {total}", + "audit.empty": "No hay eventos de auditoría coincidentes", + "audit.emptyDescription": "Intente borrar uno o más filtros, o espere a nueva actividad de seguridad.", + "audit.exportPage": "Exportar esta página", + "audit.exporting": "Exportando…", + "audit.exported": "Página de auditoría exportada", + "audit.exportError": "No se pudieron exportar los eventos de auditoría: {message}", + "audit.pagination": "Páginas del historial de auditoría", + "audit.page": "Página {page}", + "audit.modesTitle": "Decisiones permitidas", + "audit.modesDescription": "Elija cómo se registra el acceso de solo lectura permitido para cada acción. Las solicitudes que modifican algo, las denegaciones, los errores y los inicios de sesión siempre se registran. Resumir mantiene una entrada por usuario, cámara y cliente cada {minutes} minutos con un recuento.", + "audit.mode.record": "Registrar cada uno", + "audit.mode.summarize": "Resumir", + "audit.mode.off": "Desactivado", + "audit.modeOffWarning": "El acceso permitido para esta acción ya no aparecerá en el historial de auditoría.", + "audit.modesSaved": "Modos de decisión de auditoría guardados", + "audit.modesError": "No se pudieron guardar los modos de decisión de auditoría: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Tipo de evento", + "audit.eventTypeSummary": "Resúmenes", + "audit.eventTypeDecision": "Decisiones individuales", + "access.cameraSearch": "Buscar cámaras", + "access.cameraSearchPlaceholder": "Escriba al menos dos caracteres para buscar…", + "access.cameraSearchHint": "Buscar por nombre de cámara, UUID, dirección, ubicación, etiqueta, fabricante o modelo.", + "access.cameraSelected": "Seleccionadas", + "access.cameraAdd": "Añadir", + "access.cameraLimit": "Un selector puede contener como máximo 64 cámaras explícitas. Use una regla de ubicación o etiqueta para ámbitos más amplios.", + "access.roles.manage": "Gestionar roles", + "access.roles.title": "Roles de autorización", + "access.roles.description": "Agrupe acciones en roles reutilizables y asígneles ámbitos de cámaras.", + "access.roles.create": "Crear rol", + "access.roles.newRole": "Nuevo rol", + "access.roles.copyName": "Copia de {name}", + "access.roles.clone": "Clonar", + "access.roles.builtin": "Integrado", + "access.roles.builtinHelp": "Los roles integrados son plantillas fijas que no se ven afectadas por las actualizaciones. Clone uno para personalizarlo.", + "access.roles.actionCount": "{count} acciones", + "access.roles.destructive": "Acción sensible", + "access.roles.notEnforced": "Aún no se aplica en ningún endpoint", + "access.roles.destructiveWarning": "Este rol puede modificar la configuración o la evidencia. Otórguelo solo en los ámbitos donde se requiera esa autoridad.", + "access.roles.created": "Rol creado", + "access.roles.updated": "Rol actualizado", + "access.roles.deleted": "Rol eliminado", + "access.roles.saveError": "No se pudo guardar el rol: {message}", + "access.roles.deleteError": "No se pudo eliminar el rol: {message}", + "access.roles.deleteConfirm": "¿Eliminar el rol \"{name}\"? Los roles referenciados por concesiones no se pueden eliminar.", + "access.policy.manage": "Gestionar acceso", + "access.policy.column": "Acceso", + "access.policy.scopedShort": "Con ámbito", + "access.policy.title": "Política de acceso — {username}", + "access.policy.description": "Gestione las concesiones de rol con denegación predeterminada y previsualice sus ámbitos de cámara.", + "access.policy.tab.grants": "Concesiones", + "access.policy.tab.test": "Probar acceso", + "access.policy.scopedWarning": "Solo funcionarán las acciones permitidas por una concesión y un ámbito de cámara coincidentes.", + "access.policy.grants": "Concesiones de rol", + "access.policy.grantsDescription": "Una concesión combina un rol con toda la flota, una colección compartida o un selector de cámaras personalizado.", + "access.policy.addGrant": "Añadir concesión", + "access.policy.noGrants": "No hay concesiones configuradas", + "access.policy.noGrantsHelp": "Añada al menos una concesión antes de activar la política con ámbito, a menos que este usuario no deba tener acceso.", + "access.policy.role": "Rol", + "access.policy.chooseRole": "Elegir un rol", + "access.policy.scope": "Ámbito de cámara", + "access.policy.allCameras": "Toda la flota de cámaras", + "access.policy.collectionScope": "Colección compartida", + "access.policy.collection": "Colección de cámaras", + "access.policy.chooseCollection": "Elegir una colección compartida", + "access.policy.collectionHelp": "El acceso sigue la colección a medida que se añaden, eliminan o coinciden cámaras con sus reglas.", + "access.policy.dynamicScope": "Selector dinámico", + "access.policy.activateConfirm": "¿Activar la política con ámbito de denegación predeterminada para {username}? Las acciones sin una concesión coincidente serán denegadas.", + "access.policy.emptyConfirm": "¿Activar la política con ámbito para {username} sin concesiones? Esto elimina intencionalmente todo el acceso controlado por política.", + "access.policy.saved": "Política de acceso guardada", + "access.policy.saveError": "No se pudo guardar la política de acceso: {message}", + "access.policy.version": "Versión de política {version}", + "access.policy.unsaved": "Cambios sin guardar", + "access.policy.validation.invalid_mode": "Elige un modo de evaluación válido.", + "access.policy.validation.missing_role": "Cada permiso debe hacer referencia a un rol disponible.", + "access.policy.validation.invalid_scope": "Cada permiso debe usar un alcance de flota completa, colección compartida o selector.", + "access.policy.validation.invalid_selector": "Completa o corrige cada selector de cámara antes de guardar.", + "access.policy.validation.missing_collection": "Elige una colección compartida disponible para cada permiso de colección.", + "access.policy.validation.duplicate_grant": "Elimina los permisos duplicados de rol y alcance antes de guardar.", + "access.test.title": "Probar acceso efectivo", + "access.test.description": "Evalúa una acción y cámara guardadas como {username} sin ejecutarla.", + "access.test.saveFirst": "Guarda o descarta los cambios de permisos antes de probar para que el resultado refleje la política mostrada aquí.", + "access.test.action": "Acción", + "access.test.camera": "Cámara", + "access.test.run": "Probar acceso", + "access.test.running": "Probando…", + "access.test.allowed": "Permitido", + "access.test.denied": "Denegado", + "access.test.version": "Versión {version}", + "access.test.source": "Fuente: {source} · Rol: {role}", + "recordings.pullToRefresh": "Desliza para actualizar grabaciones", + "recordings.releaseToRefresh": "Suelta para actualizar grabaciones", + "recordings.refreshing": "Actualizando grabaciones…", + "recordings.refreshed": "Grabaciones actualizadas", + "recordings.refreshFailed": "No se pudieron actualizar las grabaciones: {message}", + "recordings.download": "Descargar", + "recordings.tags": "Etiquetas", + "recordings.selectRecording": "Seleccionar grabación", + "timeline.legend.recording": "Grabación", + "timeline.legend.detection": "Evento de detección", + "timeline.detectionEvent": "Evento de detección", + "streams.showCredentials": "Mostrar credenciales", + "streams.hideCredentials": "Ocultar credenciales", + "streams.streamSuccessfullyEnabled": "Transmisión habilitada correctamente.", + "streams.errorEnablingStream": "Error al habilitar la transmisión: {message}", + "system.health.tab": "Salud", + "system.health.operatorView": "Salud operativa", + "system.health.title": "Salud del sistema", + "system.health.loading": "Cargando salud del sistema…", + "system.health.loadError": "No se pudo cargar la salud del sistema.", + "system.health.refreshing": "Actualizando…", + "system.health.activeIncidentCount": "{count} incidentes activos", + "system.health.coverage": "Cobertura", + "system.health.monitoringDisabled": "El monitoreo de salud está deshabilitado", + "system.health.lastRecordedValue": "Último valor registrado", + "system.health.monitoringDisabledHelp": "Los datos de salud actuales no se están recopilando. Habilite el monitoreo de salud en Configuración → Salud; reinicie si se solicita después de guardar. El historial de incidentes muestra eventos pasados, no el uso actual de recursos.", + "system.health.monitoringRestartRequired": "El monitoreo de salud está habilitado en la configuración guardada, pero el muestreador en ejecución sigue deshabilitado. Reinicie LightNVR para aplicar el cambio. El historial de incidentes muestra eventos pasados.", + "system.health.containerCoverage": "Cobertura limitada del host", + "system.health.hostHardwareUnavailable": "Esta instalación puede ver la salud del contenedor y de los recursos montados, pero el hardware del host no está disponible. Los valores del host faltantes son desconocidos, no saludables.", + "system.health.coverageUnknown": "Aún no hay una instantánea de salud completada disponible. Los valores permanecen desconocidos hasta que se complete la recopilación.", + "system.health.coverageComplete": "Todos los datos visibles para esta instalación se recopilaron correctamente.", + "system.health.coveragePartial": "La cobertura es parcial. {count} observaciones o comprobaciones de recopilación no están disponibles, están desactualizadas o son incompletas.", + "system.health.effectiveScope": "Alcance efectivo", + "system.health.activeIncidents": "Incidentes activos", + "system.health.noActiveIncidents": "No se reportan incidentes activos para la cobertura visible.", + "system.health.duration": "Duración", + "system.health.currentValue": "Valor actual", + "system.health.thresholds": "Umbral y permanencia", + "system.health.thresholdSummary": "Advertencia {warning}, crítico {critical}, recuperación {recovery} {unit}; permanencia de advertencia {seconds}s", + "system.health.remediation": "Respuesta sugerida", + "system.health.facts": "Datos de salud", + "system.health.group.resources": "Recursos", + "system.health.group.storage": "Almacenamiento", + "system.health.group.hardware": "Hardware", + "system.health.group.network": "Red", + "system.health.group.clock": "Reloj", + "system.health.group.components": "Componentes", + "system.health.noFacts": "No hay datos visibles en este grupo.", + "system.health.observationState": "Capacidad y actualización", + "system.health.valueUnavailable": "Uno o más valores son desconocidos", + "system.health.componentStatus": "Componentes de monitoreo", + "system.health.collectors": "Recolectores", + "system.health.collectorSummary": "{total} registrados · {attention} requieren atención", + "system.health.collectorsNeedingAttention": "Recolectores que requieren atención", + "system.health.collectionFailures": "{count} fallos o tiempos de espera agotados", + "system.health.stale": "desactualizado", + "system.health.eventDelivery": "Entrega de eventos", + "system.health.degraded": "Degradado", + "system.health.circularDelivery": "Esta es la única ruta de alertas configurada, por lo que no puede reportar de forma independiente su propio fallo.", + "system.health.incidentPersistence": "Persistencia de incidentes", + "system.health.persistenceSummary": "{pending} pendientes · {failures} fallos · {retries} reintentos", + "system.health.recentSamples": "Actividad de recolección reciente", + "system.health.recentSamplesHelp": "Hasta {count} resúmenes de generación del lado del servidor; esto es actividad de cobertura, no un gráfico de valores.", + "system.health.sampleSequence": "Generación {sequence}", + "system.health.sampleCoverage": "{observations} observaciones · {dropped} descartadas", + "system.health.noSamples": "No hay generaciones de recolección completadas disponibles.", + "system.health.incidentHistory": "Historial de incidentes", + "system.health.incidentHistoryHelp": "Incidentes más recientes primero. El historial se carga en páginas limitadas.", + "system.health.loadingHistory": "Cargando historial de incidentes…", + "system.health.historyError": "No se pudo cargar el historial de incidentes.", + "system.health.emptyHistory": "No se han registrado incidentes.", + "system.health.firstSeen": "Primera vez visto", + "system.health.lastSeen": "Última vez visto", + "system.health.deliveryState": "Estado de entrega", + "system.health.historyPagination": "Páginas del historial de incidentes", + "system.health.pageCount": "{count} incidentes en esta página", + "system.health.remediation.memory": "Reduce la presión de memoria, revisa los límites de procesos y cgroup, y analiza la actividad OOM reciente.", + "system.health.remediation.cpu": "Identifica los consumidores sostenidos de CPU y verifica el rendimiento del servicio antes de cambiar los límites.", + "system.health.remediation.io": "Revisa la latencia de almacenamiento y los escritores activos; conserva las grabaciones antes de un mantenimiento disruptivo.", + "system.health.remediation.filesystem": "Revisa el sistema de archivos lógico indicado, el espacio libre o los inodos, y verifica que siga siendo escribible.", + "system.health.remediation.thermal": "Mejora la refrigeración y reduce la carga; inspecciona ventiladores y rejillas antes de que las temperaturas alcancen los límites de apagado.", + "system.health.remediation.network": "Revisa la interfaz visible, el enlace, el switch y los contadores de errores desde una ruta de red independiente.", + "system.health.remediation.clock": "Restaura la sincronización de tiempo y verifica la fuente de reloj del host antes de confiar en las marcas de tiempo de eventos.", + "system.health.remediation.process": "Inspecciona los límites de recursos y los registros de LightNVR, luego reduce la carga o aumenta los límites validados.", + "system.health.remediation.storage": "Haz una copia de seguridad de las grabaciones importantes e inspecciona el dispositivo de almacenamiento asignado antes de reemplazarlo o repararlo.", + "system.health.remediation.hardware": "Inspecciona el hardware afectado y los registros de la plataforma; programa mantenimiento si la condición persiste.", + "system.health.remediation.health": "Restaura el acceso y los permisos del recolector para poder evaluar la evidencia de salud faltante.", + "system.health.remediation.system": "Revisa la ejecución anterior y los registros del host para distinguir un reinicio de proceso de un reinicio del host.", + "system.health.remediation.event": "Usa la API local o la vista de métricas, libera la presión de la cola persistente y restaura un destino de alertas independiente.", + "system.health.remediation.default": "Revisa el componente afectado y los registros recientes, luego verifica la recuperación en una nueva generación de salud.", + "system.capacityTarget": "Objetivo de capacidad", + "system.capacityTargetValue": "Mantener {pct}% libre", + "system.fillRate": "Tasa de llenado", + "system.fillRateValue": "{value} / día", + "system.projectedToTarget": "Tiempo proyectado al objetivo", + "system.projectedNow": "En/sobre el objetivo ahora", + "system.projectedDays": "~{count} d", + "system.projectedHours": "~{count} h", + "system.projectedUnknown": "—", + "common.description": "Descripción", + "common.remove": "Eliminar", + "streams.selectStream": "Seleccionar {name}", + "streams.search": "Buscar flujos", + "streams.searchPlaceholder": "Buscar cámaras, ubicaciones o etiquetas", + "streams.noStreamsMatchFilters": "Ningún flujo coincide con los filtros actuales.", + "streamHealth.sourceConnected": "Fuente conectada", + "streamHealth.videoAdvancing": "Video avanzando", + "streamHealth.recorderWriting": "Grabador escribiendo", + "streamHealth.detectorOperating": "Detector en funcionamiento", + "streamHealth.lastSegment": "Último segmento completado", + "streams.disablingStreamsProgress": "Desactivando transmisiones…", + "streams.onvifInvalidAddress": "La dirección IP del dispositivo ONVIF falta o no es válida.", + "streams.warningFallingBackToHttp": "La conexión HTTPS falló; reintentando por HTTP. Las credenciales pueden enviarse en texto plano.", + "streamsConfig.playbackTransport": "Transporte de reproducción", + "streamsConfig.playbackTransportHelp": "Elija el método de reproducción en el navegador para esta cámara y, si corresponde, su orden de respaldo.", + "streamsConfig.playbackTransportUnavailable": "No disponible en el servidor: {transports}. Active el transporte globalmente o elija otro perfil.", + "streamsConfig.audioDisabledByPolicy": "El audio está deshabilitado por la política de la instancia", + "streamsConfig.audioDisabledByPolicyHelp": "La grabación, la escucha en vivo y la comunicación bidireccional no están disponibles mientras la política global de cumplimiento de audio esté activada.", + "streamsConfig.audioVoiceEnhancement": "Mejora de voz (grabaciones)", + "streamsConfig.customApiModel": "Detección de API personalizada", + "streamsConfig.modelNotSupportedByBuild": "no compatible con esta versión", + "streamsConfig.tierCriticalMultiplier": "Nivel crítico ×", + "streamsConfig.tierImportantMultiplier": "Nivel importante ×", + "streamsConfig.tierEphemeralMultiplier": "Nivel efímero ×", + "streamsConfig.tierMultipliersHelp": "Multiplicadores por nivel sobre la retención base. El material de nivel superior se conserva más tiempo y se elimina al último bajo presión de disco.", + "streamsConfig.storagePriority": "Prioridad de almacenamiento (1-10)", + "streamsConfig.storagePriorityHelp": "Importancia relativa del material de esta transmisión al liberar espacio; una prioridad más alta se conserva por más tiempo.", + "streamsConfig.restream": "Retransmitir / Publicar (RTMP)", + "streamsConfig.publishUrl": "URL de publicación (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "Retransmita esta cámara a un servicio como YouTube Live mediante go2rtc. Pegue la URL de ingesta RTMP completa incluyendo la clave de transmisión (p. ej. rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Para retransmitir a varios servicios a la vez, separe las URLs con comas. YouTube requiere video H264 y audio AAC; LightNVR ahora transcodifica automáticamente (H264 para cámaras no H264, AAC para audio no AAC), por lo que la mayoría de las cámaras funcionan tal cual. Nota: YouTube también requiere una pista de audio; una cámara sin audio será rechazada. Déjelo en blanco para deshabilitar.", + "streams.lastSeen": "Última conexión {time}", + "streams.claimed": "Reclamado", + "streams.duplicateSuspected": "Posible duplicado", + "streams.duplicateSuspectedHelp": "La evidencia de identidad estable o del punto final entra en conflicto con otro registro de descubrimiento.", + "streams.onvifClaimWarning": "La transmisión se agregó, pero su registro de descubrimiento no pudo marcarse como reclamado: {message}", + "common.online": "En línea", + "common.offline": "Sin conexión", + "settings.storageTargets.title": "Destinos de almacenamiento de grabación", + "settings.storageTargets.description": "Registre discos locales y sistemas de archivos NFS o SMB montados por el administrador como destinos de grabación monitoreados de forma independiente.", + "settings.storageTargets.foundationNotice": "La captura usa objetivos de sistema de archivos. Los buckets S3 y los objetivos NFS/SAN montados pueden contener copias de archivo verificadas. La presión en caliente preserva las grabaciones archivadas hasta que su retención lógica expire.", + "settings.storageTargets.add": "Agregar objetivo de almacenamiento", + "settings.storageTargets.edit": "Editar objetivo de almacenamiento", + "settings.storageTargets.editorHelp": "Los objetivos habilitados deben existir y pasar una prueba de escritura, fsync y limpieza. Guarde un montaje futuro no disponible como deshabilitado y habilítelo después de montarlo.", + "settings.storageTargets.name": "Nombre del objetivo", + "settings.storageTargets.root": "Ruta raíz montada", + "settings.storageTargets.rootLocked": "Un objetivo predeterminado o no vacío mantiene una raíz inmutable para que las grabaciones existentes no queden huérfanas.", + "settings.storageTargets.class": "Clase de rendimiento", + "settings.storageTargets.hot": "Caliente — grabación activa", + "settings.storageTargets.warm": "Templado — archivo montado", + "settings.storageTargets.cold": "Frío — acceso infrecuente", + "settings.storageTargets.reserveGb": "Espacio reservado (GB)", + "settings.storageTargets.lowWatermark": "Umbral bajo (% usado)", + "settings.storageTargets.highWatermark": "Umbral alto (% usado)", + "settings.storageTargets.migrationBandwidth": "Ancho de banda de ciclo de vida (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 es ilimitado. El límite se captura al crear un trabajo de movimiento o copia.", + "settings.storageTargets.archiveStart": "Inicio de ventana de archivo", + "settings.storageTargets.archiveEnd": "Fin de ventana de archivo", + "settings.storageTargets.archiveWindowHelp": "Hora local. Tiempos de inicio y fin iguales permiten trabajos de ciclo de vida todo el día; una ventana nocturna puede cruzar la medianoche.", + "settings.storageTargets.enabled": "Habilitado (las políticas de ubicación pueden seleccionar este objetivo)", + "settings.storageTargets.notRouted": "Ninguna política de ubicación habilitada dirige cámaras aquí. Las nuevas grabaciones se envían al objetivo predeterminado hasta que una política lo nombre como objetivo principal, miembro del grupo o de archivo.", + "settings.storageTargets.degradedNotice": "Por encima de su umbral alto o dentro de su reserva. Las políticas de ubicación omiten este objetivo hasta que se libere espacio.", + "settings.storageTargets.probePassedIneligible": "La prueba de escritura pasó, pero el objetivo está en {status}: las políticas de ubicación no lo seleccionarán.", + "settings.storageTargets.mountRequired": "Requerir un sistema de archivos montado", + "settings.storageTargets.mountRequiredHelp": "Fijar este objetivo a su punto de montaje actual no raíz. Si ese montaje NFS, SMB, bind o PVC desaparece, la grabación se pausa en lugar de escribir en el directorio subyacente del host.", + "settings.storageTargets.mountGuard": "Montaje requerido", + "settings.storageTargets.mountPending": "Se detectará cuando el objetivo esté habilitado", + "settings.storageTargets.default": "Predeterminado", + "settings.storageTargets.capacity": "Capacidad", + "settings.storageTargets.available": "Disponible", + "settings.storageTargets.recordings": "Grabaciones indexadas", + "settings.storageTargets.replicas": "{count} copias verificadas · {bytes}", + "settings.storageTargets.reserve": "Reservado", + "settings.storageTargets.pressure.normal": "Presión normal", + "settings.storageTargets.pressure.high": "Umbral alto", + "settings.storageTargets.pressure.reserve": "Reserva excedida", + "settings.storageTargets.pressure.unavailable": "Presión no disponible", + "settings.storageTargets.cleanupActive": "La limpieza por destino está activa y trabajará para mantener {target} disponible sin eliminar grabaciones asignadas a otro destino.", + "settings.storageTargets.test": "Probar destino", + "settings.storageTargets.probing": "Probando…", + "settings.storageTargets.probePassed": "Prueba de escritura del destino de almacenamiento superada", + "settings.storageTargets.duplicateFilesystem": "Esta raíz comparte el mismo sistema de archivos subyacente que otro destino. La capacidad no debe contarse dos veces cuando la colocación está habilitada.", + "settings.storageTargets.deleteLocked": "No se pueden eliminar destinos predeterminados ni con contenido.", + "settings.storageTargets.deleteConfirm": "¿Eliminar el destino de almacenamiento vacío \"{name}\"? No se eliminarán archivos.", + "settings.storageTargets.created": "Destino de almacenamiento creado", + "settings.storageTargets.updated": "Destino de almacenamiento actualizado", + "settings.storageTargets.deleted": "Destino de almacenamiento eliminado", + "settings.storageTargets.invalidThresholds": "Verifique umbrales, reserva, ancho de banda de ciclo de vida y tiempos de ventana de archivo.", + "settings.storageTargets.loadError": "No se pudieron cargar los destinos de almacenamiento", + "settings.storagePools.title": "Grupos de almacenamiento", + "settings.storagePools.description": "Agrupe destinos sanos para desbordamiento automático y replicación en destinos distintos.", + "settings.storagePools.add": "Agregar grupo", + "settings.storagePools.strategy": "Estrategia de asignación", + "settings.storagePools.mostFree": "Mayor espacio libre", + "settings.storagePools.roundRobin": "Round robin", + "settings.storagePools.priority": "Prioridad explícita", + "settings.storagePools.members": "Destinos (el orden de visualización es la prioridad de asignación)", + "settings.storagePools.enabled": "Grupo habilitado", + "settings.storagePools.active": "Activo", + "settings.storagePools.inactive": "Deshabilitado", + "settings.storagePools.strategyValue.most_free": "mayor espacio libre", + "settings.storagePools.strategyValue.round_robin": "round robin", + "settings.storagePools.strategyValue.priority": "orden de prioridad", + "settings.storagePools.created": "Grupo de almacenamiento creado", + "settings.storagePools.updated": "Grupo de almacenamiento actualizado", + "settings.storagePools.deleted": "Grupo de almacenamiento eliminado", + "settings.storagePools.deleteConfirm": "¿Eliminar el grupo de almacenamiento \"{name}\"?", + "settings.storagePools.empty": "Aún no hay grupos de almacenamiento.", + "settings.storageMigrations.title": "Trabajos de migración de grabaciones", + "settings.storageMigrations.description": "Los movimientos duraderos y las copias retenidas respetan la ventana de archivo y el límite de ancho de banda de cada destino, verifican SHA-256 y se recuperan de forma segura tras un reinicio.", + "settings.storageMigrations.empty": "Aún no hay trabajos de migración de grabaciones.", + "settings.storageMigrations.loadError": "No se pudieron cargar los trabajos de migración de grabaciones", + "settings.storageMigrations.recording": "Grabación #{id}", + "settings.storageMigrations.attempt": "Intento {current}/{max}", + "settings.storageMigrations.operation.move": "Mover", + "settings.storageMigrations.operation.copy": "Copia retenida", + "settings.storageMigrations.cancelled": "Cancelación de migración aceptada", + "settings.storageMigrations.cancelling": "Cancelando…", + "settings.storageMigrations.retried": "Migración en cola para reintentar", + "settings.storageMigrations.state.queued": "En cola", + "settings.storageMigrations.state.copying": "Copiando", + "settings.storageMigrations.state.verifying": "Verificando", + "settings.storageMigrations.state.committing": "Confirmando", + "settings.storageMigrations.state.cleanup_pending": "Limpiando origen", + "settings.storageMigrations.state.retry_wait": "Esperando para reintentar", + "settings.storageMigrations.state.completed": "Completado", + "settings.storageMigrations.state.failed": "Fallido", + "settings.storageMigrations.state.cancelled": "Cancelado", + "settings.storagePolicies.title": "Políticas de ubicación de cámaras", + "settings.storagePolicies.description": "Dirige las cámaras coincidentes a un destino de grabación principal en orden de prioridad. Una cámara usa la primera política habilitada que coincida.", + "settings.storagePolicies.add": "Agregar política de ubicación", + "settings.storagePolicies.edit": "Editar política de ubicación", + "settings.storagePolicies.editorHelp": "La política se reevalúa para los nuevos segmentos. Los cambios no mueven grabaciones que ya existen.", + "settings.storagePolicies.priority": "Prioridad (mayor primero)", + "settings.storagePolicies.priorityValue": "Prioridad {priority}", + "settings.storagePolicies.primary": "Destino principal", + "settings.storagePolicies.primaryPool": "Pool de colocación (opcional)", + "settings.storagePolicies.exactTarget": "Usar destino primario exacto", + "settings.storagePolicies.fallback": "Si el primario no está disponible", + "settings.storagePolicies.fallbackDefault": "Usar el destino predeterminado", + "settings.storagePolicies.fallbackTarget": "Usar un destino de respaldo con nombre", + "settings.storagePolicies.fallbackPause": "Pausar grabación", + "settings.storagePolicies.fallbackFail": "Fallar inicio de grabación", + "settings.storagePolicies.namedFallback": "Destino de respaldo", + "settings.storagePolicies.chooseTarget": "Elegir un destino", + "settings.storagePolicies.choosePool": "Elegir un pool", + "settings.storagePolicies.minimumDays": "Retención mínima (días)", + "settings.storagePolicies.desiredDays": "Retención deseada (días)", + "settings.storagePolicies.maximumDays": "Retención máxima (días)", + "settings.storagePolicies.copyCount": "Copias verificadas requeridas", + "settings.storagePolicies.replicationPool": "Pool de replicación", + "settings.storagePolicies.migrateAfter": "Mover tras antigüedad (días)", + "settings.storagePolicies.migrationTarget": "Destino de archivo", + "settings.storagePolicies.pressurePriority": "Prioridad de eliminación por presión (menor primero)", + "settings.storagePolicies.disabledTarget": "deshabilitado", + "settings.storagePolicies.enabled": "Política habilitada", + "settings.storagePolicies.selector": "Cámaras coincidentes", + "settings.storagePolicies.preview": "Vista previa de precedencia", + "settings.storagePolicies.previewing": "Evaluando…", + "settings.storagePolicies.previewRequired": "Vista previa del borrador actual antes de guardar para ver la superposición de cámaras y la política ganadora efectiva.", + "settings.storagePolicies.previewSummary": "Coincide con {matched} cámaras; este borrador es efectivo para {effective}.", + "settings.storagePolicies.previewShadowed": "Una política de mayor precedencia gana para {count} cámaras coincidentes.", + "settings.storagePolicies.previewWins": "Gana a \"{policy}\" (prioridad {priority}) para {count} cámaras.", + "settings.storagePolicies.previewLoses": "Pierde ante \"{policy}\" (prioridad {priority}) para {count} cámaras.", + "settings.storagePolicies.previewNoMatches": "Este selector actualmente no coincide con ninguna cámara.", + "settings.storagePolicies.invalidPriority": "La prioridad debe ser un número entero entre -1.000.000 y 1.000.000.", + "settings.storagePolicies.invalidLifecycle": "Verifique el orden de retención, el número de copias y el pool de replicación, y la edad y destino de migración.", + "settings.storagePolicies.created": "Política de colocación creada", + "settings.storagePolicies.updated": "Política de ubicación actualizada", + "settings.storagePolicies.deleted": "Política de ubicación eliminada", + "settings.storagePolicies.deleteConfirm": "¿Eliminar la política de ubicación \"{name}\"? Las grabaciones existentes no se ven afectadas.", + "settings.storagePolicies.active": "Activa", + "settings.storagePolicies.inactive": "Desactivada", + "settings.storagePolicies.routesTo": "Destino principal: {target}", + "settings.storagePolicies.lifecycleSummary": "Retención mín./deseada/máx.: {minimum}/{desired}/{maximum} días · {copies} copia(s) verificada(s)", + "settings.storagePolicies.fallsBackTo": "Destino alternativo: {target}", + "settings.storagePolicies.mode.default": "Alternativa: destino predeterminado", + "settings.storagePolicies.mode.pause": "Alternativa: pausar grabación", + "settings.storagePolicies.mode.fail": "Alternativa: cancelar inicio de grabación", + "settings.storagePolicies.empty": "No hay políticas de ubicación. Las cámaras siguen usando el destino predeterminado; otros destinos no reciben nada hasta que una política las dirija hacia ellos.", + "settings.storagePolicies.archiveNoTrigger": "Se ha configurado un destino de archivo pero nada activa un movimiento. Configure 'Mover tras antigüedad (días)', una antigüedad de archivo o una opción de archivo; de lo contrario, no se moverán grabaciones.", + "settings.storageCompliance.title": "Capacidad y cumplimiento de políticas", + "settings.storageCompliance.description": "Las tasas observadas a 30 días predicen la presión del destino y la retención alcanzada; las violaciones activas del ciclo de vida permanecen visibles hasta su resolución.", + "settings.storageCompliance.loadError": "No se pudo cargar el cumplimiento de almacenamiento", + "settings.storageCompliance.unknown": "Desconocido", + "settings.storageCompliance.days": "{days} días", + "settings.storageCompliance.day": "día", + "settings.storageCompliance.targetForecasts": "Previsiones de destino", + "settings.storageCompliance.target": "Destino", + "settings.storageCompliance.dailyRate": "Tasa observada", + "settings.storageCompliance.toHigh": "Hasta marca alta", + "settings.storageCompliance.expected": "Retención esperada", + "settings.storageCompliance.confidence": "Confianza", + "settings.storageCompliance.policyCompliance": "Cumplimiento de políticas", + "settings.storageCompliance.compliant": "Sin violaciones activas", + "settings.storageCompliance.violationCount": "{count} violación(es)", + "settings.storageCompliance.policyForecast": "Alcanzada {achieved}; prevista {expected}; deseada {desired} días.", + "settings.storageCompliance.copyDeficits": "{count} grabación(es) necesitan otra copia verificada.", + "settings.storageCompliance.activeViolations": "Violaciones activas", + "settings.storageCompliance.type.copy_count": "Número de copias", + "settings.storageCompliance.type.minimum_retention": "Capacidad mínima de retención", + "settings.storageCompliance.type.target_unavailable": "Destino no disponible", + "settings.storageCompliance.type.migration_failed": "Error en la tarea de ciclo de vida", + "settings.recordingDirectoryFormat": "Estructura de carpetas de grabación", + "settings.recordingDirectoryFormatHelp": "Organiza las nuevas grabaciones MP4 dentro de la carpeta de cada cámara. Las grabaciones existentes no se mueven.", + "settings.recordingDirectoryFlat": "Plana (solo carpeta de cámara)", + "settings.recordingDirectoryMonth": "Por mes (AAAA/MM)", + "settings.recordingDirectoryDay": "Por día (AAAA/MM/DD)", + "settings.minFreePct": "Espacio libre mínimo (%)", + "settings.minFreePctHelp": "Mantiene al menos este porcentaje del volumen libre eliminando automáticamente las grabaciones más antiguas, independientemente de los días de retención. Esto limita el uso al tamaño del disco — configúrelo y el disco nunca se llenará. 0 desactiva el límite de capacidad.", + "settings.pressureThresholds": "Umbrales de presión de disco (%)", + "settings.pressureThresholdsHelp": "Bandas de espacio libre que escalan la limpieza automática. Debe cumplir: emergencia < crítico < advertencia.", + "settings.pressureWarningPct": "Advertencia por debajo de (% libre)", + "settings.pressureCriticalPct": "Crítico por debajo de (% libre)", + "settings.pressureEmergencyPct": "Emergencia por debajo de (% libre)", + "settings.databaseBackupVerify": "Verificación de copias de seguridad", + "settings.databaseBackupVerifyFull": "Completa (integrity_check, verifica cada índice)", + "settings.databaseBackupVerifyQuick": "Rápida (quick_check, solo estructura de páginas)", + "settings.databaseBackupVerifyOff": "Desactivada (sin análisis posterior a la copia)", + "settings.databaseBackupVerifyHelp": "Escaner aplicado a cada copia de seguridad antes de publicarse. Completa puede tardar más que la propia copia en una base de datos grande sobre un disco mecánico y puede alcanzar la válvula de seguridad de 30 minutos, descartando esa copia; Rápida sigue detectando páginas dañadas o truncadas con muchas menos búsquedas.", + "settings.viewMethodAuto": "Automático — preferencia por cámara con alternativa", + "settings.resetWizardPending": "Iniciando asistente…", + "settings.apiDetectionFormat": "Formato de solicitud API", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (subida de imagen multipart)", + "settings.apiDetectionFormatDoods2": "DOODS2 (cuerpo JSON con imagen base64)", + "settings.apiDetectionFormatHelp": "Formato de comunicación que LightNVR usa al enviar instantáneas a la API de detección. Mantenga light-object-detect para light-object-detect o cualquier servidor que implemente su contrato; elija DOODS2 para un servidor DOODS2.", + "settings.apiDetectionUrlHelpDoods2": "Endpoint /detect de DOODS2, p. ej. http://localhost:8080/detect. La solicitud se envía como JSON y no se añaden parámetros de consulta.", + "settings.apiDetectionDetectorName": "Nombre del detector DOODS2", + "settings.apiDetectionDetectorNameHelp": "Se envía como detector_name en cada solicitud. Debe coincidir con un detector listado por el servidor en GET /detectors; \"default\" usa el detector predeterminado del servidor.", + "settings.defaultPlaybackTransport": "Transporte de reproducción predeterminado", + "settings.defaultPlaybackTransportHelp": "Perfil de reproducción aplicado a las nuevas transmisiones. Las transmisiones existentes mantienen su propia selección.", + "playbackTransport.auto": "Automático (recomendado)", + "playbackTransport.webrtcOnly": "Solo WebRTC", + "playbackTransport.mseOnly": "Solo MSE", + "playbackTransport.hlsOnly": "Solo HLS", + "playbackTransport.webrtcThenMse": "WebRTC, luego MSE", + "playbackTransport.mseThenHls": "MSE, luego HLS", + "investigation.experimental": "Espacio de trabajo experimental", + "investigation.title": "Investigación", + "investigation.description": "Revise varias cámaras con un cursor UTC compartido sin ocultar huecos en la grabación.", + "investigation.query": "Ventana de investigación", + "investigation.queryHelp": "Seleccione hasta 16 cámaras. Como máximo cuatro reproductores de video están activos a la vez.", + "investigation.cameras": "cámaras", + "investigation.cameraSelection": "Selección de cámaras", + "investigation.start": "Inicio", + "investigation.end": "Fin", + "investigation.load": "Cargar investigación", + "investigation.applyWindow": "Aplicar ventana de tiempo", + "investigation.loading": "Cargando investigación…", + "investigation.eventType": "Tipo de evento", + "investigation.anyEventType": "Cualquier tipo de evento", + "investigation.eventType.detection": "Detección", + "investigation.eventType.motion": "Movimiento", + "investigation.location": "Ubicación", + "investigation.anyLocation": "Cualquier ubicación", + "investigation.objectLabel": "Etiqueta de objeto", + "investigation.anyLabel": "Cualquier etiqueta", + "investigation.zone": "Zona", + "investigation.anyZone": "Cualquier zona", + "investigation.source": "Fuente de detección", + "investigation.anySource": "Cualquier fuente", + "investigation.captureMethod": "Método de captura", + "investigation.anyCaptureMethod": "Cualquier método de captura", + "investigation.recordingTag": "Etiqueta de grabación", + "investigation.anyRecordingTag": "Cualquier etiqueta de grabación", + "investigation.protection": "Protección", + "investigation.anyProtection": "Cualquier protección", + "investigation.protected": "Protegido", + "investigation.unprotected": "Sin protección", + "investigation.minimumConfidence": "Confianza mínima", + "investigation.confidenceError": "La confianza mínima debe estar entre 0 y 1.", + "investigation.metadataRegionSearch": "Búsqueda por región de metadatos", + "investigation.regionSearchHelp": "Seleccione una cámara principal con grabaciones y dibuje un área sobre su vídeo.", + "investigation.regionActive": "Buscando cajas almacenadas de {camera}. La ausencia de resultados no garantiza que nada haya cruzado el área.", + "investigation.regionMatch": "Coincidencia de cajas", + "investigation.regionMatch.center": "Centro dentro", + "investigation.regionMatch.intersects": "Cualquier intersección", + "investigation.regionMatch.minimumIntersection": "Superposición mínima", + "investigation.regionMinimumOverlap": "Superposición mínima (%)", + "investigation.regionLeft": "Izquierda (%)", + "investigation.regionTop": "Superior (%)", + "investigation.regionWidth": "Ancho (%)", + "investigation.regionHeight": "Alto (%)", + "investigation.drawRegion": "Dibujar área de búsqueda", + "investigation.drawingRegion": "Dibujando área de búsqueda…", + "investigation.clearRegion": "Borrar área", + "investigation.useFullFrame": "Usar fotograma completo", + "investigation.drawRegionPrompt": "Arrastre sobre el vídeo para definir el área de búsqueda", + "investigation.applyFilters": "Aplicar filtros", + "investigation.searching": "Buscando eventos…", + "investigation.searchResults": "Resultados de eventos", + "investigation.searchHelp": "Cargue una investigación para buscar sus metadatos de eventos persistidos.", + "investigation.resultCount": "{count} eventos coincidentes", + "investigation.results": "resultados", + "investigation.resultHistogram": "Histograma de eventos", + "investigation.histogramHelp": "Seleccione una barra para mover el cursor compartido.", + "investigation.previousResult": "Evento anterior", + "investigation.nextResult": "Siguiente evento", + "investigation.previousResultShortcut": "Evento anterior ([)", + "investigation.nextResultShortcut": "Siguiente evento (])", + "investigation.noResults": "Ningún evento persistido coincide con esta selección de cámara, hora y filtro.", + "investigation.noThumbnail": "Sin miniatura", + "investigation.exploreThumbnails": "Explorar miniaturas", + "investigation.exploreSelectedThumbnails": "Explorar alrededor del evento", + "investigation.thumbnailDrilldown": "Desglose de miniaturas", + "investigation.thumbnailDrilldownHelp": "Elija cualquier momento, incluyendo un intervalo vacío, para mover el cursor compartido y regenerar un conjunto más reducido de muestras.", + "investigation.selectThumbnailSample": "Inspeccionar alrededor de {time}", + "investigation.loadingThumbnail": "Cargando miniatura…", + "investigation.thumbnailUnavailable": "Miniatura no disponible", + "investigation.loadingSamples": "Cargando muestras de miniaturas…", + "investigation.thumbnailCoverageTruncated": "Este intervalo contiene más grabaciones de las que el muestreador pudo inspeccionar. Reduzca la ventana de tiempo para una cobertura completa.", + "investigation.bookmarks.save": "Guardar marcador", + "investigation.bookmarks.open": "Marcadores", + "investigation.bookmarks.saveTitle": "Guardar marcador de investigación", + "investigation.bookmarks.listTitle": "Marcadores de investigación", + "investigation.bookmarks.notHold": "Un marcador restaura esta vista, pero no protege las grabaciones de la retención o eliminación normal.", + "investigation.bookmarks.title": "Nombre del marcador", + "investigation.bookmarks.note": "Nota privada (opcional)", + "investigation.bookmarks.titleRequired": "Introduzca un nombre de marcador.", + "investigation.bookmarks.empty": "No tiene marcadores de investigación guardados.", + "investigation.bookmarks.cameraCount": "{count} cámara(s)", + "investigation.bookmarks.restore": "Abrir", + "investigation.bookmarks.confirmDelete": "¿Eliminar marcador?", + "investigation.actions.open": "Proteger / descargar", + "investigation.actions.title": "Grabaciones de investigación", + "investigation.actions.notEvidenceExport": "La protección evita la eliminación por retención normal. La descarga ZIP es una exportación de conveniencia, no un paquete de evidencia verificado.", + "investigation.actions.scope": "Alcance de grabación", + "investigation.actions.selectedResult": "Evento y cámara seleccionados", + "investigation.actions.fullWindow": "Todas las cámaras en la ventana de investigación", + "investigation.actions.preview": "Vista previa de grabaciones", + "investigation.actions.previewing": "Buscando grabaciones superpuestas…", + "investigation.actions.invalidRange": "Seleccione un rango de tiempo válido con el final después del inicio.", + "investigation.actions.recordingCount": "{count} grabación(es) superpuesta(s)", + "investigation.actions.protectedCount": "{count} ya protegida(s)", + "investigation.actions.noRecordings": "Ninguna grabación completada se superpone con esta selección de cámara y tiempo.", + "investigation.actions.protectDenied": "{count} grabación(es) no protegida(s) están fuera de su alcance de protección y se excluyen de esta acción.", + "investigation.actions.exportDenied": "Falta el permiso de exportación para {count} grabación(es). Las descargas son todo o nada, por lo que esta selección no se puede exportar.", + "investigation.actions.camera": "Cámara", + "investigation.actions.recording": "Grabación", + "investigation.actions.size": "Tamaño", + "investigation.actions.notPermitted": "No permitido", + "investigation.actions.protectButton": "Proteger {count}", + "investigation.actions.protecting": "Protegiendo…", + "investigation.actions.protectUnavailable": "No hay grabaciones no protegidas que pueda proteger.", + "investigation.actions.protectResult": "Protección completada: {success} correctas, {failed} fallidas.", + "investigation.actions.downloadButton": "Descargar {count}", + "investigation.actions.downloadUnavailable": "Cada grabación requiere permiso de exportación antes de crear un ZIP.", + "investigation.actions.buildingArchive": "Creando ZIP…", + "investigation.actions.downloadFailed": "La creación del ZIP falló en el servidor.", + "investigation.actions.downloadTimedOut": "La creación del ZIP no finalizó en cinco minutos. Intente un intervalo más reducido.", + "investigation.actions.downloadStarted": "Descarga del ZIP iniciada.", + "investigation.backOneLevel": "Volver un nivel", + "investigation.thumbnailMinimumWindow": "Este es el intervalo de un segundo más reducido disponible. El cursor compartido se movió igualmente al momento seleccionado.", + "investigation.localSource": "local", + "investigation.mediaAvailable": "Medios disponibles", + "investigation.durationSeconds": "Duración: {count}s", + "investigation.pageNumber": "Página {count}", + "investigation.incompleteCoverage": "{count} filas de eventos heredados no se pudieron atribuir a una identidad de cámara inmutable.", + "investigation.spatialCoverageGap": "{count} filas de eventos en el alcance no tenían cuadro delimitador y no se buscaron espacialmente.", + "investigation.noSpatialMetadata": "Ningún evento en el alcance tiene cuadros delimitadores para esta búsqueda de metadatos.", + "investigation.selectCameraError": "Seleccione al menos una cámara.", + "investigation.selectRecordingError": "Seleccione al menos una grabación.", + "investigation.investigateSelectedCount": "Investigar {count} grabación(es) seleccionada(s)", + "investigation.missingCameraIdentity": "No se puede investigar: {count} grabación(es) seleccionada(s) no tienen identidad de cámara.", + "investigation.recordingTimeError": "Las grabaciones seleccionadas no tienen un rango de tiempo válido.", + "investigation.windowLimit": "Las grabaciones seleccionadas superan el límite de investigación de 31 días.", + "investigation.timeRangeError": "La hora de fin debe ser posterior a la hora de inicio.", + "investigation.cameraLimit": "Una investigación puede incluir como máximo {count} cámaras.", + "investigation.decoderLimit": "Solo {count} reproductores de cámara pueden estar activos a la vez.", + "investigation.playbackControls": "Controles de reproducción sincronizados", + "investigation.play": "Reproducir", + "investigation.pause": "Pausar", + "investigation.mode": "Modo de reproducción", + "investigation.wallClock": "Reloj real", + "investigation.skipCommonGaps": "Omitir huecos comunes", + "investigation.speed": "Velocidad", + "investigation.sharedCursor": "Cursor UTC compartido", + "investigation.activePlayers": "reproductores activos", + "investigation.timeline": "línea de tiempo compartida", + "investigation.segments": "segmentos", + "investigation.truncated": "truncado", + "investigation.gap": "Sin grabación", + "investigation.players": "Reproductores de cámara sincronizados", + "investigation.activateCamera": "Active al menos una fila de la línea de tiempo para cargar el video.", + "investigation.noFootage": "Sin grabación", + "investigation.noFootageAtTime": "Sin grabación en la hora compartida", + "investigation.primaryAudio": "Audio principal", + "investigation.makePrimary": "Establecer como principal", + "investigation.status.loading": "Cargando medios", + "investigation.status.synchronizing": "Sincronizando", + "investigation.status.ready": "Sincronizado", + "investigation.status.late": "Atrasado — recuperando", + "investigation.status.error": "Medio no disponible", + "investigation.status.paused-by-browser": "Seleccione reproducir para permitir el medio", + "streamsConfig.eptzTitle": "ePTZ de ojo de pez", + "streamsConfig.eptzEnable": "Habilitar ePTZ de ojo de pez en el navegador", + "streamsConfig.eptzHelp": "Corrige la distorsión del flujo de ojo de pez sin procesar en Vista en vivo, Reproducción en línea de tiempo e Investigación. Esto no altera las grabaciones ni la salida de la cámara.", + "streamsConfig.eptzModelHelp": "Proyección: ojo de pez circular equidistante · Montaje: techo. El centro y el radio usan coordenadas normalizadas de la imagen de origen.", + "streamsConfig.eptzCenterX": "Centro óptico X", + "streamsConfig.eptzCenterY": "Centro óptico Y", + "streamsConfig.eptzRadius": "Radio del círculo de imagen", + "streamsConfig.eptzLensFov": "FOV del lente (grados)", + "streamsConfig.eptzRotation": "Rotación del lente (grados)", + "streamsConfig.eptzDefaultYaw": "Panorámica predeterminada (grados)", + "streamsConfig.eptzDefaultTilt": "Inclinación predeterminada (grados)", + "streamsConfig.eptzViewFov": "FOV de vista predeterminado", + "streamsConfig.eptzCalibrationHelp": "Arrastre para mover la vista, use la rueda o pellizque para acercar, y presione Inicio para restablecer la cámara virtual. Ajuste el centro y el radio si el borde del círculo de imagen no se alinea.", + "settings.archive.targetType": "Tipo de almacenamiento", + "settings.archive.filesystem": "Sistema de archivos local o montado (NFS/SAN)", + "settings.archive.s3": "Bucket de archivo compatible con S3", + "settings.archive.endpoint": "Endpoint HTTPS", + "settings.archive.region": "Región", + "settings.archive.bucket": "Bucket dedicado", + "settings.archive.credential_ref": "Referencia de credenciales", + "settings.archive.budget": "Presupuesto de archivo (GiB, 0 = ilimitado)", + "settings.archive.connectionHelp": "Use un bucket privado, sin versionado y sin reglas de expiración de ciclo de vida. La referencia de credenciales selecciona un archivo secreto montado en el servidor. Ingrese la ubicación administrada como s3://bucket/instance-prefix.", + "settings.archive.policy": "Política de archivo externo", + "settings.archive.archive_after_seconds": "Archivar después de la captura (segundos, -1 = deshabilitado)", + "settings.archive.hot_residency_seconds": "Mantener copia en caliente (segundos, -1 = mover tras el archivado)", + "settings.archive.archive_protected": "Priorizar el archivado de grabaciones protegidas", + "settings.archive.archive_on_pressure": "Archivar anticipadamente cuando el almacenamiento en caliente esté bajo presión", + "settings.archive.policyHelp": "El tiempo de archivado usa la antigüedad de la captura y requiere una grabación completada. -1 deshabilita el archivado por antigüedad o elimina el mínimo de permanencia en caliente; 0 significa inmediatamente. Las ediciones se aplican a nuevas grabaciones. Revise las grabaciones existentes para aplicarles una nueva revisión.", + "settings.archive.deletion_pending": "Eliminación pendiente", + "settings.archive.archived": "Archivado", + "settings.archive.hot": "Caliente", + "settings.archive.hot_and_archive": "Caliente + archivo", + "settings.archive.archiving": "Archivando", + "settings.archive.preparing": "Preparando reproducción", + "settings.archive.unavailable": "No disponible", + "settings.archive.operations": "Operaciones de archivo", + "settings.archive.readOnly": "Modo de recuperación: la migración y eliminación de grabaciones están en pausa.", + "settings.archive.disabledBuild": "El soporte de S3 está deshabilitado en esta versión. Los destinos de sistemas de archivos montados siguen disponibles.", + "settings.archive.stored": "Almacenado en buckets", + "settings.archive.backlog": "Cola de transferencia", + "settings.archive.cache": "Caché de recuperación", + "settings.archive.objectsRemaining": "objetos restantes", + "settings.archive.waitingForReaders": "En cola, o esperando lectores activos.", + "settings.archive.applied": "Revisión de política aplicada a grabaciones existentes", + "settings.archive.reviewExisting": "Revisar grabaciones existentes", + "settings.archive.applySummary": "{count} grabaciones ({bytes}) usarán esta revisión. {expired} ya superaron su límite de retención.", + "settings.archive.applyHelp": "Las anulaciones de protección y grabación siguen aplicándose. La retención de flujo y del sistema también se aplica. El nuevo tiempo y destino de archivo entran en vigor en el siguiente análisis de ciclo de vida.", + "settings.archive.applyBlocked": "Finalice o resuelva las transferencias asociadas antes de aplicar esta revisión.", + "settings.archive.apply": "Aplicar a grabaciones existentes", + "common.fullscreenUnsupported": "El modo de pantalla completa no es compatible con este navegador.", + "recordings.viewInTimelineTitle": "Ver este flujo en este momento en la vista de línea de tiempo", + "recordings.clickToRetry": "Haga clic para reintentar", + "timeline.previousDay": "Día anterior", + "timeline.nextDay": "Día siguiente", + "timeline.previousMonth": "Mes anterior", + "timeline.nextMonth": "Mes siguiente", + "settings.searchLabel": "Buscar ajustes", + "settings.clearSearch": "Borrar búsqueda", + "recordings.addTagPlaceholder": "Agregar una etiqueta...", + "recordings.addNewTagPlaceholder": "Agregar nueva etiqueta..." } diff --git a/web/public/locales/fil.json b/web/public/locales/fil.json index 1b55bd19..3238d789 100644 --- a/web/public/locales/fil.json +++ b/web/public/locales/fil.json @@ -1120,5 +1120,1528 @@ "streamsConfig.toggleHourAllDays": "I-toggle ang {hour} sa lahat ng araw", "streamsConfig.noRecording": "Walang recording", "streamsConfig.recordingActive": "Aktibo ang recording", - "streamsConfig.clickHeadersOrDragCells": "I-click ang mga heading o i-drag sa mga cell" + "streamsConfig.clickHeadersOrDragCells": "I-click ang mga heading o i-drag sa mga cell", + "live.plan.navigatorHelp": "Pumili ng gusali o palapag. Ang preview ng camera ay bubukas lamang kapag hinihiling.", + "live.plan.noPlans": "Wala pang building plan. Gumawa ng isa sa plan workspace.", + "live.plan.emptyTitle": "Gumawa ng spatial na view ng camera", + "live.plan.emptyDescription": "Ang plan ay nagpapakita ng mga status marker para sa buong site at nagbubukas ng video lamang kapag hinihiling ng operator. Gumuhit ng mga silid at dingding dito, o mag-upload ng scanned na floor plan, site drawing, o snapshot mula sa iyong NVR software, pagkatapos ay i-map ang mga camera sa mga tunay na silid.", + "live.plan.sketch.tools": "Mga tool ng layout", + "live.plan.sketch.tool.select": "Pumili", + "live.plan.sketch.tool.room": "Silid", + "live.plan.sketch.tool.wall": "Dingding", + "live.plan.sketch.tool.area": "Area", + "live.plan.sketch.tool.label": "Label", + "live.plan.sketch.undo": "I-undo ang pagguhit", + "live.plan.sketch.redo": "I-redo ang pagguhit", + "live.plan.sketch.snap": "I-snap sa grid", + "live.plan.sketch.hint.select": "I-drag ang mga hugis o camera upang ilipat ang mga ito. I-click ang isang hugis upang i-edit; pindutin ang Alt upang laktawan ang grid.", + "live.plan.sketch.hint.room": "I-drag sa plan upang gumuhit ng silid o outline ng gusali.", + "live.plan.sketch.hint.wall": "I-click upang magdagdag ng mga punto ng dingding. I-double-click o pindutin ang Enter upang tapusin, Escape upang kanselahin.", + "live.plan.sketch.hint.area": "I-click upang gumuhit ng outline ng area. I-click ang unang punto o pindutin ang Enter upang isara ito.", + "live.plan.sketch.hint.label": "I-click ang plan upang maglagay ng text label.", + "live.plan.sketch.type.rect": "Silid", + "live.plan.sketch.type.wall": "Dingding", + "live.plan.sketch.type.area": "Area", + "live.plan.sketch.type.label": "Label", + "live.plan.sketch.pointCount": "{count} mga punto", + "live.plan.sketch.defaultLabel": "Label", + "live.plan.sketch.shapes": "Mga Hugis ng Layout", + "live.plan.sketch.noShapes": "Wala pang ginuhit. Pumili ng tool sa itaas ng plano para magsimula.", + "live.plan.sketch.tone": "Kulay", + "live.plan.sketch.tone.slate": "Slate", + "live.plan.sketch.tone.blue": "Asul", + "live.plan.sketch.tone.green": "Berde", + "live.plan.sketch.tone.amber": "Amber", + "live.plan.sketch.tone.red": "Pula", + "live.plan.sketch.tone.violet": "Lila", + "live.plan.sketch.labelText": "Label", + "live.plan.sketch.text": "Teksto", + "live.plan.sketch.size": "Laki", + "live.plan.sketch.size.sm": "Maliit", + "live.plan.sketch.size.md": "Katamtaman", + "live.plan.sketch.size.lg": "Malaki", + "live.plan.sketch.filled": "Punan ang Silid", + "live.plan.sketch.left": "Kaliwa %", + "live.plan.sketch.top": "Itaas %", + "live.plan.sketch.width": "Lapad %", + "live.plan.sketch.height": "Taas %", + "live.plan.sketch.points": "Mga Punto", + "live.plan.sketch.point": "Punto {index}", + "live.plan.sketch.delete": "Burahin ang Hugis", + "live.plan.sketch.duplicate": "Kopyahin", + "live.plan.sketch.deselect": "Tapos", + "live.plan.sketch.emptyTitle": "Wala pa sa planong ito", + "live.plan.sketch.emptyBody": "Gumuhit ng mga silid, dingding at label dito, o mag-upload ng naka-scan na plano, site drawing, o PNG/JPEG export (hanggang 768 KB).", + "live.plan.sketch.emptyBodyReadOnly": "Ang administrator ay maaaring gumuhit ng layout o mag-upload ng plano ng aktwal na gusali.", + "live.plan.sketch.drawLayout": "Gumuhit ng layout", + "live.plan.sketch.uploadImage": "Mag-upload ng imahe", + "live.plan.sketch.limitReached": "Naabot ang limit ng hugis ({max})", + "live.plan.sketch.discardDrawing": "Kinansela ang pagguhit", + "live.plan.previewUnavailable": "Hindi available ang preview ng camera", + "live.plan.previewAlt": "Kasalukuyang view mula sa {name}", + "live.plan.degreesValue": "{value} degrees", + "live.plan.inDegrees": "{label} sa degrees", + "live.plan.imageDimensionsError": "Hindi mabasa ang dimensions ng imahe", + "live.plan.loading": "Naglo-load ng mga plano ng gusali…", + "live.plan.created": "Ginawa ang {name}", + "live.plan.renamed": "Pinalitan ng pangalan sa {name}", + "live.plan.deleted": "Tinanggal ang {name}", + "live.plan.backgroundType": "Ang background ay dapat na PNG o JPEG na imahe", + "live.plan.backgroundTooLarge": "Masyadong malaki ang background image; ang maximum ay 768 KB", + "live.plan.backgroundAspect": "Na-upload, ngunit ang aspect ratio ng imahe ay hindi tumutugma sa anumang valid na canvas size", + "live.plan.backgroundUpdatedSave": "Na-update ang background para sa {name}; i-save ang layout upang mailapat ang canvas size nito", + "live.plan.backgroundNotResized": "Na-upload ang background, ngunit hindi pinalaki ang canvas: {error}", + "live.plan.backgroundUpdated": "Na-update ang background para sa {name}", + "live.plan.backgroundRemoved": "Tinanggal ang background", + "live.plan.saved": "Na-save ang {name}", + "live.plan.createTitle": "Gumawa ng plano ng gusali", + "live.plan.createDescription": "Bigyan ng malinaw na pangalan ang gusali o palapag na ito. Iguhit ang layout o mag-upload ng larawan ng floor plan, pagkatapos ay ilagay ang mga camera.", + "live.plan.nameLabel": "Pangalan ng plano", + "live.plan.namePlaceholder": "Pangunahing gusali · Unang palapag", + "live.plan.createConfirm": "Gumawa ng plano", + "live.plan.eyebrow": "Plano ng gusali", + "live.plan.placedSummary": "{placed} na-ilagay · {live} live ngayon", + "live.plan.zoomAndPan": "Zoom at pan ng plano", + "live.plan.panLeft": "Pan kaliwa", + "live.plan.panUp": "Pan pataas", + "live.plan.panDown": "Pan pababa", + "live.plan.panRight": "Pan kanan", + "live.plan.zoomOut": "Zoom out", + "live.plan.zoomIn": "Zoom in", + "live.plan.fitTitle": "I-fit ang plano", + "live.plan.fit": "I-fit", + "live.plan.backgroundMenu": "Background…", + "live.plan.save": "I-save ang plano", + "live.plan.uploadBackgroundTitle": "Mag-upload ng PNG o JPEG na larawan bilang background ng plano", + "live.plan.replaceBackground": "Palitan ang background", + "live.plan.uploadBackground": "Mag-upload ng background", + "live.plan.removeBackground": "Alisin ang background", + "live.plan.rename": "Palitan ang pangalan", + "live.plan.newPlan": "Bagong plano", + "live.plan.editLayout": "I-edit ang layout", + "live.plan.placementHint": "I-click ang plano upang ilagay ang {name}", + "live.plan.clusterLabel": "{count} na camera; mag-zoom in", + "live.plan.markerLabel": "{name}; {availability}; nakaharap sa {rotation}° na may {fov}° na tanawin", + "live.plan.cameraFallback": "Camera", + "live.plan.legendLive": "Live", + "live.plan.canvas": "Canvas ng plano", + "live.plan.width": "Lapad", + "live.plan.height": "Taas", + "live.plan.canvasHint": "Ang pag-upload ng background image ay magbabago ng laki ng canvas upang tumugma dito.", + "live.plan.canvasInvalid": "Ang lapad ay dapat 400–4000 at ang taas ay dapat 300–4000.", + "live.plan.openLive": "Buksan ang live na camera", + "live.plan.direction": "Direksyon ng camera", + "live.plan.fov": "Saklaw ng tanawin", + "live.plan.coverageNote": "Ang mga wedge ay nagpapakita lamang ng direksyon at anggulo; ang distansya sa plano ay hindi na-calibrate.", + "live.plan.removeCamera": "Alisin sa plano", + "live.plan.selectCamera": "Pumili ng camera", + "live.plan.selectHintEditing": "I-drag ang mga nakalagay na marker para sa pag-adjust. Suriin ang status at buksan ang live view kung kinakailangan.", + "live.plan.selectHint": "Suriin ang status at buksan ang live view kung kinakailangan.", + "live.plan.cameras": "Mga camera sa plano", + "live.plan.findPlaceholder": "Hanapin sa planong ito…", + "live.plan.findLabel": "Hanapin ang camera sa planong ito", + "live.plan.unplaced": "Mga camera na hindi pa nailalagay", + "live.plan.unplacedHint": "Pumili ng camera, pagkatapos i-click ang posisyon nito sa plano.", + "live.plan.renameTitle": "Palitan ang pangalan ng plano", + "live.plan.renameDescription": "Ang mga plano ay ibinahagi sa lahat ng operator sa site na ito.", + "live.plan.deleteTitle": "Burahin ang plano", + "live.plan.deleteMessage": "Burahin ang “{name}” at ang na-upload na background nito? Ang mga posisyon ng camera sa planong ito ay aalisin; ang mga camera mismo ay hindi maaapektuhan.", + "setupWizard.welcomeTitle": "Maligayang pagdating sa LightNVR", + "setupWizard.welcomeIntro": "I-configure ang iyong NVR sa ilang mabilisang hakbang. Maaari mong balikan ang mga setting na ito anumang oras mula sa Settings page.", + "setupWizard.welcomeStorage": "Storage path at limitasyon sa laki", + "setupWizard.welcomePerformance": "Mga limitasyon sa performance para sa bilang ng iyong camera", + "setupWizard.welcomeSecurity": "Ligtas na administrator sign-in", + "setupWizard.storageTitle": "Storage at Database", + "setupWizard.storageIntro": "Saan dapat i-imbak ang mga recording at database?", + "setupWizard.storagePath": "Storage path ng mga recording", + "setupWizard.storagePathHint": "Absolute path kung saan isinusulat ang mga video file.", + "setupWizard.maxStorage": "Pinakamalaking storage size (GB)", + "setupWizard.maxStorageHint": "0 = walang limitasyon.", + "setupWizard.dbPath": "Database path", + "setupWizard.dbPathHint": "Lokasyon ng SQLite database file.", + "setupWizard.performanceTitle": "Performance", + "setupWizard.performanceIntro": "Ang mga setting na ito ay kontrolado ang kapasidad, hindi ang kalidad ng video. Karamihan ng mga user ay maaaring panatilihin ang mga default.", + "setupWizard.threadPool": "Laki ng worker thread pool", + "setupWizard.threadPoolInfo": "nakakaapekto sa background na web/server work. Karaniwang pinakamainam ang inirerekomendang default maliban kung ina-adjust mo ang performance.", + "setupWizard.maxStreams": "Pinakamataas na bilang ng concurrent streams", + "setupWizard.maxStreamsInfo": "ay ang limitasyon sa kapasidad ng camera para sa tumatakbong instance na ito. Itakda ito sa hindi bababa sa bilang ng mga camera na balak mong idagdag, plus kaunting headroom.", + "setupWizard.important": "Mahalaga:", + "setupWizard.restartWarning": "kung baguhin mo ang alinman sa mga setting, ang bagong value ay na-save na ngayon ngunit hindi gagamitin hanggang sa ma-restart ang LightNVR. Halimbawa, kung ang kasalukuyang stream limit ay 1 at itinaas mo ito sa 32, kailangan mong mag-restart bago magdagdag ng mga camera lampas sa dating limit.", + "setupWizard.threadPoolHintCores": "Inirerekomenda: {recommended} (2× ng iyong {cores}-core CPU). Kinokontrol nito ang libuv background worker threads. Saklaw: 2–128.", + "setupWizard.threadPoolHint": "Inirerekomenda: {recommended} (2× ng iyong CPU cores). Kinokontrol nito ang libuv background worker threads. Saklaw: 2–128.", + "setupWizard.maxStreamsHint": "Ilang camera ang maaaring panatilihing aktibo ng LightNVR nang sabay. Default 32, max {max}. Kung inaasahan mo ang 8 camera, pumili ng hindi bababa sa 8. Kailangang mag-restart para magkabisa.", + "setupWizard.completeTitle": "Kumpleto na ang Setup!", + "setupWizard.saved": "Matagumpay na na-save ang iyong mga setting.", + "setupWizard.notSaved": "Walang nabagong setting — gagamitin ang mga default.", + "setupWizard.restartRequired": "Kailangang i-restart", + "setupWizard.restartRequiredInfo": "ang mga pagbabago sa thread pool size at/o max streams ay na-save na, ngunit hindi magkakabisa hanggang sa ma-restart ang service. Mag-restart bago magdagdag ng mga camera o inaasahan ang bagong capacity limit.", + "setupWizard.saveFailed": "Nabigong i-save ang mga setting: {error}", + "setupWizard.back": "Bumalik", + "setupWizard.saving": "Nagsesave…", + "setupWizard.saveContinue": "I-save at Magpatuloy", + "setupWizard.next": "Susunod →", + "setupWizard.finish": "Pumunta sa Dashboard", + "setupWizard.skip": "Laktawan ang setup wizard", + "live.eptzCanvasLabel": "Fisheye electronic pan, tilt, at zoom na view", + "live.eptzCanvasHint": "I-drag para mag-pan at tilt; i-scroll o mag-pinch para mag-zoom; pindutin ang Home para i-reset", + "live.eptzReset": "I-reset ang ePTZ view", + "live.autoShort": "Auto", + "live.webrtcShort": "WebRTC", + "events.tab": "Mga Event", + "events.eyebrow": "Mga integrasyon na event-driven", + "events.title": "Mga Event at Routing", + "events.description": "Gawing matibay na MQTT stream ang mga camera at system event para sa automation, notification services, at external processing. Ang LightNVR ang nagbibigay ng event interface; ang email at SMS delivery ay nananatili sa downstream services.", + "events.routes": "Mga Route", + "events.destinations": "Mga Destination", + "events.catalog": "Katalogo ng Event", + "events.enable": "I-enable", + "events.loadError": "Hindi ma-load ang configuration ng event routing", + "events.accessDenied": "Access denied - kulang sa mga pribilehiyo", + "events.summary.routes": "Mga Route", + "events.summary.enabled": "{count} na-enabled", + "events.summary.destinations": "Mga Destination", + "events.summary.managedActive": "{count} na-manage at aktibo", + "events.summary.types": "Mga Registered na Uri", + "events.summary.registry": "Versioned na katalogo ng event", + "events.summary.interface": "Interface", + "events.summary.interfaceHelp": "Matibay na output ng event", + "events.route.add": "Magdagdag ng route", + "events.route.addTitle": "Gumawa ng event route", + "events.route.editTitle": "I-edit ang event route", + "events.route.create": "Gumawa ng route", + "events.route.editorDescription": "Piliin kung anong mga event ang kwalipikado, kung anong camera ang saklaw, kung saan pupunta, at kung paano kontrolin ang maingay na source.", + "events.route.emptyTitle": "Walang naka-configure na event route", + "events.route.emptyDescription": "Gumawa ng route upang piliin ang mga uri ng event, saklaw ng camera, iskedyul, suppression policy, at MQTT destination.", + "events.route.enabled": "Naka-enable ang route", + "events.route.enabledHelp": "Ang mga tumutugmang event ay tinatanggap para sa matibay na delivery", + "events.route.destination": "Destination", + "events.route.destinationHelp": "Ang tumutugmang event ay ini-save nang isang beses para sa bawat unique na destination.", + "events.route.eventTypes": "Mga Uri ng Event", + "events.route.eventTypesHelp": "Pumili ng isa o higit pang versioned na event contract mula sa registry.", + "events.route.detectionFilters": "I-filter ang mga object detection", + "events.route.detectionFiltersHelp": "Puwedeng humingi ng mga label, zone, o minimum confidence para sa mga object-detection event.", + "events.route.healthFilters": "I-filter ang mga system health event", + "events.route.healthFiltersHelp": "Puwedeng i-match ang mga registered health condition code o severity. Ang mga available na value ay galing sa recorder na ito.", + "events.route.healthConditions": "Mga Health Condition (kahit ano)", + "events.route.healthSeverities": "Mga Severity (kahit ano)", + "events.route.healthRegistryUnavailable": "Hindi available ang health-condition registry. I-reload bago i-configure ang mga condition filter.", + "events.route.labels": "Mga Label (kahit ano)", + "events.route.zones": "Mga Zone ID (kahit ano)", + "events.route.listHelp": "Ihiwalay ang mga value gamit ang comma.", + "events.route.minConfidence": "Minimum confidence", + "events.route.confidenceHelp": "Isang value mula 0 hanggang 1.", + "events.route.cameraScope": "Saklaw ng Camera", + "events.route.cameraScopeHelp": "Gamitin muli ang mga fleet location, tag, koleksyon ng attributes, o mga tiyak na camera nang hindi nilo-load ang buong fleet.", + "events.route.allCameras": "Lahat ng Camera", + "events.route.dynamicScope": "Dynamic na Camera Selector", + "events.route.systemScopeHelp": "Hindi camera ang mga system event. Hindi available ang mga camera selector kapag kasama sa route na ito ang mga system-scoped event.", + "events.route.schedule": "Iskedyul", + "events.route.scheduleHelp": "Gamitin ang oras ng pangyayari ng event sa IANA timezone; sinusuportahan ang mga overnight window.", + "events.route.restrictSchedule": "Sa mga naka-configure na window lamang", + "events.route.suppression": "Patakaran sa Ingay at Paghahatid", + "events.route.suppressionHelp": "Ang zero ay nagde-disable ng isang control. Ang suppression ay lumalago lamang pagkatapos tanggapin ng destination ang durable event.", + "events.route.debounce": "Mga segundo ng debounce", + "events.route.debounceHelp": "Pinapalawak ng mga paulit-ulit na obserbasyon ang tahimik na interval na ito.", + "events.route.cooldown": "Mga segundo ng cooldown", + "events.route.cooldownHelp": "Minimum na interval pagkatapos ng tinanggap na event.", + "events.route.grouping": "Mga segundo ng grouping window", + "events.route.groupingHelp": "Panatilihin ang unang event at pagsamahin ang mga paulit-ulit.", + "events.route.rateLimit": "Mga event bawat minuto", + "events.route.rateLimitHelp": "Maximum sa fixed-window bawat route at camera.", + "events.route.deliveryPolicy": "Patakaran sa Paghahatid", + "events.route.suppressionActive": "Aktibo ang mga kontrol sa ingay", + "events.route.everyMatch": "Bawat tugma", + "events.route.preview": "I-preview ang route", + "events.route.previewing": "Nagpe-preview…", + "events.route.previewResult": "Preview ng route", + "events.route.cameraMatches": "{count} camera ang tumugma", + "events.route.previewNoPublish": "Iine-validate ng preview ang buong rule at naglutas ng sample ng camera; hindi ito nagpo-publish ng event.", + "events.route.systemPreviewHelp": "Lumalaktawan ng system events ang pagpili ng camera kaya walang tumutugmang camera na inuulat sa preview na ito.", + "events.route.created": "Nagawa ang event route", + "events.route.updated": "Na-update ang event route", + "events.route.deleted": "Nabura ang event route", + "events.route.disabled": "Na-disable ang event route", + "events.route.enabledMessage": "Na-enable ang event route", + "events.route.deleteConfirm": "Burahin ang event route na \"{name}\"?", + "events.route.validation.name": "Maglagay ng pangalan ng route.", + "events.route.validation.destination": "Pumili ng destination.", + "events.route.validation.event_types": "Pumili ng kahit isang uri ng event.", + "events.route.validation.selector": "Kumpletuhin o itama ang camera selector.", + "events.route.validation.system_scope": "Hindi maaaring gamitin ang camera selector sa system-scoped events.", + "events.route.validation.detection_type": "Kailangan ng detection filters ang object-detection event type.", + "events.route.validation.detection_filter": "Magdagdag ng kahit isang detection label, zone, o confidence threshold.", + "events.route.validation.confidence": "Ang minimum confidence ay dapat mula 0 hanggang 1.", + "events.route.validation.predicate_mix": "Hindi maaaring pagsamahin ang detection at health filters sa isang route.", + "events.route.validation.health_type": "Ang health filters ay nangangailangan lamang ng registered system-health event types.", + "events.route.validation.health_filter": "Pumili ng kahit isang registered health condition o severity.", + "events.route.validation.health_condition": "Pumili lamang ng condition codes na ibinalik ng health registry ng recorder.", + "events.route.validation.health_severity": "Pumili lamang ng severities na sinusuportahan ng napiling health event types.", + "events.route.validation.timezone": "Maglagay ng naka-install na IANA timezone tulad ng UTC o America/New_York.", + "events.route.validation.schedule_window": "Ang bawat schedule window ay nangangailangan ng kahit isang araw at magkakaibang valid na oras ng simula at wakas.", + "events.route.validation.suppression": "Ang suppression values ay dapat na buong numero sa loob ng kanilang pinapayagang saklaw.", + "events.schedule.timezone": "Timezone", + "events.schedule.timezoneHelp": "Dapat na naroroon sa timezone database ng recorder.", + "events.schedule.addWindow": "Magdagdag ng time window", + "events.schedule.windowNumber": "Window {number}", + "events.schedule.start": "Simulan", + "events.schedule.end": "Tapusin", + "events.schedule.sunday": "Lin", + "events.schedule.monday": "Lun", + "events.schedule.tuesday": "Mar", + "events.schedule.wednesday": "Miy", + "events.schedule.thursday": "Huw", + "events.schedule.friday": "Biy", + "events.schedule.saturday": "Sab", + "events.destination.add": "Magdagdag ng destination", + "events.destination.addTitle": "Magdagdag ng MQTT destination", + "events.destination.editTitle": "I-edit ang MQTT destination", + "events.destination.create": "Gumawa ng destination", + "events.destination.editorDescription": "I-configure ang isang durable na event output. Ang mga credentials ay write-only lamang at hindi kailanman ibabalik ng API.", + "events.destination.default": "Default na MQTT settings", + "events.destination.settingsManaged": "Pinamamahalaan ang mga Setting", + "events.destination.defaultDescription": "Ang umiiral na MQTT configuration ay nananatiling available bilang mqtt:default at ginagamit ng {count} routes.", + "events.destination.openSettings": "Buksan ang MQTT settings", + "events.destination.emptyTitle": "Walang pinamamahalaang destination", + "events.destination.emptyDescription": "Magdagdag ng isa pang MQTT broker para sa independent na event delivery sa cloud connector, automation system, o notification service.", + "events.destination.identity": "Pagkakakilanlan ng destination", + "events.destination.enabled": "Naka-enable ang destination", + "events.destination.enabledHelp": "Kumonekta at i-drain ang kanyang durable queue", + "events.destination.active": "Aktibo", + "events.destination.paused": "Naka-pause", + "events.destination.pause": "I-pause", + "events.destination.broker": "Broker", + "events.destination.host": "Broker host", + "events.destination.hostHelp": "Hostname o IP address lamang; huwag isama ang URL scheme.", + "events.destination.port": "Port", + "events.destination.clientId": "Client ID", + "events.destination.clientIdHelp": "Dapat ay unique para sa broker connection na ito.", + "events.destination.topic": "Paksa", + "events.destination.topicTemplate": "Template ng Paksa", + "events.destination.topicHelp": "Kailangang isama ang mga token na event-type at subject-ID; hindi pinapayagan ang MQTT wildcards.", + "events.destination.keepalive": "Keepalive na segundo", + "events.destination.statusTopicTemplate": "Paksa ng status ng presence", + "events.destination.statusTopicHelp": "Opsyonal. Kailangang isama ang {installation_uuid}; available din ang {destination_uuid}. Hindi pinapayagan ang MQTT wildcards.", + "events.destination.statusTopicEnabled": "Aktibong pinagana ang presence para sa destination na ito. Hindi kailanman hinuhulaan ang paksa mula sa event topic.", + "events.destination.statusTopicDisabled": "Naka-disable ang presence para sa destination na ito. Iwanang blangko ang field na ito para manatiling naka-disable.", + "events.destination.qos": "Kalidad ng serbisyo", + "events.destination.qos0": "ipadala nang isang beses", + "events.destination.qos1": "kahit isang beses", + "events.destination.qos2": "eksaktong isang beses", + "events.destination.authentication": "Pagpapatunay", + "events.destination.passwordPreserved": "Iwanang blangko para panatilihin ang naka-imbak na write-only na password.", + "events.destination.passwordOptional": "Opsyonal kapag pinapayagan ng broker ang mga anonymous na client.", + "events.destination.clearPassword": "Burahin ang naka-imbak na password", + "events.destination.transportSecurity": "Seguridad ng transport", + "events.destination.tlsMode": "Mode ng TLS", + "events.destination.tlsSystem": "Trust store ng sistema", + "events.destination.tlsCustomCa": "Custom na certificate authority", + "events.destination.tlsMutual": "Mutual TLS", + "events.destination.tlsDisabled": "Naka-disable (plaintext)", + "events.destination.tlsHelp.system": "Beripikahin ang certificate ng broker laban sa trust store ng operating system.", + "events.destination.tlsHelp.custom_ca": "Beripikahin ang broker laban sa isang tiyak na PEM certificate authority file.", + "events.destination.tlsHelp.mutual": "Beripikahin ang broker sa pamamagitan ng isang tiyak na CA at magpresent ng client certificate at key.", + "events.destination.tlsHelp.disabled": "Walang transport encryption o beripikasyon ng identity ng broker.", + "events.destination.caFile": "CA file", + "events.destination.certFile": "File ng client certificate", + "events.destination.keyFile": "File ng client key", + "events.destination.absolutePathHelp": "Gumamit ng absolute path na mababasa ng LightNVR service.", + "events.destination.plaintextWarning": "Maaaring ilantad ng plaintext MQTT ang event metadata at mga kredensyal. Gamitin lamang ito sa isang pinagkakatiwalaan at hiwalay na network.", + "events.destination.security": "Seguridad", + "events.destination.tls.system": "Tiwala ng Sistema", + "events.destination.tls.custom_ca": "Custom CA", + "events.destination.tls.mutual": "Mutual TLS", + "events.destination.tls.disabled": "Plaintext", + "events.destination.routes": "Mga Route", + "events.destination.presence": "Presence topic", + "events.destination.deleteInUse": "Alisin o i-redirect ang mga route bago burahin ang destination na ito.", + "events.destination.created": "Nalikha ang MQTT destination", + "events.destination.updated": "Na-update ang MQTT destination", + "events.destination.deleted": "Nabura ang MQTT destination", + "events.destination.pausedMessage": "Na-pause ang MQTT destination; ang mga naka-queue na event ay mananatili hanggang sa mag-expire.", + "events.destination.enabledMessage": "Na-enable ang MQTT destination", + "events.destination.deleteConfirm": "Burahin ang MQTT destination na \"{name}\"?", + "events.destination.validation.name": "Maglagay ng pangalan ng destination.", + "events.destination.validation.host": "Maglagay ng broker hostname o IP address.", + "events.destination.validation.client_id": "Maglagay ng broker client ID.", + "events.destination.validation.topic": "Ang topic ay dapat na may kasamang event-type at subject-ID tokens at hindi maaaring maglaman ng MQTT wildcards.", + "events.destination.validation.status_topic": "Ang opsyonal na presence topic ay dapat na may kasamang installation UUID token, gumamit lamang ng mga suportadong token, at hindi maaaring maglaman ng MQTT wildcards.", + "events.destination.validation.port": "Ang port ay dapat na buong numero mula 1 hanggang 65535.", + "events.destination.validation.keepalive": "Ang keepalive ay dapat na buong numero mula 5 hanggang 3600 segundo.", + "events.destination.validation.qos": "Pumili ng MQTT QoS 0, 1, o 2.", + "events.destination.validation.username": "Ang naka-configure na password ay nangangailangan ng username.", + "events.destination.validation.ca_file": "Ang TLS mode na ito ay nangangailangan ng absolute CA file path.", + "events.destination.validation.mutual_files": "Ang Mutual TLS ay nangangailangan ng absolute CA, client certificate, at client key paths.", + "fleet.eyebrow": "Mga Operasyon ng Camera", + "fleet.title": "Inventory ng Camera", + "fleet.description": "Hanapin, suriin, at ayusin ang mga camera sa malalaking deployment nang hindi nilo-load ang buong inventory sa browser.", + "fleet.summary": "Buod ng Kalusugan ng Fleet", + "fleet.totalCameras": "Mga Tumutugmang Camera", + "fleet.needsAttention": "Nabababa", + "fleet.searchLabel": "Maghanap ng camera", + "fleet.searchPlaceholder": "Hanapin ang pangalan, address, lokasyon, tag, vendor, o model…", + "fleet.resultCount": "{count} mga kamera", + "fleet.filters": "Mga Filter", + "fleet.clearFilters": "I-clear ang mga Filter", + "fleet.filter.health": "Kalagayan", + "fleet.filter.enabled": "Estado ng Kamera", + "fleet.filter.anyState": "Anumang Estado", + "fleet.filter.recording": "Mode ng Recording", + "fleet.filter.location": "Subtree ng Lokasyon", + "fleet.filter.allLocations": "Lahat ng Lokasyon", + "fleet.filter.tags": "Mga Tag (tumugma sa kahit ano)", + "fleet.filter.collection": "Koleksyon ng Kamera", + "fleet.health.unknown": "Hindi Alam", + "fleet.health.up": "Online", + "fleet.health.degraded": "Nabababa", + "fleet.health.down": "Offline", + "fleet.health.disabled": "Naka-disable", + "fleet.recording.off": "Naka-off", + "fleet.recording.continuous": "Patuloy", + "fleet.recording.detection": "Pagtuklas", + "fleet.recordingActive": "Nagre-record ngayon", + "fleet.recordingInactive": "Hindi nagre-record", + "fleet.column.camera": "Kamera", + "fleet.column.health": "Kalagayan", + "fleet.column.location": "Lokasyon", + "fleet.column.tags": "Mga Tag", + "fleet.column.recording": "Recording", + "fleet.viewLive": "Live", + "fleet.lastFrame": "Huling Frame", + "fleet.noAddress": "Hindi available ang address", + "fleet.unassigned": "Walang Nakatalaga", + "fleet.loading": "Iniloload ang fleet ng kamera…", + "fleet.refreshing": "Nag-refresh…", + "fleet.loadError": "Hindi ma-load ang fleet ng camera", + "fleet.emptyTitle": "Walang naka-configure na camera", + "fleet.emptyDescription": "Magdagdag ng stream para maging available sa fleet workspace.", + "fleet.emptyFilteredTitle": "Walang camera na tumugma sa view na ito", + "fleet.emptyFilteredDescription": "Subukang palawakin ang paghahanap o alisin ang isa o higit pang filter.", + "fleet.paginationSummary": "Ipinapakita ang {first}–{last} ng {total}", + "fleet.perPage": "Bawat pahina", + "fleet.pageOf": "Pahina {page} ng {pages}", + "fleet.selectPage": "Piliin ang lahat ng camera sa pahinang ito", + "fleet.selectCamera": "Piliin ang {name}", + "fleet.selectedCount": "{count} camera ang napili", + "fleet.organizeSelected": "Ayusin ang napili", + "fleet.clearSelection": "Alisin ang napili", + "fleet.organization.manage": "Pamahalaan ang organisasyon", + "fleet.organization.title": "Organisasyon ng camera", + "fleet.organization.description": "Panatilihin ang reusable na hierarchy ng lokasyon at normalized na tag dictionary para sa fleet ng camera.", + "fleet.organization.locations": "Mga Lokasyon", + "fleet.organization.tags": "Mga Tag", + "fleet.organization.locationsDescription": "I-model ang mga site, gusali, palapag, at operational na lugar bilang navigable na hierarchy.", + "fleet.organization.tagsDescription": "Gumamit ng governed na tag dictionary sa halip na inconsistent na free-form na label.", + "fleet.organization.addRoot": "Magdagdag ng top-level na lokasyon", + "fleet.organization.addLocation": "Magdagdag ng lokasyon", + "fleet.organization.editLocation": "I-edit ang lokasyon", + "fleet.organization.addChild": "Magdagdag ng child", + "fleet.organization.type": "Uri", + "fleet.organization.parent": "Parent na lokasyon", + "fleet.organization.topLevel": "Top level", + "fleet.organization.sortOrder": "Pagkakasunod-sunod", + "fleet.organization.contents": "Mga Nilalaman", + "fleet.organization.cameras": "Mga Camera", + "fleet.organization.system": "Sistema", + "fleet.organization.contentCounts": "{cameras} camera · {children} child", + "fleet.organization.locationNotEmpty": "Ilipat muna ang mga camera at burahin ang mga child location", + "fleet.organization.noLocations": "Walang naka-configure na location.", + "fleet.organization.locationCreated": "Nagawa ang location", + "fleet.organization.locationUpdated": "Na-update ang location", + "fleet.organization.locationDeleted": "Nabura ang location", + "fleet.organization.deleteLocationConfirm": "Burahin ang location na \"{name}\"?", + "fleet.organization.addTag": "Magdagdag ng tag", + "fleet.organization.editTag": "I-edit ang tag", + "fleet.organization.tagLabel": "Tag", + "fleet.organization.color": "Kulay (#RRGGBB)", + "fleet.organization.tagDescription": "Paglalarawan", + "fleet.organization.noTags": "Walang naka-configure na normalized tag.", + "fleet.organization.tagCreated": "Nagawa ang tag", + "fleet.organization.tagUpdated": "Na-update ang tag", + "fleet.organization.tagDeleted": "Nabura ang tag", + "fleet.organization.deleteTagConfirm": "Burahin ang \"{name}\"? Kasalukuyang nakatalaga ito sa {count} na camera.", + "fleet.organization.merge": "Pagsamahin", + "fleet.organization.mergeTagNamed": "Pagsamahin ang \"{name}\"", + "fleet.organization.mergeInto": "Pagsamahin sa", + "fleet.organization.chooseTag": "Piliin ang tag na pananatilihin", + "fleet.organization.mergeWarning": "Lahat ng assignment ng camera ay lilipat sa tag na pananatilihin; ang source tag ay aalisin pagkatapos.", + "fleet.organization.tagsMerged": "Nagsama ang mga tag", + "fleet.organization.saveError": "Hindi ma-save: {message}", + "fleet.organization.deleteError": "Hindi mabura: {message}", + "fleet.locationType.site": "Site", + "fleet.locationType.building": "Gusali", + "fleet.locationType.floor": "Palapag", + "fleet.locationType.area": "Area", + "fleet.locationType.zone": "Zone", + "fleet.locationType.system": "Sistema", + "fleet.bulk.title": "Ayusin ang mga napiling camera", + "fleet.bulk.description": "I-apply ang mga pagbabago sa location at tag sa {count} na camera na may bounded concurrency.", + "fleet.bulk.location": "Pagtatalaga ng Lokasyon", + "fleet.bulk.locationHelp": "Lahat ng napiling camera ay ililipat sa napiling lokasyon.", + "fleet.bulk.keepLocations": "Panatilihin ang kasalukuyang lokasyon", + "fleet.bulk.tags": "Pagtatalaga ng Tag", + "fleet.bulk.tagsHelp": "Magdagdag o magtanggal ng mga tag nang hindi naaapektuhan ang ibang pagtatalaga, o palitan ang buong set ng tag.", + "fleet.bulk.tagOperation.none": "Panatilihin", + "fleet.bulk.tagOperation.add": "Magdagdag", + "fleet.bulk.tagOperation.remove": "Tanggalin", + "fleet.bulk.tagOperation.replace": "Palitan lahat", + "fleet.bulk.replaceWarning": "Ang \"Palitan lahat\" ay nagtatanggal ng lahat ng kasalukuyang tag bago ilapat ang napili. Ang walang napiling pagpipilian ay naglilinis ng lahat ng tag.", + "fleet.bulk.apply": "I-apply ang mga pagbabago", + "fleet.bulk.working": "Iinaapply ang mga pagbabago…", + "fleet.bulk.success": "Na-update ang {count} na camera", + "fleet.bulk.partial": "Na-update ang {succeeded} na camera; {failed} ang nabigo", + "fleet.bulk.error": "Hindi maayos ang mga camera: {message}", + "fleet.bulk.failures": "Mga camera na hindi ma-update", + "fleet.queues.degraded": "Mga degraded na stream", + "fleet.queues.offline": "Mga offline na camera", + "fleet.queues.oldest": "Pinakamatanda: {time}", + "fleet.queues.noneActive": "Walang aktibong kondisyon", + "fleet.views.title": "Mga naka-save na view", + "fleet.views.choose": "Pumili ng naka-save na view", + "fleet.views.none": "Wala pang naka-save na view", + "fleet.views.shared": "Ibinahagi", + "fleet.views.saveCurrent": "I-save ang kasalukuyang view", + "fleet.views.name": "Pangalan ng view", + "fleet.views.share": "Ibahagi sa lahat ng operator", + "fleet.views.saved": "Naka-save ang fleet view", + "fleet.views.saveError": "Hindi ma-save ang view: {message}", + "fleet.views.deleted": "Nabura ang fleet view", + "fleet.views.deleteConfirm": "Burahin ang naka-save na view na \"{name}\"?", + "fleet.views.deleteError": "Hindi mabura ang view: {message}", + "fleet.views.unsupported": "Hindi maipakita ng kasalukuyang mga kontrol ng filter ang naka-save na selector na ito.", + "collections.manage": "Mga Koleksyon", + "collections.all": "Lahat ng Koleksyon", + "collections.filter": "Koleksyon", + "collections.loadMembersError": "Hindi ma-load ang mga camera ng koleksyon: {message}", + "collections.title": "Mga Koleksyon ng Camera", + "collections.subtitle": "Gumawa ng mga muling magagamit na grupo ng camera para sa mga operasyon, naka-save na view, at downstream na workflow.", + "collections.listDescription": "Ang mga static na koleksyon ay may tiyak na miyembro; ang mga smart na koleksyon ay patuloy na sinusuri ang mga patakaran ng fleet.", + "collections.create": "Gumawa ng Koleksyon", + "collections.edit": "I-edit ang Koleksyon", + "collections.editorDescription": "Ang mga depinisyon ng koleksyon ay gumagamit ng stable na UUID ng camera, lokasyon, at tag.", + "collections.backToList": "Bumalik sa mga Koleksyon", + "collections.type": "Uri ng Koleksyon", + "collections.type.static": "Static", + "collections.type.smart": "Smart", + "collections.description": "Paglalarawan", + "collections.shared": "Ibinahaging Koleksyon", + "collections.sharedHelp": "Payagan ang ibang awtorisadong user na makita ang koleksyong ito; patuloy pa ring naaangkop ang mga patakaran sa access ng camera.", + "collections.typeChangeWarning": "Ang pagbabago ng uri ng koleksyon ay papalitan ang modelo ng miyembro nito. Ang mga static na miyembro o smart na patakaran mula sa naunang uri ay hindi na gagana.", + "collections.selectorError": "Hindi valid ang selector: {message}", + "collections.created": "Nagawa ang Koleksyon", + "collections.updated": "Na-update ang Koleksyon", + "collections.saveError": "Hindi ma-save ang koleksyon: {message}", + "collections.loadError": "Hindi ma-load ang koleksyon: {message}", + "collections.cameras": "mga camera", + "collections.visibility.shared": "Ibinahagi", + "collections.visibility.private": "Pribado", + "collections.selectorRedacted": "Pribadong mga Patakaran", + "collections.emptyTitle": "Wala pang koleksyon", + "collections.emptyAdmin": "Gumawa ng static na grupo o smart na rule-based na view para muling magamit ang mga piniling camera.", + "collections.emptyViewer": "Walang ibinahaging koleksyon na available para sa iyong saklaw ng camera.", + "collections.deleteConfirm": "Burahin ang koleksyong \"{name}\"?", + "collections.deleted": "Nabura ang koleksyon", + "collections.deleteError": "Hindi mabura ang koleksyon: {message}", + "collections.preview.title": "Preview ng rule", + "collections.preview.matches": "{count} na tumutugmang camera", + "collections.preview.action": "Preview", + "collections.preview.hide": "Itago ang preview", + "collections.preview.loading": "Sinusuri…", + "collections.preview.empty": "Walang tumutugmang camera sa kasalukuyan.", + "collections.preview.sample": "Ipinapakita ang {count}-camera na sample ng {total} na tugma.", + "collections.preview.error": "Hindi ma-preview ang koleksyon: {message}", + "collections.members.title": "Mga static na miyembro", + "collections.members.selected": "{count} na camera ang napili sa lahat ng pahina", + "collections.members.search": "Maghanap ng camera…", + "collections.members.selectPage": "Piliin ang pahinang ito", + "collections.members.empty": "Walang tumutugmang camera sa paghahanap na ito.", + "collections.builder.title": "Mga smart rule", + "collections.builder.description": "Ang mga rule ay sinusuri batay sa kasalukuyang organisasyon, configuration, kakayahan, at kalusugan ng camera.", + "collections.builder.match": "Tugma", + "collections.builder.allRules": "lahat ng rule", + "collections.builder.anyRule": "kahit anong rule", + "collections.builder.addRule": "Magdagdag ng rule", + "collections.builder.removeRule": "Alisin ang rule", + "collections.builder.matchesAll": "Kung walang kumpletong rule, tumutugma ang koleksyong ito sa bawat camera sa awtorisadong saklaw ng user.", + "collections.builder.incompleteRule": "Kumpletuhin o alisin ang bawat rule bago mag-save.", + "collections.builder.chooseLocation": "Pumili ng location subtree", + "collections.builder.vendorPlaceholder": "Mga pangalan ng vendor, pinaghihiwalay ng kuwit", + "collections.builder.modelPlaceholder": "Mga pangalan ng model, pinaghihiwalay ng kuwit", + "collections.builder.advancedMode": "Advanced JSON", + "collections.builder.visualMode": "Visual builder", + "collections.builder.cannotVisualize": "Ang selector na ito ay naglalaman ng nested o advanced na lohika na hindi ligtas na maipakita ng visual builder.", + "collections.rule.location_subtree": "Ang location ay nasa loob ng", + "collections.rule.camera_uuid": "Mga partikular na camera", + "collections.rule.tag_any": "May anumang tag", + "collections.rule.tag_all": "May lahat ng tag", + "collections.rule.tag_none": "Walang anumang tag", + "collections.rule.health": "Kalusugan ay", + "collections.rule.enabled": "Camera ay", + "collections.rule.recording_mode": "Mode ng Recording ay", + "collections.rule.capability_any": "May anumang capability", + "collections.rule.capability_all": "May lahat ng capability", + "collections.rule.vendor": "Vendor ay", + "collections.rule.model": "Model ay", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Audio backchannel", + "streamHealth.title": "Kalusugan ng Stream", + "streamHealth.loading": "Naglo-load ng health data...", + "streamHealth.error": "Nabigong mag-load ng health data", + "streamHealth.overallStatus": "Status", + "streamHealth.streamsUp": "Mga Stream na Gumagana", + "streamHealth.degraded": "Nababawasan", + "streamHealth.down": "Hindi Gumagana", + "streamHealth.storage": "Storage", + "streamHealth.noStreams": "Walang na-configure na stream", + "streamHealth.fps": "FPS", + "streamHealth.observedFps": "Naobserbahang FPS", + "streamHealth.expectedFps": "Inaasahan", + "streamHealth.fpsHelp": "Naobserbahan ng LightNVR; ang inaasahan ay mula sa metadata ng camera stream.", + "streamHealth.bitrate": "Bitrate", + "streamHealth.uptime": "Uptime", + "streamHealth.lastFrame": "Huling Frame", + "streamHealth.reconnects": "Mga Reconnect", + "streamHealth.framesTotal": "Kabuuang Frame", + "streamHealth.framesDropped": "Mga Frame na Tinapon", + "streamHealth.connectionLatency": "Latency ng Koneksyon", + "streamHealth.recording": "Recording", + "streamHealth.recordingGaps": "Mga Gap sa Recording", + "streamHealth.active": "Aktibo", + "streamHealth.inactive": "Hindi Aktibo", + "settings.health.title": "Kalusugan ng host at hardware", + "settings.health.description": "I-configure ang may limitasyong pag-monitor ng operating system at hardware nang hindi inilalantad ang mga device path o secrets.", + "settings.health.enabled": "I-enable ang health monitoring", + "settings.health.enabledHelp": "Kolektahin ang mga sinusuportahang signal ng host, service, storage, network, at hardware.", + "settings.health.profile": "Policy profile", + "settings.health.profileHelp": "Ang Balanced ang normal na default; ang conservative ay nangangailangan ng mas malakas na ebidensya bago mag-alert.", + "settings.health.profile.balanced": "Balanced", + "settings.health.profile.conservative": "Conservative", + "settings.health.hardwareProvider": "Hardware provider", + "settings.health.provider.auto": "Awtomatiko (kernel providers)", + "settings.health.provider.smartctl": "smartctl (explicit)", + "settings.health.providerHelp.auto": "Gumagamit lamang ng may limitasyong sysfs, NVMe, at kernel providers; hindi kailanman hinuhulaan ang smartctl.", + "settings.health.providerHelp.smartctl": "Malinaw na ina-enable ang opsyonal na may limitasyong smartctl JSON provider para sa mga natuklasang device.", + "settings.health.providerHelp.disabled": "Idinidi ang opsyonal na hardware providers habang pinapanatiling available ang portable health monitoring.", + "settings.health.writeProbe": "I-enable ang storage write probe", + "settings.health.writeProbeHelp": "Panandaliang isinasagawa ang may limitasyong naka-configure na recording-target probe.", + "settings.health.cadences": "Mga cadence ng sampling", + "settings.health.cadencesHelp": "Ang mga interval ay dapat manatiling nakaayos mula mabilis hanggang device sampling at nasa loob ng mga hangganan ng server.", + "settings.health.fastInterval": "Mabilis na interval", + "settings.health.normalInterval": "Normal na interval", + "settings.health.slowInterval": "Mabagal na interval", + "settings.health.deviceInterval": "Interval ng device", + "settings.health.presenceInterval": "Interval ng presence", + "settings.health.retention": "Retention ng insidente", + "settings.health.conditions": "Mga override ng kondisyon", + "settings.health.conditionsHelp": "I-override lamang ang mga condition code at unit na ibinabalik ng effective-policy registry.", + "settings.health.conditionOverride": "override ng kondisyon", + "settings.health.overrideMode": "Mode ng Pag-override", + "settings.health.overrideModeHelp": "Inherit ang napiling profile, pumili ng ibang bounded na profile, i-disable ang kondisyon, o magtakda ng validated na threshold.", + "settings.health.profileDefault": "Gamitin ang napiling profile", + "settings.health.custom": "Mga Custom na Threshold", + "settings.health.warning": "Threshold ng Babala", + "settings.health.critical": "Threshold ng Kritikal", + "settings.health.recovery": "Threshold ng Pagbawi", + "settings.health.warning_for_seconds": "Segundo ng dwell ng babala", + "settings.health.critical_for_seconds": "Segundo ng dwell ng kritikal", + "settings.health.recovery_for_seconds": "Segundo ng dwell ng pagbawi", + "settings.health.clearOverrides": "I-clear ang mga override", + "settings.health.registryUnavailable": "Hindi nagbalik ang server ng condition registry. I-reload bago i-edit ang mga override.", + "settings.health.resetDefaults": "I-reset ang mga default ng health", + "settings.health.reloadGuidance": "Ang pag-save ay atomic. I-reload pagkatapos ng matagumpay na save upang kumpirmahin ang epektibong policy; i-restart lamang kapag hinihiling ng server.", + "settings.health.validation.profile": "Pumili ng supported na health profile.", + "settings.health.validation.provider": "Pumili ng supported na hardware provider.", + "settings.health.validation.healthFastIntervalSeconds": "Ang fast interval ay dapat buong numero mula 5 hanggang 60 segundo.", + "settings.health.validation.healthNormalIntervalSeconds": "Ang normal interval ay dapat buong numero mula 15 hanggang 600 segundo.", + "settings.health.validation.healthSlowIntervalSeconds": "Ang slow interval ay dapat buong numero mula 60 hanggang 3600 segundo.", + "settings.health.validation.healthDeviceIntervalSeconds": "Ang device interval ay dapat buong numero mula 300 hanggang 86400 segundo.", + "settings.health.validation.healthPresenceIntervalSeconds": "Ang presence interval ay dapat buong numero mula 15 hanggang 3600 segundo.", + "settings.health.validation.healthIncidentRetentionDays": "Ang incident retention ay dapat buong numero mula 7 hanggang 3650 araw.", + "settings.health.validation.ordered": "Ang mga sampling interval ay dapat nakaayos: fast, normal, slow, at device.", + "settings.health.validation.overrides": "Ang mga condition override ay dapat gumamit ng unique na code at supported na profile mula sa server registry.", + "settings.health.validation.thresholds": "Ang mga custom na threshold ay dapat finite na halaga sa loob ng unit bounds ng kondisyon.", + "settings.health.validation.thresholdOrder": "Ang mga threshold ng babala, kritikal, at pagbawi ay dapat panatilihin ang alert direction at hysteresis ng kondisyon.", + "settings.health.validation.dwell": "Ang mga dwell time ay dapat buong segundo sa loob ng pitong araw; ang dwell ng babala at pagbawi ay hindi maaaring zero.", + "tokens.manage": "Pamahalaan ang API access", + "tokens.title": "API Access — {username}", + "tokens.description": "Gumawa ng narrowly scoped na credentials para sa integrations at i-revoke ang bawat isa nang hiwalay.", + "tokens.recommendedTitle": "Inirerekomenda ang scoped na token", + "tokens.recommendedDescription": "Ang bawat token ay nag-e-expire, may explicit na aksyon at camera scope, at hindi maaaring lumampas sa kasalukuyang access policy ng user.", + "tokens.coverageNotice": "Ang mga available na permiso ay sumasalamin sa mga pinipilit ng server na ito. Ang token ay maaari lamang gumamit ng mga permiso na mayroon na ang user nito.", + "tokens.createTitle": "Gumawa ng scoped token", + "tokens.createDescription": "Gumamit ng isang token bawat integration upang matukoy, mapalitan, at ma-revoke ito nang hindi nakakaabala sa iba.", + "tokens.name": "Pangalan ng integration", + "tokens.namePlaceholder": "hal. North garage PTZ bridge", + "tokens.expiry": "Mag-e-expire pagkatapos ng", + "tokens.expiryDays": "{days} araw", + "tokens.actions": "Mga pinapayagang aksyon", + "tokens.actionsHelp": "Piliin lamang ang kailangan ng integration na ito. Ang mga destructive na aksyon ay dapat may sariling token.", + "tokens.destructive": "Destructive", + "tokens.noEnforcedActions": "Walang token-enabled na aksyon na available sa bersyon ng server na ito.", + "tokens.scope.label": "Saklaw ng camera", + "tokens.scope.all": "Buong fleet ng camera", + "tokens.scope.collection": "Shared na koleksyon", + "tokens.scope.selector": "Custom na selector", + "tokens.scope.chooseCollection": "Shared na koleksyon ng camera", + "tokens.scope.allValue": "Buong fleet", + "tokens.scope.collectionValue": "Koleksyon: {name}", + "tokens.scope.selectorValue": "Custom na dynamic selector", + "tokens.create": "Gumawa ng token", + "tokens.creating": "Ginagawa ang token…", + "tokens.createdSuccess": "Nagawa ang scoped API token", + "tokens.createError": "Hindi nagawa ang API token: {message}", + "tokens.invalidResponse": "Ang server ay nagbalik ng hindi kumpletong credential response.", + "tokens.existingTitle": "Mga umiiral na token", + "tokens.existingDescription": "Ang mga prefix at metadata lamang ang mananatiling available pagkatapos ng paggawa.", + "tokens.emptyTitle": "Walang aktibong token", + "tokens.emptyDescription": "Gumawa ng scoped token para sa unang integration na nangangailangan ng API access.", + "tokens.showInactive": "Ipakita ang {count} hindi aktibo", + "tokens.status.active": "Aktibo", + "tokens.status.expired": "Nag-expire na", + "tokens.status.revoked": "Na-revoke", + "tokens.expires": "Pag-expire", + "tokens.expiresValue": "Mag-e-expire {date}", + "tokens.created": "Nilikha", + "tokens.lastUsed": "Huling ginamit", + "tokens.revoke": "Bawiin", + "tokens.revoking": "Binabawi…", + "tokens.revokeConfirm": "Bawiin ang \"{description}\"? Ang mga request na gumagamit nito ay titigil agad.", + "tokens.revokedSuccess": "Nabawi ang API token", + "tokens.revokeError": "Hindi mabawi ang API token: {message}", + "tokens.validation.missing_description": "Pangalanan ang integration na gagamit ng token na ito.", + "tokens.validation.description_too_long": "Panatilihin ang pangalan ng integration sa ilalim ng 128 karakter.", + "tokens.validation.invalid_expiry": "Pumili ng lifetime ng token na nasa pagitan ng 1 at 365 araw.", + "tokens.validation.missing_actions": "Pumili ng kahit isang pinapayagang aksyon.", + "tokens.validation.invalid_action": "Isa o higit pang napiling aksyon ay hindi token-enabled sa server na ito.", + "tokens.validation.invalid_scope": "Pumili ng valid na camera scope.", + "tokens.validation.requires_all_scope": "Ang mga non-camera permission ay nangangailangan ng Entire camera fleet scope. Piliin ang scope na iyon o alisin ang mga permission na iyon.", + "tokens.validation.missing_collection": "Pumili ng available na shared collection.", + "tokens.validation.invalid_selector": "Kumpletuhin o itama ang custom camera selector.", + "tokens.secret.oneTime": "Ipapakita lamang isang beses", + "tokens.secret.scopedTitle": "I-save ang scoped token na ito ngayon", + "tokens.secret.legacyTitle": "I-save ang legacy API key na ito ngayon", + "tokens.secret.scopedDescription": "lightNVR ay nag-iimbak lamang ng hash ng token na ito. Kung mawala ito, bawiin ito at gumawa ng iba.", + "tokens.secret.legacyDescription": "Ang compatibility key na ito ay ipapakita lamang dito ng isang beses. Ang pag-generate ng ibang key ay gagawing hindi na ito valid.", + "tokens.secret.value": "API credential", + "tokens.secret.copied": "Nakopya", + "tokens.secret.copySuccess": "Nakopya ang API credential", + "tokens.secret.copyError": "Hindi maaaring kopyahin nang awtomatiko; piliin at kopyahin ang credential nang manu-mano.", + "tokens.secret.savedConfirm": "Nai-save ko nang ligtas ang credential na ito", + "tokens.secret.savedHelp": "Ang pag-confirm ay magsasara ng dialog na ito. Hindi na maaaring ipakita muli ang buong value.", + "tokens.legacy.title": "Legacy compatibility key", + "tokens.legacy.description": "Ang legacy key ay may buong effective access ng user na ito, hindi nag-e-expire, at hindi maaaring i-scope ayon sa camera o aksyon.", + "tokens.legacy.warning": "Gumawa lamang ng isa para sa umiiral na integration na ang mga endpoint ay hindi pa na-migrate sa scoped-token enforcement. Ang pag-generate nito ay agad gagawing hindi valid ang naunang legacy key.", + "tokens.legacy.generate": "I-generate ang legacy key", + "tokens.legacy.confirm": "I-generate ang bagong legacy key? Agad itong magpapawalang-bisa sa kasalukuyang legacy key ng user.", + "tokens.legacy.createdSuccess": "Nagenerate ng legacy API key", + "tokens.legacy.createError": "Hindi nagenerate ng legacy API key: {message}", + "audit.manage": "Kasaysayan ng Audit", + "audit.title": "Audit ng Seguridad at Access", + "audit.description": "Sundan ang mga resulta ng login, mga desisyon sa access, at mga pagbabago sa sensitibong patakaran nang hindi ibinubunyag ang mga kredensyal.", + "audit.retention": "Retention", + "audit.retentionDescription": "Kasalukuyang tinatago ang mga event sa loob ng {days} araw. Ang pagbaba ng halagang ito ay agad mag-aalis ng mas lumang history.", + "audit.retentionDays": "Araw", + "audit.retentionInvalid": "Pumili ng panahon ng retention mula 1 hanggang 3650 araw.", + "audit.retentionSaved": "Nai-save ang audit retention; {count} expired na event ang inalis", + "audit.retentionError": "Hindi ma-save ang audit retention: {message}", + "audit.filters": "Mga Filter", + "audit.clearFilters": "I-clear ang mga filter", + "audit.applyFilters": "I-apply ang mga filter", + "audit.actor": "Actor", + "audit.unauthenticated": "Hindi na-authenticate", + "audit.outcome": "Resulta", + "audit.action": "Eksaktong aksyon", + "audit.filterToAction": "I-filter sa aksyong ito", + "audit.since": "Mula", + "audit.until": "Hanggang", + "audit.invalidDateRange": "Ang petsa ng Mula ay dapat mas maaga kaysa sa petsa ng Hanggang.", + "audit.source": "Source address", + "audit.target": "Target", + "audit.targetUuid": "Target UUID", + "audit.noTarget": "Sa buong sistema", + "audit.requestId": "Request ID", + "audit.apiToken": "Scoped token ID", + "audit.showDetails": "Ipakita ang mga detalye", + "audit.hideDetails": "Itago ang mga detalye", + "audit.pageSize": "Kada pahina", + "audit.resultRange": "Ipinapakita ang {start}–{end} ng {total}", + "audit.empty": "Walang tumugmang audit event", + "audit.emptyDescription": "Subukang alisin ang isa o higit pang filter, o maghintay ng bagong security activity.", + "audit.exportPage": "I-export ang pahinang ito", + "audit.exporting": "Ine-export…", + "audit.exported": "Na-export ang audit page", + "audit.exportError": "Hindi ma-export ang mga audit event: {message}", + "audit.pagination": "Mga pahina ng audit history", + "audit.page": "Pahina {page}", + "audit.modesTitle": "Mga pinayagang desisyon", + "audit.modesDescription": "Piliin kung paano ire-record ang pinayagang read-only access para sa bawat aksyon. Ang mga request na nagbabago ng isang bagay, pagtanggi, error, at sign-in ay palaging inirerecord. Ang Summarize ay nagpapanatili ng isang entry bawat user, camera, at client tuwing {minutes} minuto na may bilang.", + "audit.mode.record": "Itala ang bawat isa", + "audit.mode.summarize": "Buod", + "audit.mode.off": "Naka-off", + "audit.modeOffWarning": "Ang pinayagang access para sa aksyong ito ay hindi na lalabas sa audit history.", + "audit.modesSaved": "Nai-save ang mga audit decision mode", + "audit.modesError": "Hindi ma-save ang mga audit decision mode: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Uri ng event", + "audit.eventTypeSummary": "Mga Buod", + "audit.eventTypeDecision": "Indibidwal na desisyon", + "access.cameraSearch": "Maghanap ng camera", + "access.cameraSearchPlaceholder": "Mag-type ng hindi bababa sa dalawang karakter para maghanap…", + "access.cameraSearchHint": "Maghanap ayon sa pangalan ng camera, UUID, address, lokasyon, tag, vendor, o model.", + "access.cameraSelected": "Napili", + "access.cameraAdd": "Idagdag", + "access.cameraLimit": "Ang isang selector ay maaaring maglaman ng hanggang 64 na tiyak na camera. Gumamit ng location o tag rule para sa mas malawak na saklaw.", + "access.roles.manage": "Pamahalaan ang mga Role", + "access.roles.title": "Mga Role sa Awtorisasyon", + "access.roles.description": "Pagsamahin ang mga aksyon sa mga muling magagamit na role, pagkatapos ay bigyan ang mga role sa mga saklaw ng camera.", + "access.roles.create": "Gumawa ng Role", + "access.roles.newRole": "Bagong role", + "access.roles.copyName": "Kopya ng {name}", + "access.roles.clone": "I-clone", + "access.roles.builtin": "Built-in", + "access.roles.builtinHelp": "Ang mga built-in role ay fixed na template na ligtas sa upgrade. I-clone ang isa upang i-customize ito.", + "access.roles.actionCount": "{count} na aksyon", + "access.roles.destructive": "Sensitibong aksyon", + "access.roles.notEnforced": "Hindi pa ipinatutupad ng anumang endpoint", + "access.roles.destructiveWarning": "Ang role na ito ay maaaring magbago ng configuration o ebidensya. Bigyan lamang ito sa mga scope kung saan kinakailangan ang awtoridad na iyon.", + "access.roles.created": "Nagawa ang role", + "access.roles.updated": "Na-update ang role", + "access.roles.deleted": "Nabura ang role", + "access.roles.saveError": "Hindi ma-save ang role: {message}", + "access.roles.deleteError": "Hindi mabura ang role: {message}", + "access.roles.deleteConfirm": "Burahin ang role na \"{name}\"? Ang mga role na tinutukoy ng mga grant ay hindi mabubura.", + "access.policy.manage": "Pamahalaan ang Access", + "access.policy.column": "Access", + "access.policy.scopedShort": "May Scope", + "access.policy.title": "Patakaran sa Access — {username}", + "access.policy.description": "Pamahalaan ang default-deny na role grants at i-preview ang kanilang camera scopes.", + "access.policy.tab.grants": "Mga Grant", + "access.policy.tab.test": "Subukan ang Access", + "access.policy.scopedWarning": "Tanging ang mga aksyon na pinapayagan ng tumutugmang grant at camera scope ang gagana.", + "access.policy.grants": "Mga role grant", + "access.policy.grantsDescription": "Ang isang grant ay pinagsasama ang isang role sa buong fleet, isang shared collection, o isang custom na camera selector.", + "access.policy.addGrant": "Magdagdag ng Grant", + "access.policy.noGrants": "Walang naka-configure na grant", + "access.policy.noGrantsHelp": "Magdagdag ng hindi bababa sa isang grant bago i-activate ang scoped policy maliban kung dapat walang access ang user na ito.", + "access.policy.role": "Role", + "access.policy.chooseRole": "Pumili ng role", + "access.policy.scope": "Camera scope", + "access.policy.allCameras": "Buong camera fleet", + "access.policy.collectionScope": "Ibinahaging Koleksyon", + "access.policy.collection": "Koleksyon ng Camera", + "access.policy.chooseCollection": "Pumili ng ibinahaging koleksyon", + "access.policy.collectionHelp": "Sinusundan ng access ang koleksyon habang ang mga camera ay dinadagdag, tinatanggal, o inuugma sa pamamagitan ng mga tuntunin nito.", + "access.policy.dynamicScope": "Dinamikong Selector", + "access.policy.activateConfirm": "I-activate ang default-deny na patakaran sa saklaw para sa {username}? Ang mga aksyon na walang katugmang pahintulot ay tatanggihan.", + "access.policy.emptyConfirm": "I-activate ang patakaran sa saklaw para sa {username} na walang mga pahintulot? Sinasadyang tinatanggal nito ang lahat ng access na kontrolado ng patakaran.", + "access.policy.saved": "Nai-save ang patakaran sa access", + "access.policy.saveError": "Hindi ma-save ang patakaran sa access: {message}", + "access.policy.version": "Bersyon ng patakaran {version}", + "access.policy.unsaved": "Mga pagbabagong hindi pa nai-save", + "access.policy.validation.invalid_mode": "Pumili ng wastong mode ng pagsusuri.", + "access.policy.validation.missing_role": "Ang bawat pahintulot ay dapat tumukoy sa isang available na tungkulin.", + "access.policy.validation.invalid_scope": "Ang bawat pahintulot ay dapat gumamit ng saklaw na buong-fleet, ibinahaging-koleksyon, o selector.", + "access.policy.validation.invalid_selector": "Kumpletuhin o itama ang bawat camera selector bago mag-save.", + "access.policy.validation.missing_collection": "Pumili ng available na ibinahaging koleksyon para sa bawat pahintulot sa koleksyon.", + "access.policy.validation.duplicate_grant": "Alisin ang mga dobleng pahintulot sa tungkulin at saklaw bago mag-save.", + "access.test.title": "Subukan ang epektibong access", + "access.test.description": "Suriin ang isang naka-save na aksyon at camera bilang {username} nang hindi ito pinapatakbo.", + "access.test.saveFirst": "I-save o itapon ang mga pagbabago sa pahintulot bago mag-test upang ang resulta ay sumasalamin sa patakaran na ipinapakita rito.", + "access.test.action": "Aksyon", + "access.test.camera": "Camera", + "access.test.run": "Subukan ang Access", + "access.test.running": "Sinusubok…", + "access.test.allowed": "Pinayagan", + "access.test.denied": "Tinanggihan", + "access.test.version": "Bersyon {version}", + "access.test.source": "Pinagmulan: {source} · Tungkulin: {role}", + "system.health.tab": "Kalagayan", + "system.health.operatorView": "Kalagayan ng operasyon", + "system.health.title": "Kalagayan ng Sistema", + "system.health.loading": "Kinakarga ang kalagayan ng sistema…", + "system.health.loadError": "Hindi ma-load ang kalusugan ng sistema.", + "system.health.refreshing": "Nagre-refresh…", + "system.health.activeIncidentCount": "{count} aktibong insidente", + "system.health.coverage": "Saklaw", + "system.health.monitoringDisabled": "Naka-disable ang health monitoring", + "system.health.lastRecordedValue": "Huling naitalang halaga", + "system.health.monitoringDisabledHelp": "Hindi kinokolekta ang kasalukuyang health facts. I-enable ang health monitoring sa Settings → Health; i-restart kung hinihiling pagkatapos i-save. Ang incident history ay nagpapakita ng mga nakaraang pangyayari, hindi kasalukuyang paggamit ng resource.", + "system.health.monitoringRestartRequired": "Naka-enable ang health monitoring sa naka-save na configuration, ngunit ang tumatakbong sampler ay naka-disable pa rin. I-restart ang LightNVR upang mailapat ang pagbabago. Ang incident history ay nagpapakita ng mga nakaraang pangyayari.", + "system.health.containerCoverage": "Limitadong saklaw ng host", + "system.health.hostHardwareUnavailable": "Makikita ng installation na ito ang kalusugan ng container at mounted-resource, ngunit hindi available ang host hardware. Ang mga kulang na halaga ng host ay hindi alam, hindi malusog.", + "system.health.coverageUnknown": "Wala pang kumpletong health snapshot. Mananatiling hindi alam ang mga halaga hanggang sa makumpleto ang koleksyon.", + "system.health.coverageComplete": "Lahat ng facts na nakikita ng installation na ito ay matagumpay na nakolekta.", + "system.health.coveragePartial": "Ang saklaw ay bahagya. {count} na obserbasyon o collection check ang hindi available, luma, o hindi kumpleto.", + "system.health.effectiveScope": "Epektibong saklaw", + "system.health.activeIncidents": "Mga aktibong insidente", + "system.health.noActiveIncidents": "Walang naiuulat na aktibong insidente para sa nakikitang saklaw.", + "system.health.duration": "Tagal", + "system.health.currentValue": "Kasalukuyang halaga", + "system.health.thresholds": "Threshold at dwell", + "system.health.thresholdSummary": "Warning {warning}, critical {critical}, recovery {recovery} {unit}; warning dwell {seconds}s", + "system.health.remediation": "Iminumungkahing tugon", + "system.health.facts": "Mga health fact", + "system.health.group.resources": "Mga Resource", + "system.health.group.storage": "Storage", + "system.health.group.hardware": "Hardware", + "system.health.group.network": "Network", + "system.health.group.clock": "Orasan", + "system.health.group.components": "Mga Component", + "system.health.noFacts": "Walang nakikitang fact sa grupong ito.", + "system.health.observationState": "Kakayahan at sariwa", + "system.health.valueUnavailable": "Isa o higit pang halaga ang hindi alam", + "system.health.componentStatus": "Mga component ng monitoring", + "system.health.collectors": "Mga Collector", + "system.health.collectorSummary": "{total} rehistrado · {attention} nangangailangan ng pansin", + "system.health.collectorsNeedingAttention": "Mga Collector na nangangailangan ng pansin", + "system.health.collectionFailures": "{count} pagkabigo o timeout", + "system.health.stale": "luma", + "system.health.eventDelivery": "Paghatid ng Event", + "system.health.degraded": "Nabababa", + "system.health.circularDelivery": "Ito lang ang naka-configure na alert path, kaya hindi nito mag-isa maireport ang sarili nitong pagkabigo.", + "system.health.incidentPersistence": "Pagpapanatili ng Incident", + "system.health.persistenceSummary": "{pending} nasa pending · {failures} pagkabigo · {retries} retries", + "system.health.recentSamples": "Kamakailang aktibidad ng koleksyon", + "system.health.recentSamplesHelp": "Hanggang {count} na bounded server-side generation summaries; ito ay aktibidad ng coverage, hindi value chart.", + "system.health.sampleSequence": "Generation {sequence}", + "system.health.sampleCoverage": "{observations} obserbasyon · {dropped} na-drop", + "system.health.noSamples": "Walang kumpletong collection generation na available.", + "system.health.incidentHistory": "Kasaysayan ng Incident", + "system.health.incidentHistoryHelp": "Pinakabagong incident muna. Ang kasaysayan ay niloload sa bounded pages.", + "system.health.loadingHistory": "Niloload ang kasaysayan ng incident…", + "system.health.historyError": "Hindi ma-load ang kasaysayan ng incident.", + "system.health.emptyHistory": "Walang naitalang incident.", + "system.health.firstSeen": "Unang nakita", + "system.health.lastSeen": "Huling nakita", + "system.health.deliveryState": "Estado ng paghatid", + "system.health.historyPagination": "Mga pahina ng kasaysayan ng incident", + "system.health.pageCount": "{count} incident sa pahinang ito", + "system.health.remediation.memory": "Bawasan ang memory pressure, suriin ang process at cgroup limits, at tingnan ang kamakailang OOM activity.", + "system.health.remediation.cpu": "Tukuyin ang mga sustained CPU consumer at beripikahin ang service throughput bago baguhin ang limits.", + "system.health.remediation.io": "Suriin ang storage latency at active writers; i-preserve ang mga recording bago ang disruptive maintenance.", + "system.health.remediation.filesystem": "Suriin ang tinukoy na logical filesystem, free space o inodes, at beripikahin na writable pa ito.", + "system.health.remediation.thermal": "Paigtingin ang cooling at bawasan ang load; suriin ang fans at vents bago umabot ang temperatura sa shutdown limits.", + "system.health.remediation.network": "Suriin ang nakikitang interface, link, switch, at error counters mula sa independent network path.", + "system.health.remediation.clock": "Ibalik ang time synchronization at beripikahin ang host clock source bago umasa sa event timestamps.", + "system.health.remediation.process": "Suriin ang mga limitasyon sa resource at log ng LightNVR, pagkatapos ay bawasan ang load o itaas ang mga na-validate na limitasyon.", + "system.health.remediation.storage": "I-back up ang mga mahahalagang footage at suriin ang mapped na storage device bago palitan o ayusin.", + "system.health.remediation.hardware": "Suriin ang apektadong hardware at platform logs; mag-schedule ng maintenance kung patuloy ang kondisyon.", + "system.health.remediation.health": "Ibalik ang access at permissions ng collector upang masuri ang kulang na ebidensya ng kalusugan.", + "system.health.remediation.system": "Suriin ang nakaraang run at host logs upang matukoy kung process restart o host reboot.", + "system.health.remediation.event": "Gamitin ang local API o metrics view, alisin ang pressure sa durable queue, at ibalik ang independent na alert destination.", + "system.health.remediation.default": "Suriin ang apektadong component at mga kamakailang log, pagkatapos ay kumpirmahin ang pagbangon sa bagong health generation.", + "recordings.views": "Mga view ng Recording", + "system.capacityTarget": "Target na kapasidad", + "system.capacityTargetValue": "Panatilihing {pct}% na libre", + "system.fillRate": "Rate ng pagpuno", + "system.fillRateValue": "{value} / araw", + "system.projectedToTarget": "Tinayang oras hanggang target", + "system.projectedNow": "Nasa target o lampas na ngayon", + "system.projectedDays": "~{count}d", + "system.projectedHours": "~{count}h", + "system.projectedUnknown": "—", + "streamHealth.sourceConnected": "Konektado ang source", + "streamHealth.videoAdvancing": "Umuusad ang video", + "streamHealth.recorderWriting": "Nagsusulat ang recorder", + "streamHealth.detectorOperating": "Gumagana ang detector", + "streamHealth.lastSegment": "Huling natapos na segment", + "zoneEditor.zoneNumber": "Zone {number}", + "zoneEditor.unknownError": "Hindi kilalang error", + "zoneEditor.httpError": "HTTP error {status}", + "zoneEditor.failedToSaveZones": "Nabigong i-save ang mga zone: {message}", + "zoneEditor.title": "Editor ng Detection Zone", + "zoneEditor.subtitle": "Gumuhit ng mga zone kung saan nais mong mag-detect ng mga object para sa {streamName}", + "zoneEditor.streamPreviewAlt": "Preview ng stream", + "zoneEditor.loadingSnapshot": "Naglo-load ng snapshot ng stream...", + "zoneEditor.usingGo2rtcSnapshotApi": "Gumagamit ng go2rtc snapshot API", + "zoneEditor.snapshotUnavailable": "Walang available na snapshot - gumuguhit sa grid background", + "zoneEditor.drawZone": "Gumuhit ng Zone", + "zoneEditor.selectZone": "Pumili", + "zoneEditor.completeZoneWithPoints": "Kumpletuhin ang Zone ({count} puntos)", + "zoneEditor.zonesCount": "Mga Zone ({count})", + "zoneEditor.noZonesDefined": "Walang nakatakdang zone. Pindutin ang \"Gumuhit ng Zone\" at pindutin ang canvas upang gumawa ng zone.", + "zoneEditor.zoneNamePlaceholder": "Pangalan ng Zone", + "zoneEditor.color": "Kulay:", + "zoneEditor.pointsCount": "{count} puntos", + "zoneEditor.saveZones": "I-save ang mga Zone", + "streamsConfig.playbackTransport": "Transport ng Playback", + "streamsConfig.playbackTransportHelp": "Piliin ang paraan ng playback sa browser para sa camera na ito at, kung napili, ang pagkakasunod-sunod ng fallback.", + "streamsConfig.playbackTransportUnavailable": "Hindi available sa server: {transports}. I-enable ang transport globally o pumili ng ibang profile.", + "streamsConfig.audioDisabledByPolicy": "Naka-disable ang audio ng instance policy", + "streamsConfig.audioDisabledByPolicyHelp": "Hindi available ang recording, live listening, at two-way talk habang naka-enable ang global audio compliance policy.", + "streamsConfig.audioVoiceEnhancement": "Pagpapabuti ng Boses (mga recording)", + "streamsConfig.customApiModel": "Custom na pagtuklas ng API", + "streamsConfig.modelNotSupportedByBuild": "hindi sinusuportahan ng build na ito", + "streamsConfig.tierCriticalMultiplier": "Critical tier ×", + "streamsConfig.tierImportantMultiplier": "Important tier ×", + "streamsConfig.tierEphemeralMultiplier": "Ephemeral tier ×", + "streamsConfig.tierMultipliersHelp": "Per-tier multipliers sa base retention. Ang footage ng mas mataas na tier ay mas matagal na iniiwan at huling tinatanggal kapag kulang ang disk.", + "streamsConfig.storagePriority": "Priority ng Storage (1-10)", + "streamsConfig.storagePriorityHelp": "Relatibong kahalagahan ng footage ng stream na ito kapag nagpapalaya ng espasyo; mas mataas na priority ay mas matagal na iniiwan.", + "streamsConfig.restream": "Restream / I-publish (RTMP)", + "streamsConfig.publishUrl": "URL ng Pag-publish (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "I-restream ang camera na ito sa isang serbisyo tulad ng YouTube Live sa pamamagitan ng go2rtc. I-paste ang buong RTMP ingest URL kasama ang stream key (hal. rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Upang mag-restream sa maraming serbisyo nang sabay, hiwalayan ang mga URL ng mga kuwit. Kailangan ng YouTube ng H264 video at AAC audio; awtomatikong nagta-transcode ang LightNVR (H264 para sa mga camera na hindi H264, AAC para sa mga audio na hindi AAC) kaya karamihan sa mga camera ay gumagana na. Paalala: Kailangan din ng YouTube ng audio track — ang camera na walang audio ay mananatiling tatanggihan. Iwanang blangko upang i-disable.", + "settings.general": "Mga Pangkalahatang Setting", + "settings.logLevel": "Antas ng Log", + "settings.logLevelError": "Error", + "settings.logLevelWarning": "Babala", + "settings.logLevelInfo": "Impo", + "settings.logLevelDebug": "Debug", + "settings.enableSyslog": "I-enable ang Syslog", + "settings.enableSyslogHelp": "Magpadala ng mga mensahe ng log sa syslog", + "settings.syslogIdent": "Syslog Ident", + "settings.syslogIdentHelp": "Identifier na idinadagdag sa unahan ng mga mensahe ng syslog", + "settings.syslogFacility": "Syslog Facility", + "settings.syslogFacilityHelp": "Syslog facility para sa routing ng mensahe", + "settings.storage": "Mga Setting ng Storage", + "settings.storageTargets.title": "Mga target ng storage ng recording", + "settings.storageTargets.description": "I-register ang mga local disk at administrator-mounted na NFS o SMB filesystem bilang mga independiyenteng binabantayang destination ng recording.", + "settings.storageTargets.foundationNotice": "Gumagamit ang capture ng filesystem targets. Ang mga S3 bucket at mounted NFS/SAN target ay maaaring magtaglay ng mga beripikadong kopya ng archive. Ang hot pressure ay pinapanatili ang mga archived recording hanggang sa mag-expire ang kanilang logical retention.", + "settings.storageTargets.add": "Magdagdag ng storage target", + "settings.storageTargets.edit": "I-edit ang storage target", + "settings.storageTargets.editorHelp": "Ang mga naka-enable na target ay dapat umiiral na at pumasa sa write, fsync, at cleanup test. I-save ang hindi available na future mount bilang naka-disable, pagkatapos ay i-enable ito pagkatapos i-mount.", + "settings.storageTargets.name": "Pangalan ng target", + "settings.storageTargets.root": "Mounted root path", + "settings.storageTargets.rootLocked": "Ang default o hindi walang laman na target ay pinapanatili ang isang immutable root upang hindi maging orphan ang mga umiiral na footage.", + "settings.storageTargets.class": "Klase ng performance", + "settings.storageTargets.hot": "Hot — aktibong recording", + "settings.storageTargets.warm": "Warm — mounted archive", + "settings.storageTargets.cold": "Cold — hindi madalas na access", + "settings.storageTargets.reserveGb": "Nakalaang headroom (GB)", + "settings.storageTargets.lowWatermark": "Mababang watermark (% na ginamit)", + "settings.storageTargets.highWatermark": "Mataas na watermark (% na ginamit)", + "settings.storageTargets.migrationBandwidth": "Bandwidth ng lifecycle (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "Ang 0 ay walang limitasyon. Ang limitasyon ay kinukuha bilang snapshot kapag ang isang move o copy job ay ginawa.", + "settings.storageTargets.archiveStart": "Simula ng archive window", + "settings.storageTargets.archiveEnd": "Wakas ng archive window", + "settings.storageTargets.archiveWindowHelp": "Local time. Ang magkaparehong oras ng simula at wakas ay nagpapahintulot ng mga lifecycle job sa buong araw; ang overnight window ay maaaring tumawid sa hatinggabi.", + "settings.storageTargets.enabled": "Naka-enable (maaaring piliin ng mga placement policy ang target na ito)", + "settings.storageTargets.notRouted": "Walang naka-enable na placement policy na nag-reroute ng mga camera dito. Ang mga bagong recording ay patuloy na pupunta sa default target hanggang sa isang policy ang tumukoy sa target na ito bilang primary, pool member o archive target.", + "settings.storageTargets.degradedNotice": "Nasa itaas ng kanyang mataas na watermark o nasa loob ng kanyang reserve. Ang mga placement policy ay lumalaktaw sa target na ito hanggang sa may mababang espasyo.", + "settings.storageTargets.probePassedIneligible": "Pumasa ang write test, ngunit ang target ay {status}: hindi ito pipiliin ng mga placement policy.", + "settings.storageTargets.mountRequired": "Kailangan ng naka-mount na filesystem", + "settings.storageTargets.mountRequiredHelp": "I-pin ang target na ito sa kasalukuyang non-root mountpoint nito. Kung ang NFS, SMB, bind, o PVC mount na iyon ay mawala, pipigilan ang recording sa halip na isulat sa ilalim ng host directory.", + "settings.storageTargets.mountGuard": "Kinakailangang mount", + "settings.storageTargets.mountPending": "Matutukoy kapag na-enable ang target", + "settings.storageTargets.default": "Default", + "settings.storageTargets.capacity": "Kapasidad", + "settings.storageTargets.available": "Available", + "settings.storageTargets.recordings": "Mga naka-index na recording", + "settings.storageTargets.replicas": "{count} na na-verify na kopya · {bytes}", + "settings.storageTargets.reserve": "Naka-reserve", + "settings.storageTargets.pressure.normal": "Normal ang pressure", + "settings.storageTargets.pressure.high": "Mataas na watermark", + "settings.storageTargets.pressure.reserve": "Naabuso ang reserve", + "settings.storageTargets.pressure.unavailable": "Hindi available ang pressure", + "settings.storageTargets.cleanupActive": "Ang target-scoped cleanup ay aktibo at gagana patungo sa {target} available nang hindi binubura ang mga recording na nakatalaga sa ibang target.", + "settings.storageTargets.test": "I-test ang target", + "settings.storageTargets.probing": "Sinusubok…", + "settings.storageTargets.probePassed": "Pumasa ang write test ng storage target", + "settings.storageTargets.duplicateFilesystem": "Ang root na ito ay nakabahagi ng parehong underlying filesystem sa ibang target. Hindi dapat mabilang nang dalawang beses ang kapasidad kapag na-enable ang placement.", + "settings.storageTargets.deleteLocked": "Hindi mabubura ang default at hindi walang laman na targets.", + "settings.storageTargets.deleteConfirm": "Burahin ang walang laman na storage target na \"{name}\"? Walang file na aalisin.", + "settings.storageTargets.created": "Nagawa ang storage target", + "settings.storageTargets.updated": "Na-update ang storage target", + "settings.storageTargets.deleted": "Nabura ang storage target", + "settings.storageTargets.invalidThresholds": "Suriin ang watermarks, reserve, lifecycle bandwidth, at archive-window times.", + "settings.storageTargets.loadError": "Hindi ma-load ang mga storage target", + "settings.storagePools.title": "Mga storage pool", + "settings.storagePools.description": "I-grupo ang mga malusog na target para sa awtomatikong spillover at distinct-target replication.", + "settings.storagePools.add": "Magdagdag ng pool", + "settings.storagePools.strategy": "Estratehiya sa allocation", + "settings.storagePools.mostFree": "Pinakamaraming libreng espasyo", + "settings.storagePools.roundRobin": "Round robin", + "settings.storagePools.priority": "Malinaw na Prayoridad", + "settings.storagePools.members": "Mga Target (ang pagkakasunod-sunod ay prayoridad sa pag-alok)", + "settings.storagePools.enabled": "Naka-enable ang Pool", + "settings.storagePools.active": "Aktibo", + "settings.storagePools.inactive": "Naka-disable", + "settings.storagePools.strategyValue.most_free": "pinakamaraming libre", + "settings.storagePools.strategyValue.round_robin": "round robin", + "settings.storagePools.strategyValue.priority": "sunod-sunod na prayoridad", + "settings.storagePools.created": "Nagawa ang Storage Pool", + "settings.storagePools.updated": "Na-update ang Storage Pool", + "settings.storagePools.deleted": "Nabura ang Storage Pool", + "settings.storagePools.deleteConfirm": "Burahin ang storage pool na \"{name}\"?", + "settings.storagePools.empty": "Wala pang storage pool.", + "settings.storageMigrations.title": "Mga Recording Migration Job", + "settings.storageMigrations.description": "Ang mga matibay na paglipat at mga iningatan na kopya ay sumusunod sa archival window at bandwidth limit ng bawat target, beripikahin ang SHA-256, at ligtas na mabawi pagkatapos ng restart.", + "settings.storageMigrations.empty": "Wala pang recording migration job.", + "settings.storageMigrations.loadError": "Hindi ma-load ang mga recording migration job", + "settings.storageMigrations.recording": "Recording #{id}", + "settings.storageMigrations.attempt": "Pagsubok {current}/{max}", + "settings.storageMigrations.operation.move": "Ilipat", + "settings.storageMigrations.operation.copy": "Iningatan na Kopya", + "settings.storageMigrations.cancelled": "Tinanggap ang pagkansela ng migration", + "settings.storageMigrations.cancelling": "Kinakansela…", + "settings.storageMigrations.retried": "Naka-queue ang migration para sa retry", + "settings.storageMigrations.state.queued": "Naka-queue", + "settings.storageMigrations.state.copying": "Kinokopya", + "settings.storageMigrations.state.verifying": "Bineberipika", + "settings.storageMigrations.state.committing": "Nagko-commit", + "settings.storageMigrations.state.cleanup_pending": "Nililinis ang source", + "settings.storageMigrations.state.retry_wait": "Naghihintay para sa retry", + "settings.storageMigrations.state.completed": "Tapos na", + "settings.storageMigrations.state.failed": "Nabigo", + "settings.storageMigrations.state.cancelled": "Kinansela", + "settings.storagePolicies.title": "Mga Patakaran sa Paglalagay ng Camera", + "settings.storagePolicies.description": "I-route ang mga tumutugmang camera sa pangunahing recording target ayon sa priority. Gumagamit ang camera ng unang enabled na patakaran na tumutugma.", + "settings.storagePolicies.add": "Magdagdag ng Patakaran sa Paglalagay", + "settings.storagePolicies.edit": "I-edit ang Patakaran sa Paglalagay", + "settings.storagePolicies.editorHelp": "Muling sinusuri ang patakaran para sa mga bagong segment. Ang mga pagbabago ay hindi lilipat ng mga recording na umiiral na.", + "settings.storagePolicies.priority": "Priority (mas mataas muna)", + "settings.storagePolicies.priorityValue": "Priority {priority}", + "settings.storagePolicies.primary": "Pangunahing Target", + "settings.storagePolicies.primaryPool": "Placement Pool (opsyonal)", + "settings.storagePolicies.exactTarget": "Gamitin ang eksaktong pangunahing target", + "settings.storagePolicies.fallback": "Kung ang pangunahing target ay hindi available", + "settings.storagePolicies.fallbackDefault": "Gamitin ang default target", + "settings.storagePolicies.fallbackTarget": "Gamitin ang named fallback target", + "settings.storagePolicies.fallbackPause": "I-pause ang recording", + "settings.storagePolicies.fallbackFail": "Bigo ang pagsisimula ng recording", + "settings.storagePolicies.namedFallback": "Fallback Target", + "settings.storagePolicies.chooseTarget": "Pumili ng target", + "settings.storagePolicies.choosePool": "Pumili ng pool", + "settings.storagePolicies.minimumDays": "Minimum na retention (araw)", + "settings.storagePolicies.desiredDays": "Nais na retention (araw)", + "settings.storagePolicies.maximumDays": "Maximum na retention (araw)", + "settings.storagePolicies.copyCount": "Kinakailangang verified copies", + "settings.storagePolicies.replicationPool": "Replication Pool", + "settings.storagePolicies.migrateAfter": "Ilipat pagkatapos ng edad (araw)", + "settings.storagePolicies.migrationTarget": "Archive Target", + "settings.storagePolicies.pressurePriority": "Pressure-delete priority (mas mababa muna)", + "settings.storagePolicies.disabledTarget": "naka-disable", + "settings.storagePolicies.enabled": "Patakaran ay enabled", + "settings.storagePolicies.selector": "Mga tumutugmang camera", + "settings.storagePolicies.preview": "Preview precedence", + "settings.storagePolicies.previewing": "Sinusuri…", + "settings.storagePolicies.previewRequired": "Preview ang kasalukuyang draft bago i-save upang makita ang overlap ng camera at ang epektibong panalo na patakaran.", + "settings.storagePolicies.previewSummary": "Tumutugma sa {matched} na camera; ang draft na ito ay epektibo para sa {effective}.", + "settings.storagePolicies.previewShadowed": "Isang patakaran na may mas mataas na prayoridad ang panalo para sa {count} na tumutugmang camera.", + "settings.storagePolicies.previewWins": "Panalo laban sa \"{policy}\" (prayoridad {priority}) para sa {count} na camera.", + "settings.storagePolicies.previewLoses": "Natalo sa \"{policy}\" (prayoridad {priority}) para sa {count} na camera.", + "settings.storagePolicies.previewNoMatches": "Ang selector na ito ay kasalukuyang walang tumutugmang camera.", + "settings.storagePolicies.invalidPriority": "Ang prayoridad ay dapat na buong numero sa pagitan ng -1,000,000 at 1,000,000.", + "settings.storagePolicies.invalidLifecycle": "Suriin ang pagkakasunod-sunod ng retention, bilang ng kopya at replication pool, at edad at target ng migration.", + "settings.storagePolicies.created": "Nagawa ang placement policy", + "settings.storagePolicies.updated": "Na-update ang placement policy", + "settings.storagePolicies.deleted": "Tinanggal ang placement policy", + "settings.storagePolicies.deleteConfirm": "Burahin ang placement policy na \"{name}\"? Hindi apektado ang mga umiiral na recording.", + "settings.storagePolicies.active": "Aktibo", + "settings.storagePolicies.inactive": "Na-disable", + "settings.storagePolicies.routesTo": "Pangunahing target: {target}", + "settings.storagePolicies.lifecycleSummary": "Retention min/layunin/max: {minimum}/{desired}/{maximum} araw · {copies} na na-verify na kopya", + "settings.storagePolicies.fallsBackTo": "Fallback target: {target}", + "settings.storagePolicies.mode.default": "Fallback: default na target", + "settings.storagePolicies.mode.pause": "Fallback: i-pause ang recording", + "settings.storagePolicies.mode.fail": "Fallback: mabigo ang pagsisimula ng recording", + "settings.storagePolicies.empty": "Walang placement policy. Patuloy ang mga camera sa paggamit ng default na target; ang ibang target ay walang matatanggap hangga't walang patakaran na nag-reroute ng mga camera sa kanila.", + "settings.storagePolicies.archiveNoTrigger": "May nakatakdang archive target ngunit walang nag-trigger ng paglipat. Itakda ang 'Move after age (days)', archive-after age, o archive option; kung hindi, walang recording na ililipat.", + "settings.storageCompliance.title": "Kapasidad at pagsunod sa patakaran", + "settings.storageCompliance.description": "Ang naobserbahang 30-araw na rate ay humuhula sa pressure ng target at naabot na retention; ang aktibong lifecycle violation ay nananatiling nakikita hanggang sa malutas.", + "settings.storageCompliance.loadError": "Hindi ma-load ang storage compliance", + "settings.storageCompliance.unknown": "Hindi alam", + "settings.storageCompliance.days": "{days} na araw", + "settings.storageCompliance.day": "araw", + "settings.storageCompliance.targetForecasts": "Mga hula ng target", + "settings.storageCompliance.target": "Target", + "settings.storageCompliance.dailyRate": "Naobserbahang rate", + "settings.storageCompliance.toHigh": "Sa high watermark", + "settings.storageCompliance.expected": "Inaasahang Retention", + "settings.storageCompliance.confidence": "Tiyansa", + "settings.storageCompliance.policyCompliance": "Pagsunod sa Patakaran", + "settings.storageCompliance.compliant": "Walang aktibong paglabag", + "settings.storageCompliance.violationCount": "{count} paglabag", + "settings.storageCompliance.policyForecast": "Naabot {achieved}; hinulaan {expected}; nais {desired} araw.", + "settings.storageCompliance.copyDeficits": "{count} recording ang kailangan ng isa pang na-verify na kopya.", + "settings.storageCompliance.activeViolations": "Mga Aktibong Paglabag", + "settings.storageCompliance.type.copy_count": "Bilang ng Kopya", + "settings.storageCompliance.type.minimum_retention": "Pinakamaliit na Kapasidad ng Retention", + "settings.storageCompliance.type.target_unavailable": "Hindi magagamit ang target", + "settings.storageCompliance.type.migration_failed": "Nabigo ang lifecycle job", + "settings.storagePath": "Path ng Storage", + "settings.hlsStoragePath": "Path ng HLS Storage", + "settings.hlsStoragePathHelp": "Opsyonal na path para sa HLS segments. Kung hindi tinukoy, gagamitin ang storage path.", + "settings.recordingDirectoryFormat": "Layout ng Folder ng Recording", + "settings.recordingDirectoryFormatHelp": "Hinahati ang mga bagong MP4 recording sa ilalim ng bawat camera folder. Hindi ililipat ang mga existing recording.", + "settings.recordingDirectoryFlat": "Flat (camera folder lamang)", + "settings.recordingDirectoryMonth": "Buwan-buwan (YYYY/MM)", + "settings.recordingDirectoryDay": "Araw-araw (YYYY/MM/DD)", + "settings.maxStorageGb": "Pinakamalaking Laki ng Storage (GB)", + "settings.zeroUnlimited": "0 = walang limitasyon", + "settings.retentionDays": "Panahon ng Retention (araw)", + "settings.autoDeleteOldest": "Awtomatikong Burahin ang Pinakamatanda", + "settings.minFreePct": "Pinakamaliit na Free Space (%)", + "settings.minFreePctHelp": "Panatilihin ang hindi bababa sa ganitong porsyento ng volume na libre sa pamamagitan ng awtomatikong pag-aalis ng mga pinakamatandang recording, anuman ang retention days. Limitado nito ang paggamit sa laki ng disk — itakda ito at hindi mapupuno ang disk. 0 = hindi gagana ang capacity cap.", + "settings.pressureThresholds": "Mga Threshold ng Disk Pressure (%)", + "settings.pressureThresholdsHelp": "Mga band ng free space na nagpapataas ng awtomatikong cleanup. Dapat matugunan ang emergency < critical < warning.", + "settings.pressureWarningPct": "Babala sa ilalim ng (% free)", + "settings.pressureCriticalPct": "Kritikal sa ilalim ng (% free)", + "settings.pressureEmergencyPct": "Emergency sa ilalim ng (% free)", + "settings.enableGridViewThumbnails": "I-enable ang Grid View (Thumbnails)", + "settings.enableGridViewThumbnailsHelp": "Pahintulutan ang grid view na may thumbnail previews sa recordings page", + "settings.thumbnailsPerRecording": "Mga Thumbnail bawat Recording", + "settings.thumbnailsPerRecordingOne": "1 (unang frame lamang — nakakatipid ng CPU)", + "settings.thumbnailsPerRecordingThree": "3 (simula / gitna / dulo — nag-iikot sa hover)", + "settings.thumbnailsPerRecordingHelp": "Ang mabagal na CPU ay dapat gumamit ng 1: lumalaktaw sa seek na kailangan para sa gitna/dulo na frames", + "settings.databasePath": "Path ng Database", + "settings.databaseBackupIntervalMinutes": "Interval ng Database Backup (minuto)", + "settings.databaseBackupIntervalHelp": "Gaano kadalas i-flush, i-verify, at i-back up ang SQLite database habang tumatakbo ang sistema. I-set sa 0 para panatilihin lamang ang startup/shutdown backups.", + "settings.databaseBackupRetentionCopies": "Retention ng Database Backup (kopya)", + "settings.databaseBackupRetentionHelpBefore": "Ilang timestamped backups ang panatilihin. I-set sa 0 para panatilihin lamang ang pinakabagong", + "settings.databaseBackupRetentionHelpAfter": "recovery copy.", + "settings.databaseBackupVerify": "Backup Verification", + "settings.databaseBackupVerifyFull": "Buong (integrity_check, cross-checks sa bawat index)", + "settings.databaseBackupVerifyQuick": "Mabilis (quick_check, page structure lamang)", + "settings.databaseBackupVerifyOff": "Naka-off (walang post-copy scan)", + "settings.databaseBackupVerifyHelp": "Scan na ipinapataw sa bawat kopyang backup bago ito i-publish. Ang Buong ay maaaring tumagal nang mas matagal kaysa sa kopya sa malaking database sa mechanical disk at maaaring maabot ang 30-minute safety valve, na nagtatapon ng backup na iyon; ang Mabilis ay nananatiling nakakakuha ng torn o truncated pages na may mas kaunting seeks.", + "settings.postBackupScript": "Post-backup Script", + "settings.postBackupScriptHelp": "Opsyonal na absolute path sa isang executable na tumatakbo pagkatapos ng verified backup. Tinatanggap nito: backup path, database path, at backup directory.", + "settings.pendingRestartLabel": "Naghihintay na restart:", + "settings.threadPoolSize": "Laki ng Thread Pool", + "settings.threadPoolPlaceholder": "Default: 2× CPU cores", + "settings.threadPoolHelp": "Bilang ng libuv worker threads. Ang default ay 2× ang bilang ng CPU cores (clamped 2–128).", + "settings.maxStreamsHelpBefore": "Kapasidad ng stream engine — ilang camera ang maaaring tumakbo nang sabay-sabay. Ang pagbabago nito ay nangangailangan ng", + "settings.maxStreamsHelpAfter": "Gamitin ang Streams page para magdagdag ng camera hanggang sa limitasyong ito.", + "settings.demoModeHelp": "Pahintulutan ang mga hindi na-authenticate na user na makakita ng streams (viewer access lamang)", + "settings.disableWebrtcHelp": "Kapag naka-enable, lahat ng streams ay gagamit ng HLS sa halip na WebRTC", + "settings.enabledViewMethodsHelp": "Piliin kung aling live-view selectors ang lalabas sa dashboard. Ang Auto ay opsyonal; hindi bababa sa isang playback transport ay dapat manatiling naka-enable.", + "settings.viewMethodAuto": "Auto — per-camera preference na may fallback", + "settings.viewMethodWebrtc": "WebRTC — pinakamababang latency (kailangan ng go2rtc)", + "settings.viewMethodHls": "HLS — universal compatibility, mas mataas na latency", + "settings.viewMethodMse": "MSE — mababang latency sa pamamagitan ng go2rtc, consistent playback", + "settings.sessionIdleTimeoutHours": "Session Idle Timeout (oras)", + "settings.sessionIdleTimeoutHelp": "Tagal na maaaring manatiling hindi aktibo ang isang naka-sign in na session bago kailanganin ang muling pagpapatunay.", + "settings.absoluteSessionLifetimeHours": "Absolute Session Lifetime (oras)", + "settings.absoluteSessionLifetimeHelp": "Hard cap para sa session kahit aktibo pa ang user. Dapat mas malaki o katumbas ng idle timeout.", + "settings.rememberDeviceDays": "Tandaan ang Device (araw)", + "settings.rememberDeviceDaysHelp": "Tagal na maaaring laktawan ng naka-MFA-verify na device ang susunod na TOTP prompt. Ilagay ang 0 upang hindi gumana ang mga naaalalang device.", + "settings.trustedProxyCidrs": "Mga Pinagkakatiwalaang Proxy CIDR", + "settings.trustedProxyCidrsHelpBefore": "Igalang lamang ang", + "settings.trustedProxyCidrsHelpAfter": "kung ang direktang peer IP ay tumutugma sa isa sa mga CIDR na ito. Iwanang blangko upang balewalain ang mga forwarded header.", + "settings.rateLimitWindowSeconds": "Rate Limit Window (segundo)", + "settings.rateLimitWindowSecondsHelp": "Time window sa segundo para sa rate limiting (minimum 10 segundo, default 300 = 5 minuto)", + "settings.memoryOptimization": "Pag-optimize ng Memory", + "settings.bufferSizeKb": "Buffer Size (KB)", + "settings.useSwapFile": "Gumamit ng Swap File", + "settings.swapSizeMb": "Swap Size (MB)", + "settings.detectionBasedRecordingDescription": "I-configure ang detection-based recording para sa mga stream. Kapag naka-enable, ang mga recording ay ise-save lamang kapag may natukoy na object.", + "settings.motionDetectionLabel": "Motion Detection:", + "settings.motionDetectionDescription": "Ang built-in motion detection ay available nang hindi nangangailangan ng anumang external model. Piliin ang \"motion\" bilang detection model sa stream settings upang gamitin ang feature na ito. Maaari mong i-configure ang detection model para sa bawat stream sa Stream Settings page.", + "settings.optimizedMotionDetectionLabel": "Optimized Motion Detection:", + "settings.optimizedMotionDetectionDescription": "Isang memory- at CPU-optimized na variant ng motion detection na idinisenyo para sa embedded at low-power na device. Kapag \"motion\" ang napiling detection model, awtomatikong ginagamit ang optimized na implementation na ito sa mga suportadong device; walang karagdagang configuration na kailangan.", + "settings.detectionModelsPathHelp": "Directory kung saan nakaimbak ang mga detection model", + "settings.apiDetectionUrl": "API Detection URL", + "settings.apiDetectionUrlHelp": "light-object-detect endpoint, hal. http://localhost:8000/api/v1/detect. Ang snapshot ay ina-upload bilang multipart form data na may idinadagdag na backend at confidence_threshold query parameters.", + "settings.apiDetectionBackend": "API Detection Backend", + "settings.apiDetectionBackendOnnx": "ONNX Runtime", + "settings.apiDetectionBackendTflite": "TensorFlow Lite", + "settings.apiDetectionBackendOpencv": "OpenCV DNN", + "settings.apiDetectionBackendHelp": "Inference backend na hinihiling mula sa light-object-detect (ipinapadala bilang backend query parameter)", + "settings.apiDetectionFormat": "API Request Format", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (multipart image upload)", + "settings.apiDetectionFormatDoods2": "DOODS2 (JSON body na may base64 image)", + "settings.apiDetectionFormatHelp": "Wire format na ginagamit ng LightNVR kapag nagpo-post ito ng snapshot sa detection API. Panatilihin ang light-object-detect para sa light-object-detect o anumang server na nag-i-implement ng kanyang contract; piliin ang DOODS2 para sa DOODS2 server.", + "settings.apiDetectionUrlHelpDoods2": "DOODS2 /detect endpoint, hal. http://localhost:8080/detect. Ang request ay ipinapadala bilang JSON at walang query parameter na idinadagdag.", + "settings.apiDetectionDetectorName": "Pangalan ng DOODS2 Detector", + "settings.apiDetectionDetectorNameHelp": "Ipinadala bilang detector_name sa bawat request. Kailangang tumugma sa detector na nakalista sa GET /detectors ng server; ang \"default\" ay gumagamit ng default detector ng server.", + "settings.detectionEngine": "Engine ng Pagtuklas (Local LiteRT)", + "settings.detectionEngineEnabled": "Paganahin ang Local Engine", + "settings.detectionEngineEnabledHelp": "Magpapatakbo ng TFLite/LiteRT inference sa loob ng LightNVR. Ang mga stream na ang model_path ay .tflite file ay gagamit ng engine na ito.", + "settings.detectionEngineThreads": "Mga Thread", + "settings.detectionEngineDelegate": "Delegate", + "settings.detectionEngineDelegateXnnpack": "XNNPACK (CPU optimized)", + "settings.detectionEngineDelegateGpu": "GPU", + "settings.detectionEngineDelegateNone": "Wala (reference)", + "settings.defaultDetectionThresholdHelp": "Threshold ng kumpiyansa para sa pagtuklas (0-100%)", + "settings.detectionGracePeriod": "Panahon ng Biyaya sa Pagtuklas (segundo)", + "settings.detectionGracePeriodHelp": "Bilang ng segundo pagkatapos ng huling pagtuklas bago lumipat ang recording sa post-buffer. Dagdagan kung ang mga pagtuklas ay may maikling puwang na dapat ituring bilang tuloy-tuloy na galaw (0–60, default: 2).", + "settings.defaultPreDetectionBufferHelp": "Bilang ng segundo ng video na itatago bago ang pagtuklas", + "settings.defaultPostDetectionBufferHelp": "Bilang ng segundo ng video na itatago pagkatapos ng pagtuklas", + "settings.defaultPlaybackTransport": "Default na Transport ng Playback", + "settings.defaultPlaybackTransportHelp": "Playback profile na ilalapat sa mga bagong ginawang stream. Ang mga umiiral na stream ay mananatili sa kanilang sariling pinili.", + "playbackTransport.auto": "Awtomatiko (inirerekomenda)", + "playbackTransport.webrtcOnly": "WebRTC lamang", + "playbackTransport.mseOnly": "MSE lamang", + "playbackTransport.hlsOnly": "HLS lamang", + "playbackTransport.webrtcThenMse": "WebRTC, pagkatapos MSE", + "playbackTransport.mseThenHls": "MSE, pagkatapos HLS", + "settings.go2rtcIntegrationDescription": "Ang go2rtc ay nagbibigay ng WebRTC at HLS streaming. Ang mga pagbabago ay nangangailangan ng restart upang maging epektibo.", + "settings.enableGo2rtcHelp": "Kung hindi pinagana, ang go2rtc ay hindi sisimulan at ang HLS ay direktang kumokonekta sa mga stream ng camera. Nakakatipid ito ng bandwidth para sa WiFi cameras ngunit pinapatawid ang WebRTC live view.", + "settings.forceNativeHls": "Pilitin ang Native HLS", + "settings.forceNativeHlsHelp": "Gamitin ang native FFmpeg-based HLS ng lightNVR sa halip na go2rtc HLS para sa live view. Kapaki-pakinabang kung ang go2rtc HLS ay may mga isyu sa compatibility. Hindi naaapektuhan ang WebRTC.", + "settings.binaryPath": "Path ng Binary", + "settings.go2rtcBinaryPathHelp": "Path ng go2rtc binary", + "settings.configDirectory": "Directory ng Config", + "settings.go2rtcConfigDirectoryHelp": "Directory para sa mga configuration file ng go2rtc", + "settings.apiPort": "Port ng API", + "settings.go2rtcApiPortHelp": "Port ng go2rtc API (default: 1984)", + "settings.rtspPort": "Port ng RTSP", + "settings.go2rtcRtspPortHelp": "Port ng RTSP listen (default: 8554)", + "settings.enableWebrtcHelp": "Paganahin ang WebRTC streaming sa pamamagitan ng go2rtc", + "settings.webrtcListenPort": "Port ng WebRTC Listen", + "settings.webrtcListenPortHelp": "Port ng WebRTC listen (default: 8555)", + "settings.enableStun": "Paganahin ang STUN", + "settings.enableStunHelp": "Paganahin ang STUN para sa NAT traversal (kinakailangan para sa remote WebRTC)", + "settings.stunServer": "STUN Server", + "settings.stunServerHelp": "Address ng STUN server para sa NAT traversal", + "settings.externalIp": "External IP", + "settings.autoDetect": "Awtomatikong pagtukoy", + "settings.externalIpHelp": "Opsyonal: External IP para sa NAT (iwanang blangko para sa awtomatikong pagtukoy)", + "settings.iceServers": "ICE Servers", + "settings.iceServersPlaceholder": "Opsyonal na ICE servers na pinaghihiwalay ng kuwit", + "settings.iceServersHelp": "Opsyonal: Custom ICE servers (pinaghihiwalay ng kuwit)", + "settings.go2rtcConfigOverride": "Config Override (YAML)", + "settings.go2rtcConfigOverrideHelp": "Advanced: Magdagdag ng custom YAML sections sa go2rtc.yaml. Ang mga duplicate na top-level key ay mag-o-override sa mga awtomatikong nabuo (last-key-wins). Gamitin para sa source-module credentials (wyze:, homekit:, hass:, roborock:), custom ffmpeg presets, publish destinations, log levels, atbp. Ang pagbabago nito ay mag-re-restart ng go2rtc.", + "settings.mqttEventStreamingDescription": "I-publish ang mga detection event sa MQTT broker para sa integrasyon sa Home Assistant o iba pang sistema.", + "settings.enableMqttHelp": "I-stream ang mga detection event sa MQTT broker", + "settings.brokerHostHelp": "Hostname o IP address ng MQTT broker", + "settings.brokerPortHelp": "Default: 1883 (8883 para sa TLS)", + "settings.clientId": "Client ID", + "settings.clientIdHelp": "Natatanging identifier para sa client na ito", + "settings.topicPrefix": "Topic Prefix", + "settings.topicPrefixPublishedTo": "Mga event na na-publish sa: {prefix}/detections/", + "settings.enableTlsHelp": "Gumamit ng encrypted na koneksyon (karaniwang port 8883)", + "settings.keepaliveSeconds": "Keepalive (segundo)", + "settings.keepaliveSecondsHelp": "Interval para suriin ang kalusugan ng koneksyon", + "settings.qosLevel": "Antas ng QoS", + "settings.qosAtMostOnce": "0 - Isang beses lang (fire and forget)", + "settings.qosAtLeastOnce": "1 - Hindi bababa sa isang beses (inirerekomenda)", + "settings.qosExactlyOnce": "2 - Eksakto na isang beses (pinakamataas na overhead)", + "settings.retainMessagesHelp": "Iniimbak ng broker ang huling mensahe para sa mga bagong subscriber", + "settings.homeAssistantAutoDiscoveryDescription": "Awtomatikong i-rehistro ang mga camera at sensor sa Home Assistant sa pamamagitan ng MQTT discovery. Kailangan ang parehong MQTT broker na ginagamit ng Home Assistant.", + "settings.enableHaDiscoveryHelp": "Awtomatikong lilitaw ang mga camera at motion sensor sa Home Assistant", + "settings.discoveryPrefix": "Discovery Prefix", + "settings.discoveryPrefixHelp": "Dapat tumugma sa MQTT discovery prefix ng Home Assistant (default: homeassistant)", + "settings.snapshotIntervalSeconds": "Snapshot Interval (segundo)", + "settings.snapshotIntervalSecondsHelp": "Gaano kadalas i-publish ang mga snapshot ng camera (0 = naka-disable, max 300)", + "settings.webrtcTurnServer": "WebRTC TURN Server", + "settings.webrtcTurnServerDescription": "I-configure ang TURN relay server para sa WebRTC kapag nabigo ang direktang peer-to-peer na koneksyon (hal., sa likod ng restrictive NAT/firewall).", + "settings.enableTurnRelay": "I-enable ang TURN Relay", + "settings.enableTurnRelayHelp": "Gumamit ng TURN server para sa WebRTC relay kapag nabigo ang direktang koneksyon", + "settings.turnServerUrl": "TURN Server URL", + "settings.turnServerUrlPlaceholder": "turn:turn.example.com:3478", + "settings.turnServerUrlHelp": "Format: turn:hostname:port o turn:hostname:port?transport=tcp", + "settings.onvifDiscoveryDescription": "I-configure ang mga setting ng ONVIF camera discovery. Gumamit ng CIDR notation (hal., 192.168.1.0/24) o \"auto\" para sa awtomatikong network detection.", + "settings.enableOnvifDiscoveryHelp": "Awtomatikong tuklasin ang mga ONVIF camera sa network", + "settings.discoveryIntervalSeconds": "Discovery Interval (segundo)", + "settings.discoveryIntervalSecondsRangeHelp": "Gaano kadalas i-scan para sa mga camera (30–3600 segundo)", + "settings.discoveryNetworkExamples": "Mga halimbawa: 192.168.1.0/24, 10.0.0.0/16, auto", + "investigation.experimental": "Eksperimental na workspace", + "investigation.title": "Imbestigasyon", + "investigation.description": "Suriin ang ilang camera laban sa isang shared UTC cursor nang hindi tinatago ang mga puwang sa footage.", + "investigation.query": "Bintana ng imbestigasyon", + "investigation.queryHelp": "Pumili ng hanggang 16 na camera. Hanggang apat na video player ang aktibo sa isang pagkakataon.", + "investigation.cameras": "mga camera", + "investigation.cameraSelection": "Pagpili ng camera", + "investigation.start": "Simula", + "investigation.end": "Wakas", + "investigation.load": "I-load ang imbestigasyon", + "investigation.applyWindow": "I-apply ang time window", + "investigation.loading": "Ini-load ang imbestigasyon…", + "investigation.eventType": "Uri ng pangyayari", + "investigation.anyEventType": "Anumang uri ng pangyayari", + "investigation.eventType.detection": "Pagtuklas", + "investigation.eventType.motion": "Galaw", + "investigation.location": "Lokasyon", + "investigation.anyLocation": "Anumang lokasyon", + "investigation.objectLabel": "Label ng bagay", + "investigation.anyLabel": "Anumang label", + "investigation.zone": "Sona", + "investigation.anyZone": "Anumang sona", + "investigation.source": "Pinagmulan ng pagtuklas", + "investigation.anySource": "Anumang pinagmulan", + "investigation.captureMethod": "Paraan ng pagkuha", + "investigation.anyCaptureMethod": "Anumang paraan ng pagkuha", + "investigation.recordingTag": "Tag ng recording", + "investigation.anyRecordingTag": "Anumang tag ng recording", + "investigation.protection": "Proteksyon", + "investigation.anyProtection": "Anumang proteksyon", + "investigation.protected": "Protektado", + "investigation.unprotected": "Hindi protektado", + "investigation.minimumConfidence": "Pinakamababang kumpiyansa", + "investigation.confidenceError": "Ang pinakamababang kumpiyansa ay dapat nasa pagitan ng 0 at 1.", + "investigation.metadataRegionSearch": "Paghahanap ng rehiyon ng metadata", + "investigation.regionSearchHelp": "Pumili ng pangunahing camera na may footage, pagkatapos ay gumuhit ng area sa ibabaw ng video nito.", + "investigation.regionActive": "Hinahanap ang mga naka-imbak na box mula sa {camera}. Ang kawalan ng resulta ay hindi patunay na walang tumawid sa area.", + "investigation.regionMatch": "Pagtutugma ng box", + "investigation.regionMatch.center": "Nasa loob ang sentro", + "investigation.regionMatch.intersects": "Anumang intersection", + "investigation.regionMatch.minimumIntersection": "Pinakamababang overlap", + "investigation.regionMinimumOverlap": "Pinakamababang overlap (%)", + "investigation.regionLeft": "Kaliwa (%)", + "investigation.regionTop": "Itaas (%)", + "investigation.regionWidth": "Lapad (%)", + "investigation.regionHeight": "Taas (%)", + "investigation.drawRegion": "Iguhit ang lugar ng paghahanap", + "investigation.drawingRegion": "Ginuguhit ang lugar ng paghahanap…", + "investigation.clearRegion": "Burahin ang lugar", + "investigation.useFullFrame": "Gamitin ang buong frame", + "investigation.drawRegionPrompt": "I-drag sa video upang tukuyin ang lugar ng paghahanap", + "investigation.applyFilters": "I-apply ang mga filter", + "investigation.searching": "Naghahanap ng mga event…", + "investigation.searchResults": "Mga resulta ng event", + "investigation.searchHelp": "Mag-load ng imbestigasyon upang hanapin ang naka-save na metadata ng event.", + "investigation.resultCount": "{count} tumutugmang event", + "investigation.results": "mga resulta", + "investigation.resultHistogram": "Histogram ng event", + "investigation.histogramHelp": "Pumili ng bar upang ilipat ang shared cursor.", + "investigation.previousResult": "Nakaraang event", + "investigation.nextResult": "Susunod na event", + "investigation.previousResultShortcut": "Nakaraang event ([)", + "investigation.nextResultShortcut": "Susunod na event (])", + "investigation.noResults": "Walang naka-save na event na tumutugma sa napiling camera, oras, at filter.", + "investigation.noThumbnail": "Walang thumbnail", + "investigation.exploreThumbnails": "Tuklasin ang mga thumbnail", + "investigation.exploreSelectedThumbnails": "Tuklasin sa paligid ng event", + "investigation.thumbnailDrilldown": "Drill-down ng thumbnail", + "investigation.thumbnailDrilldownHelp": "Pumili ng kahit anong sandali, kabilang ang puwang, upang ilipat ang shared cursor at bumuo ng mas makitid na set ng mga sample.", + "investigation.selectThumbnailSample": "Suriin sa paligid ng {time}", + "investigation.loadingThumbnail": "Naglo-load ng thumbnail…", + "investigation.thumbnailUnavailable": "Hindi available ang thumbnail", + "investigation.loadingSamples": "Naglo-load ng mga sample ng thumbnail…", + "investigation.thumbnailCoverageTruncated": "Ang interval na ito ay naglalaman ng mas maraming recording kaysa sa kayang suriin ng sampler. Liitain ang time window para sa kumpletong saklaw.", + "investigation.bookmarks.save": "I-save ang bookmark", + "investigation.bookmarks.open": "Mga Bookmark", + "investigation.bookmarks.saveTitle": "I-save ang bookmark ng imbestigasyon", + "investigation.bookmarks.listTitle": "Mga bookmark ng imbestigasyon", + "investigation.bookmarks.notHold": "Ibabalik ng bookmark ang view na ito, ngunit hindi nito pinoprotektahan ang mga recording mula sa normal na retention o pagtanggal.", + "investigation.bookmarks.title": "Pangalan ng bookmark", + "investigation.bookmarks.note": "Pribadong tala (opsyonal)", + "investigation.bookmarks.titleRequired": "Maglagay ng pangalan ng bookmark.", + "investigation.bookmarks.empty": "Wala kang naka-save na bookmark ng imbestigasyon.", + "investigation.bookmarks.cameraCount": "{count} camera", + "investigation.bookmarks.restore": "Buksan", + "investigation.bookmarks.confirmDelete": "Burahin ang bookmark?", + "investigation.actions.open": "Protektahan / i-download", + "investigation.actions.title": "Mga recording ng imbestigasyon", + "investigation.actions.notEvidenceExport": "Pipigilan ng proteksyon ang normal na pagtanggal ng retention. Ang ZIP download ay para sa kaginhawaan lamang, hindi isang beripikadong evidence package.", + "investigation.actions.scope": "Saklaw ng recording", + "investigation.actions.selectedResult": "Napiling event at camera", + "investigation.actions.fullWindow": "Lahat ng camera sa investigation window", + "investigation.actions.preview": "I-preview ang mga recording", + "investigation.actions.previewing": "Hinahanap ang mga nag-o-overlap na recording…", + "investigation.actions.invalidRange": "Pumili ng wastong saklaw ng oras na ang wakas ay pagkatapos ng simula.", + "investigation.actions.recordingCount": "{count} nag-o-overlap na recording", + "investigation.actions.protectedCount": "{count} ay protektado na", + "investigation.actions.noRecordings": "Walang kumpletong recording ang nag-o-overlap sa napiling camera at oras.", + "investigation.actions.protectDenied": "{count} hindi protektadong recording ang nasa labas ng iyong saklaw ng proteksyon at hindi kasama sa aksyong ito.", + "investigation.actions.exportDenied": "Kulang ang pahintulot sa pag-export para sa {count} recording. Ang mga download ay all-or-nothing, kaya hindi ma-export ang napili.", + "investigation.actions.camera": "Camera", + "investigation.actions.recording": "Recording", + "investigation.actions.size": "Laki", + "investigation.actions.notPermitted": "Hindi pinapayagan", + "investigation.actions.protectButton": "Protektahan ang {count}", + "investigation.actions.protecting": "Pinoprotektahan…", + "investigation.actions.protectUnavailable": "Walang hindi protektadong recording na pinapayagan kang protektahan.", + "investigation.actions.protectResult": "Tapos ang proteksyon: {success} matagumpay, {failed} nabigo.", + "investigation.actions.downloadButton": "I-download ang {count}", + "investigation.actions.downloadUnavailable": "Kailangan ng pahintulot sa pag-export bago makagawa ng ZIP.", + "investigation.actions.buildingArchive": "Ginagawa ang ZIP…", + "investigation.actions.downloadFailed": "Nabigo ang paggawa ng ZIP sa server.", + "investigation.actions.downloadTimedOut": "Hindi natapos ang paggawa ng ZIP sa loob ng limang minuto. Subukan ang mas makitid na interval.", + "investigation.actions.downloadStarted": "Nagsimula ang pag-download ng ZIP.", + "investigation.backOneLevel": "Bumalik sa isang antas", + "investigation.thumbnailMinimumWindow": "Ito ang pinakamakitid na available na isang-segundong interval. Ang shared cursor ay lumipat pa rin sa napiling sandali.", + "investigation.localSource": "lokal", + "investigation.mediaAvailable": "May available na media", + "investigation.durationSeconds": "{count}s na tagal", + "investigation.pageNumber": "Pahina {count}", + "investigation.incompleteCoverage": "Hindi ma-attribute ang {count} legacy event rows sa isang immutable na camera identity.", + "investigation.spatialCoverageGap": "Ang {count} in-scope event rows ay walang bounding box at hindi hinanap sa espasyo.", + "investigation.noSpatialMetadata": "Walang in-scope events na may bounding box para sa metadata search na ito.", + "investigation.selectCameraError": "Pumili ng kahit isang camera.", + "investigation.selectRecordingError": "Pumili ng kahit isang recording.", + "investigation.investigateSelectedCount": "Imbestigahan ang {count} napiling recording", + "investigation.missingCameraIdentity": "Hindi maimbestigahan: ang {count} napiling recording ay walang camera identity.", + "investigation.recordingTimeError": "Ang napiling recordings ay walang wasteng time range.", + "investigation.windowLimit": "Ang napiling recordings ay lampas sa 31-araw na limitasyon sa imbestigasyon.", + "investigation.timeRangeError": "Ang end time ay dapat pagkatapos ng start time.", + "investigation.cameraLimit": "Ang isang imbestigasyon ay maaaring maglaman ng hanggang {count} cameras.", + "investigation.decoderLimit": "Hanggang {count} camera players lamang ang maaaring aktibo sa isang pagkakataon.", + "investigation.playbackControls": "Mga kontrol sa synchronized playback", + "investigation.play": "I-play", + "investigation.pause": "I-pause", + "investigation.mode": "Mode ng playback", + "investigation.wallClock": "Wall-clock", + "investigation.skipCommonGaps": "Laktawan ang karaniwang gaps", + "investigation.speed": "Bilis", + "investigation.sharedCursor": "Shared UTC cursor", + "investigation.activePlayers": "mga aktibong player", + "investigation.timeline": "ibinahaging timeline", + "investigation.segments": "mga segment", + "investigation.truncated": "naputol", + "investigation.gap": "Walang footage", + "investigation.players": "Mga naka-synchronize na camera player", + "investigation.activateCamera": "I-activate ang kahit isang timeline row upang mag-load ng video.", + "investigation.noFootage": "Walang footage", + "investigation.noFootageAtTime": "Walang footage sa ibinahaging oras", + "investigation.primaryAudio": "Pangunahing audio", + "investigation.makePrimary": "Gawing pangunahin", + "investigation.status.loading": "Naglo-load ng media", + "investigation.status.synchronizing": "Nagsi-synchronize", + "investigation.status.ready": "Naka-synchronize", + "investigation.status.late": "Huli — nagre-recover", + "investigation.status.error": "Hindi available ang media", + "investigation.status.paused-by-browser": "Piliin ang play upang payagan ang media", + "streamsConfig.eptzTitle": "Fisheye ePTZ", + "streamsConfig.eptzEnable": "I-enable ang browser-side fisheye ePTZ", + "streamsConfig.eptzHelp": "I-dewarp ang hindi binagong fisheye stream sa Live View, Timeline playback, at Investigation. Hindi nito binabago ang mga recording o output ng camera.", + "streamsConfig.eptzModelHelp": "Projection: equidistant circular fisheye · Mount: kisame. Ang center at radius ay gumagamit ng normalized source-image coordinates.", + "streamsConfig.eptzCenterX": "Optical center X", + "streamsConfig.eptzCenterY": "Optical center Y", + "streamsConfig.eptzRadius": "Image-circle radius", + "streamsConfig.eptzLensFov": "Lens FOV (degrees)", + "streamsConfig.eptzRotation": "Lens rotation (degrees)", + "streamsConfig.eptzDefaultYaw": "Default pan (degrees)", + "streamsConfig.eptzDefaultTilt": "Default tilt (degrees)", + "streamsConfig.eptzViewFov": "Default view FOV", + "streamsConfig.eptzCalibrationHelp": "I-drag upang tumingin sa paligid, gamitin ang wheel o pinch upang mag-zoom, at pindutin ang Home upang i-reset ang virtual camera. I-fine-tune ang center at radius kung hindi nakaka-align ang gilid ng image-circle.", + "settings.archive.targetType": "Uri ng storage", + "settings.archive.filesystem": "Lokal o naka-mount na filesystem (NFS/SAN)", + "settings.archive.s3": "S3-compatible na bucket ng archive", + "settings.archive.endpoint": "HTTPS endpoint", + "settings.archive.region": "Rehiyon", + "settings.archive.bucket": "Dedikadong bucket", + "settings.archive.credential_ref": "Sanggunian ng kredensyal", + "settings.archive.budget": "Budget ng archive (GiB, 0 = walang limitasyon)", + "settings.archive.connectionHelp": "Gumamit ng pribadong bucket na walang versioning at walang lifecycle expiry rules. Ang sanggunian ng kredensyal ay pumipili ng secret file na naka-mount sa server. Ilagay ang managed location bilang s3://bucket/instance-prefix.", + "settings.archive.policy": "Patakaran sa external archive", + "settings.archive.archive_after_seconds": "I-archive pagkatapos ng capture (segundo, -1 = hindi pinagana)", + "settings.archive.hot_residency_seconds": "Panatilihin ang hot copy (segundo, -1 = ilipat pagkatapos i-archive)", + "settings.archive.archive_protected": "Bigyan ng prayoridad ang pag-archive ng mga protektadong recording", + "settings.archive.archive_on_pressure": "Maagang i-archive kapag ang hot storage ay nalilipatan", + "settings.archive.policyHelp": "Ang archive timing ay gumagamit ng capture age at nangangailangan ng kumpletong recording. Ang -1 ay hindi pinagana ang age-based archival o tinatanggal ang hot-residency minimum; ang 0 ay agad. Ang mga pagbabago ay naaangkop sa mga bagong recording. Suriin ang mga umiiral na recording upang mailapat ang bagong rebisyon sa mga ito.", + "settings.archive.deletion_pending": "Nakabinbin ang pagtanggal", + "settings.archive.archived": "Na-archive", + "settings.archive.hot": "Hot", + "settings.archive.hot_and_archive": "Hot + archive", + "settings.archive.archiving": "Ina-archive", + "settings.archive.preparing": "Inihahanda ang playback", + "settings.archive.unavailable": "Hindi available", + "settings.archive.operations": "Mga operasyon ng archive", + "settings.archive.readOnly": "Recovery mode: Nakapause ang paglipat at pagtanggal ng recording.", + "settings.archive.disabledBuild": "Hindi pinagana ang S3 support sa build na ito. Ang mga mounted filesystem target ay nananatiling available.", + "settings.archive.stored": "Nakaimbak sa mga bucket", + "settings.archive.backlog": "Backlog ng paglilipat", + "settings.archive.cache": "Cache ng pagkuha", + "settings.archive.objectsRemaining": "objects ang natitira", + "settings.archive.waitingForReaders": "Naka-queue, o naghihintay ng aktibong reader.", + "settings.archive.applied": "Rebisyon ng patakaran na inilapat sa mga umiiral na recording", + "settings.archive.reviewExisting": "Suriin ang mga umiiral na recording", + "settings.archive.applySummary": "{count} recording ({bytes}) ang gagamit ng rebisyong ito. Ang {expired} ay lampas na sa retention limit nito.", + "settings.archive.applyHelp": "Nananatiling naaangkop ang protection at recording overrides. Naaangkop din ang stream at system retention. Ang bagong archive timing at destination ay magkakaroon ng bisa sa susunod na lifecycle scan.", + "settings.archive.applyBlocked": "Kumpletuhin o ayusin ang mga kaugnay na transfer bago i-apply ang rebisyon na ito.", + "settings.archive.apply": "I-apply sa mga umiiral na recording", + "common.fullscreenUnsupported": "Hindi sinusuportahan ang fullscreen mode sa browser na ito.", + "recordings.viewInTimelineTitle": "Tingnan ang stream na ito sa puntong ito sa Timeline view", + "recordings.clickToRetry": "I-click upang subukan muli", + "timeline.previousDay": "Nakaraang araw", + "timeline.nextDay": "Susunod na araw", + "timeline.previousMonth": "Nakaraang buwan", + "timeline.nextMonth": "Susunod na buwan", + "settings.searchLabel": "Hanapin ang mga setting", + "settings.clearSearch": "I-clear ang paghahanap", + "recordings.addTagPlaceholder": "Magdagdag ng tag...", + "recordings.addNewTagPlaceholder": "Magdagdag ng bagong tag..." } diff --git a/web/public/locales/fr.json b/web/public/locales/fr.json index 6e76c162..e5c4a8b8 100644 --- a/web/public/locales/fr.json +++ b/web/public/locales/fr.json @@ -9,6 +9,84 @@ "nav.timeline": "Chronologie", "nav.health": "Santé", "nav.toggleMenu": "Afficher/masquer le menu", + "live.navigator.title": "Navigateur", + "live.navigator.subtitle": "Emplacements, dispositions et activité", + "live.navigator.cameras": "Caméras", + "live.navigator.plans": "Plan", + "live.navigator.views": "Vues", + "live.navigator.events": "Événements", + "live.navigator.search": "Rechercher une caméra…", + "live.navigator.allCameras": "Toutes les caméras", + "live.navigator.unassigned": "Non attribuées", + "live.navigator.noCameras": "Aucune caméra ne correspond à cette portée.", + "live.navigator.saveCurrent": "Enregistrer la disposition actuelle", + "live.navigator.noLayouts": "Aucune disposition enregistrée pour le moment.", + "live.navigator.layoutNamePrompt": "Nommer cette disposition de vue en direct", + "live.navigator.shareLayoutPrompt": "Partager cette disposition avec d’autres opérateurs ?", + "live.navigator.layoutSaved": "{name} enregistrée", + "live.navigator.layoutLoaded": "{name} chargée", + "live.navigator.deleteLayoutConfirm": "Supprimer {name} ?", + "live.navigator.shared": "Partagée", + "live.navigator.loadingEvents": "Chargement des événements récents…", + "live.navigator.noRecentEvents": "Aucune détection au cours de la dernière heure.", + "live.navigator.expand": "Déplier le navigateur", + "live.navigator.collapse": "Replier le navigateur", + "live.plan.navigatorHelp": "Choisissez un bâtiment ou un étage. Les aperçus des caméras ne s’ouvrent que sur demande.", + "live.plan.noPlans": "Aucun plan de bâtiment pour le moment. Créez-en un dans l’espace de travail des plans.", + "live.plan.emptyTitle": "Créer une vue spatiale des caméras", + "live.plan.emptyDescription": "Un plan affiche des marqueurs d’état pour tout le site et n’ouvre la vidéo que lorsqu’un opérateur le demande. Dessinez ici les pièces et les murs, ou importez un plan numérisé, un croquis du site ou une capture de votre logiciel NVR, puis associez les caméras aux pièces réelles.", + "live.plan.sketch.tools": "Outils de disposition", + "live.plan.sketch.tool.select": "Sélectionner", + "live.plan.sketch.tool.room": "Pièce", + "live.plan.sketch.tool.wall": "Mur", + "live.plan.sketch.tool.area": "Zone", + "live.plan.sketch.tool.label": "Étiquette", + "live.plan.sketch.undo": "Annuler le dessin", + "live.plan.sketch.redo": "Rétablir le dessin", + "live.plan.sketch.snap": "Aligner sur la grille", + "live.plan.sketch.hint.select": "Faites glisser formes ou caméras pour les déplacer. Cliquez sur une forme pour la modifier ; maintenez Alt pour ignorer la grille.", + "live.plan.sketch.hint.room": "Faites glisser sur le plan pour dessiner une pièce ou le contour d’un bâtiment.", + "live.plan.sketch.hint.wall": "Cliquez pour ajouter des points de mur. Double-cliquez ou appuyez sur Enter pour terminer, Escape pour annuler.", + "live.plan.sketch.hint.area": "Cliquez pour délimiter une zone. Cliquez sur le premier point ou appuyez sur Enter pour la fermer.", + "live.plan.sketch.hint.label": "Cliquez sur le plan pour placer une étiquette de texte.", + "live.plan.sketch.type.rect": "Pièce", + "live.plan.sketch.type.wall": "Mur", + "live.plan.sketch.type.area": "Zone", + "live.plan.sketch.type.label": "Étiquette", + "live.plan.sketch.pointCount": "{count} points", + "live.plan.sketch.defaultLabel": "Étiquette", + "live.plan.sketch.shapes": "Formes de la disposition", + "live.plan.sketch.noShapes": "Rien n’est dessiné pour le moment. Choisissez un outil au-dessus du plan pour commencer.", + "live.plan.sketch.tone": "Couleur", + "live.plan.sketch.tone.slate": "Ardoise", + "live.plan.sketch.tone.blue": "Bleu", + "live.plan.sketch.tone.green": "Vert", + "live.plan.sketch.tone.amber": "Ambre", + "live.plan.sketch.tone.red": "Rouge", + "live.plan.sketch.tone.violet": "Violet", + "live.plan.sketch.labelText": "Étiquette", + "live.plan.sketch.text": "Texte", + "live.plan.sketch.size": "Taille", + "live.plan.sketch.size.sm": "Petite", + "live.plan.sketch.size.md": "Moyenne", + "live.plan.sketch.size.lg": "Grande", + "live.plan.sketch.filled": "Remplir la pièce", + "live.plan.sketch.left": "Gauche %", + "live.plan.sketch.top": "Haut %", + "live.plan.sketch.width": "Largeur %", + "live.plan.sketch.height": "Hauteur %", + "live.plan.sketch.points": "Points", + "live.plan.sketch.point": "Point {index}", + "live.plan.sketch.delete": "Supprimer la forme", + "live.plan.sketch.duplicate": "Dupliquer", + "live.plan.sketch.deselect": "Terminé", + "live.plan.sketch.emptyTitle": "Rien sur ce plan pour le moment", + "live.plan.sketch.emptyBody": "Dessinez ici des pièces, des murs et des étiquettes, ou importez un plan numérisé, un croquis du site ou une exportation PNG/JPEG (jusqu’à 768 Ko).", + "live.plan.sketch.emptyBodyReadOnly": "Un administrateur peut dessiner la disposition ou importer un plan du bâtiment réel.", + "live.plan.sketch.drawLayout": "Dessiner la disposition", + "live.plan.sketch.uploadImage": "Importer une image", + "live.plan.sketch.limitReached": "Limite de formes atteinte ({max})", + "live.plan.sketch.discardDrawing": "Dessin annulé", "streamHealth.title": "Santé du flux", "streamHealth.loading": "Chargement des données de santé...", "streamHealth.error": "Échec du chargement des données de santé", @@ -326,13 +404,13 @@ "timeline.help.arrowKeys": "Utilisez les flèches gauche et droite pour passer d’un enregistrement à l’autre ; cliquez sur la vidéo pour faire passer les flèches à un déplacement de 1 seconde", "timeline.help.playFromCursor": "Utilisez le bouton de lecture vert pour démarrer la lecture depuis la position actuelle du curseur", "timeline.help.zoomControls": "Utilisez les boutons Ajuster, + et − ou Ctrl/Cmd + molette pour zoomer sur la chronologie", - "timeline.help.panControls": "Déplacez-vous à gauche ou à droite au niveau de zoom actuel avec Maj + molette ou un geste horizontal sur le pavé tactile", + "timeline.help.panControls": "Déplacez-vous à gauche ou à droite au niveau de zoom actuel avec Shift + molette ou un geste horizontal sur le pavé tactile", "timeline.help.actions": "Utilisez Instantané, Télécharger, Protéger ou Supprimer sur l’enregistrement en cours de lecture", "timeline.arrowKeysHelpTitle": "Cliquez sur la vidéo pour faire passer les flèches à un déplacement de 1 seconde. Cliquez ailleurs pour revenir au saut entre enregistrements.", "timeline.arrowKeys": "Touches fléchées", "timeline.seekOneSecond": "chercher ±1 s", "timeline.jumpRecordings": "passer entre les enregistrements", - "timeline.inlineHint": "Cliquez sur la vidéo pour un déplacement de 1 s avec les flèches · Cliquez sur la chronologie pour passer d’un enregistrement à l’autre · Maj+molette pour déplacer · Ctrl/Cmd+molette pour zoomer", + "timeline.inlineHint": "Cliquez sur la vidéo pour un déplacement de 1 s avec les flèches · Cliquez sur la chronologie pour passer d’un enregistrement à l’autre · Shift+molette pour déplacer · Ctrl/Cmd+molette pour zoomer", "timeline.selectedRecordingsTimeline": "Chronologie des ou des enregistrements sélectionnés", "timeline.timelinePlayback": "Lecture de la chronologie", "timeline.recordingsCount": "{count} enregistrements", @@ -405,6 +483,12 @@ "live.errorProcessingStreams": "Erreur de traitement des flux : {message}", "live.couldNotEnableFullscreen": "Impossible de passer en plein écran : {message}", "live.allTags": "Toutes les étiquettes", + "live.favorites": "Favoris", + "live.favoritesOnly": "Afficher uniquement les caméras favorites", + "live.addFavorite": "Ajouter {stream} aux favoris", + "live.removeFavorite": "Retirer {stream} des favoris", + "live.noFavorites": "Aucune caméra favorite pour le moment. Utilisez l’étoile d’une vignette de caméra pour en ajouter une.", + "live.favoriteUpdateError": "Impossible de mettre à jour les favoris : {message}", "live.tags": "Étiquettes", "live.stream": "Flux", "live.filterByTag": "Filtrer par étiquette: {tag}", @@ -589,6 +673,7 @@ "live.forceRefreshWarning": "Cela interrompra brièvement la connexion go2rtc, interrompant ainsi l'enregistrement actif. L'enregistrement reprendra automatiquement.", "live.viewInTimeline": "Afficher dans la chronologie", "live.toggleFullscreen": "Basculer en plein écran", + "live.resetZoom": "Réinitialiser le zoom", "live.streamStarting": "Démarrage du flux...", "live.go2rtcNotRespondingRetry": "go2rtc est activé mais ne répond pas. Vérifiez l'état du service go2rtc. Cliquez sur Réessayer pour réessayer.", "live.go2rtcHlsFailedRetry": "Échec du flux HLS go2rtc. Cliquez sur Réessayer pour réessayer.", @@ -603,12 +688,14 @@ "live.failedToCreateMediaBuffer": "Échec de la création du tampon multimédia", "live.webSocketConnectionError": "Erreur de connexion WebSocket", "live.webrtcAutoplayBlocked": "Cliquez pour lire la vidéo (lecture automatique bloquée)", + "live.audioPlaybackBlocked": "Le navigateur a bloqué l’audio de la caméra. Cliquez à nouveau sur le bouton haut-parleur pour réessayer.", "live.webrtcConnectionLostRetry": "Connexion WebRTC perdue. Cliquez sur Réessayer pour vous reconnecter.", "live.streamConnectedNoVideoDataRetry": "Flux connecté mais pas de données vidéo. Cliquez sur Réessayer pour vous reconnecter.", "live.failedToLoadVideo": "Échec du chargement de la vidéo", "live.webrtcIceConnectionFailed": "Échec de la connexion ICE WebRTC", "live.webrtcConnectionLostPleaseRetry": "Connexion WebRTC perdue. Veuillez réessayer.", "live.autoRetryingIn": "Nouvelle tentative dans {seconds}s…", + "live.fullscreenSubStreamFallback": "{stream} : bande passante insuffisante pour le flux en pleine résolution en plein écran — passage au sous-flux.", "live.connectionTimeoutCheckNetwork": "Expiration du délai de connexion. Vérifiez les paramètres réseau/pare-feu.", "live.failedToEstablishWebrtcConnection": "Échec de l'établissement de la connexion WebRTC", "live.cannotConnectToSource": "Impossible de se connecter à la source caméra", @@ -622,6 +709,16 @@ "live.connectionQuality.bad": "Mauvaise", "live.muteCameraAudio": "Couper le son de la caméra", "live.unmuteCameraAudio": "Activer le son de la caméra", + "live.tileActions": "Actions de caméra", + "live.takeSnapshot": "Prendre un instantané", + "live.openStreamRecordings": "Ouvrir les enregistrements de ce flux", + "live.enterReorderMode": "Réordonner les caméras", + "live.pullToRefresh": "Tirer pour actualiser les flux", + "live.releaseToRefresh": "Relâcher pour actualiser les flux", + "live.refreshingStreams": "Actualisation des flux…", + "live.streamsRefreshed": "Flux actualisés", + "live.refreshStreamsFailed": "Impossible d’actualiser les flux : {message}", + "live.tipDoubleTapFullscreen": "Astuce : touchez deux fois une vignette pour l’ouvrir en plein écran.", "live.switchToToggleMode": "Passer en mode bascule", "live.switchToPushToTalkMode": "Passer au Push-to-Talk", "live.releaseToStopTalking": "Relâchez pour arrêter de parler", @@ -636,6 +733,40 @@ "live.pauseForPrivacyConfirm": "Suspendre ce flux pour des raisons de confidentialité ? L'enregistrement et la visualisation en direct s'arrêteront, mais le flux restera visible sur cette page avec une superposition de confidentialité. Cliquez sur Reprendre lorsque vous avez terminé.", "live.streamPausedForPrivacy": "Flux suspendu pour des raisons de confidentialité", "live.resumeStream": "Reprendre le flux", + "live.dayNightControl": "Mode jour/nuit", + "live.dayNightLoading": "Chargement…", + "live.dayNightApplying": "Application…", + "live.dayNightMode_auto": "Auto", + "live.dayNightMode_day": "Jour", + "live.dayNightMode_night": "Nuit", + "live.dayNightMode_unknown": "Inconnu", + "live.dayNightApplied": "Mode jour/nuit réglé sur {mode}", + "live.dayNightApplyFailed": "Échec du réglage du mode jour/nuit", + "live.dayNightLoadFailed": "Échec de lecture du mode jour/nuit", + "live.playbackFallbackUsed": "Repli : {transport}", + "live.playbackTransportUnavailable": "{transport} est désactivé sur le serveur pour ce flux.", + "live.recordingMode.constant": "Enregistrement continu", + "live.recordingMode.detection": "Enregistrement sur détection", + "live.recordingMode.schedule": "Enregistrement programmé", + "live.recordingMode.none": "Pas d’enregistrement", + "live.health.healthy": "Flux sain", + "live.health.degraded": "Flux en mémoire tampon ou en récupération", + "live.health.offline": "Flux indisponible", + "live.enterPictureInPicture": "Ouvrir l’image dans l’image", + "live.exitPictureInPicture": "Fermer l’image dans l’image", + "live.pictureInPictureError": "Échec de l’image dans l’image : {message}", + "live.alwaysFullscreenOnTapEnable": "Activer le plein écran par simple toucher de vignette", + "live.alwaysFullscreenOnTapDisable": "Désactiver le plein écran par simple toucher de vignette", + "live.displayMode": "Mode d’affichage", + "live.displayModeFit": "Ajuster", + "live.displayModeFill": "Remplir", + "live.displayModeFitDescription": "Ajuster : afficher toute l’image avec bandes noires", + "live.displayModeFillDescription": "Remplir : remplir la vignette et rogner les bords de l’image", + "live.slideshowStartCameras": "Démarrer le diaporama : parcourir les caméras", + "live.slideshowStartPages": "Démarrer le diaporama : parcourir les pages de la grille", + "live.slideshowStop": "Arrêter le diaporama", + "live.slideshowInterval": "Intervalle du diaporama", + "live.slideshowSeconds": "{seconds} s", "streams.toggleDisable": "Désactiver le flux", "streams.toggleEnable": "Activer le flux", "streams.readOnlyInsufficientPermissions": "Lecture seule (autorisations insuffisantes pour modifier)", @@ -759,9 +890,9 @@ "streamsConfig.streamNameImmutable": "Le nom du flux ne peut plus être modifié après sa création", "streamsConfig.streamNameAllowedChars": "Seuls les lettres, chiffres, '.', '-' et '_' sont autorisés (sans espaces).", "streamsConfig.streamUrl": "URL du flux", - "streamsConfig.streamUrlPlaceholder": "rtsp://nom d'utilisateur:mot de passe@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "URL du sous-flux (facultatif)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://nom d'utilisateur:password@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "URL du flux basse résolution pour la vue grille du tableau de bord. Laissez vide pour utiliser le flux principal partout. Le sous-flux n'est utilisé que pour l'aperçu en direct en mode grille ; l'enregistrement et le plein écran utilisent toujours le flux principal.", "streamsConfig.urlCredentialsHiddenTitle": "Les identifiants URL sont masqués en mode démo/visualiseur", "streamsConfig.urlCredentialsHidden": "Identifiants masqués dans l'URL pour des raisons de sécurité", @@ -819,7 +950,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "Assurez-vous que light-object-detect est exécuté sous cet URL", "streamsConfig.customApiEndpointUrl": "URL de l'API personnalisé", "streamsConfig.useDefaultEndpoint": "Utiliser l'URL par défaut", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "Entrez l'URL complet de l'API de détection personnalisée", "streamsConfig.overrideWithCustomEndpoint": "Remplacer par un URL personnalisé", "streamsConfig.detectionThreshold": "Seuil de détection", @@ -1056,7 +1187,7 @@ "settings.detectionModelsPath": "Chemin des modèles de détection", "settings.detectionModelsPathHelp": "Répertoire où sont stockés les modèles de détection", "settings.apiDetectionUrl": "API Détection URL", - "settings.apiDetectionUrlHelp": "URL du point de terminaison de détection d'objet externe API", + "settings.apiDetectionUrlHelp": "Endpoint light-object-detect, ex. http://localhost:8000/api/v1/detect. L'instantané est téléversé en données de formulaire multipart avec les paramètres de requête backend et confidence_threshold ajoutés.", "settings.apiDetectionBackend": "API Backend de détection", "settings.apiDetectionBackendOnnx": "ONNX Durée d'exécution", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1156,5 +1287,1361 @@ "settings.discoveryIntervalSecondsRangeHelp": "À quelle fréquence rechercher des caméras (30 à 3 600 secondes)", "settings.discoveryNetwork": "Réseau de découverte", "settings.discoveryNetworkExamples": "Exemples : 192.168.1.0/24, 10.0.0.0/16, automatique", - "settings.saveSettings": "Enregistrer les paramètres" -} \ No newline at end of file + "settings.saveSettings": "Enregistrer les paramètres", + "live.plan.previewUnavailable": "Aperçu de caméra indisponible", + "live.plan.previewAlt": "Vue actuelle de {name}", + "live.plan.degreesValue": "{value} degrés", + "live.plan.inDegrees": "{label} en degrés", + "live.plan.imageDimensionsError": "Impossible de lire les dimensions de l’image", + "live.plan.loading": "Chargement des plans de bâtiment…", + "live.plan.created": "{name} créé", + "live.plan.renamed": "Renommé en {name}", + "live.plan.deleted": "{name} supprimé", + "live.plan.backgroundType": "L’arrière-plan doit être une image PNG ou JPEG", + "live.plan.backgroundTooLarge": "Image d’arrière-plan trop grande ; le maximum est de 768 Ko", + "live.plan.backgroundAspect": "Importée, mais les proportions de l’image ne correspondent à aucune taille de canevas valide", + "live.plan.backgroundUpdatedSave": "Arrière-plan mis à jour pour {name} ; enregistrez la disposition pour appliquer sa taille de canevas", + "live.plan.backgroundNotResized": "Arrière-plan importé, mais le canevas n’a pas été redimensionné : {error}", + "live.plan.backgroundUpdated": "Arrière-plan mis à jour pour {name}", + "live.plan.backgroundRemoved": "Arrière-plan supprimé", + "live.plan.saved": "{name} enregistré", + "live.plan.createTitle": "Créer un plan de bâtiment", + "live.plan.createDescription": "Donnez un nom clair à ce bâtiment ou étage. Dessinez la disposition ou importez une image de plan, puis placez les caméras.", + "live.plan.nameLabel": "Nom du plan", + "live.plan.namePlaceholder": "Bâtiment principal · Premier étage", + "live.plan.createConfirm": "Créer le plan", + "live.plan.eyebrow": "Plan de bâtiment", + "live.plan.placedSummary": "{placed} placées · {live} en direct", + "live.plan.zoomAndPan": "Zoom et déplacement du plan", + "live.plan.panLeft": "Déplacer vers la gauche", + "live.plan.panUp": "Déplacer vers le haut", + "live.plan.panDown": "Déplacer vers le bas", + "live.plan.panRight": "Déplacer vers la droite", + "live.plan.zoomOut": "Zoom arrière", + "live.plan.zoomIn": "Zoom avant", + "live.plan.fitTitle": "Ajuster le plan", + "live.plan.fit": "Ajuster", + "live.plan.backgroundMenu": "Arrière-plan…", + "live.plan.save": "Enregistrer le plan", + "live.plan.uploadBackgroundTitle": "Importer une image PNG ou JPEG comme arrière-plan du plan", + "live.plan.replaceBackground": "Remplacer l’arrière-plan", + "live.plan.uploadBackground": "Importer un arrière-plan", + "live.plan.removeBackground": "Retirer l’arrière-plan", + "live.plan.rename": "Renommer", + "live.plan.newPlan": "Nouveau plan", + "live.plan.editLayout": "Modifier la disposition", + "live.plan.placementHint": "Cliquez sur le plan pour positionner {name}", + "live.plan.clusterLabel": "{count} caméras ; zoom avant", + "live.plan.markerLabel": "{name} ; {availability} ; orientée à {rotation}° avec un champ de vision de {fov}°", + "live.plan.cameraFallback": "Caméra", + "live.plan.legendLive": "En direct", + "live.plan.canvas": "Canevas du plan", + "live.plan.width": "Largeur", + "live.plan.height": "Hauteur", + "live.plan.canvasHint": "L’importation d’une image d’arrière-plan redimensionne le canevas pour correspondre à celle-ci.", + "live.plan.canvasInvalid": "La largeur doit être comprise entre 400 et 4000, et la hauteur entre 300 et 4000.", + "live.plan.openLive": "Ouvrir la caméra en direct", + "live.plan.direction": "Direction de la caméra", + "live.plan.fov": "Champ de vision", + "live.plan.coverageNote": "Les secteurs n’indiquent que la direction et l’angle ; la distance sur le plan n’est pas calibrée.", + "live.plan.removeCamera": "Retirer du plan", + "live.plan.selectCamera": "Sélectionnez une caméra", + "live.plan.selectHintEditing": "Faites glisser les marqueurs placés pour affiner. Consultez l’état et ouvrez une vue en direct à la demande.", + "live.plan.selectHint": "Consultez l’état et ouvrez une vue en direct à la demande.", + "live.plan.cameras": "Caméras du plan", + "live.plan.findPlaceholder": "Rechercher sur ce plan…", + "live.plan.findLabel": "Rechercher une caméra sur ce plan", + "live.plan.unplaced": "Caméras non placées", + "live.plan.unplacedHint": "Sélectionnez une caméra, puis cliquez sur sa position sur le plan.", + "live.plan.renameTitle": "Renommer le plan", + "live.plan.renameDescription": "Les plans sont partagés avec tous les opérateurs de ce site.", + "live.plan.deleteTitle": "Supprimer le plan", + "live.plan.deleteMessage": "Supprimer « {name} » et son arrière-plan importé ? Les emplacements de caméras de ce plan sont supprimés ; les caméras elles-mêmes restent inchangées.", + "setupWizard.welcomeTitle": "Bienvenue dans LightNVR", + "setupWizard.welcomeIntro": "Configurons votre NVR en quelques étapes rapides. Vous pourrez revenir sur ces réglages à tout moment depuis la page Paramètres.", + "setupWizard.welcomeStorage": "Chemin de stockage et limites de taille", + "setupWizard.welcomePerformance": "Limites de performance pour votre nombre de caméras", + "setupWizard.welcomeSecurity": "Connexion sécurisée de l’administrateur", + "setupWizard.storageTitle": "Stockage et base de données", + "setupWizard.storageIntro": "Où les enregistrements et la base de données doivent-ils être stockés ?", + "setupWizard.storagePath": "Chemin de stockage des enregistrements", + "setupWizard.storagePathHint": "Chemin absolu où les fichiers vidéo sont écrits.", + "setupWizard.maxStorage": "Taille de stockage maximale (Go)", + "setupWizard.maxStorageHint": "0 = illimité.", + "setupWizard.dbPath": "Chemin de la base de données", + "setupWizard.dbPathHint": "Emplacement du fichier de base de données SQLite.", + "setupWizard.performanceTitle": "Performance", + "setupWizard.performanceIntro": "Ces réglages contrôlent la capacité, pas la qualité vidéo. La plupart des utilisateurs peuvent conserver les valeurs par défaut.", + "setupWizard.threadPool": "Taille du pool de threads de travail", + "setupWizard.threadPoolInfo": "concerne le travail en arrière-plan du web/serveur. La valeur recommandée par défaut est généralement la meilleure, sauf si vous optimisez les performances.", + "setupWizard.maxStreams": "Nombre maximal de flux simultanés", + "setupWizard.maxStreamsInfo": "est la limite de capacité des caméras pour cette instance en cours d’exécution. Réglez-la au moins au nombre de caméras que vous prévoyez d’ajouter, plus une petite marge.", + "setupWizard.important": "Important :", + "setupWizard.restartWarning": "si vous modifiez l’un de ces deux réglages, la nouvelle valeur est enregistrée maintenant, mais ne sera pas utilisée avant le redémarrage de LightNVR. Par exemple, si la limite actuelle de flux est de 1 et que vous la montez à 32, vous devez redémarrer avant d’ajouter des caméras au-delà de l’ancienne limite.", + "setupWizard.threadPoolHintCores": "Recommandé : {recommended} (2× votre processeur à {cores} cœurs). Cela contrôle les threads de travail en arrière-plan de libuv. Plage : 2–128.", + "setupWizard.threadPoolHint": "Recommandé : {recommended} (2× les cœurs de votre processeur). Cela contrôle les threads de travail en arrière-plan de libuv. Plage : 2–128.", + "setupWizard.maxStreamsHint": "Combien de caméras LightNVR peut garder actives à la fois. Par défaut 32, maximum {max}. Si vous prévoyez 8 caméras, choisissez au moins 8. Nécessite un redémarrage pour prendre effet.", + "setupWizard.completeTitle": "Configuration terminée !", + "setupWizard.saved": "Vos réglages ont été enregistrés avec succès.", + "setupWizard.notSaved": "Aucun réglage n’a été modifié — les valeurs par défaut seront utilisées.", + "setupWizard.restartRequired": "Redémarrage requis", + "setupWizard.restartRequiredInfo": "les modifications de la taille du pool de threads et/ou du nombre maximal de flux sont enregistrées, mais elles ne prendront effet qu’après le redémarrage du service. Redémarrez avant d’ajouter des caméras ou d’attendre l’application de la nouvelle limite de capacité.", + "setupWizard.saveFailed": "Échec de l’enregistrement des réglages : {error}", + "setupWizard.back": "Retour", + "setupWizard.saving": "Enregistrement…", + "setupWizard.saveContinue": "Enregistrer et continuer", + "setupWizard.next": "Suivant →", + "setupWizard.finish": "Aller au tableau de bord", + "setupWizard.skip": "Ignorer l’assistant de configuration", + "live.eptzCanvasLabel": "Vue électronique de pan, inclinaison et zoom pour objectif fisheye", + "live.eptzCanvasHint": "Faites glisser pour paner et incliner ; molette ou pincement pour zoomer ; Home réinitialise", + "live.eptzReset": "Réinitialiser la vue ePTZ", + "live.autoShort": "Auto", + "live.webrtcShort": "WebRTC", + "nav.investigation": "Investigation", + "availability.label": "Disponibilité des caméras", + "availability.live": "En direct maintenant", + "availability.offline": "Hors ligne (précédemment connecté)", + "availability.neverConnected": "Jamais connecté", + "availability.disabled": "Désactivé", + "availability.all": "Toutes les caméras", + "streams.inventory": "Inventaire", + "streams.configuration": "Configuration", + "events.tab": "Événements", + "events.eyebrow": "Intégrations pilotées par événements", + "events.title": "Événements et routage", + "events.description": "Transformez les événements caméra et système en flux MQTT durables pour l'automatisation, les services de notification et le traitement externe. LightNVR fournit l'interface événementielle ; la livraison par e-mail et SMS reste dans les services en aval.", + "events.routes": "Routes", + "events.destinations": "Destinations", + "events.catalog": "Catalogue d'événements", + "events.enable": "Activer", + "events.loadError": "Impossible de charger la configuration de routage des événements", + "events.accessDenied": "Accès refusé - privilèges insuffisants", + "events.summary.routes": "Routes", + "events.summary.enabled": "{count} activées", + "events.summary.destinations": "Destinations", + "events.summary.managedActive": "{count} gérées et actives", + "events.summary.types": "Types enregistrés", + "events.summary.registry": "Catalogue d'événements versionné", + "events.summary.interface": "Interface", + "events.summary.interfaceHelp": "Sortie d'événements durable", + "events.route.add": "Ajouter une route", + "events.route.addTitle": "Créer une route d'événements", + "events.route.editTitle": "Modifier la route d'événements", + "events.route.create": "Créer une route", + "events.route.editorDescription": "Choisissez les événements qualifiés, les caméras concernées, la destination et le contrôle du bruit des sources.", + "events.route.emptyTitle": "Aucune route d'événements configurée", + "events.route.emptyDescription": "Créez une route pour sélectionner les types d'événements, la portée des caméras, l'horaire, la politique de suppression et la destination MQTT.", + "events.route.enabled": "Route activée", + "events.route.enabledHelp": "Les événements correspondants sont acceptés pour une livraison durable", + "events.route.destination": "Destination", + "events.route.destinationHelp": "Un événement correspondant est persisté une fois pour chaque destination unique.", + "events.route.eventTypes": "Types d'événements", + "events.route.eventTypesHelp": "Sélectionnez un ou plusieurs contrats d'événements versionnés depuis le registre.", + "events.route.detectionFilters": "Filtrer les détections d'objets", + "events.route.detectionFiltersHelp": "Exigez éventuellement des étiquettes, des zones ou une confiance minimale pour les événements de détection d'objets.", + "events.route.healthFilters": "Filtrer les événements d'état du système", + "events.route.healthFiltersHelp": "Faites correspondre éventuellement des codes de conditions de santé ou des sévérités enregistrés. Les valeurs disponibles proviennent de cet enregistreur.", + "events.route.healthConditions": "Conditions de santé (toutes)", + "events.route.healthSeverities": "Sévérités (toutes)", + "events.route.healthRegistryUnavailable": "Le registre des conditions de santé est indisponible. Rechargez avant de configurer les filtres de conditions.", + "events.route.labels": "Étiquettes (toutes)", + "events.route.zones": "ID de zones (tous)", + "events.route.listHelp": "Séparez les valeurs par des virgules.", + "events.route.minConfidence": "Confiance minimale", + "events.route.confidenceHelp": "Une valeur de 0 à 1.", + "events.route.cameraScope": "Portée des caméras", + "events.route.cameraScopeHelp": "Réutilisez les emplacements de la flotte, les étiquettes, les collections d'attributs ou des caméras explicites sans charger toute la flotte.", + "events.route.allCameras": "Toutes les caméras", + "events.route.dynamicScope": "Sélecteur de caméras dynamique", + "events.route.systemScopeHelp": "Les événements système ne sont pas des caméras. Les sélecteurs de caméras sont indisponibles lorsque cette route inclut des événements de portée système.", + "events.route.schedule": "Horaire", + "events.route.scheduleHelp": "Utilisez l'heure de survenue de l'événement dans un fuseau horaire IANA ; les fenêtres nocturnes sont prises en charge.", + "events.route.restrictSchedule": "Uniquement pendant les fenêtres configurées", + "events.route.suppression": "Politique de bruit et de livraison", + "events.route.suppressionHelp": "Zéro désactive un contrôle. La suppression n'avance qu'après que cette destination accepte l'événement durable.", + "events.route.debounce": "Secondes de debounce", + "events.route.debounceHelp": "Les observations répétées prolongent cet intervalle silencieux.", + "events.route.cooldown": "Secondes de temporisation", + "events.route.cooldownHelp": "Intervalle minimal après un événement accepté.", + "events.route.grouping": "Secondes de fenêtre de regroupement", + "events.route.groupingHelp": "Conserver le premier événement et regrouper les doublons.", + "events.route.rateLimit": "Événements par minute", + "events.route.rateLimitHelp": "Maximum par fenêtre fixe pour chaque route et caméra.", + "events.route.deliveryPolicy": "Politique de diffusion", + "events.route.suppressionActive": "Contrôles de bruit actifs", + "events.route.everyMatch": "Chaque correspondance", + "events.route.preview": "Aperçu de la route", + "events.route.previewing": "Aperçu en cours…", + "events.route.previewResult": "Aperçu de la route", + "events.route.cameraMatches": "{count} caméras correspondent", + "events.route.previewNoPublish": "L'aperçu valide la règle complète et résout un échantillon de caméras ; il ne publie jamais d'événement.", + "events.route.systemPreviewHelp": "Les événements système ignorent la sélection de caméras et signalent donc zéro caméra correspondante dans cet aperçu.", + "events.route.created": "Route d'événements créée", + "events.route.updated": "Route d'événements mise à jour", + "events.route.deleted": "Route d'événements supprimée", + "events.route.disabled": "Route d'événements désactivée", + "events.route.enabledMessage": "Route d'événements activée", + "events.route.deleteConfirm": "Supprimer la route d'événements « {name} » ?", + "events.route.validation.name": "Saisissez un nom de route.", + "events.route.validation.destination": "Choisissez une destination.", + "events.route.validation.event_types": "Sélectionnez au moins un type d'événement.", + "events.route.validation.selector": "Complétez ou corrigez le sélecteur de caméras.", + "events.route.validation.system_scope": "Les sélecteurs de caméras ne peuvent pas être utilisés avec des événements de portée système.", + "events.route.validation.detection_type": "Les filtres de détection nécessitent le type d'événement de détection d'objets.", + "events.route.validation.detection_filter": "Ajoutez au moins un libellé de détection, une zone ou un seuil de confiance.", + "events.route.validation.confidence": "La confiance minimale doit être comprise entre 0 et 1.", + "events.route.validation.predicate_mix": "Les filtres de détection et de santé ne peuvent pas être combinés dans une même route.", + "events.route.validation.health_type": "Les filtres de santé nécessitent uniquement des types d'événements de santé système enregistrés.", + "events.route.validation.health_filter": "Sélectionnez au moins une condition de santé ou une sévérité enregistrée.", + "events.route.validation.health_condition": "Sélectionnez uniquement les codes de condition renvoyés par le registre de santé de l'enregistreur.", + "events.route.validation.health_severity": "Sélectionnez uniquement les sévérités prises en charge par les types d'événements de santé sélectionnés.", + "events.route.validation.timezone": "Saisissez un fuseau horaire IANA installé tel que UTC ou America/New_York.", + "events.route.validation.schedule_window": "Chaque fenêtre de planification nécessite au moins un jour et des heures de début et de fin valides distinctes.", + "events.route.validation.suppression": "Les valeurs de suppression doivent être des nombres entiers dans les plages autorisées.", + "events.schedule.timezone": "Fuseau horaire", + "events.schedule.timezoneHelp": "Doit être présent dans la base de données de fuseaux horaires de l'enregistreur.", + "events.schedule.addWindow": "Ajouter une fenêtre horaire", + "events.schedule.windowNumber": "Fenêtre {number}", + "events.schedule.start": "Début", + "events.schedule.end": "Fin", + "events.schedule.sunday": "Dim", + "events.schedule.monday": "Lun", + "events.schedule.tuesday": "Mar", + "events.schedule.wednesday": "Mer", + "events.schedule.thursday": "Jeu", + "events.schedule.friday": "Ven", + "events.schedule.saturday": "Sam", + "events.destination.add": "Ajouter une destination", + "events.destination.addTitle": "Ajouter une destination MQTT", + "events.destination.editTitle": "Modifier la destination MQTT", + "events.destination.create": "Créer une destination", + "events.destination.editorDescription": "Configurez une sortie d'événements durable. Les identifiants restent en écriture seule et ne sont jamais renvoyés par l'API.", + "events.destination.default": "Paramètres MQTT par défaut", + "events.destination.settingsManaged": "Paramètres gérés", + "events.destination.defaultDescription": "La configuration MQTT existante reste disponible sous mqtt:default et est utilisée par {count} routes.", + "events.destination.openSettings": "Ouvrir les paramètres MQTT", + "events.destination.emptyTitle": "Aucune destination gérée", + "events.destination.emptyDescription": "Ajoutez un autre courtier MQTT pour la livraison indépendante d'événements vers un connecteur cloud, un système d'automatisation ou un service de notification.", + "events.destination.identity": "Identité de la destination", + "events.destination.enabled": "Destination activée", + "events.destination.enabledHelp": "Se connecter et vider sa file d'attente durable", + "events.destination.active": "Actif", + "events.destination.paused": "En pause", + "events.destination.pause": "Pause", + "events.destination.broker": "Broker", + "events.destination.host": "Hôte du broker", + "events.destination.hostHelp": "Nom d'hôte ou adresse IP uniquement ; n'incluez pas de schéma d'URL.", + "events.destination.port": "Port", + "events.destination.clientId": "ID client", + "events.destination.clientIdHelp": "Doit être unique pour cette connexion au broker.", + "events.destination.topic": "Sujet", + "events.destination.topicTemplate": "Modèle de sujet", + "events.destination.topicHelp": "Doit inclure les jetons event-type et subject-ID ; les caractères génériques MQTT ne sont pas autorisés.", + "events.destination.keepalive": "Keepalive en secondes", + "events.destination.statusTopicTemplate": "Sujet d'état de présence", + "events.destination.statusTopicHelp": "Facultatif. Doit inclure {installation_uuid} ; {destination_uuid} est également disponible. Les caractères génériques MQTT ne sont pas autorisés.", + "events.destination.statusTopicEnabled": "La présence est explicitement activée pour cette destination. Le sujet n'est jamais déduit du sujet d'événement.", + "events.destination.statusTopicDisabled": "La présence est désactivée pour cette destination. Laissez ce champ vide pour la maintenir désactivée.", + "events.destination.qos": "Qualité de service", + "events.destination.qos0": "envoyer une fois", + "events.destination.qos1": "au moins une fois", + "events.destination.qos2": "exactement une fois", + "events.destination.authentication": "Authentification", + "events.destination.passwordPreserved": "Laissez vide pour conserver le mot de passe en écriture seule stocké.", + "events.destination.passwordOptional": "Facultatif lorsque le broker autorise les clients anonymes.", + "events.destination.clearPassword": "Effacer le mot de passe stocké", + "events.destination.transportSecurity": "Sécurité du transport", + "events.destination.tlsMode": "Mode TLS", + "events.destination.tlsSystem": "Magasin de confiance du système", + "events.destination.tlsCustomCa": "Autorité de certification personnalisée", + "events.destination.tlsMutual": "TLS mutuel", + "events.destination.tlsDisabled": "Désactivé (texte en clair)", + "events.destination.tlsHelp.system": "Vérifiez le certificat du broker par rapport au magasin de confiance du système d'exploitation.", + "events.destination.tlsHelp.custom_ca": "Vérifier le broker à l'aide d'un fichier d'autorité de certification PEM explicite.", + "events.destination.tlsHelp.mutual": "Vérifier le broker avec une CA explicite et présenter un certificat et une clé client.", + "events.destination.tlsHelp.disabled": "Aucun chiffrement de transport ni vérification d'identité du broker.", + "events.destination.caFile": "Fichier CA", + "events.destination.certFile": "Fichier de certificat client", + "events.destination.keyFile": "Fichier de clé client", + "events.destination.absolutePathHelp": "Utilisez un chemin absolu lisible par le service LightNVR.", + "events.destination.plaintextWarning": "MQTT en clair peut exposer les métadonnées d'événements et les identifiants. Utilisez-le uniquement sur un réseau de confiance isolé.", + "events.destination.security": "Sécurité", + "events.destination.tls.system": "Confiance système", + "events.destination.tls.custom_ca": "CA personnalisée", + "events.destination.tls.mutual": "TLS mutuel", + "events.destination.tls.disabled": "En clair", + "events.destination.routes": "Routes", + "events.destination.presence": "Sujet de présence", + "events.destination.deleteInUse": "Supprimez ou redirigez les routes avant de supprimer cette destination.", + "events.destination.created": "Destination MQTT créée", + "events.destination.updated": "Destination MQTT mise à jour", + "events.destination.deleted": "Destination MQTT supprimée", + "events.destination.pausedMessage": "Destination MQTT en pause ; les événements en file d'attente restent persistants jusqu'à expiration.", + "events.destination.enabledMessage": "Destination MQTT activée", + "events.destination.deleteConfirm": "Supprimer la destination MQTT « {name} » ?", + "events.destination.validation.name": "Saisissez un nom de destination.", + "events.destination.validation.host": "Saisissez un nom d'hôte ou une adresse IP du broker.", + "events.destination.validation.client_id": "Saisissez un ID client du broker.", + "events.destination.validation.topic": "Le sujet doit inclure les jetons event-type et subject-ID et ne peut pas contenir de caractères génériques MQTT.", + "events.destination.validation.status_topic": "Le sujet de présence facultatif doit inclure le jeton installation UUID, utiliser uniquement les jetons pris en charge et ne peut pas contenir de caractères génériques MQTT.", + "events.destination.validation.port": "Le port doit être un nombre entier compris entre 1 et 65535.", + "events.destination.validation.keepalive": "Le keepalive doit être un nombre entier compris entre 5 et 3600 secondes.", + "events.destination.validation.qos": "Choisissez un QoS MQTT 0, 1 ou 2.", + "events.destination.validation.username": "Un mot de passe configuré nécessite un nom d'utilisateur.", + "events.destination.validation.ca_file": "Ce mode TLS nécessite un chemin absolu vers le fichier CA.", + "events.destination.validation.mutual_files": "Le TLS mutuel nécessite des chemins absolus pour l'autorité de certification, le certificat client et la clé client.", + "fleet.eyebrow": "Opérations sur les caméras", + "fleet.title": "Inventaire des caméras", + "fleet.description": "Trouver, évaluer et organiser les caméras sur de grands déploiements sans charger l'inventaire complet dans le navigateur.", + "fleet.summary": "Résumé de l'état du parc", + "fleet.totalCameras": "Caméras correspondantes", + "fleet.needsAttention": "Dégradé", + "fleet.searchLabel": "Rechercher des caméras", + "fleet.searchPlaceholder": "Rechercher par nom, adresse, emplacement, étiquette, fabricant ou modèle…", + "fleet.resultCount": "{count} caméras", + "fleet.filters": "Filtres", + "fleet.clearFilters": "Effacer les filtres", + "fleet.filter.health": "Santé", + "fleet.filter.enabled": "État de la caméra", + "fleet.filter.anyState": "Tous les états", + "fleet.filter.recording": "Mode d'enregistrement", + "fleet.filter.location": "Sous-arborescence d'emplacement", + "fleet.filter.allLocations": "Tous les emplacements", + "fleet.filter.tags": "Étiquettes (correspondance quelconque)", + "fleet.filter.collection": "Collection de caméras", + "fleet.health.unknown": "Inconnu", + "fleet.health.up": "En ligne", + "fleet.health.degraded": "Dégradé", + "fleet.health.down": "Hors ligne", + "fleet.health.disabled": "Désactivé", + "fleet.recording.off": "Arrêté", + "fleet.recording.continuous": "Continu", + "fleet.recording.detection": "Détection", + "fleet.recordingActive": "Enregistrement en cours", + "fleet.recordingInactive": "Non enregistré", + "fleet.column.camera": "Caméra", + "fleet.column.health": "Santé", + "fleet.column.location": "Emplacement", + "fleet.column.tags": "Étiquettes", + "fleet.column.recording": "Enregistrement", + "fleet.viewLive": "Vue en direct", + "fleet.lastFrame": "Dernière image", + "fleet.noAddress": "Adresse indisponible", + "fleet.unassigned": "Non attribué", + "fleet.loading": "Chargement du parc de caméras…", + "fleet.refreshing": "Actualisation…", + "fleet.loadError": "Impossible de charger le parc de caméras", + "fleet.emptyTitle": "Aucune caméra configurée", + "fleet.emptyDescription": "Ajoutez un flux pour le rendre disponible dans l'espace de travail du parc.", + "fleet.emptyFilteredTitle": "Aucune caméra ne correspond à cette vue", + "fleet.emptyFilteredDescription": "Essayez d'élargir la recherche ou de supprimer un ou plusieurs filtres.", + "fleet.paginationSummary": "Affichage de {first}–{last} sur {total}", + "fleet.perPage": "Par page", + "fleet.pageOf": "Page {page} sur {pages}", + "fleet.selectPage": "Sélectionner toutes les caméras de cette page", + "fleet.selectCamera": "Sélectionner {name}", + "fleet.selectedCount": "{count} caméras sélectionnées", + "fleet.organizeSelected": "Organiser la sélection", + "fleet.clearSelection": "Effacer la sélection", + "fleet.organization.manage": "Gérer l'organisation", + "fleet.organization.title": "Organisation des caméras", + "fleet.organization.description": "Maintenez une hiérarchie d'emplacements réutilisable et un dictionnaire d'étiquettes normalisé pour le parc de caméras.", + "fleet.organization.locations": "Emplacements", + "fleet.organization.tags": "Étiquettes", + "fleet.organization.locationsDescription": "Modélisez les sites, bâtiments, étages et zones opérationnelles sous forme de hiérarchie navigable.", + "fleet.organization.tagsDescription": "Utilisez un dictionnaire d'étiquettes structuré plutôt que des libellés libres incohérents.", + "fleet.organization.addRoot": "Ajouter un emplacement de premier niveau", + "fleet.organization.addLocation": "Ajouter un emplacement", + "fleet.organization.editLocation": "Modifier l'emplacement", + "fleet.organization.addChild": "Ajouter un sous-emplacement", + "fleet.organization.type": "Type", + "fleet.organization.parent": "Emplacement parent", + "fleet.organization.topLevel": "Niveau supérieur", + "fleet.organization.sortOrder": "Ordre de tri", + "fleet.organization.contents": "Contenu", + "fleet.organization.cameras": "Caméras", + "fleet.organization.system": "Système", + "fleet.organization.contentCounts": "{cameras} caméras · {children} sous-emplacements", + "fleet.organization.locationNotEmpty": "Déplacez les caméras et supprimez les sous-emplacements d'abord", + "fleet.organization.noLocations": "Aucun emplacement n'est configuré.", + "fleet.organization.locationCreated": "Emplacement créé", + "fleet.organization.locationUpdated": "Emplacement mis à jour", + "fleet.organization.locationDeleted": "Emplacement supprimé", + "fleet.organization.deleteLocationConfirm": "Supprimer l'emplacement « {name} » ?", + "fleet.organization.addTag": "Ajouter un tag", + "fleet.organization.editTag": "Modifier le tag", + "fleet.organization.tagLabel": "Tag", + "fleet.organization.color": "Couleur (#RRGGBB)", + "fleet.organization.tagDescription": "Description", + "fleet.organization.noTags": "Aucun tag normalisé n'est configuré.", + "fleet.organization.tagCreated": "Tag créé", + "fleet.organization.tagUpdated": "Tag mis à jour", + "fleet.organization.tagDeleted": "Tag supprimé", + "fleet.organization.deleteTagConfirm": "Supprimer « {name} » ? Il est actuellement attribué à {count} caméras.", + "fleet.organization.merge": "Fusionner", + "fleet.organization.mergeTagNamed": "Fusionner « {name} »", + "fleet.organization.mergeInto": "Fusionner dans", + "fleet.organization.chooseTag": "Choisissez le tag à conserver", + "fleet.organization.mergeWarning": "Toutes les attributions de caméras sont déplacées vers le tag conservé ; le tag source est ensuite supprimé.", + "fleet.organization.tagsMerged": "Tags fusionnés", + "fleet.organization.saveError": "Impossible d'enregistrer : {message}", + "fleet.organization.deleteError": "Suppression impossible : {message}", + "fleet.locationType.site": "Site", + "fleet.locationType.building": "Bâtiment", + "fleet.locationType.floor": "Étage", + "fleet.locationType.area": "Secteur", + "fleet.locationType.zone": "Zone", + "fleet.locationType.system": "Système", + "fleet.bulk.title": "Organiser les caméras sélectionnées", + "fleet.bulk.description": "Appliquer les modifications d'emplacement et d'étiquette à {count} caméras avec une concurrence limitée.", + "fleet.bulk.location": "Attribution d'emplacement", + "fleet.bulk.locationHelp": "Toutes les caméras sélectionnées seront déplacées vers l'emplacement choisi.", + "fleet.bulk.keepLocations": "Conserver les emplacements actuels", + "fleet.bulk.tags": "Attribution d'étiquettes", + "fleet.bulk.tagsHelp": "Ajouter ou supprimer des étiquettes sans affecter les autres attributions, ou remplacer explicitement l'ensemble des étiquettes.", + "fleet.bulk.tagOperation.none": "Conserver", + "fleet.bulk.tagOperation.add": "Ajouter", + "fleet.bulk.tagOperation.remove": "Supprimer", + "fleet.bulk.tagOperation.replace": "Remplacer tout", + "fleet.bulk.replaceWarning": "Remplacer tout supprime toutes les étiquettes actuelles avant d'appliquer cette sélection. Une sélection vide efface toutes les étiquettes.", + "fleet.bulk.apply": "Appliquer les modifications", + "fleet.bulk.working": "Application des modifications…", + "fleet.bulk.success": "{count} caméras mises à jour", + "fleet.bulk.partial": "{succeeded} caméras mises à jour ; {failed} en échec", + "fleet.bulk.error": "Impossible d'organiser les caméras : {message}", + "fleet.bulk.failures": "Caméras n'ayant pas pu être mises à jour", + "fleet.queues.degraded": "Flux dégradés", + "fleet.queues.offline": "Caméras hors ligne", + "fleet.queues.oldest": "Plus ancien : {time}", + "fleet.queues.noneActive": "Aucune condition active", + "fleet.views.title": "Vues enregistrées", + "fleet.views.choose": "Choisir une vue enregistrée", + "fleet.views.none": "Aucune vue enregistrée", + "fleet.views.shared": "Partagé", + "fleet.views.saveCurrent": "Enregistrer la vue actuelle", + "fleet.views.name": "Nom de la vue", + "fleet.views.share": "Partager avec tous les opérateurs", + "fleet.views.saved": "Vue de parc enregistrée", + "fleet.views.saveError": "Impossible d'enregistrer la vue : {message}", + "fleet.views.deleted": "Vue de parc supprimée", + "fleet.views.deleteConfirm": "Supprimer la vue enregistrée « {name} » ?", + "fleet.views.deleteError": "Impossible de supprimer la vue : {message}", + "fleet.views.unsupported": "Ce sélecteur enregistré ne peut pas être représenté par les contrôles de filtre actuels.", + "collections.manage": "Collections", + "collections.all": "Toutes les collections", + "collections.filter": "Collection", + "collections.loadMembersError": "Impossible de charger les caméras de la collection : {message}", + "collections.title": "Collections de caméras", + "collections.subtitle": "Créez des groupes de caméras réutilisables pour les opérations, les vues enregistrées et les flux de travail en aval.", + "collections.listDescription": "Les collections statiques conservent une appartenance explicite ; les collections intelligentes évaluent en continu les règles du parc.", + "collections.create": "Créer une collection", + "collections.edit": "Modifier la collection", + "collections.editorDescription": "Les définitions de collections utilisent des UUID stables de caméras, d'emplacements et d'étiquettes.", + "collections.backToList": "Retour aux collections", + "collections.type": "Type de collection", + "collections.type.static": "Statique", + "collections.type.smart": "Intelligente", + "collections.description": "Description", + "collections.shared": "Collection partagée", + "collections.sharedHelp": "Autoriser les autres utilisateurs autorisés à voir cette collection ; les règles d'accès aux caméras s'appliquent toujours.", + "collections.typeChangeWarning": "La modification du type de collection remplace son modèle d'appartenance. Les membres statiques ou les règles intelligentes du type précédent ne s'appliqueront plus.", + "collections.selectorError": "Le sélecteur n'est pas valide : {message}", + "collections.created": "Collection créée", + "collections.updated": "Collection mise à jour", + "collections.saveError": "Impossible d'enregistrer la collection : {message}", + "collections.loadError": "Impossible de charger la collection : {message}", + "collections.cameras": "caméras", + "collections.visibility.shared": "Partagées", + "collections.visibility.private": "Privées", + "collections.selectorRedacted": "Règles privées", + "collections.emptyTitle": "Aucune collection pour le moment", + "collections.emptyAdmin": "Créez un groupe statique ou une vue intelligente basée sur des règles pour réutiliser des sélections de caméras.", + "collections.emptyViewer": "Aucune collection partagée n'est disponible pour votre périmètre de caméras.", + "collections.deleteConfirm": "Supprimer la collection « {name} » ?", + "collections.deleted": "Collection supprimée", + "collections.deleteError": "Impossible de supprimer la collection : {message}", + "collections.preview.title": "Aperçu des règles", + "collections.preview.matches": "{count} caméras correspondantes", + "collections.preview.action": "Aperçu", + "collections.preview.hide": "Masquer l'aperçu", + "collections.preview.loading": "Évaluation…", + "collections.preview.empty": "Aucune caméra ne correspond actuellement.", + "collections.preview.sample": "Affichage d'un échantillon de {count} caméras sur {total} correspondances.", + "collections.preview.error": "Impossible de prévisualiser la collection : {message}", + "collections.members.title": "Membres statiques", + "collections.members.selected": "{count} caméras sélectionnées sur toutes les pages", + "collections.members.search": "Rechercher des caméras…", + "collections.members.selectPage": "Sélectionner cette page", + "collections.members.empty": "Aucune caméra ne correspond à cette recherche.", + "collections.builder.title": "Règles intelligentes", + "collections.builder.description": "Les règles sont évaluées selon l'organisation, la configuration, les capacités et l'état de santé actuels des caméras.", + "collections.builder.match": "Correspondance", + "collections.builder.allRules": "toutes les règles", + "collections.builder.anyRule": "n'importe quelle règle", + "collections.builder.addRule": "Ajouter une règle", + "collections.builder.removeRule": "Supprimer la règle", + "collections.builder.matchesAll": "Sans règle complète, cette collection correspond à toutes les caméras du périmètre autorisé de l'utilisateur.", + "collections.builder.incompleteRule": "Complétez ou supprimez chaque règle avant d'enregistrer.", + "collections.builder.chooseLocation": "Choisir un sous-arbre d'emplacement", + "collections.builder.vendorPlaceholder": "Noms de fabricants, séparés par des virgules", + "collections.builder.modelPlaceholder": "Noms de modèles, séparés par des virgules", + "collections.builder.advancedMode": "JSON avancé", + "collections.builder.visualMode": "Constructeur visuel", + "collections.builder.cannotVisualize": "Ce sélecteur contient une logique imbriquée ou avancée que le constructeur visuel ne peut pas représenter de manière fiable.", + "collections.rule.location_subtree": "Emplacement dans", + "collections.rule.camera_uuid": "Caméras spécifiques", + "collections.rule.tag_any": "Possède un tag", + "collections.rule.tag_all": "Possède tous les tags", + "collections.rule.tag_none": "Ne possède aucun tag", + "collections.rule.health": "État de santé", + "collections.rule.enabled": "Caméra", + "collections.rule.recording_mode": "Mode d'enregistrement", + "collections.rule.capability_any": "Possède une capacité", + "collections.rule.capability_all": "Possède toutes les capacités", + "collections.rule.vendor": "Fabricant", + "collections.rule.model": "Modèle", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Canal retour audio", + "streamHealth.observedFps": "IPS observé", + "streamHealth.expectedFps": "Attendu", + "streamHealth.fpsHelp": "Observé par LightNVR ; attendu provient des métadonnées du flux de la caméra.", + "login.passwordChanged": "Mot de passe modifié avec succès. Connectez-vous avec votre nouveau mot de passe.", + "passwordChangeRequired.title": "Modifier le mot de passe par défaut", + "passwordChangeRequired.description": "Cette installation utilise toujours le mot de passe administrateur par défaut. Remplacez-le avant de continuer vers LightNVR. L'authentification multifacteur, si activée, sera vérifiée lors de votre prochaine connexion.", + "passwordChangeRequired.currentPassword": "Mot de passe actuel", + "passwordChangeRequired.newPassword": "Nouveau mot de passe", + "passwordChangeRequired.confirmPassword": "Confirmer le nouveau mot de passe", + "passwordChangeRequired.passwordHelp": "Utilisez au moins 8 caractères. Le mot de passe ne peut pas être admin.", + "passwordChangeRequired.submit": "Changer le mot de passe", + "passwordChangeRequired.saving": "Changement du mot de passe…", + "passwordChangeRequired.error.currentRequired": "Saisissez votre mot de passe actuel.", + "passwordChangeRequired.error.tooShort": "Le nouveau mot de passe doit contenir au moins 8 caractères.", + "passwordChangeRequired.error.defaultPassword": "Le nouveau mot de passe ne peut pas être admin.", + "passwordChangeRequired.error.mismatch": "Les nouveaux mots de passe ne correspondent pas.", + "passwordChangeRequired.error.generic": "Le mot de passe n'a pas pu être modifié. Réessayez.", + "settings.tab.health": "Santé", + "settings.tab.workspaces": "Espaces de travail", + "settings.health.title": "Santé de l'hôte et du matériel", + "settings.health.description": "Configurez la surveillance bornée du système d'exploitation et du matériel sans exposer les chemins d'appareils ni les secrets.", + "settings.health.enabled": "Activer la surveillance de santé", + "settings.health.enabledHelp": "Collectez les signaux pris en charge pour l'hôte, les services, le stockage, le réseau et le matériel.", + "settings.health.profile": "Profil de stratégie", + "settings.health.profileHelp": "Équilibré est le défaut normal ; conservateur exige des preuves plus solides avant d'alerter.", + "settings.health.profile.balanced": "Équilibré", + "settings.health.profile.conservative": "Conservateur", + "settings.health.hardwareProvider": "Fournisseur matériel", + "settings.health.provider.auto": "Automatique (fournisseurs du noyau)", + "settings.health.provider.smartctl": "smartctl (explicite)", + "settings.health.providerHelp.auto": "Utilise uniquement les fournisseurs bornés sysfs, NVMe et du noyau ; smartctl n'est jamais déduit.", + "settings.health.providerHelp.smartctl": "Active explicitement le fournisseur JSON smartctl borné optionnel pour les appareils découverts.", + "settings.health.providerHelp.disabled": "Désactive les fournisseurs matériels optionnels tout en laissant la surveillance de santé portable disponible.", + "settings.health.writeProbe": "Activer la sonde d'écriture du stockage", + "settings.health.writeProbeHelp": "Effectue périodiquement la sonde bornée de la cible d'enregistrement configurée.", + "settings.health.cadences": "Cadences d'échantillonnage", + "settings.health.cadencesHelp": "Les intervalles doivent rester ordonnés du plus rapide à l'échantillonnage des appareils et dans les limites du serveur.", + "settings.health.fastInterval": "Intervalle rapide", + "settings.health.normalInterval": "Intervalle normal", + "settings.health.slowInterval": "Intervalle lent", + "settings.health.deviceInterval": "Intervalle appareil", + "settings.health.presenceInterval": "Intervalle de présence", + "settings.health.retention": "Rétention des incidents", + "settings.health.conditions": "Substitutions de conditions", + "settings.health.conditionsHelp": "Substituez uniquement les codes de conditions et les unités renvoyés par le registre de politique effective.", + "settings.health.conditionOverride": "substitution de condition", + "settings.health.overrideMode": "Mode de substitution", + "settings.health.overrideModeHelp": "Héritez du profil sélectionné, sélectionnez un autre profil borné, désactivez la condition ou définissez des seuils validés.", + "settings.health.profileDefault": "Utiliser le profil sélectionné", + "settings.health.custom": "Seuils personnalisés", + "settings.health.warning": "Seuil d'avertissement", + "settings.health.critical": "Seuil critique", + "settings.health.recovery": "Seuil de rétablissement", + "settings.health.warning_for_seconds": "Secondes de maintien d'avertissement", + "settings.health.critical_for_seconds": "Secondes de maintien critique", + "settings.health.recovery_for_seconds": "Secondes de maintien de rétablissement", + "settings.health.clearOverrides": "Effacer les substitutions", + "settings.health.registryUnavailable": "Le serveur n'a pas renvoyé de registre de conditions. Rechargez avant de modifier les substitutions.", + "settings.health.resetDefaults": "Réinitialiser les valeurs par défaut de santé", + "settings.health.reloadGuidance": "L'enregistrement est atomique. Rechargez après un enregistrement réussi pour confirmer la politique effective ; ne redémarrez que si le serveur le demande explicitement.", + "settings.health.validation.profile": "Choisissez un profil de santé pris en charge.", + "settings.health.validation.provider": "Choisissez un fournisseur matériel pris en charge.", + "settings.health.validation.healthFastIntervalSeconds": "L'intervalle rapide doit être un nombre entier de 5 à 60 secondes.", + "settings.health.validation.healthNormalIntervalSeconds": "L'intervalle normal doit être un nombre entier de 15 à 600 secondes.", + "settings.health.validation.healthSlowIntervalSeconds": "L'intervalle lent doit être un nombre entier de 60 à 3600 secondes.", + "settings.health.validation.healthDeviceIntervalSeconds": "L'intervalle de périphérique doit être un nombre entier de 300 à 86400 secondes.", + "settings.health.validation.healthPresenceIntervalSeconds": "L'intervalle de présence doit être un nombre entier de 15 à 3600 secondes.", + "settings.health.validation.healthIncidentRetentionDays": "La rétention des incidents doit être un nombre entier de 7 à 3650 jours.", + "settings.health.validation.ordered": "Les intervalles d'échantillonnage doivent être ordonnés : rapide, normal, lent, puis périphérique.", + "settings.health.validation.overrides": "Les substitutions de conditions doivent utiliser des codes uniques et des profils pris en charge par le registre du serveur.", + "settings.health.validation.thresholds": "Les seuils personnalisés doivent être des valeurs finies comprises dans les bornes d'unité de la condition.", + "settings.health.validation.thresholdOrder": "Les seuils d'avertissement, critique et de rétablissement doivent préserver la direction d'alerte et l'hystérésis de la condition.", + "settings.health.validation.dwell": "Les temps de maintien doivent être des secondes entières inférieures à sept jours ; le maintien d'avertissement et de rétablissement ne peut pas être nul.", + "workspaces.title": "Espaces de travail opérateur", + "workspaces.description": "Choisissez les espaces de travail spécialisés à afficher dans votre navigation et l'interface.", + "workspaces.saved": "Préférences d'espace de travail enregistrées", + "workspaces.saveError": "Impossible d'enregistrer les préférences d'espace de travail : {message}", + "workspaces.loadError": "Impossible de charger les préférences d'espace de travail.", + "workspaces.showWorkspace": "Afficher {name}", + "workspaces.authorizationNote": "Ce paramètre contrôle uniquement l'affichage. Les URL directes et l'accès API suivent toujours votre politique d'autorisation.", + "workspaces.liveNavigator": "Navigateur en direct amélioré", + "workspaces.liveNavigatorDescription": "Arborescence des emplacements, filtres de disponibilité, dispositions enregistrées et événements récents.", + "workspaces.investigation": "Investigation", + "workspaces.investigationDescription": "Rechercher, corréler, protéger et exporter les preuves enregistrées.", + "settings.reduceMotion": "Réduire les animations", + "settings.reduceMotionHelp": "Désactive les animations et transitions non essentielles. Le mode Auto suit la préférence de votre système d'exploitation.", + "settings.reduceMotionPreference": "Préférence de réduction des animations", + "settings.reduceMotionAuto": "Auto", + "settings.reduceMotionOn": "Activé", + "settings.reduceMotionOff": "Désactivé", + "settings.audioCompliance": "Conformité audio", + "settings.disableAudioGlobally": "Désactiver l'audio sur cette instance", + "settings.audioDisabled": "L'audio est désactivé globalement", + "settings.audioComplianceHelp": "Empêche l'écoute en direct, la communication bidirectionnelle et l'audio dans les nouveaux enregistrements sur cette instance. L'enregistrement redémarre les sessions multimédias go2rtc actives. Les enregistrements existants ne sont pas modifiés.", + "tokens.manage": "Gérer l'accès API", + "tokens.title": "Accès API — {username}", + "tokens.description": "Créez des identifiants à périmètre restreint pour les intégrations et révoquez-les indépendamment.", + "tokens.recommendedTitle": "Les jetons à périmètre défini sont recommandés", + "tokens.recommendedDescription": "Chaque jeton a une date d'expiration, des actions explicites et un périmètre de caméras, et ne peut jamais dépasser la politique d'accès actuelle de l'utilisateur.", + "tokens.coverageNotice": "Les permissions disponibles reflètent ce que ce serveur applique. Un jeton ne peut utiliser que les permissions déjà accordées à son utilisateur.", + "tokens.createTitle": "Créer un jeton à périmètre défini", + "tokens.createDescription": "Utilisez un jeton par intégration afin de pouvoir l'identifier, le faire tourner et le révoquer sans perturber le reste.", + "tokens.name": "Nom de l'intégration", + "tokens.namePlaceholder": "ex. : Pont PTZ du garage nord", + "tokens.expiry": "Expire après", + "tokens.expiryDays": "{days} jours", + "tokens.actions": "Actions autorisées", + "tokens.actionsHelp": "Sélectionnez uniquement ce dont cette intégration a besoin. Les actions destructives nécessitent leur propre jeton.", + "tokens.destructive": "Destructive", + "tokens.noEnforcedActions": "Aucune action activable par jeton n'est disponible avec cette version du serveur.", + "tokens.scope.label": "Périmètre des caméras", + "tokens.scope.all": "Flotte de caméras complète", + "tokens.scope.collection": "Collection partagée", + "tokens.scope.selector": "Sélecteur personnalisé", + "tokens.scope.chooseCollection": "Collection de caméras partagée", + "tokens.scope.allValue": "Flotte complète", + "tokens.scope.collectionValue": "Collection : {name}", + "tokens.scope.selectorValue": "Sélecteur dynamique personnalisé", + "tokens.create": "Créer un jeton", + "tokens.creating": "Création du jeton…", + "tokens.createdSuccess": "Jeton d'API à périmètre créé", + "tokens.createError": "Impossible de créer le jeton d'API : {message}", + "tokens.invalidResponse": "Le serveur a renvoyé une réponse d'identifiants incomplète.", + "tokens.existingTitle": "Jetons existants", + "tokens.existingDescription": "Seuls les préfixes et les métadonnées restent disponibles après la création.", + "tokens.emptyTitle": "Aucun jeton actif", + "tokens.emptyDescription": "Créez un jeton à périmètre pour la première intégration nécessitant un accès à l'API.", + "tokens.showInactive": "Afficher {count} inactif(s)", + "tokens.status.active": "Actif", + "tokens.status.expired": "Expiré", + "tokens.status.revoked": "Révoqué", + "tokens.expires": "Expire", + "tokens.expiresValue": "Expire le {date}", + "tokens.created": "Créé", + "tokens.lastUsed": "Dernière utilisation", + "tokens.revoke": "Révoquer", + "tokens.revoking": "Révocation…", + "tokens.revokeConfirm": "Révoquer « {description} » ? Les requêtes l'utilisant cesseront de fonctionner immédiatement.", + "tokens.revokedSuccess": "Jeton API révoqué", + "tokens.revokeError": "Impossible de révoquer le jeton API : {message}", + "tokens.validation.missing_description": "Nommez l'intégration qui utilisera ce jeton.", + "tokens.validation.description_too_long": "Le nom de l'intégration doit contenir moins de 128 caractères.", + "tokens.validation.invalid_expiry": "Choisissez une durée de validité du jeton entre 1 et 365 jours.", + "tokens.validation.missing_actions": "Choisissez au moins une action autorisée.", + "tokens.validation.invalid_action": "Une ou plusieurs actions sélectionnées ne sont pas activées pour les jetons sur ce serveur.", + "tokens.validation.invalid_scope": "Choisissez un périmètre de caméra valide.", + "tokens.validation.requires_all_scope": "Les permissions hors caméra nécessitent le périmètre Flotte complète de caméras. Choisissez ce périmètre ou retirez ces permissions.", + "tokens.validation.missing_collection": "Choisissez une collection partagée disponible.", + "tokens.validation.invalid_selector": "Complétez ou corrigez le sélecteur de caméra personnalisé.", + "tokens.secret.oneTime": "Affiché une seule fois", + "tokens.secret.scopedTitle": "Enregistrez ce jeton à périmètre maintenant", + "tokens.secret.legacyTitle": "Enregistrez cette clé API héritée maintenant", + "tokens.secret.scopedDescription": "lightNVR ne stocke qu'un hachage de ce jeton. En cas de perte, révoquez-le et créez-en un autre.", + "tokens.secret.legacyDescription": "Cette clé de compatibilité n'est affichée qu'une seule fois ici. La génération d'une autre clé l'invalidera.", + "tokens.secret.value": "Identifiant API", + "tokens.secret.copied": "Copié", + "tokens.secret.copySuccess": "Identifiant API copié", + "tokens.secret.copyError": "Impossible de copier automatiquement ; sélectionnez et copiez l'identifiant manuellement.", + "tokens.secret.savedConfirm": "J'ai enregistré cet identifiant en toute sécurité", + "tokens.secret.savedHelp": "La confirmation ferme cette boîte de dialogue. La valeur complète ne pourra plus être affichée.", + "tokens.legacy.title": "Clé de compatibilité héritée", + "tokens.legacy.description": "La clé héritée dispose de l'accès effectif complet de cet utilisateur, n'expire pas et ne peut pas être limitée par caméra ou par action.", + "tokens.legacy.warning": "Générez-en une uniquement pour une intégration existante dont les points de terminaison n'ont pas migré vers l'application des jetons à périmètre. Sa génération invalide immédiatement la clé héritée précédente.", + "tokens.legacy.generate": "Générer une clé héritée", + "tokens.legacy.confirm": "Générer une nouvelle clé héritée ? Cela invalide immédiatement la clé héritée actuelle de l'utilisateur.", + "tokens.legacy.createdSuccess": "Clé API héritée générée", + "tokens.legacy.createError": "Impossible de générer la clé API héritée : {message}", + "audit.manage": "Historique d'audit", + "audit.title": "Audit de sécurité et d'accès", + "audit.description": "Tracez les résultats de connexion, les décisions d'accès et les modifications de politique sensibles sans exposer les identifiants.", + "audit.retention": "Rétention", + "audit.retentionDescription": "Les événements sont actuellement conservés pendant {days} jours. La réduction de cette valeur supprime immédiatement l'historique plus ancien.", + "audit.retentionDays": "Jours", + "audit.retentionInvalid": "Choisissez une période de rétention entre 1 et 3650 jours.", + "audit.retentionSaved": "Rétention d'audit enregistrée ; {count} événements expirés supprimés", + "audit.retentionError": "Impossible d'enregistrer la rétention d'audit : {message}", + "audit.filters": "Filtres", + "audit.clearFilters": "Effacer les filtres", + "audit.applyFilters": "Appliquer les filtres", + "audit.actor": "Acteur", + "audit.unauthenticated": "Non authentifié", + "audit.outcome": "Résultat", + "audit.action": "Action exacte", + "audit.filterToAction": "Filtrer sur cette action", + "audit.since": "De", + "audit.until": "À", + "audit.invalidDateRange": "La date de début doit être antérieure à la date de fin.", + "audit.source": "Adresse source", + "audit.target": "Cible", + "audit.targetUuid": "UUID de la cible", + "audit.noTarget": "À l'échelle du système", + "audit.requestId": "ID de requête", + "audit.apiToken": "ID du jeton à portée", + "audit.showDetails": "Afficher les détails", + "audit.hideDetails": "Masquer les détails", + "audit.pageSize": "Par page", + "audit.resultRange": "Affichage de {start}–{end} sur {total}", + "audit.empty": "Aucun événement d'audit correspondant", + "audit.emptyDescription": "Essayez d'effacer un ou plusieurs filtres, ou attendez une nouvelle activité de sécurité.", + "audit.exportPage": "Exporter cette page", + "audit.exporting": "Exportation…", + "audit.exported": "Page d'audit exportée", + "audit.exportError": "Impossible d'exporter les événements d'audit : {message}", + "audit.pagination": "Pages de l'historique d'audit", + "audit.page": "Page {page}", + "audit.modesTitle": "Décisions autorisées", + "audit.modesDescription": "Choisissez comment les accès en lecture seule autorisés sont enregistrés pour chaque action. Les requêtes qui modifient quelque chose, les refus, les erreurs et les connexions sont toujours enregistrés. Résumer conserve une entrée par utilisateur, caméra et client toutes les {minutes} minutes avec un compteur.", + "audit.mode.record": "Enregistrer chaque", + "audit.mode.summarize": "Résumer", + "audit.mode.off": "Désactivé", + "audit.modeOffWarning": "Les accès autorisés pour cette action n'apparaîtront plus dans l'historique d'audit.", + "audit.modesSaved": "Modes de décision d'audit enregistrés", + "audit.modesError": "Impossible d'enregistrer les modes de décision d'audit : {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Type d'événement", + "audit.eventTypeSummary": "Résumés", + "audit.eventTypeDecision": "Décisions individuelles", + "access.cameraSearch": "Rechercher des caméras", + "access.cameraSearchPlaceholder": "Saisissez au moins deux caractères pour rechercher…", + "access.cameraSearchHint": "Rechercher par nom de caméra, UUID, adresse, emplacement, étiquette, fabricant ou modèle.", + "access.cameraSelected": "Sélectionné", + "access.cameraAdd": "Ajouter", + "access.cameraLimit": "Un sélecteur peut contenir au maximum 64 caméras explicites. Utilisez une règle d'emplacement ou d'étiquette pour des périmètres plus larges.", + "access.roles.manage": "Gérer les rôles", + "access.roles.title": "Rôles d'autorisation", + "access.roles.description": "Regroupez des actions dans des rôles réutilisables, puis attribuez ces rôles sur des périmètres de caméras.", + "access.roles.create": "Créer un rôle", + "access.roles.newRole": "Nouveau rôle", + "access.roles.copyName": "Copie de {name}", + "access.roles.clone": "Dupliquer", + "access.roles.builtin": "Intégré", + "access.roles.builtinHelp": "Les rôles intégrés sont des modèles fixes et sûrs lors des mises à jour. Dupliquez-en un pour le personnaliser.", + "access.roles.actionCount": "{count} actions", + "access.roles.destructive": "Action sensible", + "access.roles.notEnforced": "Pas encore appliqué par un point de terminaison", + "access.roles.destructiveWarning": "Ce rôle peut modifier la configuration ou les preuves. Ne l'accordez que sur les périmètres où cette autorité est requise.", + "access.roles.created": "Rôle créé", + "access.roles.updated": "Rôle mis à jour", + "access.roles.deleted": "Rôle supprimé", + "access.roles.saveError": "Impossible d'enregistrer le rôle : {message}", + "access.roles.deleteError": "Impossible de supprimer le rôle : {message}", + "access.roles.deleteConfirm": "Supprimer le rôle « {name} » ? Les rôles référencés par des autorisations ne peuvent pas être supprimés.", + "access.policy.manage": "Gérer l'accès", + "access.policy.column": "Accès", + "access.policy.scopedShort": "À périmètre", + "access.policy.title": "Politique d'accès — {username}", + "access.policy.description": "Gérer les autorisations de rôle (refus par défaut) et prévisualiser leurs périmètres de caméra.", + "access.policy.tab.grants": "Autorisations", + "access.policy.tab.test": "Tester l'accès", + "access.policy.scopedWarning": "Seules les actions autorisées par une correspondance d'autorisation et de périmètre de caméra fonctionneront.", + "access.policy.grants": "Autorisations de rôle", + "access.policy.grantsDescription": "Une autorisation combine un rôle avec l'ensemble du parc, une collection partagée ou un sélecteur de caméra personnalisé.", + "access.policy.addGrant": "Ajouter une autorisation", + "access.policy.noGrants": "Aucune autorisation configurée", + "access.policy.noGrantsHelp": "Ajoutez au moins une autorisation avant d'activer la politique à périmètre, sauf si cet utilisateur ne doit avoir aucun accès.", + "access.policy.role": "Rôle", + "access.policy.chooseRole": "Choisir un rôle", + "access.policy.scope": "Périmètre de caméra", + "access.policy.allCameras": "Ensemble du parc de caméras", + "access.policy.collectionScope": "Collection partagée", + "access.policy.collection": "Collection de caméras", + "access.policy.chooseCollection": "Choisir une collection partagée", + "access.policy.collectionHelp": "L'accès suit la collection au fil des ajouts, suppressions ou correspondances de règles.", + "access.policy.dynamicScope": "Sélecteur dynamique", + "access.policy.activateConfirm": "Activer la politique à périmètre avec refus par défaut pour {username} ? Les actions sans autorisation correspondante seront refusées.", + "access.policy.emptyConfirm": "Activer la politique à périmètre pour {username} sans autorisation ? Cela supprime intentionnellement tout accès contrôlé par la politique.", + "access.policy.saved": "Politique d'accès enregistrée", + "access.policy.saveError": "Impossible d'enregistrer la politique d'accès : {message}", + "access.policy.version": "Version de la politique {version}", + "access.policy.unsaved": "Modifications non enregistrées", + "access.policy.validation.invalid_mode": "Choisissez un mode d'évaluation valide.", + "access.policy.validation.missing_role": "Chaque autorisation doit référencer un rôle disponible.", + "access.policy.validation.invalid_scope": "Chaque autorisation doit utiliser une portée de parc entier, de collection partagée ou de sélecteur.", + "access.policy.validation.invalid_selector": "Complétez ou corrigez chaque sélecteur de caméra avant d'enregistrer.", + "access.policy.validation.missing_collection": "Choisissez une collection partagée disponible pour chaque autorisation de collection.", + "access.policy.validation.duplicate_grant": "Supprimez les autorisations en double de rôle et de portée avant d'enregistrer.", + "access.test.title": "Tester l'accès effectif", + "access.test.description": "Évaluez une action enregistrée et une caméra en tant que {username} sans les exécuter.", + "access.test.saveFirst": "Enregistrez ou annulez les modifications d'autorisation avant de tester afin que le résultat reflète la politique affichée ici.", + "access.test.action": "Action", + "access.test.camera": "Caméra", + "access.test.run": "Tester l'accès", + "access.test.running": "Test en cours…", + "access.test.allowed": "Autorisé", + "access.test.denied": "Refusé", + "access.test.version": "Version {version}", + "access.test.source": "Source : {source} · Rôle : {role}", + "recordings.pullToRefresh": "Tirez pour actualiser les enregistrements", + "recordings.releaseToRefresh": "Relâchez pour actualiser les enregistrements", + "recordings.refreshing": "Actualisation des enregistrements…", + "recordings.refreshed": "Enregistrements actualisés", + "recordings.refreshFailed": "Impossible d'actualiser les enregistrements : {message}", + "recordings.download": "Télécharger", + "recordings.tags": "Étiquettes", + "recordings.selectRecording": "Sélectionner un enregistrement", + "timeline.legend.recording": "Enregistrement", + "timeline.legend.detection": "Événement de détection", + "timeline.detectionEvent": "Événement de détection", + "streams.showCredentials": "Afficher les identifiants", + "streams.hideCredentials": "Masquer les identifiants", + "streams.streamSuccessfullyEnabled": "Flux activé avec succès.", + "streams.errorEnablingStream": "Erreur lors de l'activation du flux : {message}", + "system.health.tab": "Santé", + "system.health.operatorView": "Santé opérationnelle", + "system.health.title": "Santé du système", + "system.health.loading": "Chargement de la santé du système…", + "system.health.loadError": "Impossible de charger la santé du système.", + "system.health.refreshing": "Actualisation…", + "system.health.activeIncidentCount": "{count} incidents actifs", + "system.health.coverage": "Couverture", + "system.health.monitoringDisabled": "Le suivi de santé est désactivé", + "system.health.lastRecordedValue": "Dernière valeur enregistrée", + "system.health.monitoringDisabledHelp": "Les données de santé actuelles ne sont pas collectées. Activez le suivi de santé dans Paramètres → Santé ; redémarrez si demandé après l'enregistrement. L'historique des incidents affiche les événements passés, non l'utilisation actuelle des ressources.", + "system.health.monitoringRestartRequired": "Le suivi de santé est activé dans la configuration enregistrée, mais l'échantillonneur en cours d'exécution est toujours désactivé. Redémarrez LightNVR pour appliquer la modification. L'historique des incidents affiche les événements passés.", + "system.health.containerCoverage": "Couverture hôte limitée", + "system.health.hostHardwareUnavailable": "Cette installation peut voir la santé des conteneurs et des ressources montées, mais le matériel hôte est indisponible. Les valeurs hôtes manquantes sont inconnues, non saines.", + "system.health.coverageUnknown": "Aucun instantané de santé complet n'est encore disponible. Les valeurs restent inconnues tant que la collecte n'est pas terminée.", + "system.health.coverageComplete": "Toutes les données visibles par cette installation ont été collectées avec succès.", + "system.health.coveragePartial": "La couverture est partielle. {count} observations ou vérifications de collecte sont indisponibles, obsolètes ou incomplètes.", + "system.health.effectiveScope": "Portée effective", + "system.health.activeIncidents": "Incidents actifs", + "system.health.noActiveIncidents": "Aucun incident actif n'est signalé pour la couverture visible.", + "system.health.duration": "Durée", + "system.health.currentValue": "Valeur actuelle", + "system.health.thresholds": "Seuil et temps de maintien", + "system.health.thresholdSummary": "Avertissement {warning}, critique {critical}, rétablissement {recovery} {unit} ; temps de maintien avertissement {seconds} s", + "system.health.remediation": "Réponse suggérée", + "system.health.facts": "Données de santé", + "system.health.group.resources": "Ressources", + "system.health.group.storage": "Stockage", + "system.health.group.hardware": "Matériel", + "system.health.group.network": "Réseau", + "system.health.group.clock": "Horloge", + "system.health.group.components": "Composants", + "system.health.noFacts": "Aucune information visible dans ce groupe.", + "system.health.observationState": "Capacité et fraîcheur", + "system.health.valueUnavailable": "Une ou plusieurs valeurs sont inconnues", + "system.health.componentStatus": "Composants de supervision", + "system.health.collectors": "Collecteurs", + "system.health.collectorSummary": "{total} enregistrés · {attention} nécessitent une attention", + "system.health.collectorsNeedingAttention": "Collecteurs nécessitant une attention", + "system.health.collectionFailures": "{count} échecs ou délais dépassés", + "system.health.stale": "obsolète", + "system.health.eventDelivery": "Livraison d'événements", + "system.health.degraded": "Dégradé", + "system.health.circularDelivery": "Il s'agit du seul canal d'alerte configuré, il ne peut donc pas signaler indépendamment sa propre défaillance.", + "system.health.incidentPersistence": "Persistance des incidents", + "system.health.persistenceSummary": "{pending} en attente · {failures} échecs · {retries} tentatives", + "system.health.recentSamples": "Activité de collecte récente", + "system.health.recentSamplesHelp": "Jusqu'à {count} résumés de génération côté serveur ; il s'agit d'une activité de couverture, non d'un graphique de valeurs.", + "system.health.sampleSequence": "Génération {sequence}", + "system.health.sampleCoverage": "{observations} observations · {dropped} perdues", + "system.health.noSamples": "Aucune génération de collecte terminée n'est disponible.", + "system.health.incidentHistory": "Historique des incidents", + "system.health.incidentHistoryHelp": "Incidents les plus récents en premier. L'historique est chargé par pages limitées.", + "system.health.loadingHistory": "Chargement de l'historique des incidents…", + "system.health.historyError": "Impossible de charger l'historique des incidents.", + "system.health.emptyHistory": "Aucun incident n'a été enregistré.", + "system.health.firstSeen": "Première occurrence", + "system.health.lastSeen": "Dernière occurrence", + "system.health.deliveryState": "État de livraison", + "system.health.historyPagination": "Pages de l'historique des incidents", + "system.health.pageCount": "{count} incidents sur cette page", + "system.health.remediation.memory": "Réduisez la pression mémoire, vérifiez les limites de processus et de cgroup, et examinez l'activité OOM récente.", + "system.health.remediation.cpu": "Identifiez les consommateurs CPU soutenus et vérifiez le débit du service avant de modifier les limites.", + "system.health.remediation.io": "Vérifiez la latence du stockage et les écritures actives ; sauvegardez les enregistrements avant toute maintenance perturbante.", + "system.health.remediation.filesystem": "Vérifiez le système de fichiers logique nommé, l'espace libre ou les inœuds, et assurez-vous qu'il reste accessible en écriture.", + "system.health.remediation.thermal": "Améliorez le refroidissement et réduisez la charge ; inspectez les ventilateurs et les aérations avant que les températures n'atteignent les limites d'arrêt.", + "system.health.remediation.network": "Vérifiez l'interface visible, le lien, le commutateur et les compteurs d'erreurs depuis un chemin réseau indépendant.", + "system.health.remediation.clock": "Restaurez la synchronisation horaire et vérifiez la source d'horloge de l'hôte avant de vous fier aux horodatages des événements.", + "system.health.remediation.process": "Inspectez les limites de ressources et les journaux de LightNVR, puis réduisez la charge ou augmentez les limites validées.", + "system.health.remediation.storage": "Sauvegardez les séquences importantes et inspectez le périphérique de stockage mappé avant remplacement ou réparation.", + "system.health.remediation.hardware": "Inspectez le matériel affecté et les journaux de la plateforme ; planifiez une maintenance si la condition persiste.", + "system.health.remediation.health": "Restaurez l'accès et les permissions du collecteur afin que les éléments de diagnostic manquants puissent être évalués.", + "system.health.remediation.system": "Examinez l'exécution précédente et les journaux de l'hôte pour distinguer un redémarrage de processus d'un redémarrage de l'hôte.", + "system.health.remediation.event": "Utilisez l'API locale ou la vue des métriques, réduisez la pression de la file d'attente persistante et restaurez une destination d'alerte indépendante.", + "system.health.remediation.default": "Examinez le composant affecté et les journaux récents, puis vérifiez la récupération dans une nouvelle génération de santé.", + "system.capacityTarget": "Objectif de capacité", + "system.capacityTargetValue": "Conserver {pct} % d'espace libre", + "system.fillRate": "Taux de remplissage", + "system.fillRateValue": "{value} / jour", + "system.projectedToTarget": "Temps estimé avant l'objectif", + "system.projectedNow": "Objectif atteint/dépassé", + "system.projectedDays": "~{count} j", + "system.projectedHours": "~{count} h", + "system.projectedUnknown": "—", + "common.description": "Description", + "common.remove": "Supprimer", + "streams.selectStream": "Sélectionner {name}", + "streams.search": "Rechercher des flux", + "streams.searchPlaceholder": "Rechercher des caméras, emplacements ou étiquettes", + "streams.noStreamsMatchFilters": "Aucun flux ne correspond aux filtres actuels.", + "streamHealth.sourceConnected": "Source connectée", + "streamHealth.videoAdvancing": "Vidéo en progression", + "streamHealth.recorderWriting": "Enregistrement en cours", + "streamHealth.detectorOperating": "Détecteur actif", + "streamHealth.lastSegment": "Dernier segment terminé", + "streams.disablingStreamsProgress": "Désactivation des flux…", + "streams.onvifInvalidAddress": "L'adresse IP du périphérique ONVIF est manquante ou invalide.", + "streams.warningFallingBackToHttp": "La connexion HTTPS a échoué ; nouvelle tentative en HTTP. Les identifiants peuvent être envoyés en clair.", + "streamsConfig.playbackTransport": "Transport de lecture", + "streamsConfig.playbackTransportHelp": "Choisissez la méthode de lecture du navigateur pour cette caméra et, le cas échéant, son ordre de repli.", + "streamsConfig.playbackTransportUnavailable": "Indisponible sur le serveur : {transports}. Activez le transport globalement ou choisissez un autre profil.", + "streamsConfig.audioDisabledByPolicy": "L'audio est désactivé par la politique de l'instance", + "streamsConfig.audioDisabledByPolicyHelp": "L'enregistrement, l'écoute en direct et la communication bidirectionnelle sont indisponibles tant que la politique de conformité audio globale est activée.", + "streamsConfig.audioVoiceEnhancement": "Amélioration vocale (enregistrements)", + "streamsConfig.customApiModel": "Détection API personnalisée", + "streamsConfig.modelNotSupportedByBuild": "non pris en charge par cette version", + "streamsConfig.tierCriticalMultiplier": "Niveau critique ×", + "streamsConfig.tierImportantMultiplier": "Niveau important ×", + "streamsConfig.tierEphemeralMultiplier": "Niveau éphémère ×", + "streamsConfig.tierMultipliersHelp": "Multiplicateurs par niveau sur la rétention de base. Les images de niveau supérieur sont conservées plus longtemps et supprimées en dernier en cas de pression sur le disque.", + "streamsConfig.storagePriority": "Priorité de stockage (1-10)", + "streamsConfig.storagePriorityHelp": "Importance relative des images de ce flux lors de la récupération d'espace ; une priorité plus élevée est préservée plus longtemps.", + "streamsConfig.restream": "Rediffusion / Publication (RTMP)", + "streamsConfig.publishUrl": "URL de publication (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "Rediffusez cette caméra vers un service comme YouTube Live via go2rtc. Collez l'URL d'ingestion RTMP complète incluant la clé de flux (ex. rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Pour rediffuser vers plusieurs services à la fois, séparez les URL par des virgules. YouTube nécessite une vidéo H264 et un audio AAC ; LightNVR transcode désormais automatiquement (H264 pour les caméras non-H264, AAC pour l'audio non-AAC), donc la plupart des caméras fonctionnent telles quelles. Remarque : YouTube exige également une piste audio — une caméra sans audio sera toujours rejetée. Laissez vide pour désactiver.", + "streams.lastSeen": "Vu pour la dernière fois {time}", + "streams.claimed": "Réclamé", + "streams.duplicateSuspected": "Doublon possible", + "streams.duplicateSuspectedHelp": "L'identité stable ou les preuves de point de terminaison entrent en conflit avec un autre enregistrement de découverte.", + "streams.onvifClaimWarning": "Le flux a été ajouté, mais son enregistrement de découverte n'a pas pu être marqué comme réclamé : {message}", + "common.online": "En ligne", + "common.offline": "Hors ligne", + "settings.storageTargets.title": "Cibles de stockage des enregistrements", + "settings.storageTargets.description": "Enregistrez les disques locaux et les systèmes de fichiers NFS ou SMB montés par l'administrateur comme destinations d'enregistrement surveillées indépendamment.", + "settings.storageTargets.foundationNotice": "La capture utilise des cibles système de fichiers. Les buckets S3 et les cibles NFS/SAN montées peuvent contenir des copies d'archive vérifiées. La pression chaude préserve les enregistrements archivés jusqu'à l'expiration de leur rétention logique.", + "settings.storageTargets.add": "Ajouter une cible de stockage", + "settings.storageTargets.edit": "Modifier la cible de stockage", + "settings.storageTargets.editorHelp": "Les cibles activées doivent déjà exister et réussir un test d'écriture, de fsync et de nettoyage. Enregistrez un montage futur indisponible comme désactivé, puis activez-le après le montage.", + "settings.storageTargets.name": "Nom de la cible", + "settings.storageTargets.root": "Chemin racine monté", + "settings.storageTargets.rootLocked": "Une cible par défaut ou non vide conserve une racine immuable afin que les enregistrements existants ne puissent pas être orphelins.", + "settings.storageTargets.class": "Classe de performance", + "settings.storageTargets.hot": "Chaud — enregistrement actif", + "settings.storageTargets.warm": "Tiède — archive montée", + "settings.storageTargets.cold": "Froid — accès peu fréquent", + "settings.storageTargets.reserveGb": "Espace réservé (Go)", + "settings.storageTargets.lowWatermark": "Seuil bas (% utilisé)", + "settings.storageTargets.highWatermark": "Seuil haut (% utilisé)", + "settings.storageTargets.migrationBandwidth": "Bande passante du cycle de vie (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 signifie illimité. La limite est figée lors de la création d'une tâche de déplacement ou de copie.", + "settings.storageTargets.archiveStart": "Début de la fenêtre d'archivage", + "settings.storageTargets.archiveEnd": "Fin de la fenêtre d'archivage", + "settings.storageTargets.archiveWindowHelp": "Heure locale. Des heures de début et de fin identiques autorisent les tâches du cycle de vie toute la journée ; une fenêtre nocturne peut chevaucher minuit.", + "settings.storageTargets.enabled": "Activée (les politiques de placement peuvent sélectionner cette cible)", + "settings.storageTargets.notRouted": "Aucune politique de placement activée ne dirige les caméras ici. Les nouveaux enregistrements continuent d'aller vers la cible par défaut jusqu'à ce qu'une politique nomme cette cible comme cible principale, membre du pool ou cible d'archivage.", + "settings.storageTargets.degradedNotice": "Au-dessus de son seuil haut ou dans sa réserve. Les politiques de placement ignorent cette cible tant que de l'espace n'est pas libéré.", + "settings.storageTargets.probePassedIneligible": "Test d'écriture réussi, mais la cible est {status} : les politiques de placement ne la sélectionneront pas.", + "settings.storageTargets.mountRequired": "Exiger un système de fichiers monté", + "settings.storageTargets.mountRequiredHelp": "Épingler cette cible à son point de montage non racine actuel. Si ce montage NFS, SMB, bind ou PVC disparaît, l'enregistrement se met en pause au lieu d'écrire dans le répertoire hôte sous-jacent.", + "settings.storageTargets.mountGuard": "Montage requis", + "settings.storageTargets.mountPending": "Sera détecté lors de l'activation de la cible", + "settings.storageTargets.default": "Par défaut", + "settings.storageTargets.capacity": "Capacité", + "settings.storageTargets.available": "Disponible", + "settings.storageTargets.recordings": "Enregistrements indexés", + "settings.storageTargets.replicas": "{count} copies vérifiées · {bytes}", + "settings.storageTargets.reserve": "Réservé", + "settings.storageTargets.pressure.normal": "Pression normale", + "settings.storageTargets.pressure.high": "Seuil haut", + "settings.storageTargets.pressure.reserve": "Réserve dépassée", + "settings.storageTargets.pressure.unavailable": "Pression indisponible", + "settings.storageTargets.cleanupActive": "Le nettoyage ciblé est actif et tendra vers {target} disponible sans supprimer les enregistrements affectés à une autre cible.", + "settings.storageTargets.test": "Tester la cible", + "settings.storageTargets.probing": "Test en cours…", + "settings.storageTargets.probePassed": "Test d'écriture de la cible de stockage réussi", + "settings.storageTargets.duplicateFilesystem": "Cette racine partage le même système de fichiers sous-jacent qu'une autre cible. La capacité ne doit pas être comptée deux fois lorsque le placement est activé.", + "settings.storageTargets.deleteLocked": "Les cibles par défaut et non vides ne peuvent pas être supprimées.", + "settings.storageTargets.deleteConfirm": "Supprimer la cible de stockage vide « {name} » ? Aucun fichier ne sera supprimé.", + "settings.storageTargets.created": "Cible de stockage créée", + "settings.storageTargets.updated": "Cible de stockage mise à jour", + "settings.storageTargets.deleted": "Cible de stockage supprimée", + "settings.storageTargets.invalidThresholds": "Vérifiez les seuils, la réserve, la bande passante du cycle de vie et les fenêtres d'archivage.", + "settings.storageTargets.loadError": "Impossible de charger les cibles de stockage", + "settings.storagePools.title": "Pools de stockage", + "settings.storagePools.description": "Regroupez les cibles saines pour le débordement automatique et la réplication sur des cibles distinctes.", + "settings.storagePools.add": "Ajouter un pool", + "settings.storagePools.strategy": "Stratégie d'allocation", + "settings.storagePools.mostFree": "Espace libre maximal", + "settings.storagePools.roundRobin": "Round robin", + "settings.storagePools.priority": "Priorité explicite", + "settings.storagePools.members": "Cibles (l'ordre d'affichage correspond à la priorité d'allocation)", + "settings.storagePools.enabled": "Pool activé", + "settings.storagePools.active": "Actif", + "settings.storagePools.inactive": "Désactivé", + "settings.storagePools.strategyValue.most_free": "espace libre max", + "settings.storagePools.strategyValue.round_robin": "round robin", + "settings.storagePools.strategyValue.priority": "ordre de priorité", + "settings.storagePools.created": "Pool de stockage créé", + "settings.storagePools.updated": "Pool de stockage mis à jour", + "settings.storagePools.deleted": "Pool de stockage supprimé", + "settings.storagePools.deleteConfirm": "Supprimer le pool de stockage « {name} » ?", + "settings.storagePools.empty": "Aucun pool de stockage pour le moment.", + "settings.storageMigrations.title": "Tâches de migration des enregistrements", + "settings.storageMigrations.description": "Les déplacements durables et les copies conservées respectent la fenêtre d'archivage et la limite de bande passante de chaque cible, vérifient le SHA-256 et se rétablissent en toute sécurité après un redémarrage.", + "settings.storageMigrations.empty": "Aucune tâche de migration des enregistrements pour le moment.", + "settings.storageMigrations.loadError": "Impossible de charger les tâches de migration des enregistrements", + "settings.storageMigrations.recording": "Enregistrement #{id}", + "settings.storageMigrations.attempt": "Tentative {current}/{max}", + "settings.storageMigrations.operation.move": "Déplacer", + "settings.storageMigrations.operation.copy": "Copie conservée", + "settings.storageMigrations.cancelled": "Annulation de la migration acceptée", + "settings.storageMigrations.cancelling": "Annulation…", + "settings.storageMigrations.retried": "Migration mise en file d'attente pour nouvelle tentative", + "settings.storageMigrations.state.queued": "En file d'attente", + "settings.storageMigrations.state.copying": "Copie en cours", + "settings.storageMigrations.state.verifying": "Vérification en cours", + "settings.storageMigrations.state.committing": "Validation en cours", + "settings.storageMigrations.state.cleanup_pending": "Nettoyage de la source", + "settings.storageMigrations.state.retry_wait": "En attente de nouvelle tentative", + "settings.storageMigrations.state.completed": "Terminé", + "settings.storageMigrations.state.failed": "Échoué", + "settings.storageMigrations.state.cancelled": "Annulé", + "settings.storagePolicies.title": "Stratégies de placement des caméras", + "settings.storagePolicies.description": "Achemine les caméras correspondantes vers une cible d'enregistrement principale par ordre de priorité. Une caméra utilise la première stratégie activée qui correspond.", + "settings.storagePolicies.add": "Ajouter une stratégie de placement", + "settings.storagePolicies.edit": "Modifier la stratégie de placement", + "settings.storagePolicies.editorHelp": "La stratégie est réévaluée pour les nouveaux segments. Les modifications ne déplacent pas les enregistrements existants.", + "settings.storagePolicies.priority": "Priorité (la plus élevée en premier)", + "settings.storagePolicies.priorityValue": "Priorité {priority}", + "settings.storagePolicies.primary": "Cible principale", + "settings.storagePolicies.primaryPool": "Pool de placement (facultatif)", + "settings.storagePolicies.exactTarget": "Utiliser la cible primaire exacte", + "settings.storagePolicies.fallback": "Si la cible primaire est indisponible", + "settings.storagePolicies.fallbackDefault": "Utiliser la cible par défaut", + "settings.storagePolicies.fallbackTarget": "Utiliser une cible de repli nommée", + "settings.storagePolicies.fallbackPause": "Suspendre l'enregistrement", + "settings.storagePolicies.fallbackFail": "Échouer au démarrage de l'enregistrement", + "settings.storagePolicies.namedFallback": "Cible de repli", + "settings.storagePolicies.chooseTarget": "Choisir une cible", + "settings.storagePolicies.choosePool": "Choisir un pool", + "settings.storagePolicies.minimumDays": "Rétention minimale (jours)", + "settings.storagePolicies.desiredDays": "Rétention souhaitée (jours)", + "settings.storagePolicies.maximumDays": "Rétention maximale (jours)", + "settings.storagePolicies.copyCount": "Copies vérifiées requises", + "settings.storagePolicies.replicationPool": "Pool de réplication", + "settings.storagePolicies.migrateAfter": "Déplacer après ancienneté (jours)", + "settings.storagePolicies.migrationTarget": "Cible d'archivage", + "settings.storagePolicies.pressurePriority": "Priorité de suppression sous pression (la plus basse en premier)", + "settings.storagePolicies.disabledTarget": "désactivé", + "settings.storagePolicies.enabled": "Stratégie activée", + "settings.storagePolicies.selector": "Caméras correspondantes", + "settings.storagePolicies.preview": "Aperçu de la priorité", + "settings.storagePolicies.previewing": "Évaluation…", + "settings.storagePolicies.previewRequired": "Prévisualisez le brouillon actuel avant l'enregistrement pour voir les chevauchements de caméras et la stratégie gagnante effective.", + "settings.storagePolicies.previewSummary": "Correspond à {matched} caméras ; ce brouillon est effectif pour {effective}.", + "settings.storagePolicies.previewShadowed": "Une stratégie de priorité supérieure l'emporte pour {count} caméras correspondantes.", + "settings.storagePolicies.previewWins": "L'emporte sur « {policy} » (priorité {priority}) pour {count} caméras.", + "settings.storagePolicies.previewLoses": "Perd face à « {policy} » (priorité {priority}) pour {count} caméras.", + "settings.storagePolicies.previewNoMatches": "Ce sélecteur ne correspond actuellement à aucune caméra.", + "settings.storagePolicies.invalidPriority": "La priorité doit être un nombre entier compris entre -1 000 000 et 1 000 000.", + "settings.storagePolicies.invalidLifecycle": "Vérifiez l'ordre de rétention, le nombre de copies et le pool de réplication, ainsi que l'ancienneté de migration et la cible.", + "settings.storagePolicies.created": "Stratégie de placement créée", + "settings.storagePolicies.updated": "Politique de placement mise à jour", + "settings.storagePolicies.deleted": "Politique de placement supprimée", + "settings.storagePolicies.deleteConfirm": "Supprimer la politique de placement « {name} » ? Les enregistrements existants ne sont pas affectés.", + "settings.storagePolicies.active": "Active", + "settings.storagePolicies.inactive": "Désactivée", + "settings.storagePolicies.routesTo": "Cible principale : {target}", + "settings.storagePolicies.lifecycleSummary": "Rétention min/souhaitée/max : {minimum}/{desired}/{maximum} jours · {copies} copie(s) vérifiée(s)", + "settings.storagePolicies.fallsBackTo": "Cible de repli : {target}", + "settings.storagePolicies.mode.default": "Repli : cible par défaut", + "settings.storagePolicies.mode.pause": "Repli : mettre l'enregistrement en pause", + "settings.storagePolicies.mode.fail": "Repli : échec du démarrage de l'enregistrement", + "settings.storagePolicies.empty": "Aucune politique de placement. Les caméras continuent d'utiliser la cible par défaut ; les autres cibles ne reçoivent rien tant qu'une politique ne les y dirige pas.", + "settings.storagePolicies.archiveNoTrigger": "Une cible d'archivage est définie mais rien ne déclenche de déplacement. Définissez « Déplacer après (jours) », un âge d'archivage ou une option d'archivage ; sinon aucun enregistrement ne sera déplacé.", + "settings.storageCompliance.title": "Capacité et conformité aux politiques", + "settings.storageCompliance.description": "Les taux observés sur 30 jours prédisent la pression sur les cibles et la rétention atteinte ; les violations actives du cycle de vie restent visibles tant qu'elles ne sont pas résolues.", + "settings.storageCompliance.loadError": "Impossible de charger la conformité du stockage", + "settings.storageCompliance.unknown": "Inconnu", + "settings.storageCompliance.days": "{days} jours", + "settings.storageCompliance.day": "jour", + "settings.storageCompliance.targetForecasts": "Prévisions des cibles", + "settings.storageCompliance.target": "Cible", + "settings.storageCompliance.dailyRate": "Taux observé", + "settings.storageCompliance.toHigh": "Jusqu'au seuil haut", + "settings.storageCompliance.expected": "Rétention attendue", + "settings.storageCompliance.confidence": "Confiance", + "settings.storageCompliance.policyCompliance": "Conformité aux politiques", + "settings.storageCompliance.compliant": "Aucune violation active", + "settings.storageCompliance.violationCount": "{count} violation(s)", + "settings.storageCompliance.policyForecast": "Atteint {achieved} ; prévu {expected} ; souhaité {desired} jours.", + "settings.storageCompliance.copyDeficits": "{count} enregistrement(s) nécessitent une autre copie vérifiée.", + "settings.storageCompliance.activeViolations": "Violations actives", + "settings.storageCompliance.type.copy_count": "Nombre de copies", + "settings.storageCompliance.type.minimum_retention": "Capacité minimale de rétention", + "settings.storageCompliance.type.target_unavailable": "Cible indisponible", + "settings.storageCompliance.type.migration_failed": "Échec de la tâche de cycle de vie", + "settings.recordingDirectoryFormat": "Disposition des dossiers d'enregistrement", + "settings.recordingDirectoryFormatHelp": "Répartit les nouveaux enregistrements MP4 sous chaque dossier de caméra. Les enregistrements existants ne sont pas déplacés.", + "settings.recordingDirectoryFlat": "Plat (dossier de caméra uniquement)", + "settings.recordingDirectoryMonth": "Par mois (AAAA/MM)", + "settings.recordingDirectoryDay": "Par jour (AAAA/MM/JJ)", + "settings.minFreePct": "Espace libre minimal (%)", + "settings.minFreePctHelp": "Conserve au moins ce pourcentage de volume libre en supprimant automatiquement les enregistrements les plus anciens, indépendamment des jours de rétention. Cela limite l'utilisation à la taille du disque — définissez-le et le disque ne se remplira jamais. 0 désactive la limite de capacité.", + "settings.pressureThresholds": "Seuils de pression disque (%)", + "settings.pressureThresholdsHelp": "Paliers d'espace libre qui intensifient le nettoyage automatique. Doit respecter : urgence < critique < avertissement.", + "settings.pressureWarningPct": "Avertissement en dessous (% libre)", + "settings.pressureCriticalPct": "Critique en dessous (% libre)", + "settings.pressureEmergencyPct": "Urgence en dessous (% libre)", + "settings.databaseBackupVerify": "Vérification des sauvegardes", + "settings.databaseBackupVerifyFull": "Complète (integrity_check, vérifie chaque index)", + "settings.databaseBackupVerifyQuick": "Rapide (quick_check, structure des pages uniquement)", + "settings.databaseBackupVerifyOff": "Désactivée (aucune analyse post-copie)", + "settings.databaseBackupVerifyHelp": "Analyse appliquée à chaque sauvegarde copiée avant sa publication. Complète peut prendre plus de temps que la copie sur une grande base de données avec un disque mécanique et peut atteindre la soupape de sécurité de 30 minutes, ce qui annule cette sauvegarde ; Rapide détecte tout de même les pages corrompues ou tronquées avec beaucoup moins de recherches.", + "settings.viewMethodAuto": "Auto — préférence par caméra avec repli", + "settings.resetWizardPending": "Démarrage de l'assistant…", + "settings.apiDetectionFormat": "Format de requête API", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (téléversement d'image multipart)", + "settings.apiDetectionFormatDoods2": "DOODS2 (corps JSON avec image base64)", + "settings.apiDetectionFormatHelp": "Format de transmission utilisé par LightNVR pour envoyer les instantanés à l'API de détection. Conservez light-object-detect pour light-object-detect ou tout serveur implémentant son contrat ; choisissez DOODS2 pour un serveur DOODS2.", + "settings.apiDetectionUrlHelpDoods2": "Endpoint /detect de DOODS2, ex. http://localhost:8080/detect. La requête est envoyée en JSON et aucun paramètre de requête n'est ajouté.", + "settings.apiDetectionDetectorName": "Nom du détecteur DOODS2", + "settings.apiDetectionDetectorNameHelp": "Envoyé en tant que detector_name dans chaque requête. Doit correspondre à un détecteur listé par le serveur via GET /detectors ; « default » utilise le détecteur par défaut du serveur.", + "settings.defaultPlaybackTransport": "Transport de lecture par défaut", + "settings.defaultPlaybackTransportHelp": "Profil de lecture appliqué aux nouveaux flux. Les flux existants conservent leur propre sélection.", + "playbackTransport.auto": "Auto (recommandé)", + "playbackTransport.webrtcOnly": "WebRTC uniquement", + "playbackTransport.mseOnly": "MSE uniquement", + "playbackTransport.hlsOnly": "HLS uniquement", + "playbackTransport.webrtcThenMse": "WebRTC, puis MSE", + "playbackTransport.mseThenHls": "MSE, puis HLS", + "investigation.experimental": "Espace de travail expérimental", + "investigation.title": "Investigation", + "investigation.description": "Consultez plusieurs caméras avec un curseur UTC partagé sans masquer les lacunes dans les enregistrements.", + "investigation.query": "Fenêtre d'investigation", + "investigation.queryHelp": "Sélectionnez jusqu'à 16 caméras. Au maximum quatre lecteurs vidéo sont actifs simultanément.", + "investigation.cameras": "caméras", + "investigation.cameraSelection": "Sélection de caméras", + "investigation.start": "Début", + "investigation.end": "Fin", + "investigation.load": "Charger l'investigation", + "investigation.applyWindow": "Appliquer la fenêtre temporelle", + "investigation.loading": "Chargement de l'investigation…", + "investigation.eventType": "Type d'événement", + "investigation.anyEventType": "Tous les types d'événements", + "investigation.eventType.detection": "Détection", + "investigation.eventType.motion": "Mouvement", + "investigation.location": "Emplacement", + "investigation.anyLocation": "Tous les emplacements", + "investigation.objectLabel": "Étiquette d'objet", + "investigation.anyLabel": "Toutes les étiquettes", + "investigation.zone": "Zone", + "investigation.anyZone": "Toutes les zones", + "investigation.source": "Source de détection", + "investigation.anySource": "Toutes les sources", + "investigation.captureMethod": "Méthode de capture", + "investigation.anyCaptureMethod": "Toutes les méthodes de capture", + "investigation.recordingTag": "Étiquette d'enregistrement", + "investigation.anyRecordingTag": "Tout tag d'enregistrement", + "investigation.protection": "Protection", + "investigation.anyProtection": "Toute protection", + "investigation.protected": "Protégé", + "investigation.unprotected": "Non protégé", + "investigation.minimumConfidence": "Confiance minimale", + "investigation.confidenceError": "La confiance minimale doit être comprise entre 0 et 1.", + "investigation.metadataRegionSearch": "Recherche par région de métadonnées", + "investigation.regionSearchHelp": "Choisissez une caméra principale avec des images, puis dessinez une zone sur sa vidéo.", + "investigation.regionActive": "Recherche des boîtes stockées depuis {camera}. Un résultat manquant ne prouve pas que rien n'a traversé la zone.", + "investigation.regionMatch": "Correspondance de boîte", + "investigation.regionMatch.center": "Centre à l'intérieur", + "investigation.regionMatch.intersects": "Toute intersection", + "investigation.regionMatch.minimumIntersection": "Recouvrement minimal", + "investigation.regionMinimumOverlap": "Recouvrement minimal (%)", + "investigation.regionLeft": "Gauche (%)", + "investigation.regionTop": "Haut (%)", + "investigation.regionWidth": "Largeur (%)", + "investigation.regionHeight": "Hauteur (%)", + "investigation.drawRegion": "Dessiner la zone de recherche", + "investigation.drawingRegion": "Dessin de la zone de recherche…", + "investigation.clearRegion": "Effacer la zone", + "investigation.useFullFrame": "Utiliser l'image complète", + "investigation.drawRegionPrompt": "Faites glisser sur la vidéo pour définir la zone de recherche", + "investigation.applyFilters": "Appliquer les filtres", + "investigation.searching": "Recherche d'événements…", + "investigation.searchResults": "Résultats d'événements", + "investigation.searchHelp": "Chargez une investigation pour rechercher ses métadonnées d'événements persistées.", + "investigation.resultCount": "{count} événements correspondants", + "investigation.results": "résultats", + "investigation.resultHistogram": "Histogramme d'événements", + "investigation.histogramHelp": "Sélectionnez une barre pour déplacer le curseur partagé.", + "investigation.previousResult": "Événement précédent", + "investigation.nextResult": "Événement suivant", + "investigation.previousResultShortcut": "Événement précédent ([)", + "investigation.nextResultShortcut": "Événement suivant (])", + "investigation.noResults": "Aucun événement persisté ne correspond à cette caméra, cette période et ce filtre.", + "investigation.noThumbnail": "Aucune miniature", + "investigation.exploreThumbnails": "Explorer les miniatures", + "investigation.exploreSelectedThumbnails": "Explorer autour de l'événement", + "investigation.thumbnailDrilldown": "Exploration par miniature", + "investigation.thumbnailDrilldownHelp": "Choisissez un moment, y compris un intervalle vide, pour déplacer le curseur partagé et régénérer un ensemble d'échantillons plus restreint.", + "investigation.selectThumbnailSample": "Inspecter autour de {time}", + "investigation.loadingThumbnail": "Chargement de la miniature…", + "investigation.thumbnailUnavailable": "Miniature indisponible", + "investigation.loadingSamples": "Chargement des échantillons de miniatures…", + "investigation.thumbnailCoverageTruncated": "Cet intervalle contient plus d'enregistrements que l'échantillonneur n'a pu en inspecter. Réduisez la fenêtre temporelle pour une couverture complète.", + "investigation.bookmarks.save": "Enregistrer un signet", + "investigation.bookmarks.open": "Signets", + "investigation.bookmarks.saveTitle": "Enregistrer un signet d'investigation", + "investigation.bookmarks.listTitle": "Signets d'investigation", + "investigation.bookmarks.notHold": "Un signet restaure cette vue, mais ne protège pas les enregistrements de la rétention ou de la suppression normales.", + "investigation.bookmarks.title": "Nom du signet", + "investigation.bookmarks.note": "Note privée (facultatif)", + "investigation.bookmarks.titleRequired": "Saisissez un nom de signet.", + "investigation.bookmarks.empty": "Vous n'avez aucun signet d'investigation enregistré.", + "investigation.bookmarks.cameraCount": "{count} caméra(s)", + "investigation.bookmarks.restore": "Ouvrir", + "investigation.bookmarks.confirmDelete": "Supprimer le signet ?", + "investigation.actions.open": "Protéger / télécharger", + "investigation.actions.title": "Enregistrements d'investigation", + "investigation.actions.notEvidenceExport": "La protection empêche la suppression par rétention normale. Le téléchargement ZIP est un export de convenance, non un dossier de preuves vérifié.", + "investigation.actions.scope": "Portée de l'enregistrement", + "investigation.actions.selectedResult": "Événement et caméra sélectionnés", + "investigation.actions.fullWindow": "Toutes les caméras dans la fenêtre d'investigation", + "investigation.actions.preview": "Aperçu des enregistrements", + "investigation.actions.previewing": "Recherche d'enregistrements chevauchants…", + "investigation.actions.invalidRange": "Choisissez une plage horaire valide avec une fin postérieure au début.", + "investigation.actions.recordingCount": "{count} enregistrement(s) chevauchant(s)", + "investigation.actions.protectedCount": "{count} déjà protégé(s)", + "investigation.actions.noRecordings": "Aucun enregistrement terminé ne chevauche cette caméra et cette sélection temporelle.", + "investigation.actions.protectDenied": "{count} enregistrement(s) non protégé(s) sont hors de votre périmètre de protection et sont exclus de cette action.", + "investigation.actions.exportDenied": "Permission d'export manquante pour {count} enregistrement(s). Les téléchargements sont tout ou rien, cette sélection ne peut donc pas être exportée.", + "investigation.actions.camera": "Caméra", + "investigation.actions.recording": "Enregistrement", + "investigation.actions.size": "Taille", + "investigation.actions.notPermitted": "Non autorisé", + "investigation.actions.protectButton": "Protéger {count}", + "investigation.actions.protecting": "Protection en cours…", + "investigation.actions.protectUnavailable": "Aucun enregistrement non protégé que vous êtes autorisé à protéger.", + "investigation.actions.protectResult": "Protection terminée : {success} réussis, {failed} échoués.", + "investigation.actions.downloadButton": "Télécharger {count}", + "investigation.actions.downloadUnavailable": "Chaque enregistrement nécessite une permission d'export avant la création d'un ZIP.", + "investigation.actions.buildingArchive": "Création du ZIP…", + "investigation.actions.downloadFailed": "La création du ZIP a échoué sur le serveur.", + "investigation.actions.downloadTimedOut": "La création du ZIP n'a pas abouti en moins de cinq minutes. Essayez un intervalle plus restreint.", + "investigation.actions.downloadStarted": "Téléchargement du ZIP démarré.", + "investigation.backOneLevel": "Niveau précédent", + "investigation.thumbnailMinimumWindow": "Ceci est l'intervalle d'une seconde le plus restreint disponible. Le curseur partagé a tout de même été déplacé au moment sélectionné.", + "investigation.localSource": "local", + "investigation.mediaAvailable": "Média disponible", + "investigation.durationSeconds": "Durée : {count} s", + "investigation.pageNumber": "Page {count}", + "investigation.incompleteCoverage": "{count} lignes d'événements héritées n'ont pas pu être attribuées à une identité de caméra immuable.", + "investigation.spatialCoverageGap": "{count} lignes d'événements dans le périmètre n'avaient pas de zone délimitante et n'ont pas été recherchées spatialement.", + "investigation.noSpatialMetadata": "Aucun événement dans le périmètre ne possède de zone délimitante pour cette recherche par métadonnées.", + "investigation.selectCameraError": "Sélectionnez au moins une caméra.", + "investigation.selectRecordingError": "Sélectionnez au moins un enregistrement.", + "investigation.investigateSelectedCount": "Enquêter sur {count} enregistrement(s) sélectionné(s)", + "investigation.missingCameraIdentity": "Impossible d'enquêter : {count} enregistrement(s) sélectionné(s) n'ont pas d'identité de caméra.", + "investigation.recordingTimeError": "Les enregistrements sélectionnés n'ont pas de plage horaire valide.", + "investigation.windowLimit": "Les enregistrements sélectionnés dépassent la limite d'enquête de 31 jours.", + "investigation.timeRangeError": "L'heure de fin doit être postérieure à l'heure de début.", + "investigation.cameraLimit": "Une enquête peut inclure au maximum {count} caméras.", + "investigation.decoderLimit": "Seuls {count} lecteurs de caméra peuvent être actifs à la fois.", + "investigation.playbackControls": "Contrôles de lecture synchronisée", + "investigation.play": "Lecture", + "investigation.pause": "Pause", + "investigation.mode": "Mode de lecture", + "investigation.wallClock": "Temps réel", + "investigation.skipCommonGaps": "Ignorer les lacunes communes", + "investigation.speed": "Vitesse", + "investigation.sharedCursor": "Curseur UTC partagé", + "investigation.activePlayers": "lecteurs actifs", + "investigation.timeline": "chronologie partagée", + "investigation.segments": "segments", + "investigation.truncated": "tronqué", + "investigation.gap": "Aucune séquence", + "investigation.players": "Lecteurs de caméra synchronisés", + "investigation.activateCamera": "Activez au moins une ligne de chronologie pour charger la vidéo.", + "investigation.noFootage": "Aucune séquence", + "investigation.noFootageAtTime": "Aucune séquence au moment partagé", + "investigation.primaryAudio": "Audio principal", + "investigation.makePrimary": "Définir comme principal", + "investigation.status.loading": "Chargement du média", + "investigation.status.synchronizing": "Synchronisation", + "investigation.status.ready": "Synchronisé", + "investigation.status.late": "En retard — récupération", + "investigation.status.error": "Média indisponible", + "investigation.status.paused-by-browser": "Sélectionnez Lecture pour autoriser le média", + "streamsConfig.eptzTitle": "ePTZ fisheye", + "streamsConfig.eptzEnable": "Activer l'ePTZ fisheye côté navigateur", + "streamsConfig.eptzHelp": "Corrigez la distorsion du flux fisheye brut dans la Vue en direct, la lecture de la chronologie et l'Investigation. Cela ne modifie ni les enregistrements ni la sortie de la caméra.", + "streamsConfig.eptzModelHelp": "Projection : fisheye circulaire équidistant · Montage : plafond. Le centre et le rayon utilisent des coordonnées normalisées de l'image source.", + "streamsConfig.eptzCenterX": "Centre optique X", + "streamsConfig.eptzCenterY": "Centre optique Y", + "streamsConfig.eptzRadius": "Rayon du cercle image", + "streamsConfig.eptzLensFov": "Champ de vision de l'objectif (degrés)", + "streamsConfig.eptzRotation": "Rotation de l'objectif (degrés)", + "streamsConfig.eptzDefaultYaw": "Panoramique par défaut (degrés)", + "streamsConfig.eptzDefaultTilt": "Inclinaison par défaut (degrés)", + "streamsConfig.eptzViewFov": "Champ de vision par défaut", + "streamsConfig.eptzCalibrationHelp": "Faites glisser pour regarder autour, utilisez la molette ou le pincement pour zoomer, et appuyez sur Début pour réinitialiser la caméra virtuelle. Ajustez le centre et le rayon si le bord du cercle image n'est pas aligné.", + "settings.archive.targetType": "Type de stockage", + "settings.archive.filesystem": "Système de fichiers local ou monté (NFS/SAN)", + "settings.archive.s3": "Bucket d'archivage compatible S3", + "settings.archive.endpoint": "Point de terminaison HTTPS", + "settings.archive.region": "Région", + "settings.archive.bucket": "Bucket dédié", + "settings.archive.credential_ref": "Référence d'identifiants", + "settings.archive.budget": "Budget d'archivage (GiB, 0 = illimité)", + "settings.archive.connectionHelp": "Utilisez un bucket privé, sans versionnage et sans règles d'expiration de cycle de vie. La référence d'identifiants sélectionne un fichier secret monté sur le serveur. Saisissez l'emplacement géré sous la forme s3://bucket/instance-prefix.", + "settings.archive.policy": "Politique d'archivage externe", + "settings.archive.archive_after_seconds": "Archiver après capture (secondes, -1 = désactivé)", + "settings.archive.hot_residency_seconds": "Conserver une copie chaude (secondes, -1 = déplacer après archivage)", + "settings.archive.archive_protected": "Prioriser l'archivage des enregistrements protégés", + "settings.archive.archive_on_pressure": "Archiver en priorité lorsque le stockage chaud est sous pression", + "settings.archive.policyHelp": "Le délai d'archivage utilise l'âge de la capture et nécessite un enregistrement terminé. -1 désactive l'archivage basé sur l'âge ou supprime le minimum de résidence chaude ; 0 signifie immédiatement. Les modifications s'appliquent aux nouveaux enregistrements. Vérifiez les enregistrements existants pour leur appliquer une nouvelle révision.", + "settings.archive.deletion_pending": "Suppression en attente", + "settings.archive.archived": "Archivé", + "settings.archive.hot": "Chaud", + "settings.archive.hot_and_archive": "Chaud + archive", + "settings.archive.archiving": "Archivage", + "settings.archive.preparing": "Préparation de la lecture", + "settings.archive.unavailable": "Indisponible", + "settings.archive.operations": "Opérations d'archivage", + "settings.archive.readOnly": "Mode récupération : la migration et la suppression des enregistrements sont suspendues.", + "settings.archive.disabledBuild": "Le support S3 est désactivé dans cette version. Les cibles de système de fichiers montées restent disponibles.", + "settings.archive.stored": "Stocké dans des buckets", + "settings.archive.backlog": "File d'attente de transfert", + "settings.archive.cache": "Cache de récupération", + "settings.archive.objectsRemaining": "objets restants", + "settings.archive.waitingForReaders": "En file d'attente ou en attente de lecteurs actifs.", + "settings.archive.applied": "Révision de la politique appliquée aux enregistrements existants", + "settings.archive.reviewExisting": "Vérifier les enregistrements existants", + "settings.archive.applySummary": "{count} enregistrements ({bytes}) utiliseront cette révision. {expired} ont déjà dépassé sa limite de rétention.", + "settings.archive.applyHelp": "Les protections et les remplacements d'enregistrement s'appliquent toujours. La rétention du flux et du système s'applique également. Le nouveau délai et la nouvelle destination d'archivage prendront effet lors de la prochaine analyse du cycle de vie.", + "settings.archive.applyBlocked": "Terminez ou résolvez les transferts associés avant d'appliquer cette révision.", + "settings.archive.apply": "Appliquer aux enregistrements existants", + "common.fullscreenUnsupported": "Le mode plein écran n'est pas pris en charge par ce navigateur.", + "recordings.viewInTimelineTitle": "Afficher ce flux à ce moment dans la vue Chronologie", + "recordings.clickToRetry": "Cliquez pour réessayer", + "timeline.previousDay": "Jour précédent", + "timeline.nextDay": "Jour suivant", + "timeline.previousMonth": "Mois précédent", + "timeline.nextMonth": "Mois suivant", + "settings.searchLabel": "Rechercher dans les paramètres", + "settings.clearSearch": "Effacer la recherche", + "recordings.addTagPlaceholder": "Ajouter un tag…", + "recordings.addNewTagPlaceholder": "Ajouter un nouveau tag…" +} diff --git a/web/public/locales/it.json b/web/public/locales/it.json index a48f684a..17831a79 100644 --- a/web/public/locales/it.json +++ b/web/public/locales/it.json @@ -9,6 +9,84 @@ "nav.timeline": "Cronologia", "nav.health": "Salute", "nav.toggleMenu": "Mostra/nascondi menu", + "live.navigator.title": "Navigatore", + "live.navigator.subtitle": "Posizioni, layout e attività", + "live.navigator.cameras": "Telecamere", + "live.navigator.plans": "Pianta", + "live.navigator.views": "Viste", + "live.navigator.events": "Eventi", + "live.navigator.search": "Trova una telecamera…", + "live.navigator.allCameras": "Tutte le telecamere", + "live.navigator.unassigned": "Non assegnate", + "live.navigator.noCameras": "Nessuna telecamera corrisponde a questo ambito.", + "live.navigator.saveCurrent": "Salva il layout corrente", + "live.navigator.noLayouts": "Nessun layout salvato per ora.", + "live.navigator.layoutNamePrompt": "Dai un nome a questo layout della vista live", + "live.navigator.shareLayoutPrompt": "Condividere questo layout con altri operatori?", + "live.navigator.layoutSaved": "{name} salvato", + "live.navigator.layoutLoaded": "{name} caricato", + "live.navigator.deleteLayoutConfirm": "Eliminare {name}?", + "live.navigator.shared": "Condiviso", + "live.navigator.loadingEvents": "Caricamento degli eventi recenti…", + "live.navigator.noRecentEvents": "Nessun rilevamento nell'ultima ora.", + "live.navigator.expand": "Espandi il navigatore", + "live.navigator.collapse": "Comprimi il navigatore", + "live.plan.navigatorHelp": "Scegli un edificio o un piano. Le anteprime delle telecamere si aprono solo su richiesta.", + "live.plan.noPlans": "Nessuna pianta di edificio per ora. Creane una nello spazio di lavoro delle piante.", + "live.plan.emptyTitle": "Crea una vista spaziale delle telecamere", + "live.plan.emptyDescription": "Una pianta mostra i marcatori di stato per l'intero sito e apre il video solo quando un operatore lo richiede. Disegna qui le stanze e i muri, oppure carica una pianta scansionata, un disegno del sito o un'istantaneo dal tuo software NVR, poi mappa le telecamere sulle stanze reali.", + "live.plan.sketch.tools": "Strumenti di layout", + "live.plan.sketch.tool.select": "Seleziona", + "live.plan.sketch.tool.room": "Stanza", + "live.plan.sketch.tool.wall": "Muro", + "live.plan.sketch.tool.area": "Area", + "live.plan.sketch.tool.label": "Etichetta", + "live.plan.sketch.undo": "Annulla disegno", + "live.plan.sketch.redo": "Ripeti disegno", + "live.plan.sketch.snap": "Aggancia alla griglia", + "live.plan.sketch.hint.select": "Trascina forme o telecamere per spostarle. Fai clic su una forma per modificarla; tieni premuto Alt per ignorare la griglia.", + "live.plan.sketch.hint.room": "Trascina sulla pianta per disegnare una stanza o il contorno di un edificio.", + "live.plan.sketch.hint.wall": "Fai clic per aggiungere punti del muro. Doppio clic o Enter per terminare, Escape per annullare.", + "live.plan.sketch.hint.area": "Fai clic per delimitare un'area. Fai clic sul primo punto o premi Enter per chiuderla.", + "live.plan.sketch.hint.label": "Fai clic sulla pianta per posizionare un'etichetta di testo.", + "live.plan.sketch.type.rect": "Stanza", + "live.plan.sketch.type.wall": "Muro", + "live.plan.sketch.type.area": "Area", + "live.plan.sketch.type.label": "Etichetta", + "live.plan.sketch.pointCount": "{count} punti", + "live.plan.sketch.defaultLabel": "Etichetta", + "live.plan.sketch.shapes": "Forme del layout", + "live.plan.sketch.noShapes": "Nessun disegno per ora. Scegli uno strumento sopra la pianta per iniziare.", + "live.plan.sketch.tone": "Colore", + "live.plan.sketch.tone.slate": "Grigio piombo", + "live.plan.sketch.tone.blue": "Blu", + "live.plan.sketch.tone.green": "Verde", + "live.plan.sketch.tone.amber": "Ambra", + "live.plan.sketch.tone.red": "Rosso", + "live.plan.sketch.tone.violet": "Viola", + "live.plan.sketch.labelText": "Etichetta", + "live.plan.sketch.text": "Testo", + "live.plan.sketch.size": "Dimensione", + "live.plan.sketch.size.sm": "Piccola", + "live.plan.sketch.size.md": "Media", + "live.plan.sketch.size.lg": "Grande", + "live.plan.sketch.filled": "Riempi la stanza", + "live.plan.sketch.left": "Sinistra %", + "live.plan.sketch.top": "Alto %", + "live.plan.sketch.width": "Larghezza %", + "live.plan.sketch.height": "Altezza %", + "live.plan.sketch.points": "Punti", + "live.plan.sketch.point": "Punto {index}", + "live.plan.sketch.delete": "Elimina la forma", + "live.plan.sketch.duplicate": "Duplica", + "live.plan.sketch.deselect": "Fatto", + "live.plan.sketch.emptyTitle": "Ancora niente su questa pianta", + "live.plan.sketch.emptyBody": "Disegna qui stanze, muri ed etichette, oppure carica una pianta scansionata, un disegno del sito o un'esportazione PNG/JPEG (fino a 768 KB).", + "live.plan.sketch.emptyBodyReadOnly": "Un amministratore può disegnare il layout o caricare una pianta dell'edificio reale.", + "live.plan.sketch.drawLayout": "Disegna il layout", + "live.plan.sketch.uploadImage": "Carica immagine", + "live.plan.sketch.limitReached": "Limite forme raggiunto ({max})", + "live.plan.sketch.discardDrawing": "Disegno annullato", "streamHealth.title": "Flusso di salute", "streamHealth.loading": "Caricamento dati sanitari...", "streamHealth.error": "Impossibile caricare i dati sanitari", @@ -326,13 +404,13 @@ "timeline.help.arrowKeys": "Usa le frecce sinistra e destra per saltare tra le registrazioni; fai clic sul video per usare le frecce come spostamento di 1 secondo", "timeline.help.playFromCursor": "Usa il pulsante verde di riproduzione per avviare dalla posizione corrente del cursore", "timeline.help.zoomControls": "Usa i pulsanti Adatta, + e − oppure Ctrl/Cmd + rotella del mouse per zoomare la timeline", - "timeline.help.panControls": "Spostati a sinistra/destra al livello di zoom corrente con Maiusc + rotella del mouse o un gesto orizzontale sul trackpad", + "timeline.help.panControls": "Spostati a sinistra/destra al livello di zoom corrente con Shift + rotella del mouse o un gesto orizzontale sul trackpad", "timeline.help.actions": "Usa Snapshot, Scarica, Proteggi o Elimina sulla registrazione attualmente in riproduzione", "timeline.arrowKeysHelpTitle": "Fai clic sul video per usare le frecce come spostamento di 1 secondo. Fai clic altrove per tornare al salto tra registrazioni.", "timeline.arrowKeys": "Tasti freccia", "timeline.seekOneSecond": "sposta ±1 s", "timeline.jumpRecordings": "salta tra le registrazioni", - "timeline.inlineHint": "Fai clic sul video per spostarti di 1 s con le frecce · Fai clic sulla timeline per passare tra le registrazioni · Maiusc+rotella per spostare · Ctrl/Cmd+rotella per zoomare", + "timeline.inlineHint": "Fai clic sul video per spostarti di 1 s con le frecce · Fai clic sulla timeline per passare tra le registrazioni · Shift+rotella per spostare · Ctrl/Cmd+rotella per zoomare", "timeline.selectedRecordingsTimeline": "Timeline delle registrazioni selezionate", "timeline.timelinePlayback": "Riproduzione timeline", "timeline.recordingsCount": "{count} registrazioni", @@ -405,6 +483,12 @@ "live.errorProcessingStreams": "Errore nell'elaborazione dei flussi: {message}", "live.couldNotEnableFullscreen": "Impossibile abilitare la modalità a schermo intero: {message}", "live.allTags": "Tutti i tag", + "live.favorites": "Preferiti", + "live.favoritesOnly": "Mostra solo le telecamere preferite", + "live.addFavorite": "Aggiungi {stream} ai preferiti", + "live.removeFavorite": "Rimuovi {stream} dai preferiti", + "live.noFavorites": "Nessuna telecamera preferita per ora. Usa la stella su una scheda telecamera per aggiungerne una.", + "live.favoriteUpdateError": "Impossibile aggiornare i preferiti: {message}", "live.tags": "Tag", "live.stream": "Flusso", "live.filterByTag": "Filtra per tag: {tag}", @@ -589,6 +673,7 @@ "live.forceRefreshWarning": "Ciò interromperà brevemente la connessione go2rtc, interrompendo la registrazione attiva. La registrazione riprenderà automaticamente.", "live.viewInTimeline": "Visualizza nella sequenza temporale", "live.toggleFullscreen": "Attiva/disattiva schermo intero", + "live.resetZoom": "Reimposta lo zoom", "live.streamStarting": "Avvio del flusso...", "live.go2rtcNotRespondingRetry": "go2rtc è abilitato ma non risponde. Controlla lo stato del servizio go2rtc. Fai clic su Riprova per riprovare.", "live.go2rtcHlsFailedRetry": "Errore del flusso HLS di go2rtc. Fai clic su Riprova per riprovare.", @@ -603,12 +688,14 @@ "live.failedToCreateMediaBuffer": "Impossibile creare il buffer multimediale", "live.webSocketConnectionError": "Errore di connessione WebSocket", "live.webrtcAutoplayBlocked": "Fai clic per riprodurre il video (riproduzione automatica bloccata)", + "live.audioPlaybackBlocked": "Il browser ha bloccato l'audio della telecamera. Fai di nuovo clic sul pulsante altoparlante per riprovare.", "live.webrtcConnectionLostRetry": "Connessione WebRTC interrotta. Fai clic su Riprova per riconnetterti.", "live.streamConnectedNoVideoDataRetry": "Flusso connesso ma senza dati video. Fai clic su Riprova per riconnetterti.", "live.failedToLoadVideo": "Impossibile caricare il video", "live.webrtcIceConnectionFailed": "WebRTC ICE connessione non riuscita", "live.webrtcConnectionLostPleaseRetry": "WebRTC connessione interrotta. Per favore riprova.", "live.autoRetryingIn": "Nuovo tentativo tra {seconds} s…", + "live.fullscreenSubStreamFallback": "{stream}: banda passante insufficiente per il flusso a piena risoluzione a schermo intero; passato al sotto-flusso.", "live.connectionTimeoutCheckNetwork": "Timeout della connessione. Controlla le impostazioni di rete/firewall.", "live.failedToEstablishWebrtcConnection": "Impossibile stabilire la connessione WebRTC", "live.cannotConnectToSource": "Impossibile connettersi alla sorgente telecamera", @@ -622,6 +709,16 @@ "live.connectionQuality.bad": "Cattivo", "live.muteCameraAudio": "Disattiva l'audio della fotocamera", "live.unmuteCameraAudio": "Riattiva l'audio della fotocamera", + "live.tileActions": "Azioni telecamera", + "live.takeSnapshot": "Scatta un'istantanea", + "live.openStreamRecordings": "Apri le registrazioni di questo flusso", + "live.enterReorderMode": "Riordina le telecamere", + "live.pullToRefresh": "Trascina per aggiornare i flussi", + "live.releaseToRefresh": "Rilascia per aggiornare i flussi", + "live.refreshingStreams": "Aggiornamento dei flussi…", + "live.streamsRefreshed": "Flussi aggiornati", + "live.refreshStreamsFailed": "Impossibile aggiornare i flussi: {message}", + "live.tipDoubleTapFullscreen": "Suggerimento: tocca due volte una scheda per aprirla a schermo intero.", "live.switchToToggleMode": "Passa alla modalità di commutazione", "live.switchToPushToTalkMode": "Passa a Push-to-Talk", "live.releaseToStopTalking": "Rilascia per smettere di parlare", @@ -636,6 +733,40 @@ "live.pauseForPrivacyConfirm": "Mettere in pausa questo streaming per motivi di privacy? La registrazione e la visualizzazione dal vivo verranno interrotte, ma lo streaming rimarrà visibile su questa pagina con un overlay sulla privacy. Al termine, fare clic su Riprendi.", "live.streamPausedForPrivacy": "Flusso sospeso per privacy", "live.resumeStream": "Riprendi streaming", + "live.dayNightControl": "Modalità giorno/notte", + "live.dayNightLoading": "Caricamento…", + "live.dayNightApplying": "Applicazione…", + "live.dayNightMode_auto": "Auto", + "live.dayNightMode_day": "Giorno", + "live.dayNightMode_night": "Notte", + "live.dayNightMode_unknown": "Sconosciuto", + "live.dayNightApplied": "Modalità giorno/notte impostata su {mode}", + "live.dayNightApplyFailed": "Impossibile impostare la modalità giorno/notte", + "live.dayNightLoadFailed": "Impossibile leggere la modalità giorno/notte", + "live.playbackFallbackUsed": "Ripiego: {transport}", + "live.playbackTransportUnavailable": "{transport} è disabilitato sul server per questo flusso.", + "live.recordingMode.constant": "Registrazione continua", + "live.recordingMode.detection": "Registrazione su rilevamento", + "live.recordingMode.schedule": "Registrazione programmata", + "live.recordingMode.none": "Non in registrazione", + "live.health.healthy": "Flusso integro", + "live.health.degraded": "Flusso in buffering o in recupero", + "live.health.offline": "Flusso non disponibile", + "live.enterPictureInPicture": "Apri immagine nell'immagine", + "live.exitPictureInPicture": "Chiudi immagine nell'immagine", + "live.pictureInPictureError": "Immagine nell'immagine non riuscita: {message}", + "live.alwaysFullscreenOnTapEnable": "Attiva lo schermo intero con un solo tocco sulla scheda", + "live.alwaysFullscreenOnTapDisable": "Disattiva lo schermo intero con un solo tocco sulla scheda", + "live.displayMode": "Modalità di visualizzazione", + "live.displayModeFit": "Adatta", + "live.displayModeFill": "Riempi", + "live.displayModeFitDescription": "Adatta: mostra tutto il fotogramma con bordi neri", + "live.displayModeFillDescription": "Riempi: riempi la scheda e ritaglia i bordi del fotogramma", + "live.slideshowStartCameras": "Avvia presentazione: scorri le telecamere", + "live.slideshowStartPages": "Avvia presentazione: scorri le pagine della griglia", + "live.slideshowStop": "Ferma la presentazione", + "live.slideshowInterval": "Intervallo della presentazione", + "live.slideshowSeconds": "{seconds} s", "streams.toggleDisable": "Disabilita flusso", "streams.toggleEnable": "Abilita flusso", "streams.readOnlyInsufficientPermissions": "Sola lettura (autorizzazioni insufficienti per la modifica)", @@ -759,9 +890,9 @@ "streamsConfig.streamNameImmutable": "Il nome del flusso non può essere modificato dopo la creazione", "streamsConfig.streamNameAllowedChars": "Sono consentiti solo lettere, numeri, \".\", \"-\" e \"_\" (senza spazi).", "streamsConfig.streamUrl": "URL del flusso", - "streamsConfig.streamUrlPlaceholder": "rtsp://nomeutente:password@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "Flusso secondario URL (opzionale)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://nomeutente:password@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "URL del flusso a bassa risoluzione per la vista griglia della dashboard. Lascia vuoto per usare ovunque il flusso principale. Il flusso secondario viene usato solo per l'anteprima live in modalità griglia; registrazione e schermo intero usano sempre il flusso principale.", "streamsConfig.urlCredentialsHiddenTitle": "Le credenziali URL sono nascoste in modalità demo/visualizzatore", "streamsConfig.urlCredentialsHidden": "URL credenziali nascoste per sicurezza", @@ -819,7 +950,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "Assicurati che light-object-detect sia in esecuzione su questo endpoint", "streamsConfig.customApiEndpointUrl": "Personalizzato API Endpoint URL", "streamsConfig.useDefaultEndpoint": "Usa endpoint predefinito", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "Inserisci il valore URL completo nell'endpoint API di rilevamento personalizzato", "streamsConfig.overrideWithCustomEndpoint": "Sostituisci con endpoint personalizzato", "streamsConfig.detectionThreshold": "Soglia di rilevamento", @@ -1056,7 +1187,7 @@ "settings.detectionModelsPath": "Percorso dei modelli di rilevamento", "settings.detectionModelsPathHelp": "Directory in cui sono archiviati i modelli di rilevamento", "settings.apiDetectionUrl": "API Rilevamento URL", - "settings.apiDetectionUrlHelp": "URL dell'endpoint di rilevamento oggetti esterni API", + "settings.apiDetectionUrlHelp": "Endpoint light-object-detect, es. http://localhost:8000/api/v1/detect. Lo snapshot viene caricato come multipart form data con i parametri di query backend e confidence_threshold aggiunti.", "settings.apiDetectionBackend": "API Backend di rilevamento", "settings.apiDetectionBackendOnnx": "ONNX Tempo di esecuzione", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1156,5 +1287,1361 @@ "settings.discoveryIntervalSecondsRangeHelp": "La frequenza con cui eseguire la scansione delle fotocamere (30-3600 secondi)", "settings.discoveryNetwork": "Rete di scoperta", "settings.discoveryNetworkExamples": "Esempi: 192.168.1.0/24, 10.0.0.0/16, automatico", - "settings.saveSettings": "Salva impostazioni" + "settings.saveSettings": "Salva impostazioni", + "live.plan.previewUnavailable": "Anteprime telecamera non disponibili", + "live.plan.previewAlt": "Vista attuale da {name}", + "live.plan.degreesValue": "{value} gradi", + "live.plan.inDegrees": "{label} in gradi", + "live.plan.imageDimensionsError": "Impossibile leggere le dimensioni dell'immagine", + "live.plan.loading": "Caricamento delle piante di edificio…", + "live.plan.created": "{name} creata", + "live.plan.renamed": "Rinominata in {name}", + "live.plan.deleted": "{name} eliminata", + "live.plan.backgroundType": "Lo sfondo deve essere un'immagine PNG o JPEG", + "live.plan.backgroundTooLarge": "Immagine di sfondo troppo grande; il massimo è 768 KB", + "live.plan.backgroundAspect": "Caricata, ma le proporzioni dell'immagine non corrispondono a nessuna dimensione di tela valida", + "live.plan.backgroundUpdatedSave": "Sfondo aggiornato per {name}; salva il layout per applicarne la dimensione della tela", + "live.plan.backgroundNotResized": "Sfondo caricato, ma la tela non è stata ridimensionata: {error}", + "live.plan.backgroundUpdated": "Sfondo aggiornato per {name}", + "live.plan.backgroundRemoved": "Sfondo rimosso", + "live.plan.saved": "{name} salvata", + "live.plan.createTitle": "Crea pianta di edificio", + "live.plan.createDescription": "Dai un nome chiaro a questo edificio o piano. Disegna il layout o carica un'immagine della pianta, poi posiziona le telecamere.", + "live.plan.nameLabel": "Nome della pianta", + "live.plan.namePlaceholder": "Edificio principale · Primo piano", + "live.plan.createConfirm": "Crea pianta", + "live.plan.eyebrow": "Pianta di edificio", + "live.plan.placedSummary": "{placed} posizionate · {live} live ora", + "live.plan.zoomAndPan": "Zoom e scorrimento della pianta", + "live.plan.panLeft": "Scorri a sinistra", + "live.plan.panUp": "Scorri verso l'alto", + "live.plan.panDown": "Scorri verso il basso", + "live.plan.panRight": "Scorri a destra", + "live.plan.zoomOut": "Riduci lo zoom", + "live.plan.zoomIn": "Aumenta lo zoom", + "live.plan.fitTitle": "Adatta la pianta", + "live.plan.fit": "Adatta", + "live.plan.backgroundMenu": "Sfondo…", + "live.plan.save": "Salva la pianta", + "live.plan.uploadBackgroundTitle": "Carica un'immagine PNG o JPEG come sfondo della pianta", + "live.plan.replaceBackground": "Sostituisci lo sfondo", + "live.plan.uploadBackground": "Carica lo sfondo", + "live.plan.removeBackground": "Rimuovi lo sfondo", + "live.plan.rename": "Rinomina", + "live.plan.newPlan": "Nuova pianta", + "live.plan.editLayout": "Modifica il layout", + "live.plan.placementHint": "Fai clic sulla pianta per posizionare {name}", + "live.plan.clusterLabel": "{count} telecamere; ingrandisci", + "live.plan.markerLabel": "{name}; {availability}; orientata a {rotation}° con un campo visivo di {fov}°", + "live.plan.cameraFallback": "Telecamera", + "live.plan.legendLive": "Live", + "live.plan.canvas": "Tela della pianta", + "live.plan.width": "Larghezza", + "live.plan.height": "Altezza", + "live.plan.canvasHint": "Il caricamento di un'immagine di sfondo ridimensiona la tela per corrisponderle.", + "live.plan.canvasInvalid": "La larghezza deve essere 400–4000 e l'altezza 300–4000.", + "live.plan.openLive": "Apri la telecamera live", + "live.plan.direction": "Direzione della telecamera", + "live.plan.fov": "Campo visivo", + "live.plan.coverageNote": "Gli spicchi mostrano solo direzione e angolo; la distanza sulla pianta non è calibrata.", + "live.plan.removeCamera": "Rimuovi dalla pianta", + "live.plan.selectCamera": "Seleziona una telecamera", + "live.plan.selectHintEditing": "Trascina i marcatori posizionati per rifinire. Ispeziona lo stato e apri una vista live su richiesta.", + "live.plan.selectHint": "Ispeziona lo stato e apri una vista live su richiesta.", + "live.plan.cameras": "Telecamere della pianta", + "live.plan.findPlaceholder": "Trova su questa pianta…", + "live.plan.findLabel": "Trova una telecamera su questa pianta", + "live.plan.unplaced": "Telecamere non posizionate", + "live.plan.unplacedHint": "Seleziona una telecamera, poi fai clic sulla sua posizione nella pianta.", + "live.plan.renameTitle": "Rinomina la pianta", + "live.plan.renameDescription": "Le piante sono condivise con ogni operatore di questo sito.", + "live.plan.deleteTitle": "Elimina pianta", + "live.plan.deleteMessage": "Eliminare “{name}” e lo sfondo caricato? Le posizioni delle telecamere su questa pianta vengono rimosse; le telecamere stesse restano invariate.", + "setupWizard.welcomeTitle": "Benvenuto in LightNVR", + "setupWizard.welcomeIntro": "Configuriamo il tuo NVR in pochi passaggi rapidi. Potrai sempre rivedere queste impostazioni in seguito dalla pagina Impostazioni.", + "setupWizard.welcomeStorage": "Percorso di archiviazione e limiti di dimensione", + "setupWizard.welcomePerformance": "Limiti di prestazioni per il numero di telecamere", + "setupWizard.welcomeSecurity": "Accesso amministratore protetto", + "setupWizard.storageTitle": "Archiviazione e database", + "setupWizard.storageIntro": "Dove conservare registrazioni e database?", + "setupWizard.storagePath": "Percorso di archiviazione delle registrazioni", + "setupWizard.storagePathHint": "Percorso assoluto in cui vengono scritti i file video.", + "setupWizard.maxStorage": "Dimensione massima archiviazione (GB)", + "setupWizard.maxStorageHint": "0 = illimitato.", + "setupWizard.dbPath": "Percorso del database", + "setupWizard.dbPathHint": "Posizione del file di database SQLite.", + "setupWizard.performanceTitle": "Prestazioni", + "setupWizard.performanceIntro": "Queste impostazioni controllano la capacità, non la qualità video. La maggior parte degli utenti può mantenere i valori predefiniti.", + "setupWizard.threadPool": "Dimensione del pool di thread di lavoro", + "setupWizard.threadPoolInfo": "riguarda le attività in background di web/server. Il valore consigliato è in genere il migliore, salvo ottimizzazioni delle prestazioni.", + "setupWizard.maxStreams": "Numero massimo di flussi simultanei", + "setupWizard.maxStreamsInfo": "è il limite di capacità telecamere di questa istanza in esecuzione. Impostalo almeno al numero di telecamere che prevedi di aggiungere, più un piccolo margine.", + "setupWizard.important": "Importante:", + "setupWizard.restartWarning": "se modifichi una delle due impostazioni, il nuovo valore viene salvato ora ma non sarà usato fino al riavvio di LightNVR. Ad esempio, se il limite attuale dei flussi è 1 e lo porti a 32, devi riavviare prima di aggiungere telecamere oltre il vecchio limite.", + "setupWizard.threadPoolHintCores": "Consigliato: {recommended} (2× la tua CPU a {cores} core). Controlla i thread di lavoro in background di libuv. Intervallo: 2–128.", + "setupWizard.threadPoolHint": "Consigliato: {recommended} (2× i core della tua CPU). Controlla i thread di lavoro in background di libuv. Intervallo: 2–128.", + "setupWizard.maxStreamsHint": "Quante telecamere LightNVR può mantenere attive contemporaneamente. Predefinito 32, massimo {max}. Se prevedi 8 telecamere, scegli almeno 8. Richiede il riavvio per avere effetto.", + "setupWizard.completeTitle": "Configurazione completata!", + "setupWizard.saved": "Le impostazioni sono state salvate correttamente.", + "setupWizard.notSaved": "Nessuna impostazione modificata: verranno usati i valori predefiniti.", + "setupWizard.restartRequired": "Riavvio richiesto", + "setupWizard.restartRequiredInfo": "le modifiche alla dimensione del pool di thread e/o al numero massimo di flussi sono salvate, ma non avranno effetto fino al riavvio del servizio. Riavvia prima di aggiungere telecamere o di attendere il nuovo limite di capacità.", + "setupWizard.saveFailed": "Salvataggio delle impostazioni non riuscito: {error}", + "setupWizard.back": "Indietro", + "setupWizard.saving": "Salvataggio…", + "setupWizard.saveContinue": "Salva e continua", + "setupWizard.next": "Avanti →", + "setupWizard.finish": "Vai alla dashboard", + "setupWizard.skip": "Salta la procedura guidata", + "live.eptzCanvasLabel": "Vista fisheye con pan, tilt e zoom elettronici", + "live.eptzCanvasHint": "Trascina per pan e tilt; rotella o pizzico per lo zoom; Home ripristina", + "live.eptzReset": "Reimposta la vista ePTZ", + "live.autoShort": "Auto", + "live.webrtcShort": "WebRTC", + "nav.investigation": "Indagine", + "availability.label": "Disponibilità telecamere", + "availability.live": "Live ora", + "availability.offline": "Offline (connessa in precedenza)", + "availability.neverConnected": "Mai connessa", + "availability.disabled": "Disabilitata", + "availability.all": "Tutte le telecamere", + "streams.inventory": "Inventario", + "streams.configuration": "Configurazione", + "events.tab": "Eventi", + "events.eyebrow": "Integrazioni basate su eventi", + "events.title": "Eventi e routing", + "events.description": "Trasforma gli eventi di telecamera e di sistema in flussi MQTT persistenti per automazione, servizi di notifica ed elaborazione esterna. LightNVR fornisce l'interfaccia eventi; la consegna via email e SMS resta nei servizi a valle.", + "events.routes": "Rotte", + "events.destinations": "Destinazioni", + "events.catalog": "Catalogo eventi", + "events.enable": "Abilita", + "events.loadError": "Impossibile caricare la configurazione di routing degli eventi", + "events.accessDenied": "Accesso negato - privilegi insufficienti", + "events.summary.routes": "Rotte", + "events.summary.enabled": "{count} abilitate", + "events.summary.destinations": "Destinazioni", + "events.summary.managedActive": "{count} gestite e attive", + "events.summary.types": "Tipi registrati", + "events.summary.registry": "Catalogo eventi versionato", + "events.summary.interface": "Interfaccia", + "events.summary.interfaceHelp": "Output eventi persistente", + "events.route.add": "Aggiungi rotta", + "events.route.addTitle": "Crea rotta eventi", + "events.route.editTitle": "Modifica rotta eventi", + "events.route.create": "Crea rotta", + "events.route.editorDescription": "Scegli quali eventi qualificano, quali telecamere sono incluse, dove vengono inviati e come vengono controllate le sorgenti rumorose.", + "events.route.emptyTitle": "Nessun percorso di eventi configurato", + "events.route.emptyDescription": "Crea un percorso per selezionare tipi di eventi, ambito telecamere, pianificazione, policy di soppressione e destinazione MQTT.", + "events.route.enabled": "Percorso abilitato", + "events.route.enabledHelp": "Gli eventi corrispondenti vengono accettati per la consegna persistente", + "events.route.destination": "Destinazione", + "events.route.destinationHelp": "Un evento corrispondente viene persistito una volta per ogni destinazione univoca.", + "events.route.eventTypes": "Tipi di eventi", + "events.route.eventTypesHelp": "Seleziona uno o più contratti di evento versionati dal registro.", + "events.route.detectionFilters": "Filtra rilevamenti di oggetti", + "events.route.detectionFiltersHelp": "Richiedi facoltativamente etichette, zone o una confidenza minima per gli eventi di rilevamento oggetti.", + "events.route.healthFilters": "Filtra eventi di stato di sistema", + "events.route.healthFiltersHelp": "Abbina facoltativamente codici di condizione di stato o gravità registrati. I valori disponibili provengono da questo registratore.", + "events.route.healthConditions": "Condizioni di stato (qualsiasi)", + "events.route.healthSeverities": "Gravità (qualsiasi)", + "events.route.healthRegistryUnavailable": "Il registro delle condizioni di stato non è disponibile. Ricarica prima di configurare i filtri delle condizioni.", + "events.route.labels": "Etichette (qualsiasi)", + "events.route.zones": "ID zona (qualsiasi)", + "events.route.listHelp": "Separa i valori con virgole.", + "events.route.minConfidence": "Confidenza minima", + "events.route.confidenceHelp": "Un valore da 0 a 1.", + "events.route.cameraScope": "Ambito telecamere", + "events.route.cameraScopeHelp": "Riutilizza posizioni della flotta, tag, raccolte di attributi o telecamere esplicite senza caricare l'intera flotta.", + "events.route.allCameras": "Tutte le telecamere", + "events.route.dynamicScope": "Selettore telecamere dinamico", + "events.route.systemScopeHelp": "Gli eventi di sistema non sono telecamere. I selettori di telecamere non sono disponibili quando questo percorso include eventi a livello di sistema.", + "events.route.schedule": "Pianificazione", + "events.route.scheduleHelp": "Utilizza l'ora di occorrenza dell'evento in un fuso orario IANA; sono supportate finestre notturne.", + "events.route.restrictSchedule": "Solo durante le finestre configurate", + "events.route.suppression": "Policy di rumore e consegna", + "events.route.suppressionHelp": "Lo zero disabilita un controllo. La soppressione avanza solo dopo che la destinazione accetta l'evento persistente.", + "events.route.debounce": "Secondi di debounce", + "events.route.debounceHelp": "Le osservazioni ripetute estendono questo intervallo di silenzio.", + "events.route.cooldown": "Secondi di cooldown", + "events.route.cooldownHelp": "Intervallo minimo dopo un evento accettato.", + "events.route.grouping": "Secondi della finestra di raggruppamento", + "events.route.groupingHelp": "Mantieni il primo evento e unisci le ripetizioni.", + "events.route.rateLimit": "Eventi al minuto", + "events.route.rateLimitHelp": "Massimo a finestra fissa per percorso e telecamera.", + "events.route.deliveryPolicy": "Criterio di consegna", + "events.route.suppressionActive": "Controlli rumore attivi", + "events.route.everyMatch": "Ogni corrispondenza", + "events.route.preview": "Anteprima percorso", + "events.route.previewing": "Anteprima in corso…", + "events.route.previewResult": "Anteprima percorso", + "events.route.cameraMatches": "{count} telecamere corrispondono", + "events.route.previewNoPublish": "L'anteprima valida la regola completa e risolve un campione di telecamere; non pubblica mai un evento.", + "events.route.systemPreviewHelp": "Gli eventi di sistema ignorano la selezione delle telecamere e pertanto riportano zero telecamere corrispondenti in questa anteprima.", + "events.route.created": "Percorso evento creato", + "events.route.updated": "Percorso evento aggiornato", + "events.route.deleted": "Percorso evento eliminato", + "events.route.disabled": "Percorso evento disabilitato", + "events.route.enabledMessage": "Percorso evento abilitato", + "events.route.deleteConfirm": "Eliminare il percorso evento \"{name}\"?", + "events.route.validation.name": "Inserisci un nome per il percorso.", + "events.route.validation.destination": "Scegli una destinazione.", + "events.route.validation.event_types": "Seleziona almeno un tipo di evento.", + "events.route.validation.selector": "Completa o correggi il selettore di telecamere.", + "events.route.validation.system_scope": "I selettori di telecamere non possono essere utilizzati con eventi a livello di sistema.", + "events.route.validation.detection_type": "I filtri di rilevamento richiedono il tipo di evento object-detection.", + "events.route.validation.detection_filter": "Aggiungi almeno un'etichetta di rilevamento, una zona o una soglia di confidenza.", + "events.route.validation.confidence": "La confidenza minima deve essere compresa tra 0 e 1.", + "events.route.validation.predicate_mix": "I filtri di rilevamento e di stato non possono essere combinati in un unico percorso.", + "events.route.validation.health_type": "I filtri di stato richiedono solo tipi di evento di stato del sistema registrati.", + "events.route.validation.health_filter": "Seleziona almeno una condizione di stato o gravità registrata.", + "events.route.validation.health_condition": "Seleziona solo i codici di condizione restituiti dal registro di salute del registratore.", + "events.route.validation.health_severity": "Seleziona solo le gravità supportate dai tipi di evento di salute selezionati.", + "events.route.validation.timezone": "Inserisci un fuso orario IANA installato, ad esempio UTC o America/New_York.", + "events.route.validation.schedule_window": "Ogni finestra di pianificazione richiede almeno un giorno e orari di inizio e fine validi e distinti.", + "events.route.validation.suppression": "I valori di soppressione devono essere numeri interi compresi negli intervalli consentiti.", + "events.schedule.timezone": "Fuso orario", + "events.schedule.timezoneHelp": "Deve essere presente nel database dei fusi orari del registratore.", + "events.schedule.addWindow": "Aggiungi finestra temporale", + "events.schedule.windowNumber": "Finestra {number}", + "events.schedule.start": "Inizio", + "events.schedule.end": "Fine", + "events.schedule.sunday": "Dom", + "events.schedule.monday": "Lun", + "events.schedule.tuesday": "Mar", + "events.schedule.wednesday": "Mer", + "events.schedule.thursday": "Gio", + "events.schedule.friday": "Ven", + "events.schedule.saturday": "Sab", + "events.destination.add": "Aggiungi destinazione", + "events.destination.addTitle": "Aggiungi destinazione MQTT", + "events.destination.editTitle": "Modifica destinazione MQTT", + "events.destination.create": "Crea destinazione", + "events.destination.editorDescription": "Configura un output di eventi persistente. Le credenziali restano di sola scrittura e non vengono mai restituite dall'API.", + "events.destination.default": "Impostazioni MQTT predefinite", + "events.destination.settingsManaged": "Impostazioni gestite", + "events.destination.defaultDescription": "La configurazione MQTT esistente resta disponibile come mqtt:default e viene utilizzata da {count} rotte.", + "events.destination.openSettings": "Apri impostazioni MQTT", + "events.destination.emptyTitle": "Nessuna destinazione gestita", + "events.destination.emptyDescription": "Aggiungi un altro broker MQTT per la consegna indipendente di eventi a un connettore cloud, un sistema di automazione o un servizio di notifica.", + "events.destination.identity": "Identità della destinazione", + "events.destination.enabled": "Destinazione abilitata", + "events.destination.enabledHelp": "Connetti e svuota la sua coda persistente", + "events.destination.active": "Attivo", + "events.destination.paused": "In pausa", + "events.destination.pause": "Pausa", + "events.destination.broker": "Broker", + "events.destination.host": "Host del broker", + "events.destination.hostHelp": "Solo nome host o indirizzo IP; non includere lo schema URL.", + "events.destination.port": "Porta", + "events.destination.clientId": "ID client", + "events.destination.clientIdHelp": "Deve essere univoco per questa connessione al broker.", + "events.destination.topic": "Topic", + "events.destination.topicTemplate": "Modello di topic", + "events.destination.topicHelp": "Deve includere i token event-type e subject-ID; i caratteri jolly MQTT non sono consentiti.", + "events.destination.keepalive": "Secondi di keepalive", + "events.destination.statusTopicTemplate": "Topic di stato presenza", + "events.destination.statusTopicHelp": "Facoltativo. Deve includere {installation_uuid}; è disponibile anche {destination_uuid}. I caratteri jolly MQTT non sono consentiti.", + "events.destination.statusTopicEnabled": "La presenza è abilitata esplicitamente per questa destinazione. Il topic non viene mai dedotto dal topic dell'evento.", + "events.destination.statusTopicDisabled": "La presenza è disabilitata per questa destinazione. Lascia questo campo vuoto per mantenerla disabilitata.", + "events.destination.qos": "Qualità del servizio", + "events.destination.qos0": "invia una volta", + "events.destination.qos1": "almeno una volta", + "events.destination.qos2": "esattamente una volta", + "events.destination.authentication": "Autenticazione", + "events.destination.passwordPreserved": "Lascia vuoto per mantenere la password write-only memorizzata.", + "events.destination.passwordOptional": "Facoltativo quando il broker consente client anonimi.", + "events.destination.clearPassword": "Cancella la password memorizzata", + "events.destination.transportSecurity": "Sicurezza del trasporto", + "events.destination.tlsMode": "Modalità TLS", + "events.destination.tlsSystem": "Archivio certificati di sistema", + "events.destination.tlsCustomCa": "Autorità di certificazione personalizzata", + "events.destination.tlsMutual": "TLS reciproco", + "events.destination.tlsDisabled": "Disabilitato (testo in chiaro)", + "events.destination.tlsHelp.system": "Verifica il certificato del broker rispetto all'archivio certificati del sistema operativo.", + "events.destination.tlsHelp.custom_ca": "Verifica il broker rispetto a un file di autorità di certificazione PEM esplicito.", + "events.destination.tlsHelp.mutual": "Verifica il broker con un CA esplicito e presenta un certificato e una chiave client.", + "events.destination.tlsHelp.disabled": "Nessuna crittografia del trasporto né verifica dell'identità del broker.", + "events.destination.caFile": "File CA", + "events.destination.certFile": "File del certificato client", + "events.destination.keyFile": "File della chiave client", + "events.destination.absolutePathHelp": "Usa un percorso assoluto leggibile dal servizio LightNVR.", + "events.destination.plaintextWarning": "MQTT in chiaro può esporre i metadati degli eventi e le credenziali. Usalo solo su una rete affidabile e isolata.", + "events.destination.security": "Sicurezza", + "events.destination.tls.system": "Fiducia di sistema", + "events.destination.tls.custom_ca": "CA personalizzato", + "events.destination.tls.mutual": "TLS mutuo", + "events.destination.tls.disabled": "In chiaro", + "events.destination.routes": "Rotte", + "events.destination.presence": "Topic di presenza", + "events.destination.deleteInUse": "Rimuovi o reindirizza le rotte prima di eliminare questa destinazione.", + "events.destination.created": "Destinazione MQTT creata", + "events.destination.updated": "Destinazione MQTT aggiornata", + "events.destination.deleted": "Destinazione MQTT eliminata", + "events.destination.pausedMessage": "Destinazione MQTT in pausa; gli eventi in coda restano persistenti fino alla scadenza.", + "events.destination.enabledMessage": "Destinazione MQTT abilitata", + "events.destination.deleteConfirm": "Eliminare la destinazione MQTT \"{name}\"?", + "events.destination.validation.name": "Inserisci un nome per la destinazione.", + "events.destination.validation.host": "Inserisci un hostname o un indirizzo IP del broker.", + "events.destination.validation.client_id": "Inserisci un client ID del broker.", + "events.destination.validation.topic": "Il topic deve includere i token event-type e subject-ID e non può contenere caratteri jolly MQTT.", + "events.destination.validation.status_topic": "Il topic di presenza opzionale deve includere il token installation UUID, usare solo token supportati e non può contenere caratteri jolly MQTT.", + "events.destination.validation.port": "La porta deve essere un numero intero da 1 a 65535.", + "events.destination.validation.keepalive": "Il keepalive deve essere un numero intero da 5 a 3600 secondi.", + "events.destination.validation.qos": "Scegli MQTT QoS 0, 1 o 2.", + "events.destination.validation.username": "Una password configurata richiede un nome utente.", + "events.destination.validation.ca_file": "Questa modalità TLS richiede un percorso assoluto del file CA.", + "events.destination.validation.mutual_files": "Mutual TLS richiede percorsi assoluti per CA, certificato client e chiave client.", + "fleet.eyebrow": "Operazioni telecamera", + "fleet.title": "Inventario telecamere", + "fleet.description": "Trova, valuta e organizza le telecamere in distribuzioni di grandi dimensioni senza caricare l'intero inventario nel browser.", + "fleet.summary": "Riepilogo stato flotta", + "fleet.totalCameras": "Telecamere corrispondenti", + "fleet.needsAttention": "Degradato", + "fleet.searchLabel": "Cerca telecamere", + "fleet.searchPlaceholder": "Cerca per nome, indirizzo, ubicazione, tag, produttore o modello…", + "fleet.resultCount": "{count} telecamere", + "fleet.filters": "Filtri", + "fleet.clearFilters": "Cancella filtri", + "fleet.filter.health": "Stato", + "fleet.filter.enabled": "Stato telecamera", + "fleet.filter.anyState": "Qualsiasi stato", + "fleet.filter.recording": "Modalità di registrazione", + "fleet.filter.location": "Sottostruttura ubicazioni", + "fleet.filter.allLocations": "Tutte le ubicazioni", + "fleet.filter.tags": "Tag (qualsiasi corrispondenza)", + "fleet.filter.collection": "Raccolta telecamere", + "fleet.health.unknown": "Sconosciuto", + "fleet.health.up": "Online", + "fleet.health.degraded": "Degradato", + "fleet.health.down": "Offline", + "fleet.health.disabled": "Disabilitato", + "fleet.recording.off": "Disattivato", + "fleet.recording.continuous": "Continuo", + "fleet.recording.detection": "Rilevamento", + "fleet.recordingActive": "Registrazione in corso", + "fleet.recordingInactive": "Non in registrazione", + "fleet.column.camera": "Telecamera", + "fleet.column.health": "Stato", + "fleet.column.location": "Posizione", + "fleet.column.tags": "Tag", + "fleet.column.recording": "Registrazione", + "fleet.viewLive": "Live", + "fleet.lastFrame": "Ultimo fotogramma", + "fleet.noAddress": "Indirizzo non disponibile", + "fleet.unassigned": "Non assegnato", + "fleet.loading": "Caricamento flotta telecamere…", + "fleet.refreshing": "Aggiornamento…", + "fleet.loadError": "Impossibile caricare la flotta telecamere", + "fleet.emptyTitle": "Nessuna telecamera configurata", + "fleet.emptyDescription": "Aggiungi un flusso per renderlo disponibile nell'area di lavoro della flotta.", + "fleet.emptyFilteredTitle": "Nessuna telecamera corrisponde a questa vista", + "fleet.emptyFilteredDescription": "Prova ad ampliare la ricerca o a rimuovere uno o più filtri.", + "fleet.paginationSummary": "Visualizzazione di {first}–{last} di {total}", + "fleet.perPage": "Per pagina", + "fleet.pageOf": "Pagina {page} di {pages}", + "fleet.selectPage": "Seleziona tutte le telecamere in questa pagina", + "fleet.selectCamera": "Seleziona {name}", + "fleet.selectedCount": "{count} telecamere selezionate", + "fleet.organizeSelected": "Organizza selezionate", + "fleet.clearSelection": "Cancella selezione", + "fleet.organization.manage": "Gestisci organizzazione", + "fleet.organization.title": "Organizzazione telecamere", + "fleet.organization.description": "Mantieni una gerarchia di posizioni riutilizzabile e un dizionario di tag normalizzato per la flotta telecamere.", + "fleet.organization.locations": "Posizioni", + "fleet.organization.tags": "Tag", + "fleet.organization.locationsDescription": "Modella siti, edifici, piani e aree operative come una gerarchia navigabile.", + "fleet.organization.tagsDescription": "Utilizza un dizionario di tag governato anziché etichette incoerenti a testo libero.", + "fleet.organization.addRoot": "Aggiungi posizione di primo livello", + "fleet.organization.addLocation": "Aggiungi posizione", + "fleet.organization.editLocation": "Modifica posizione", + "fleet.organization.addChild": "Aggiungi sotto-posizione", + "fleet.organization.type": "Tipo", + "fleet.organization.parent": "Posizione genitore", + "fleet.organization.topLevel": "Livello superiore", + "fleet.organization.sortOrder": "Ordine di ordinamento", + "fleet.organization.contents": "Contenuti", + "fleet.organization.cameras": "Telecamere", + "fleet.organization.system": "Sistema", + "fleet.organization.contentCounts": "{cameras} telecamere · {children} sotto-posizioni", + "fleet.organization.locationNotEmpty": "Sposta prima le telecamere ed elimina le sotto-posizioni", + "fleet.organization.noLocations": "Nessuna posizione configurata.", + "fleet.organization.locationCreated": "Posizione creata", + "fleet.organization.locationUpdated": "Posizione aggiornata", + "fleet.organization.locationDeleted": "Posizione eliminata", + "fleet.organization.deleteLocationConfirm": "Eliminare la posizione \"{name}\"?", + "fleet.organization.addTag": "Aggiungi tag", + "fleet.organization.editTag": "Modifica tag", + "fleet.organization.tagLabel": "Tag", + "fleet.organization.color": "Colore (#RRGGBB)", + "fleet.organization.tagDescription": "Descrizione", + "fleet.organization.noTags": "Nessun tag normalizzato configurato.", + "fleet.organization.tagCreated": "Tag creato", + "fleet.organization.tagUpdated": "Tag aggiornato", + "fleet.organization.tagDeleted": "Tag eliminato", + "fleet.organization.deleteTagConfirm": "Eliminare \"{name}\"? È attualmente assegnato a {count} telecamere.", + "fleet.organization.merge": "Unisci", + "fleet.organization.mergeTagNamed": "Unisci \"{name}\"", + "fleet.organization.mergeInto": "Unisci in", + "fleet.organization.chooseTag": "Scegli il tag da mantenere", + "fleet.organization.mergeWarning": "Tutte le assegnazioni alle telecamere verranno spostate sul tag mantenuto; il tag di origine verrà quindi rimosso.", + "fleet.organization.tagsMerged": "Tag uniti", + "fleet.organization.saveError": "Impossibile salvare: {message}", + "fleet.organization.deleteError": "Impossibile eliminare: {message}", + "fleet.locationType.site": "Sito", + "fleet.locationType.building": "Edificio", + "fleet.locationType.floor": "Piano", + "fleet.locationType.area": "Area", + "fleet.locationType.zone": "Zona", + "fleet.locationType.system": "Sistema", + "fleet.bulk.title": "Organizza telecamere selezionate", + "fleet.bulk.description": "Applica modifiche a posizione e tag a {count} telecamere con concorrenza limitata.", + "fleet.bulk.location": "Assegnazione posizione", + "fleet.bulk.locationHelp": "Tutte le telecamere selezionate verranno spostate nella posizione scelta.", + "fleet.bulk.keepLocations": "Mantieni posizioni attuali", + "fleet.bulk.tags": "Assegnazione tag", + "fleet.bulk.tagsHelp": "Aggiungi o rimuovi tag senza modificare altre assegnazioni, oppure sostituisci esplicitamente l'insieme completo di tag.", + "fleet.bulk.tagOperation.none": "Mantieni", + "fleet.bulk.tagOperation.add": "Aggiungi", + "fleet.bulk.tagOperation.remove": "Rimuovi", + "fleet.bulk.tagOperation.replace": "Sostituisci tutti", + "fleet.bulk.replaceWarning": "Sostituisci tutti rimuove ogni tag attuale prima di applicare la selezione. Una selezione vuota rimuove tutti i tag.", + "fleet.bulk.apply": "Applica modifiche", + "fleet.bulk.working": "Applicazione modifiche…", + "fleet.bulk.success": "{count} telecamere aggiornate", + "fleet.bulk.partial": "{succeeded} telecamere aggiornate; {failed} non riuscite", + "fleet.bulk.error": "Impossibile organizzare le telecamere: {message}", + "fleet.bulk.failures": "Telecamere non aggiornabili", + "fleet.queues.degraded": "Flussi degradati", + "fleet.queues.offline": "Telecamere offline", + "fleet.queues.oldest": "Più vecchio: {time}", + "fleet.queues.noneActive": "Nessuna condizione attiva", + "fleet.views.title": "Viste salvate", + "fleet.views.choose": "Scegli una vista salvata", + "fleet.views.none": "Nessuna vista salvata", + "fleet.views.shared": "Condivisa", + "fleet.views.saveCurrent": "Salva vista corrente", + "fleet.views.name": "Nome vista", + "fleet.views.share": "Condividi con tutti gli operatori", + "fleet.views.saved": "Vista flotta salvata", + "fleet.views.saveError": "Impossibile salvare la vista: {message}", + "fleet.views.deleted": "Vista flotta eliminata", + "fleet.views.deleteConfirm": "Eliminare la vista salvata \"{name}\"?", + "fleet.views.deleteError": "Impossibile eliminare la vista: {message}", + "fleet.views.unsupported": "Questo selettore salvato non può essere rappresentato dai controlli di filtro attuali.", + "collections.manage": "Raccolte", + "collections.all": "Tutte le raccolte", + "collections.filter": "Raccolta", + "collections.loadMembersError": "Impossibile caricare le telecamere della raccolta: {message}", + "collections.title": "Raccolte di telecamere", + "collections.subtitle": "Crea gruppi di telecamere riutilizzabili per operazioni, viste salvate e flussi di lavoro a valle.", + "collections.listDescription": "Le raccolte statiche mantengono un'appartenenza esplicita; le raccolte intelligenti valutano continuamente le regole della flotta.", + "collections.create": "Crea raccolta", + "collections.edit": "Modifica raccolta", + "collections.editorDescription": "Le definizioni delle raccolte utilizzano UUID stabili di telecamere, ubicazioni e tag.", + "collections.backToList": "Torna alle raccolte", + "collections.type": "Tipo di raccolta", + "collections.type.static": "Statica", + "collections.type.smart": "Intelligente", + "collections.description": "Descrizione", + "collections.shared": "Raccolta condivisa", + "collections.sharedHelp": "Consenti ad altri utenti autorizzati di vedere questa raccolta; le regole di accesso alle telecamere restano valide.", + "collections.typeChangeWarning": "La modifica del tipo di raccolta sostituisce il modello di appartenenza. I membri statici o le regole intelligenti del tipo precedente non saranno più applicati.", + "collections.selectorError": "Selettore non valido: {message}", + "collections.created": "Raccolta creata", + "collections.updated": "Raccolta aggiornata", + "collections.saveError": "Impossibile salvare la raccolta: {message}", + "collections.loadError": "Impossibile caricare la raccolta: {message}", + "collections.cameras": "telecamere", + "collections.visibility.shared": "Condivise", + "collections.visibility.private": "Private", + "collections.selectorRedacted": "Regole private", + "collections.emptyTitle": "Nessuna raccolta disponibile", + "collections.emptyAdmin": "Crea un gruppo statico o una vista basata su regole intelligenti per riutilizzare le selezioni di telecamere.", + "collections.emptyViewer": "Nessuna raccolta condivisa disponibile per l'ambito delle tue telecamere.", + "collections.deleteConfirm": "Eliminare la raccolta \"{name}\"?", + "collections.deleted": "Raccolta eliminata", + "collections.deleteError": "Impossibile eliminare la raccolta: {message}", + "collections.preview.title": "Anteprima regole", + "collections.preview.matches": "{count} telecamere corrispondenti", + "collections.preview.action": "Anteprima", + "collections.preview.hide": "Nascondi anteprima", + "collections.preview.loading": "Valutazione in corso…", + "collections.preview.empty": "Nessuna telecamera corrisponde attualmente.", + "collections.preview.sample": "Mostrato un campione di {count} telecamere su {total} corrispondenze.", + "collections.preview.error": "Impossibile visualizzare l'anteprima della raccolta: {message}", + "collections.members.title": "Membri statici", + "collections.members.selected": "{count} telecamere selezionate su tutte le pagine", + "collections.members.search": "Cerca telecamere…", + "collections.members.selectPage": "Seleziona questa pagina", + "collections.members.empty": "Nessuna telecamera corrisponde a questa ricerca.", + "collections.builder.title": "Regole intelligenti", + "collections.builder.description": "Le regole vengono valutate in base all'organizzazione, alla configurazione, alle funzionalità e allo stato di salute attuali delle telecamere.", + "collections.builder.match": "Corrispondenza", + "collections.builder.allRules": "tutte le regole", + "collections.builder.anyRule": "qualsiasi regola", + "collections.builder.addRule": "Aggiungi regola", + "collections.builder.removeRule": "Rimuovi regola", + "collections.builder.matchesAll": "In assenza di regole complete, questa raccolta corrisponde a tutte le telecamere nell'ambito autorizzato dell'utente.", + "collections.builder.incompleteRule": "Completa o rimuovi ogni regola prima di salvare.", + "collections.builder.chooseLocation": "Scegli un sottoalbero delle ubicazioni", + "collections.builder.vendorPlaceholder": "Nomi dei produttori, separati da virgola", + "collections.builder.modelPlaceholder": "Nomi dei modelli, separati da virgola", + "collections.builder.advancedMode": "JSON avanzato", + "collections.builder.visualMode": "Editor visuale", + "collections.builder.cannotVisualize": "Questo selettore contiene una logica nidificata o avanzata che l'editor visuale non può rappresentare in modo sicuro.", + "collections.rule.location_subtree": "Ubicazione è all'interno di", + "collections.rule.camera_uuid": "Telecamere specifiche", + "collections.rule.tag_any": "Ha un qualsiasi tag", + "collections.rule.tag_all": "Ha tutti i tag", + "collections.rule.tag_none": "Non ha nessuno dei tag", + "collections.rule.health": "Stato di salute è", + "collections.rule.enabled": "La telecamera è", + "collections.rule.recording_mode": "La modalità di registrazione è", + "collections.rule.capability_any": "Ha una qualsiasi funzionalità", + "collections.rule.capability_all": "Ha tutte le funzionalità", + "collections.rule.vendor": "Il produttore è", + "collections.rule.model": "Il modello è", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Canale audio di ritorno", + "streamHealth.observedFps": "FPS osservati", + "streamHealth.expectedFps": "Previsti", + "streamHealth.fpsHelp": "Osservati da LightNVR; i valori previsti provengono dai metadati del flusso della telecamera.", + "login.passwordChanged": "Password modificata correttamente. Accedi con la tua nuova password.", + "passwordChangeRequired.title": "Modifica la password predefinita", + "passwordChangeRequired.description": "Questa installazione utilizza ancora la password predefinita dell'amministratore. Sostituiscila prima di continuare con LightNVR. L'MFA, se abilitata, verrà verificata al prossimo accesso.", + "passwordChangeRequired.currentPassword": "Password attuale", + "passwordChangeRequired.newPassword": "Nuova password", + "passwordChangeRequired.confirmPassword": "Conferma la nuova password", + "passwordChangeRequired.passwordHelp": "Usa almeno 8 caratteri. La password non può essere admin.", + "passwordChangeRequired.submit": "Cambia password", + "passwordChangeRequired.saving": "Cambio password...", + "passwordChangeRequired.error.currentRequired": "Inserisci la password attuale.", + "passwordChangeRequired.error.tooShort": "La nuova password deve contenere almeno 8 caratteri.", + "passwordChangeRequired.error.defaultPassword": "La nuova password non può essere admin.", + "passwordChangeRequired.error.mismatch": "Le nuove password non corrispondono.", + "passwordChangeRequired.error.generic": "Impossibile modificare la password. Riprova.", + "settings.tab.health": "Salute", + "settings.tab.workspaces": "Aree di lavoro", + "settings.health.title": "Stato di salute di host e hardware", + "settings.health.description": "Configura il monitoraggio limitato del sistema operativo e dell'hardware senza esporre percorsi dei dispositivi o segreti.", + "settings.health.enabled": "Abilita monitoraggio salute", + "settings.health.enabledHelp": "Raccogli i segnali supportati di host, servizi, archiviazione, rete e hardware.", + "settings.health.profile": "Profilo di policy", + "settings.health.profileHelp": "Bilanciato è il valore predefinito normale; conservativo richiede prove più solide prima di generare avvisi.", + "settings.health.profile.balanced": "Bilanciato", + "settings.health.profile.conservative": "Conservativo", + "settings.health.hardwareProvider": "Provider hardware", + "settings.health.provider.auto": "Automatico (provider kernel)", + "settings.health.provider.smartctl": "smartctl (esplicito)", + "settings.health.providerHelp.auto": "Utilizza solo provider sysfs, NVMe e kernel limitati; smartctl non viene mai dedotto.", + "settings.health.providerHelp.smartctl": "Abilita esplicitamente il provider JSON smartctl opzionale e limitato per i dispositivi rilevati.", + "settings.health.providerHelp.disabled": "Disabilita i provider hardware opzionali mantenendo disponibile il monitoraggio salute portatile.", + "settings.health.writeProbe": "Abilita probe di scrittura su archiviazione", + "settings.health.writeProbeHelp": "Esegue periodicamente il probe configurato e limitato della destinazione di registrazione.", + "settings.health.cadences": "Cadenze di campionamento", + "settings.health.cadencesHelp": "Gli intervalli devono rimanere ordinati dal rapido al campionamento dei dispositivi e all'interno dei limiti del server.", + "settings.health.fastInterval": "Intervallo rapido", + "settings.health.normalInterval": "Intervallo normale", + "settings.health.slowInterval": "Intervallo lento", + "settings.health.deviceInterval": "Intervallo dispositivo", + "settings.health.presenceInterval": "Intervallo di presenza", + "settings.health.retention": "Conservazione incidenti", + "settings.health.conditions": "Override delle condizioni", + "settings.health.conditionsHelp": "Esegui override solo dei codici e delle unità delle condizioni restituiti dal registro delle policy effettive.", + "settings.health.conditionOverride": "override della condizione", + "settings.health.overrideMode": "Modalità override", + "settings.health.overrideModeHelp": "Eredita il profilo selezionato, scegli un altro profilo con limiti, disattiva la condizione o imposta soglie validate.", + "settings.health.profileDefault": "Usa profilo selezionato", + "settings.health.custom": "Soglie personalizzate", + "settings.health.warning": "Soglia di avviso", + "settings.health.critical": "Soglia critica", + "settings.health.recovery": "Soglia di recupero", + "settings.health.warning_for_seconds": "Secondi di permanenza in avviso", + "settings.health.critical_for_seconds": "Secondi di permanenza in critico", + "settings.health.recovery_for_seconds": "Secondi di permanenza in recupero", + "settings.health.clearOverrides": "Cancella override", + "settings.health.registryUnavailable": "Il server non ha restituito un registro delle condizioni. Ricarica prima di modificare gli override.", + "settings.health.resetDefaults": "Ripristina valori predefiniti di stato", + "settings.health.reloadGuidance": "Il salvataggio è atomico. Ricarica dopo un salvataggio riuscito per confermare la policy effettiva; riavvia solo quando il server lo richiede esplicitamente.", + "settings.health.validation.profile": "Scegli un profilo di stato supportato.", + "settings.health.validation.provider": "Scegli un provider hardware supportato.", + "settings.health.validation.healthFastIntervalSeconds": "L'intervallo rapido deve essere un numero intero da 5 a 60 secondi.", + "settings.health.validation.healthNormalIntervalSeconds": "L'intervallo normale deve essere un numero intero da 15 a 600 secondi.", + "settings.health.validation.healthSlowIntervalSeconds": "L'intervallo lento deve essere un numero intero da 60 a 3600 secondi.", + "settings.health.validation.healthDeviceIntervalSeconds": "L'intervallo dispositivo deve essere un numero intero da 300 a 86400 secondi.", + "settings.health.validation.healthPresenceIntervalSeconds": "L'intervallo di presenza deve essere un numero intero da 15 a 3600 secondi.", + "settings.health.validation.healthIncidentRetentionDays": "La conservazione degli incidenti deve essere un numero intero da 7 a 3650 giorni.", + "settings.health.validation.ordered": "Gli intervalli di campionamento devono essere ordinati: rapido, normale, lento, dispositivo.", + "settings.health.validation.overrides": "Gli override delle condizioni devono utilizzare codici univoci e profili supportati dal registro del server.", + "settings.health.validation.thresholds": "Le soglie personalizzate devono essere valori finiti entro i limiti dell'unità della condizione.", + "settings.health.validation.thresholdOrder": "Le soglie di avviso, critica e recupero devono preservare la direzione di allarme e l'isteresi della condizione.", + "settings.health.validation.dwell": "I tempi di permanenza devono essere secondi interi entro sette giorni; la permanenza in avviso e in recupero non può essere zero.", + "workspaces.title": "Aree di lavoro operatore", + "workspaces.description": "Scegli quali spazi di lavoro specializzati appaiono nella navigazione e nell'interfaccia.", + "workspaces.saved": "Preferenze spazio di lavoro salvate", + "workspaces.saveError": "Impossibile salvare le preferenze dello spazio di lavoro: {message}", + "workspaces.loadError": "Impossibile caricare le preferenze dello spazio di lavoro.", + "workspaces.showWorkspace": "Mostra {name}", + "workspaces.authorizationNote": "Controlla solo la presentazione. URL diretti e accesso API seguono comunque la policy di autorizzazione.", + "workspaces.liveNavigator": "Navigatore live avanzato", + "workspaces.liveNavigatorDescription": "Albero delle ubicazioni, filtri di disponibilità, layout salvati ed eventi recenti.", + "workspaces.investigation": "Indagine", + "workspaces.investigationDescription": "Cerca, correla, proteggi ed esporta le prove registrate.", + "settings.reduceMotion": "Riduci animazioni", + "settings.reduceMotionHelp": "Disattiva animazioni e transizioni non essenziali. Auto segue la preferenza del sistema operativo.", + "settings.reduceMotionPreference": "Preferenza riduzione animazioni", + "settings.reduceMotionAuto": "Auto", + "settings.reduceMotionOn": "Attivo", + "settings.reduceMotionOff": "Disattivo", + "settings.audioCompliance": "Conformità audio", + "settings.disableAudioGlobally": "Disattiva audio su tutta l'istanza", + "settings.audioDisabled": "L'audio è disattivato a livello globale", + "settings.audioComplianceHelp": "Impedisce l'ascolto live, la comunicazione bidirezionale e l'audio nelle nuove registrazioni su tutta l'istanza. Il salvataggio riavvia le sessioni multimediali go2rtc attive. Le registrazioni esistenti non vengono modificate.", + "tokens.manage": "Gestisci accesso API", + "tokens.title": "Accesso API — {username}", + "tokens.description": "Crea credenziali con ambito ristretto per le integrazioni e revoca ciascuna in modo indipendente.", + "tokens.recommendedTitle": "I token con ambito sono consigliati", + "tokens.recommendedDescription": "Ogni token scade, ha azioni esplicite e un ambito telecamere, e non può mai superare la policy di accesso corrente dell'utente.", + "tokens.coverageNotice": "Le autorizzazioni disponibili riflettono ciò che questo server impone. Un token può utilizzare solo le autorizzazioni già possedute dall'utente.", + "tokens.createTitle": "Crea token con ambito", + "tokens.createDescription": "Usa un token per integrazione in modo da poterlo identificare, ruotare e revocare senza interrompere nulla.", + "tokens.name": "Nome integrazione", + "tokens.namePlaceholder": "es. Bridge PTZ garage nord", + "tokens.expiry": "Scade dopo", + "tokens.expiryDays": "{days} giorni", + "tokens.actions": "Azioni consentite", + "tokens.actionsHelp": "Seleziona solo ciò che questa integrazione richiede. Le azioni distruttive richiedono un token dedicato.", + "tokens.destructive": "Distruttive", + "tokens.noEnforcedActions": "Nessuna azione abilitata per i token è disponibile in questa versione del server.", + "tokens.scope.label": "Ambito telecamere", + "tokens.scope.all": "Tutta la flotta di telecamere", + "tokens.scope.collection": "Raccolta condivisa", + "tokens.scope.selector": "Selettore personalizzato", + "tokens.scope.chooseCollection": "Raccolta telecamere condivisa", + "tokens.scope.allValue": "Tutta la flotta", + "tokens.scope.collectionValue": "Raccolta: {name}", + "tokens.scope.selectorValue": "Selettore dinamico personalizzato", + "tokens.create": "Crea token", + "tokens.creating": "Creazione token…", + "tokens.createdSuccess": "Token API con ambito creato", + "tokens.createError": "Impossibile creare il token API: {message}", + "tokens.invalidResponse": "Il server ha restituito una risposta incompleta per le credenziali.", + "tokens.existingTitle": "Token esistenti", + "tokens.existingDescription": "Dopo la creazione saranno disponibili solo prefissi e metadati.", + "tokens.emptyTitle": "Nessun token attivo", + "tokens.emptyDescription": "Crea un token con ambito per la prima integrazione che necessita di accesso API.", + "tokens.showInactive": "Mostra {count} inattivi", + "tokens.status.active": "Attivo", + "tokens.status.expired": "Scaduto", + "tokens.status.revoked": "Revocato", + "tokens.expires": "Scadenza", + "tokens.expiresValue": "Scade il {date}", + "tokens.created": "Creato", + "tokens.lastUsed": "Ultimo utilizzo", + "tokens.revoke": "Revoca", + "tokens.revoking": "Revoca in corso…", + "tokens.revokeConfirm": "Revocare \"{description}\"? Le richieste che lo utilizzano smetteranno di funzionare immediatamente.", + "tokens.revokedSuccess": "Token API revocato", + "tokens.revokeError": "Impossibile revocare il token API: {message}", + "tokens.validation.missing_description": "Assegna un nome all'integrazione che utilizzerà questo token.", + "tokens.validation.description_too_long": "Mantieni il nome dell'integrazione sotto i 128 caratteri.", + "tokens.validation.invalid_expiry": "Scegli una durata del token tra 1 e 365 giorni.", + "tokens.validation.missing_actions": "Scegli almeno un'azione consentita.", + "tokens.validation.invalid_action": "Una o più azioni selezionate non supportano i token su questo server.", + "tokens.validation.invalid_scope": "Scegli un ambito telecamera valido.", + "tokens.validation.requires_all_scope": "Le autorizzazioni non relative alle telecamere richiedono l'ambito Intera flotta di telecamere. Scegli quell'ambito o rimuovi tali autorizzazioni.", + "tokens.validation.missing_collection": "Scegli una raccolta condivisa disponibile.", + "tokens.validation.invalid_selector": "Completa o correggi il selettore telecamere personalizzato.", + "tokens.secret.oneTime": "Mostrato una sola volta", + "tokens.secret.scopedTitle": "Salva subito questo token con ambito", + "tokens.secret.legacyTitle": "Salva subito questa chiave API legacy", + "tokens.secret.scopedDescription": "lightNVR memorizza solo un hash di questo token. Se viene perso, revocalo e creane un altro.", + "tokens.secret.legacyDescription": "Questa chiave di compatibilità viene mostrata qui una sola volta. La generazione di un'altra chiave la renderà non valida.", + "tokens.secret.value": "Credenziale API", + "tokens.secret.copied": "Copiato", + "tokens.secret.copySuccess": "Credenziale API copiata", + "tokens.secret.copyError": "Impossibile copiare automaticamente; seleziona e copia la credenziale manualmente.", + "tokens.secret.savedConfirm": "Ho salvato questa credenziale in modo sicuro", + "tokens.secret.savedHelp": "La conferma chiude questa finestra. Il valore completo non potrà essere visualizzato di nuovo.", + "tokens.legacy.title": "Chiave di compatibilità legacy", + "tokens.legacy.description": "La chiave legacy ha l'accesso effettivo completo di questo utente, non scade e non può essere limitata per telecamera o azione.", + "tokens.legacy.warning": "Generala solo per un'integrazione esistente i cui endpoint non sono stati migrati all'applicazione dei token con ambito. La generazione invalida immediatamente la chiave legacy precedente.", + "tokens.legacy.generate": "Genera chiave legacy", + "tokens.legacy.confirm": "Generare una nuova chiave legacy? Questa operazione invalida immediatamente la chiave legacy attuale dell'utente.", + "tokens.legacy.createdSuccess": "Chiave API legacy generata", + "tokens.legacy.createError": "Impossibile generare la chiave API legacy: {message}", + "audit.manage": "Cronologia audit", + "audit.title": "Audit di sicurezza e accesso", + "audit.description": "Traccia gli esiti dei login, le decisioni di accesso e le modifiche alle policy sensibili senza esporre le credenziali.", + "audit.retention": "Ritenzione", + "audit.retentionDescription": "Gli eventi vengono attualmente conservati per {days} giorni. Riducendo questo valore, la cronologia più vecchia viene eliminata immediatamente.", + "audit.retentionDays": "Giorni", + "audit.retentionInvalid": "Scegli un periodo di ritenzione tra 1 e 3650 giorni.", + "audit.retentionSaved": "Ritenzione audit salvata; {count} eventi scaduti eliminati", + "audit.retentionError": "Impossibile salvare la ritenzione audit: {message}", + "audit.filters": "Filtri", + "audit.clearFilters": "Cancella filtri", + "audit.applyFilters": "Applica filtri", + "audit.actor": "Attore", + "audit.unauthenticated": "Non autenticato", + "audit.outcome": "Esito", + "audit.action": "Azione esatta", + "audit.filterToAction": "Filtra per questa azione", + "audit.since": "Da", + "audit.until": "A", + "audit.invalidDateRange": "La data di inizio deve essere precedente a quella di fine.", + "audit.source": "Indirizzo di origine", + "audit.target": "Destinazione", + "audit.targetUuid": "UUID di destinazione", + "audit.noTarget": "A livello di sistema", + "audit.requestId": "ID richiesta", + "audit.apiToken": "ID token con ambito", + "audit.showDetails": "Mostra dettagli", + "audit.hideDetails": "Nascondi dettagli", + "audit.pageSize": "Per pagina", + "audit.resultRange": "Visualizzazione di {start}–{end} di {total}", + "audit.empty": "Nessun evento di audit corrispondente", + "audit.emptyDescription": "Prova a cancellare uno o più filtri, oppure attendi nuova attività di sicurezza.", + "audit.exportPage": "Esporta questa pagina", + "audit.exporting": "Esportazione…", + "audit.exported": "Pagina di audit esportata", + "audit.exportError": "Impossibile esportare gli eventi di audit: {message}", + "audit.pagination": "Pagine della cronologia di audit", + "audit.page": "Pagina {page}", + "audit.modesTitle": "Decisioni consentite", + "audit.modesDescription": "Scegli come registrare l'accesso in sola lettura consentito per ogni azione. Le richieste che apportano modifiche, gli accessi negati, gli errori e i login sono sempre registrati. Riepilogo mantiene una voce per utente, telecamera e client ogni {minutes} minuti con un conteggio.", + "audit.mode.record": "Registra ogni", + "audit.mode.summarize": "Riepilogo", + "audit.mode.off": "Disattivato", + "audit.modeOffWarning": "L'accesso consentito per questa azione non verrà più visualizzato nella cronologia di audit.", + "audit.modesSaved": "Modalità di decisione di audit salvate", + "audit.modesError": "Impossibile salvare le modalità di decisione di audit: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Tipo di evento", + "audit.eventTypeSummary": "Riepiloghi", + "audit.eventTypeDecision": "Decisioni individuali", + "access.cameraSearch": "Cerca telecamere", + "access.cameraSearchPlaceholder": "Digita almeno due caratteri per cercare…", + "access.cameraSearchHint": "Cerca per nome telecamera, UUID, indirizzo, ubicazione, tag, produttore o modello.", + "access.cameraSelected": "Selezionate", + "access.cameraAdd": "Aggiungi", + "access.cameraLimit": "Un selettore può contenere al massimo 64 telecamere esplicite. Usa una regola per ubicazione o tag per ambiti più ampi.", + "access.roles.manage": "Gestisci ruoli", + "access.roles.title": "Ruoli di autorizzazione", + "access.roles.description": "Raggruppa le azioni in ruoli riutilizzabili, quindi concedi tali ruoli su ambiti di telecamere.", + "access.roles.create": "Crea ruolo", + "access.roles.newRole": "Nuovo ruolo", + "access.roles.copyName": "Copia di {name}", + "access.roles.clone": "Clona", + "access.roles.builtin": "Integrato", + "access.roles.builtinHelp": "I ruoli integrati sono modelli fissi e sicuri per gli aggiornamenti. Clonane uno per personalizzarlo.", + "access.roles.actionCount": "{count} azioni", + "access.roles.destructive": "Azione sensibile", + "access.roles.notEnforced": "Non ancora applicato da alcun endpoint", + "access.roles.destructiveWarning": "Questo ruolo può modificare la configurazione o le prove. Concedilo solo negli ambiti in cui tale autorità è necessaria.", + "access.roles.created": "Ruolo creato", + "access.roles.updated": "Ruolo aggiornato", + "access.roles.deleted": "Ruolo eliminato", + "access.roles.saveError": "Impossibile salvare il ruolo: {message}", + "access.roles.deleteError": "Impossibile eliminare il ruolo: {message}", + "access.roles.deleteConfirm": "Eliminare il ruolo \"{name}\"? I ruoli a cui fanno riferimento delle concessioni non possono essere eliminati.", + "access.policy.manage": "Gestisci accesso", + "access.policy.column": "Accesso", + "access.policy.scopedShort": "Con ambito", + "access.policy.title": "Criteri di accesso — {username}", + "access.policy.description": "Gestisci le concessioni di ruolo con negazione predefinita e anteprima dei relativi ambiti telecamera.", + "access.policy.tab.grants": "Concessioni", + "access.policy.tab.test": "Prova accesso", + "access.policy.scopedWarning": "Funzioneranno solo le azioni consentite da una concessione e da un ambito telecamera corrispondenti.", + "access.policy.grants": "Concessioni di ruolo", + "access.policy.grantsDescription": "Una concessione combina un ruolo con l'intera flotta, una raccolta condivisa o un selettore telecamera personalizzato.", + "access.policy.addGrant": "Aggiungi concessione", + "access.policy.noGrants": "Nessuna concessione configurata", + "access.policy.noGrantsHelp": "Aggiungi almeno una concessione prima di attivare i criteri con ambito, a meno che questo utente non debba avere alcun accesso.", + "access.policy.role": "Ruolo", + "access.policy.chooseRole": "Scegli un ruolo", + "access.policy.scope": "Ambito telecamera", + "access.policy.allCameras": "Intera flotta telecamere", + "access.policy.collectionScope": "Raccolta condivisa", + "access.policy.collection": "Raccolta telecamere", + "access.policy.chooseCollection": "Scegli una raccolta condivisa", + "access.policy.collectionHelp": "L'accesso segue la raccolta man mano che le telecamere vengono aggiunte, rimosse o corrispondono alle sue regole.", + "access.policy.dynamicScope": "Selettore dinamico", + "access.policy.activateConfirm": "Attivare i criteri con ambito a negazione predefinita per {username}? Le azioni senza una concessione corrispondente verranno negate.", + "access.policy.emptyConfirm": "Attivare i criteri con ambito per {username} senza concessioni? Questo rimuove intenzionalmente tutto l'accesso controllato dai criteri.", + "access.policy.saved": "Criterio di accesso salvato", + "access.policy.saveError": "Impossibile salvare il criterio di accesso: {message}", + "access.policy.version": "Versione criterio {version}", + "access.policy.unsaved": "Modifiche non salvate", + "access.policy.validation.invalid_mode": "Scegli una modalità di valutazione valida.", + "access.policy.validation.missing_role": "Ogni autorizzazione deve fare riferimento a un ruolo disponibile.", + "access.policy.validation.invalid_scope": "Ogni autorizzazione deve utilizzare un ambito a flotta intera, raccolta condivisa o selettore.", + "access.policy.validation.invalid_selector": "Completa o correggi ogni selettore di telecamere prima di salvare.", + "access.policy.validation.missing_collection": "Scegli una raccolta condivisa disponibile per ogni autorizzazione di raccolta.", + "access.policy.validation.duplicate_grant": "Rimuovi le autorizzazioni duplicate per ruolo e ambito prima di salvare.", + "access.test.title": "Testa accesso effettivo", + "access.test.description": "Valuta un'azione salvata e una telecamera come {username} senza eseguirla.", + "access.test.saveFirst": "Salva o scarta le modifiche alle autorizzazioni prima del test, in modo che il risultato rifletta il criterio mostrato qui.", + "access.test.action": "Azione", + "access.test.camera": "Telecamera", + "access.test.run": "Testa accesso", + "access.test.running": "Test in corso…", + "access.test.allowed": "Consentito", + "access.test.denied": "Negato", + "access.test.version": "Versione {version}", + "access.test.source": "Origine: {source} · Ruolo: {role}", + "recordings.pullToRefresh": "Trascina per aggiornare le registrazioni", + "recordings.releaseToRefresh": "Rilascia per aggiornare le registrazioni", + "recordings.refreshing": "Aggiornamento registrazioni…", + "recordings.refreshed": "Registrazioni aggiornate", + "recordings.refreshFailed": "Impossibile aggiornare le registrazioni: {message}", + "recordings.download": "Scarica", + "recordings.tags": "Tag", + "recordings.selectRecording": "Seleziona registrazione", + "timeline.legend.recording": "Registrazione", + "timeline.legend.detection": "Evento di rilevamento", + "timeline.detectionEvent": "Evento di rilevamento", + "streams.showCredentials": "Mostra credenziali", + "streams.hideCredentials": "Nascondi credenziali", + "streams.streamSuccessfullyEnabled": "Stream abilitato correttamente.", + "streams.errorEnablingStream": "Errore durante l'abilitazione dello stream: {message}", + "system.health.tab": "Stato di salute", + "system.health.operatorView": "Stato operativo", + "system.health.title": "Stato di salute del sistema", + "system.health.loading": "Caricamento stato di salute del sistema…", + "system.health.loadError": "Impossibile caricare lo stato di salute del sistema.", + "system.health.refreshing": "Aggiornamento in corso…", + "system.health.activeIncidentCount": "{count} incidenti attivi", + "system.health.coverage": "Copertura", + "system.health.monitoringDisabled": "Il monitoraggio dello stato di salute è disabilitato", + "system.health.lastRecordedValue": "Ultimo valore registrato", + "system.health.monitoringDisabledHelp": "I dati di stato correnti non vengono raccolti. Abilita il monitoraggio dello stato di salute in Impostazioni → Stato di salute; riavvia se richiesto dopo il salvataggio. La cronologia degli incidenti mostra eventi passati, non l'utilizzo attuale delle risorse.", + "system.health.monitoringRestartRequired": "Il monitoraggio dello stato di salute è abilitato nella configurazione salvata, ma il sampler in esecuzione è ancora disabilitato. Riavvia LightNVR per applicare la modifica. La cronologia degli incidenti mostra eventi passati.", + "system.health.containerCoverage": "Copertura host limitata", + "system.health.hostHardwareUnavailable": "Questa installazione può visualizzare lo stato di salute dei container e delle risorse montate, ma l'hardware dell'host non è disponibile. I valori host mancanti sono sconosciuti, non sani.", + "system.health.coverageUnknown": "Nessuno snapshot di stato completato è ancora disponibile. I valori rimangono sconosciuti fino al completamento della raccolta.", + "system.health.coverageComplete": "Tutti i dati visibili a questa installazione sono stati raccolti correttamente.", + "system.health.coveragePartial": "La copertura è parziale. {count} osservazioni o controlli di raccolta non sono disponibili, sono obsoleti o incompleti.", + "system.health.effectiveScope": "Ambito effettivo", + "system.health.activeIncidents": "Incidenti attivi", + "system.health.noActiveIncidents": "Nessun incidente attivo segnalato per la copertura visibile.", + "system.health.duration": "Durata", + "system.health.currentValue": "Valore corrente", + "system.health.thresholds": "Soglia e tempo di permanenza", + "system.health.thresholdSummary": "Avviso {warning}, critico {critical}, recupero {recovery} {unit}; permanenza in avviso {seconds}s", + "system.health.remediation": "Risposta suggerita", + "system.health.facts": "Dati di stato", + "system.health.group.resources": "Risorse", + "system.health.group.storage": "Archiviazione", + "system.health.group.hardware": "Hardware", + "system.health.group.network": "Rete", + "system.health.group.clock": "Orologio", + "system.health.group.components": "Componenti", + "system.health.noFacts": "Nessun dato visibile in questo gruppo.", + "system.health.observationState": "Capacità e aggiornamento", + "system.health.valueUnavailable": "Uno o più valori sconosciuti", + "system.health.componentStatus": "Componenti di monitoraggio", + "system.health.collectors": "Collettori", + "system.health.collectorSummary": "{total} registrati · {attention} richiedono attenzione", + "system.health.collectorsNeedingAttention": "Collettori che richiedono attenzione", + "system.health.collectionFailures": "{count} errori o timeout", + "system.health.stale": "obsoleto", + "system.health.eventDelivery": "Consegna eventi", + "system.health.degraded": "Degradato", + "system.health.circularDelivery": "Questo è l'unico percorso di avviso configurato, quindi non può segnalare autonomamente un proprio malfunzionamento.", + "system.health.incidentPersistence": "Persistenza incidenti", + "system.health.persistenceSummary": "{pending} in attesa · {failures} errori · {retries} tentativi", + "system.health.recentSamples": "Attività di raccolta recente", + "system.health.recentSamplesHelp": "Fino a {count} riepiloghi di generazione lato server; questa è un'attività di copertura, non un grafico dei valori.", + "system.health.sampleSequence": "Generazione {sequence}", + "system.health.sampleCoverage": "{observations} osservazioni · {dropped} scartate", + "system.health.noSamples": "Nessuna generazione di raccolta completata disponibile.", + "system.health.incidentHistory": "Cronologia incidenti", + "system.health.incidentHistoryHelp": "Incidenti più recenti per primi. La cronologia viene caricata in pagine limitate.", + "system.health.loadingHistory": "Caricamento cronologia incidenti…", + "system.health.historyError": "Impossibile caricare la cronologia incidenti.", + "system.health.emptyHistory": "Nessun incidente registrato.", + "system.health.firstSeen": "Prima rilevazione", + "system.health.lastSeen": "Ultima rilevazione", + "system.health.deliveryState": "Stato di consegna", + "system.health.historyPagination": "Pagine della cronologia incidenti", + "system.health.pageCount": "{count} incidenti in questa pagina", + "system.health.remediation.memory": "Riduci la pressione sulla memoria, verifica i limiti di processo e cgroup e controlla l'attività OOM recente.", + "system.health.remediation.cpu": "Identifica i processi con elevato utilizzo CPU sostenuto e verifica la produttività del servizio prima di modificare i limiti.", + "system.health.remediation.io": "Verifica la latenza di archiviazione e i writer attivi; conserva le registrazioni prima di interventi di manutenzione invasivi.", + "system.health.remediation.filesystem": "Verifica il filesystem logico specificato, lo spazio libero o gli inode e assicurati che resti scrivibile.", + "system.health.remediation.thermal": "Migliora il raffreddamento e riduci il carico; ispeziona ventole e prese d'aria prima che le temperature raggiungano i limiti di spegnimento.", + "system.health.remediation.network": "Verifica l'interfaccia visibile, il collegamento, lo switch e i contatori di errore da un percorso di rete indipendente.", + "system.health.remediation.clock": "Ripristina la sincronizzazione oraria e verifica la sorgente dell'orologio dell'host prima di affidarsi ai timestamp degli eventi.", + "system.health.remediation.process": "Ispeziona i limiti di risorse e i log di LightNVR, quindi riduci il carico o aumenta i limiti validati.", + "system.health.remediation.storage": "Esegui il backup delle registrazioni importanti e ispeziona il dispositivo di archiviazione mappato prima della sostituzione o riparazione.", + "system.health.remediation.hardware": "Ispeziona l'hardware interessato e i log della piattaforma; pianifica la manutenzione se la condizione persiste.", + "system.health.remediation.health": "Ripristina l'accesso e le autorizzazioni del collector per poter valutare le prove di integrità mancanti.", + "system.health.remediation.system": "Controlla l'esecuzione precedente e i log dell'host per distinguere un riavvio del processo da un riavvio dell'host.", + "system.health.remediation.event": "Utilizza l'API locale o la vista metriche, elimina la pressione sulla coda persistente e ripristina una destinazione di avviso indipendente.", + "system.health.remediation.default": "Controlla il componente interessato e i log recenti, quindi verifica il recupero in una nuova generazione di integrità.", + "system.capacityTarget": "Obiettivo di capacità", + "system.capacityTargetValue": "Mantieni {pct}% libero", + "system.fillRate": "Tasso di riempimento", + "system.fillRateValue": "{value} / giorno", + "system.projectedToTarget": "Tempo stimato per raggiungere l'obiettivo", + "system.projectedNow": "Obiettivo raggiunto o superato", + "system.projectedDays": "~{count}g", + "system.projectedHours": "~{count}h", + "system.projectedUnknown": "—", + "common.description": "Descrizione", + "common.remove": "Rimuovi", + "streams.selectStream": "Seleziona {name}", + "streams.search": "Cerca stream", + "streams.searchPlaceholder": "Cerca telecamere, ubicazioni o tag", + "streams.noStreamsMatchFilters": "Nessuno stream corrisponde ai filtri correnti.", + "streamHealth.sourceConnected": "Sorgente connessa", + "streamHealth.videoAdvancing": "Video in avanzamento", + "streamHealth.recorderWriting": "Scrittura del registratore", + "streamHealth.detectorOperating": "Rilevatore in esecuzione", + "streamHealth.lastSegment": "Ultimo segmento completato", + "streams.disablingStreamsProgress": "Disattivazione flussi…", + "streams.onvifInvalidAddress": "L'indirizzo IP del dispositivo ONVIF è mancante o non valido.", + "streams.warningFallingBackToHttp": "Connessione HTTPS fallita; nuovo tentativo tramite HTTP. Le credenziali potrebbero essere inviate in testo in chiaro.", + "streamsConfig.playbackTransport": "Trasporto di riproduzione", + "streamsConfig.playbackTransportHelp": "Scegli il metodo di riproduzione nel browser per questa telecamera e, se selezionato, il relativo ordine di fallback.", + "streamsConfig.playbackTransportUnavailable": "Non disponibile sul server: {transports}. Abilita il trasporto a livello globale o scegli un altro profilo.", + "streamsConfig.audioDisabledByPolicy": "L'audio è disabilitato dalla policy dell'istanza", + "streamsConfig.audioDisabledByPolicyHelp": "Registrazione, ascolto live e comunicazione bidirezionale non sono disponibili mentre la policy di conformità audio globale è abilitata.", + "streamsConfig.audioVoiceEnhancement": "Miglioramento vocale (registrazioni)", + "streamsConfig.customApiModel": "Rilevamento API personalizzato", + "streamsConfig.modelNotSupportedByBuild": "non supportato da questa build", + "streamsConfig.tierCriticalMultiplier": "Livello critico ×", + "streamsConfig.tierImportantMultiplier": "Livello importante ×", + "streamsConfig.tierEphemeralMultiplier": "Livello effimero ×", + "streamsConfig.tierMultipliersHelp": "Moltiplicatori per livello sulla ritenzione di base. I filmati di livello superiore vengono conservati più a lungo e rimossi per ultimi in caso di pressione sul disco.", + "streamsConfig.storagePriority": "Priorità di archiviazione (1-10)", + "streamsConfig.storagePriorityHelp": "Importanza relativa dei filmati di questo flusso durante il recupero di spazio; una priorità più alta viene preservata più a lungo.", + "streamsConfig.restream": "Restream / Pubblicazione (RTMP)", + "streamsConfig.publishUrl": "URL di pubblicazione (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "Esegui il restream di questa telecamera verso un servizio come YouTube Live tramite go2rtc. Incolla l'URL di ingest RTMP completo, inclusa la chiave di stream (es. rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Per eseguire il restream verso più servizi contemporaneamente, separa gli URL con virgole. YouTube richiede video H264 e audio AAC; LightNVR ora esegue il transcoding automaticamente (H264 per telecamere non-H264, AAC per audio non-AAC), quindi la maggior parte delle telecamere funziona senza configurazione. Nota: YouTube richiede anche una traccia audio; una telecamera priva di audio verrà comunque rifiutata. Lascia vuoto per disabilitare.", + "streams.lastSeen": "Ultima connessione {time}", + "streams.claimed": "Assegnato", + "streams.duplicateSuspected": "Possibile duplicato", + "streams.duplicateSuspectedHelp": "L'identità stabile o le prove dell'endpoint sono in conflitto con un altro record di rilevamento.", + "streams.onvifClaimWarning": "Il flusso è stato aggiunto, ma non è stato possibile contrassegnare il suo record di rilevamento come assegnato: {message}", + "common.online": "Online", + "common.offline": "Offline", + "settings.storageTargets.title": "Destinazioni di archiviazione registrazioni", + "settings.storageTargets.description": "Registra dischi locali e filesystem NFS o SMB montati dall'amministratore come destinazioni di registrazione monitorate in modo indipendente.", + "settings.storageTargets.foundationNotice": "La cattura utilizza target di filesystem. I bucket S3 e i target NFS/SAN montati possono contenere copie di archivio verificate. La pressione hot conserva le registrazioni archiviate fino alla scadenza della loro retention logica.", + "settings.storageTargets.add": "Aggiungi target di archiviazione", + "settings.storageTargets.edit": "Modifica target di archiviazione", + "settings.storageTargets.editorHelp": "I target abilitati devono già esistere e superare un test di scrittura, fsync e pulizia. Salva un futuro mount non disponibile come disabilitato, quindi abilitalo dopo il montaggio.", + "settings.storageTargets.name": "Nome target", + "settings.storageTargets.root": "Percorso root montato", + "settings.storageTargets.rootLocked": "Un target predefinito o non vuoto mantiene un root immutabile in modo che le riprese esistenti non possano essere orfane.", + "settings.storageTargets.class": "Classe di prestazioni", + "settings.storageTargets.hot": "Hot — registrazione attiva", + "settings.storageTargets.warm": "Warm — archivio montato", + "settings.storageTargets.cold": "Cold — accesso poco frequente", + "settings.storageTargets.reserveGb": "Spazio riservato (GB)", + "settings.storageTargets.lowWatermark": "Soglia bassa (% utilizzato)", + "settings.storageTargets.highWatermark": "Soglia alta (% utilizzato)", + "settings.storageTargets.migrationBandwidth": "Banda di ciclo di vita (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 significa illimitato. Il limite viene fissato quando viene creato un job di spostamento o copia.", + "settings.storageTargets.archiveStart": "Inizio finestra di archiviazione", + "settings.storageTargets.archiveEnd": "Fine finestra di archiviazione", + "settings.storageTargets.archiveWindowHelp": "Ora locale. Inizio e fine uguali consentono job di ciclo di vita per tutto il giorno; una finestra notturna può attraversare la mezzanotte.", + "settings.storageTargets.enabled": "Abilitato (le policy di posizionamento possono selezionare questo target)", + "settings.storageTargets.notRouted": "Nessuna policy di posizionamento abilitata instrada le telecamere qui. Le nuove registrazioni continuano ad andare al target predefinito finché una policy non nomina questo target come primario, membro del pool o target di archiviazione.", + "settings.storageTargets.degradedNotice": "Oltre la soglia alta o all'interno della riserva. Le policy di posizionamento ignorano questo target finché non viene liberato spazio.", + "settings.storageTargets.probePassedIneligible": "Test di scrittura superato, ma il target è {status}: le policy di posizionamento non lo selezioneranno.", + "settings.storageTargets.mountRequired": "Richiedi un filesystem montato", + "settings.storageTargets.mountRequiredHelp": "Blocca questo target al suo attuale mountpoint non root. Se quel mount NFS, SMB, bind o PVC scompare, la registrazione si mette in pausa invece di scrivere nella directory host sottostante.", + "settings.storageTargets.mountGuard": "Mount richiesto", + "settings.storageTargets.mountPending": "Verrà rilevato quando il target viene abilitato", + "settings.storageTargets.default": "Predefinito", + "settings.storageTargets.capacity": "Capacità", + "settings.storageTargets.available": "Disponibile", + "settings.storageTargets.recordings": "Registrazioni indicizzate", + "settings.storageTargets.replicas": "{count} copie verificate · {bytes}", + "settings.storageTargets.reserve": "Riservato", + "settings.storageTargets.pressure.normal": "Pressione normale", + "settings.storageTargets.pressure.high": "Soglia alta", + "settings.storageTargets.pressure.reserve": "Riserva superata", + "settings.storageTargets.pressure.unavailable": "Pressione non disponibile", + "settings.storageTargets.cleanupActive": "La pulizia limitata al target è attiva e lavorerà per raggiungere {target} di spazio disponibile senza eliminare registrazioni assegnate a un altro target.", + "settings.storageTargets.test": "Test del target", + "settings.storageTargets.probing": "Test in corso…", + "settings.storageTargets.probePassed": "Test di scrittura sul target di archiviazione superato", + "settings.storageTargets.duplicateFilesystem": "Questa radice condivide lo stesso filesystem sottostante di un altro target. La capacità non deve essere conteggiata due volte quando il posizionamento è abilitato.", + "settings.storageTargets.deleteLocked": "I target predefiniti e non vuoti non possono essere eliminati.", + "settings.storageTargets.deleteConfirm": "Eliminare il target di archiviazione vuoto \"{name}\"? Nessun file verrà rimosso.", + "settings.storageTargets.created": "Target di archiviazione creato", + "settings.storageTargets.updated": "Target di archiviazione aggiornato", + "settings.storageTargets.deleted": "Target di archiviazione eliminato", + "settings.storageTargets.invalidThresholds": "Verificare soglie, riserva, larghezza di banda del ciclo di vita e finestre di archiviazione.", + "settings.storageTargets.loadError": "Impossibile caricare i target di archiviazione", + "settings.storagePools.title": "Pool di archiviazione", + "settings.storagePools.description": "Raggruppa i target sani per lo spillover automatico e la replica su target distinti.", + "settings.storagePools.add": "Aggiungi pool", + "settings.storagePools.strategy": "Strategia di allocazione", + "settings.storagePools.mostFree": "Spazio libero maggiore", + "settings.storagePools.roundRobin": "Round robin", + "settings.storagePools.priority": "Priorità esplicita", + "settings.storagePools.members": "Target (l'ordine di visualizzazione è la priorità di allocazione)", + "settings.storagePools.enabled": "Pool abilitato", + "settings.storagePools.active": "Attivo", + "settings.storagePools.inactive": "Disabilitato", + "settings.storagePools.strategyValue.most_free": "spazio libero maggiore", + "settings.storagePools.strategyValue.round_robin": "round robin", + "settings.storagePools.strategyValue.priority": "ordine di priorità", + "settings.storagePools.created": "Pool di archiviazione creato", + "settings.storagePools.updated": "Pool di archiviazione aggiornato", + "settings.storagePools.deleted": "Pool di archiviazione eliminato", + "settings.storagePools.deleteConfirm": "Eliminare il pool di archiviazione \"{name}\"?", + "settings.storagePools.empty": "Nessun pool di archiviazione.", + "settings.storageMigrations.title": "Attività di migrazione registrazioni", + "settings.storageMigrations.description": "Spostamenti persistenti e copie conservate rispettano la finestra di archiviazione e il limite di banda di ogni destinazione, verificano SHA-256 e si recuperano in modo sicuro dopo il riavvio.", + "settings.storageMigrations.empty": "Nessuna attività di migrazione registrazioni.", + "settings.storageMigrations.loadError": "Impossibile caricare le attività di migrazione registrazioni", + "settings.storageMigrations.recording": "Registrazione #{id}", + "settings.storageMigrations.attempt": "Tentativo {current}/{max}", + "settings.storageMigrations.operation.move": "Sposta", + "settings.storageMigrations.operation.copy": "Copia conservata", + "settings.storageMigrations.cancelled": "Cancellazione migrazione accettata", + "settings.storageMigrations.cancelling": "Cancellazione…", + "settings.storageMigrations.retried": "Migrazione in coda per il nuovo tentativo", + "settings.storageMigrations.state.queued": "In coda", + "settings.storageMigrations.state.copying": "Copia in corso", + "settings.storageMigrations.state.verifying": "Verifica in corso", + "settings.storageMigrations.state.committing": "Conferma in corso", + "settings.storageMigrations.state.cleanup_pending": "Pulizia sorgente", + "settings.storageMigrations.state.retry_wait": "In attesa di nuovo tentativo", + "settings.storageMigrations.state.completed": "Completato", + "settings.storageMigrations.state.failed": "Fallito", + "settings.storageMigrations.state.cancelled": "Annullato", + "settings.storagePolicies.title": "Criteri di posizionamento telecamere", + "settings.storagePolicies.description": "Instrada le telecamere corrispondenti verso una destinazione di registrazione primaria in ordine di priorità. Una telecamera utilizza il primo criterio abilitato corrispondente.", + "settings.storagePolicies.add": "Aggiungi criterio di posizionamento", + "settings.storagePolicies.edit": "Modifica criterio di posizionamento", + "settings.storagePolicies.editorHelp": "Il criterio viene rivalutato per i nuovi segmenti. Le modifiche non spostano le registrazioni già esistenti.", + "settings.storagePolicies.priority": "Priorità (dalla più alta)", + "settings.storagePolicies.priorityValue": "Priorità {priority}", + "settings.storagePolicies.primary": "Destinazione primaria", + "settings.storagePolicies.primaryPool": "Pool di posizionamento (facoltativo)", + "settings.storagePolicies.exactTarget": "Usa il target primario esatto", + "settings.storagePolicies.fallback": "Se il primario non è disponibile", + "settings.storagePolicies.fallbackDefault": "Usa il target predefinito", + "settings.storagePolicies.fallbackTarget": "Usa un target di fallback denominato", + "settings.storagePolicies.fallbackPause": "Sospendi registrazione", + "settings.storagePolicies.fallbackFail": "Interrompi avvio registrazione", + "settings.storagePolicies.namedFallback": "Target di fallback", + "settings.storagePolicies.chooseTarget": "Scegli un target", + "settings.storagePolicies.choosePool": "Scegli un pool", + "settings.storagePolicies.minimumDays": "Ritenzione minima (giorni)", + "settings.storagePolicies.desiredDays": "Ritenzione desiderata (giorni)", + "settings.storagePolicies.maximumDays": "Ritenzione massima (giorni)", + "settings.storagePolicies.copyCount": "Copie verificate richieste", + "settings.storagePolicies.replicationPool": "Pool di replica", + "settings.storagePolicies.migrateAfter": "Sposta dopo (giorni)", + "settings.storagePolicies.migrationTarget": "Target di archiviazione", + "settings.storagePolicies.pressurePriority": "Priorità eliminazione sotto pressione (prima le più basse)", + "settings.storagePolicies.disabledTarget": "disabilitato", + "settings.storagePolicies.enabled": "Criterio abilitato", + "settings.storagePolicies.selector": "Telecamere corrispondenti", + "settings.storagePolicies.preview": "Precedenza in anteprima", + "settings.storagePolicies.previewing": "Valutazione in corso…", + "settings.storagePolicies.previewRequired": "Anteprima della bozza corrente prima del salvataggio per verificare la sovrapposizione delle telecamere e il criterio effettivo vincente.", + "settings.storagePolicies.previewSummary": "Corrisponde a {matched} telecamere; questa bozza è efficace per {effective}.", + "settings.storagePolicies.previewShadowed": "Un criterio con precedenza superiore prevale per {count} telecamere corrispondenti.", + "settings.storagePolicies.previewWins": "Prevale su \"{policy}\" (priorità {priority}) per {count} telecamere.", + "settings.storagePolicies.previewLoses": "Perde contro \"{policy}\" (priorità {priority}) per {count} telecamere.", + "settings.storagePolicies.previewNoMatches": "Questo selettore attualmente non corrisponde a nessuna telecamera.", + "settings.storagePolicies.invalidPriority": "La priorità deve essere un numero intero compreso tra -1.000.000 e 1.000.000.", + "settings.storagePolicies.invalidLifecycle": "Verifica l'ordinamento della ritenzione, il numero di copie e il pool di replica, l'età di migrazione e il target.", + "settings.storagePolicies.created": "Criterio di posizionamento creato", + "settings.storagePolicies.updated": "Criterio di posizionamento aggiornato", + "settings.storagePolicies.deleted": "Criterio di posizionamento eliminato", + "settings.storagePolicies.deleteConfirm": "Eliminare il criterio di posizionamento \"{name}\"? Le registrazioni esistenti non verranno interessate.", + "settings.storagePolicies.active": "Attivo", + "settings.storagePolicies.inactive": "Disabilitato", + "settings.storagePolicies.routesTo": "Destinazione primaria: {target}", + "settings.storagePolicies.lifecycleSummary": "Conservazione min/desiderata/max: {minimum}/{desired}/{maximum} giorni · {copies} copia/e verificate", + "settings.storagePolicies.fallsBackTo": "Destinazione di riserva: {target}", + "settings.storagePolicies.mode.default": "Riserva: destinazione predefinita", + "settings.storagePolicies.mode.pause": "Riserva: pausa registrazione", + "settings.storagePolicies.mode.fail": "Riserva: errore avvio registrazione", + "settings.storagePolicies.empty": "Nessun criterio di posizionamento. Le telecamere continuano a utilizzare la destinazione predefinita; le altre destinazioni non ricevono nulla finché un criterio non le instrada.", + "settings.storagePolicies.archiveNoTrigger": "Una destinazione di archiviazione è impostata ma nulla attiva lo spostamento. Imposta 'Sposta dopo (giorni)', un'età di archiviazione o un'opzione di archiviazione; altrimenti nessuna registrazione verrà spostata.", + "settings.storageCompliance.title": "Capacità e conformità ai criteri", + "settings.storageCompliance.description": "I tassi osservati su 30 giorni prevedono la pressione sulla destinazione e la conservazione raggiunta; le violazioni attive del ciclo di vita restano visibili finché non risolte.", + "settings.storageCompliance.loadError": "Impossibile caricare la conformità dell'archiviazione", + "settings.storageCompliance.unknown": "Sconosciuto", + "settings.storageCompliance.days": "{days} giorni", + "settings.storageCompliance.day": "giorno", + "settings.storageCompliance.targetForecasts": "Previsioni destinazione", + "settings.storageCompliance.target": "Destinazione", + "settings.storageCompliance.dailyRate": "Tasso osservato", + "settings.storageCompliance.toHigh": "Alla soglia massima", + "settings.storageCompliance.expected": "Conservazione prevista", + "settings.storageCompliance.confidence": "Affidabilità", + "settings.storageCompliance.policyCompliance": "Conformità ai criteri", + "settings.storageCompliance.compliant": "Nessuna violazione attiva", + "settings.storageCompliance.violationCount": "{count} violazione/i", + "settings.storageCompliance.policyForecast": "Raggiunta {achieved}; prevista {expected}; desiderata {desired} giorni.", + "settings.storageCompliance.copyDeficits": "{count} registrazione/i richiede/no un'altra copia verificata.", + "settings.storageCompliance.activeViolations": "Violazioni attive", + "settings.storageCompliance.type.copy_count": "Numero di copie", + "settings.storageCompliance.type.minimum_retention": "Capacità minima di conservazione", + "settings.storageCompliance.type.target_unavailable": "Destinazione non disponibile", + "settings.storageCompliance.type.migration_failed": "Operazione di ciclo di vita fallita", + "settings.recordingDirectoryFormat": "Struttura cartelle registrazioni", + "settings.recordingDirectoryFormatHelp": "Organizza le nuove registrazioni MP4 in sottocartelle nella cartella di ogni telecamera. Le registrazioni esistenti non vengono spostate.", + "settings.recordingDirectoryFlat": "Piana (solo cartella telecamera)", + "settings.recordingDirectoryMonth": "Per mese (AAAA/MM)", + "settings.recordingDirectoryDay": "Per giorno (AAAA/MM/GG)", + "settings.minFreePct": "Spazio libero minimo (%)", + "settings.minFreePctHelp": "Mantieni almeno questa percentuale di spazio libero sul volume eliminando automaticamente le registrazioni più vecchie, indipendentemente dai giorni di conservazione. Questo limita l'utilizzo alla dimensione del disco — impostalo e il disco non si riempirà mai. 0 disattiva il limite di capacità.", + "settings.pressureThresholds": "Soglie di pressione disco (%)", + "settings.pressureThresholdsHelp": "Fasce di spazio libero che intensificano la pulizia automatica. Devono rispettare: emergenza < critico < avviso.", + "settings.pressureWarningPct": "Avviso sotto (% libero)", + "settings.pressureCriticalPct": "Critico sotto (% libero)", + "settings.pressureEmergencyPct": "Emergenza sotto (% libero)", + "settings.databaseBackupVerify": "Verifica backup", + "settings.databaseBackupVerifyFull": "Completa (integrity_check, verifica incrociata di ogni indice)", + "settings.databaseBackupVerifyQuick": "Rapida (quick_check, solo struttura delle pagine)", + "settings.databaseBackupVerifyOff": "Disattivata (nessuna scansione post-copia)", + "settings.databaseBackupVerifyHelp": "Scansione applicata a ogni backup copiato prima della pubblicazione. Completa può richiedere più tempo della copia su un database di grandi dimensioni su disco meccanico e potrebbe superare la soglia di sicurezza di 30 minuti, scartando quel backup; Rapida rileva comunque pagine danneggiate o troncate con molte meno ricerche.", + "settings.viewMethodAuto": "Auto — preferenza per telecamera con fallback", + "settings.resetWizardPending": "Avvio procedura guidata…", + "settings.apiDetectionFormat": "Formato richiesta API", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (caricamento immagine multipart)", + "settings.apiDetectionFormatDoods2": "DOODS2 (corpo JSON con immagine base64)", + "settings.apiDetectionFormatHelp": "Formato di trasmissione che LightNVR utilizza per inviare snapshot all'API di rilevamento. Mantieni light-object-detect per light-object-detect o qualsiasi server che ne implementi il contratto; scegli DOODS2 per un server DOODS2.", + "settings.apiDetectionUrlHelpDoods2": "Endpoint DOODS2 /detect, es. http://localhost:8080/detect. La richiesta viene inviata come JSON e non vengono aggiunti parametri di query.", + "settings.apiDetectionDetectorName": "Nome rilevatore DOODS2", + "settings.apiDetectionDetectorNameHelp": "Inviato come detector_name in ogni richiesta. Deve corrispondere a un rilevatore elencato da GET /detectors del server; \"default\" utilizza il rilevatore predefinito del server.", + "settings.defaultPlaybackTransport": "Trasporto di riproduzione predefinito", + "settings.defaultPlaybackTransportHelp": "Profilo di riproduzione applicato ai nuovi stream. Gli stream esistenti mantengono la propria selezione.", + "playbackTransport.auto": "Auto (consigliato)", + "playbackTransport.webrtcOnly": "Solo WebRTC", + "playbackTransport.mseOnly": "Solo MSE", + "playbackTransport.hlsOnly": "Solo HLS", + "playbackTransport.webrtcThenMse": "WebRTC, poi MSE", + "playbackTransport.mseThenHls": "MSE, poi HLS", + "investigation.experimental": "Area di lavoro sperimentale", + "investigation.title": "Indagine", + "investigation.description": "Rivedi più telecamere con un unico cursore UTC condiviso senza nascondere le lacune nelle registrazioni.", + "investigation.query": "Finestra di indagine", + "investigation.queryHelp": "Seleziona fino a 16 telecamere. Al massimo quattro lettori video sono attivi contemporaneamente.", + "investigation.cameras": "telecamere", + "investigation.cameraSelection": "Selezione telecamere", + "investigation.start": "Inizio", + "investigation.end": "Fine", + "investigation.load": "Carica indagine", + "investigation.applyWindow": "Applica intervallo di tempo", + "investigation.loading": "Caricamento indagine…", + "investigation.eventType": "Tipo di evento", + "investigation.anyEventType": "Qualsiasi tipo di evento", + "investigation.eventType.detection": "Rilevamento", + "investigation.eventType.motion": "Movimento", + "investigation.location": "Posizione", + "investigation.anyLocation": "Qualsiasi posizione", + "investigation.objectLabel": "Etichetta oggetto", + "investigation.anyLabel": "Qualsiasi etichetta", + "investigation.zone": "Zona", + "investigation.anyZone": "Qualsiasi zona", + "investigation.source": "Sorgente di rilevamento", + "investigation.anySource": "Qualsiasi sorgente", + "investigation.captureMethod": "Metodo di acquisizione", + "investigation.anyCaptureMethod": "Qualsiasi metodo di acquisizione", + "investigation.recordingTag": "Tag di registrazione", + "investigation.anyRecordingTag": "Qualsiasi tag di registrazione", + "investigation.protection": "Protezione", + "investigation.anyProtection": "Qualsiasi protezione", + "investigation.protected": "Protetto", + "investigation.unprotected": "Non protetto", + "investigation.minimumConfidence": "Confidenza minima", + "investigation.confidenceError": "La confidenza minima deve essere compresa tra 0 e 1.", + "investigation.metadataRegionSearch": "Ricerca per regione dei metadati", + "investigation.regionSearchHelp": "Scegli una telecamera principale con riprese, quindi disegna un'area sul suo video.", + "investigation.regionActive": "Ricerca di box archiviati da {camera}. Un risultato mancante non è la prova che nulla abbia attraversato l'area.", + "investigation.regionMatch": "Corrispondenza box", + "investigation.regionMatch.center": "Centro all'interno", + "investigation.regionMatch.intersects": "Qualsiasi intersezione", + "investigation.regionMatch.minimumIntersection": "Sovrapposizione minima", + "investigation.regionMinimumOverlap": "Sovrapposizione minima (%)", + "investigation.regionLeft": "Sinistra (%)", + "investigation.regionTop": "Alto (%)", + "investigation.regionWidth": "Larghezza (%)", + "investigation.regionHeight": "Altezza (%)", + "investigation.drawRegion": "Disegna area di ricerca", + "investigation.drawingRegion": "Disegno area di ricerca…", + "investigation.clearRegion": "Cancella area", + "investigation.useFullFrame": "Usa fotogramma completo", + "investigation.drawRegionPrompt": "Trascina sul video per definire l'area di ricerca", + "investigation.applyFilters": "Applica filtri", + "investigation.searching": "Ricerca eventi…", + "investigation.searchResults": "Risultati eventi", + "investigation.searchHelp": "Carica un'indagine per cercare i suoi metadati degli eventi persistiti.", + "investigation.resultCount": "{count} eventi corrispondenti", + "investigation.results": "risultati", + "investigation.resultHistogram": "Istogramma eventi", + "investigation.histogramHelp": "Seleziona una barra per spostare il cursore condiviso.", + "investigation.previousResult": "Evento precedente", + "investigation.nextResult": "Evento successivo", + "investigation.previousResultShortcut": "Evento precedente ([)", + "investigation.nextResultShortcut": "Evento successivo (])", + "investigation.noResults": "Nessun evento persistito corrisponde alla telecamera, all'intervallo di tempo e ai filtri selezionati.", + "investigation.noThumbnail": "Nessuna miniatura", + "investigation.exploreThumbnails": "Esplora miniature", + "investigation.exploreSelectedThumbnails": "Esplora attorno all'evento", + "investigation.thumbnailDrilldown": "Approfondimento miniature", + "investigation.thumbnailDrilldownHelp": "Scegli un momento qualsiasi, anche in un intervallo vuoto, per spostare il cursore condiviso e rigenerare un insieme più ristretto di campioni.", + "investigation.selectThumbnailSample": "Ispeziona attorno a {time}", + "investigation.loadingThumbnail": "Caricamento miniatura…", + "investigation.thumbnailUnavailable": "Miniatura non disponibile", + "investigation.loadingSamples": "Caricamento campioni di miniature…", + "investigation.thumbnailCoverageTruncated": "Questo intervallo contiene più registrazioni di quante il campionatore possa ispezionarne. Riduci la finestra temporale per una copertura completa.", + "investigation.bookmarks.save": "Salva segnalibro", + "investigation.bookmarks.open": "Segnalibri", + "investigation.bookmarks.saveTitle": "Salva segnalibro di indagine", + "investigation.bookmarks.listTitle": "Segnalibri di indagine", + "investigation.bookmarks.notHold": "Un segnalibro ripristina questa vista, ma non protegge le registrazioni dalla normale conservazione o eliminazione.", + "investigation.bookmarks.title": "Nome segnalibro", + "investigation.bookmarks.note": "Nota privata (facoltativa)", + "investigation.bookmarks.titleRequired": "Inserisci un nome per il segnalibro.", + "investigation.bookmarks.empty": "Non sono presenti segnalibri di indagine salvati.", + "investigation.bookmarks.cameraCount": "{count} telecamera/e", + "investigation.bookmarks.restore": "Apri", + "investigation.bookmarks.confirmDelete": "Eliminare il segnalibro?", + "investigation.actions.open": "Proteggi / scarica", + "investigation.actions.title": "Registrazioni di indagine", + "investigation.actions.notEvidenceExport": "La protezione impedisce l'eliminazione per scadenza della conservazione. Il download ZIP è un'esportazione di comodo, non un pacchetto di prove verificato.", + "investigation.actions.scope": "Ambito di registrazione", + "investigation.actions.selectedResult": "Evento e telecamera selezionati", + "investigation.actions.fullWindow": "Tutte le telecamere nella finestra di indagine", + "investigation.actions.preview": "Anteprima registrazioni", + "investigation.actions.previewing": "Ricerca di registrazioni sovrapposte…", + "investigation.actions.invalidRange": "Seleziona un intervallo di tempo valido con la fine successiva all'inizio.", + "investigation.actions.recordingCount": "{count} registrazioni sovrapposte", + "investigation.actions.protectedCount": "{count} già protette", + "investigation.actions.noRecordings": "Nessuna registrazione completata si sovrappone a questa telecamera e selezione temporale.", + "investigation.actions.protectDenied": "{count} registrazioni non protette sono fuori dall'ambito di protezione e sono escluse da questa azione.", + "investigation.actions.exportDenied": "Permesso di esportazione mancante per {count} registrazioni. I download sono tutto-o-nulla, quindi questa selezione non può essere esportata.", + "investigation.actions.camera": "Telecamera", + "investigation.actions.recording": "Registrazione", + "investigation.actions.size": "Dimensione", + "investigation.actions.notPermitted": "Non consentito", + "investigation.actions.protectButton": "Proteggi {count}", + "investigation.actions.protecting": "Protezione in corso…", + "investigation.actions.protectUnavailable": "Non ci sono registrazioni non protette che puoi proteggere.", + "investigation.actions.protectResult": "Protezione completata: {success} riuscite, {failed} fallite.", + "investigation.actions.downloadButton": "Scarica {count}", + "investigation.actions.downloadUnavailable": "Ogni registrazione richiede il permesso di esportazione prima di creare un ZIP.", + "investigation.actions.buildingArchive": "Creazione ZIP in corso…", + "investigation.actions.downloadFailed": "Creazione ZIP fallita sul server.", + "investigation.actions.downloadTimedOut": "La creazione ZIP non è terminata entro cinque minuti. Prova un intervallo più ristretto.", + "investigation.actions.downloadStarted": "Download ZIP avviato.", + "investigation.backOneLevel": "Torna di un livello", + "investigation.thumbnailMinimumWindow": "Questo è l'intervallo di un secondo più ristretto disponibile. Il cursore condiviso si è comunque spostato al momento selezionato.", + "investigation.localSource": "locale", + "investigation.mediaAvailable": "Media disponibile", + "investigation.durationSeconds": "Durata {count}s", + "investigation.pageNumber": "Pagina {count}", + "investigation.incompleteCoverage": "{count} righe di eventi legacy non hanno potuto essere attribuite a un'identità di telecamera immutabile.", + "investigation.spatialCoverageGap": "{count} righe di eventi nell'ambito non avevano un riquadro di delimitazione e non sono state cercate spazialmente.", + "investigation.noSpatialMetadata": "Nessun evento nell'ambito ha un riquadro di delimitazione per questa ricerca di metadati.", + "investigation.selectCameraError": "Seleziona almeno una telecamera.", + "investigation.selectRecordingError": "Seleziona almeno una registrazione.", + "investigation.investigateSelectedCount": "Indaga su {count} registrazioni selezionate", + "investigation.missingCameraIdentity": "Impossibile indagare: {count} registrazioni selezionate non hanno un'identità della telecamera.", + "investigation.recordingTimeError": "Le registrazioni selezionate non hanno un intervallo di tempo valido.", + "investigation.windowLimit": "Le registrazioni selezionate superano il limite di indagine di 31 giorni.", + "investigation.timeRangeError": "L'ora di fine deve essere successiva all'ora di inizio.", + "investigation.cameraLimit": "Un'indagine può includere al massimo {count} telecamere.", + "investigation.decoderLimit": "Solo {count} lettori di telecamere possono essere attivi contemporaneamente.", + "investigation.playbackControls": "Controlli di riproduzione sincronizzati", + "investigation.play": "Riproduci", + "investigation.pause": "Pausa", + "investigation.mode": "Modalità di riproduzione", + "investigation.wallClock": "Orologio di sistema", + "investigation.skipCommonGaps": "Salta intervalli comuni", + "investigation.speed": "Velocità", + "investigation.sharedCursor": "Cursore UTC condiviso", + "investigation.activePlayers": "lettori attivi", + "investigation.timeline": "timeline condivisa", + "investigation.segments": "segmenti", + "investigation.truncated": "troncati", + "investigation.gap": "Nessun filmato", + "investigation.players": "Lettori di telecamere sincronizzati", + "investigation.activateCamera": "Attiva almeno una riga della timeline per caricare il video.", + "investigation.noFootage": "Nessun filmato", + "investigation.noFootageAtTime": "Nessun filmato all'orario condiviso", + "investigation.primaryAudio": "Audio primario", + "investigation.makePrimary": "Rendi primario", + "investigation.status.loading": "Caricamento media", + "investigation.status.synchronizing": "Sincronizzazione", + "investigation.status.ready": "Sincronizzato", + "investigation.status.late": "In ritardo — recupero in corso", + "investigation.status.error": "Media non disponibile", + "investigation.status.paused-by-browser": "Seleziona play per consentire i media", + "streamsConfig.eptzTitle": "Fisheye ePTZ", + "streamsConfig.eptzEnable": "Abilita fisheye ePTZ lato browser", + "streamsConfig.eptzHelp": "Correggi la distorsione del flusso fisheye originale in Vista live, Riproduzione timeline e Indagine. Questo non altera le registrazioni né l'output della telecamera.", + "streamsConfig.eptzModelHelp": "Proiezione: fisheye circolare equidistante · Montaggio: soffitto. Centro e raggio utilizzano coordinate normalizzate dell'immagine sorgente.", + "streamsConfig.eptzCenterX": "Centro ottico X", + "streamsConfig.eptzCenterY": "Centro ottico Y", + "streamsConfig.eptzRadius": "Raggio del cerchio immagine", + "streamsConfig.eptzLensFov": "FOV obiettivo (gradi)", + "streamsConfig.eptzRotation": "Rotazione obiettivo (gradi)", + "streamsConfig.eptzDefaultYaw": "Pan predefinito (gradi)", + "streamsConfig.eptzDefaultTilt": "Tilt predefinito (gradi)", + "streamsConfig.eptzViewFov": "FOV vista predefinita", + "streamsConfig.eptzCalibrationHelp": "Trascina per spostare la visuale, usa la rotella o il pinch per lo zoom e premi Home per reimpostare la telecamera virtuale. Regola centro e raggio se il bordo del cerchio immagine non è allineato.", + "settings.archive.targetType": "Tipo di archiviazione", + "settings.archive.filesystem": "File system locale o montato (NFS/SAN)", + "settings.archive.s3": "Bucket di archiviazione compatibile S3", + "settings.archive.endpoint": "Endpoint HTTPS", + "settings.archive.region": "Regione", + "settings.archive.bucket": "Bucket dedicato", + "settings.archive.credential_ref": "Riferimento credenziali", + "settings.archive.budget": "Budget di archiviazione (GiB, 0 = illimitato)", + "settings.archive.connectionHelp": "Utilizza un bucket privato, senza versionamento e senza regole di scadenza del ciclo di vita. Il riferimento credenziali seleziona un file segreto montato sul server. Inserisci il percorso gestito nel formato s3://bucket/instance-prefix.", + "settings.archive.policy": "Criterio di archiviazione esterna", + "settings.archive.archive_after_seconds": "Archivia dopo la cattura (secondi, -1 = disabilitato)", + "settings.archive.hot_residency_seconds": "Mantieni copia hot (secondi, -1 = sposta dopo l'archiviazione)", + "settings.archive.archive_protected": "Dai priorità all'archiviazione delle registrazioni protette", + "settings.archive.archive_on_pressure": "Archivia in anticipo quando l'archiviazione hot è sotto pressione", + "settings.archive.policyHelp": "La temporizzazione dell'archiviazione si basa sull'età della cattura e richiede una registrazione completata. -1 disabilita l'archiviazione basata sull'età o rimuove il minimo di permanenza hot; 0 significa immediatamente. Le modifiche si applicano alle nuove registrazioni. Rivedi le registrazioni esistenti per applicare loro una nuova revisione.", + "settings.archive.deletion_pending": "Eliminazione in sospeso", + "settings.archive.archived": "Archiviato", + "settings.archive.hot": "Hot", + "settings.archive.hot_and_archive": "Hot + archivio", + "settings.archive.archiving": "Archiviazione", + "settings.archive.preparing": "Preparazione della riproduzione", + "settings.archive.unavailable": "Non disponibile", + "settings.archive.operations": "Operazioni di archiviazione", + "settings.archive.readOnly": "Modalità di recupero: migrazione ed eliminazione delle registrazioni sono sospese.", + "settings.archive.disabledBuild": "Il supporto S3 è disabilitato in questa versione. I target di filesystem montati restano disponibili.", + "settings.archive.stored": "Archiviati in bucket", + "settings.archive.backlog": "Coda di trasferimento", + "settings.archive.cache": "Cache di recupero", + "settings.archive.objectsRemaining": "oggetti rimanenti", + "settings.archive.waitingForReaders": "In coda, o in attesa di lettori attivi.", + "settings.archive.applied": "Revisione della policy applicata alle registrazioni esistenti", + "settings.archive.reviewExisting": "Verifica registrazioni esistenti", + "settings.archive.applySummary": "{count} registrazioni ({bytes}) utilizzeranno questa revisione. {expired} hanno già superato il limite di conservazione.", + "settings.archive.applyHelp": "Le protezioni e gli override di registrazione restano attivi. Si applicano anche la conservazione di stream e sistema. I nuovi tempi e destinazioni di archiviazione avranno effetto alla prossima scansione del ciclo di vita.", + "settings.archive.applyBlocked": "Completa o risolvi i trasferimenti associati prima di applicare questa revisione.", + "settings.archive.apply": "Applica alle registrazioni esistenti", + "common.fullscreenUnsupported": "La modalità a schermo intero non è supportata in questo browser.", + "recordings.viewInTimelineTitle": "Visualizza questo stream in questo momento nella vista Timeline", + "recordings.clickToRetry": "Clicca per riprovare", + "timeline.previousDay": "Giorno precedente", + "timeline.nextDay": "Giorno successivo", + "timeline.previousMonth": "Mese precedente", + "timeline.nextMonth": "Mese successivo", + "settings.searchLabel": "Cerca impostazioni", + "settings.clearSearch": "Cancella ricerca", + "recordings.addTagPlaceholder": "Aggiungi un tag...", + "recordings.addNewTagPlaceholder": "Aggiungi nuovo tag..." } diff --git a/web/public/locales/ja.json b/web/public/locales/ja.json index 57a7218c..1ea01513 100644 --- a/web/public/locales/ja.json +++ b/web/public/locales/ja.json @@ -759,9 +759,9 @@ "streamsConfig.streamNameImmutable": "ストリーム名は作成後に変更できません", "streamsConfig.streamNameAllowedChars": "文字、数字、「.」、「-」、および「_」のみを使用できます (スペースは使用できません)。", "streamsConfig.streamUrl": "ストリームURL", - "streamsConfig.streamUrlPlaceholder": "rtsp://ユーザー名:パスワード@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "サブストリーム URL (オプション)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://ユーザー名:パスワード@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "ダッシュボード グリッド ビューの低解像度ストリーム URL。どこでもメインストリームを使用するには、空のままにします。サブストリームはグリッド モードでのライブ プレビューにのみ使用されます。録画と全画面表示では常にメイン ストリームが使用されます。", "streamsConfig.urlCredentialsHiddenTitle": "URL 認証情報はデモ/ビューア モードでは非表示になります", "streamsConfig.urlCredentialsHidden": "URL 認証情報はセキュリティのために非表示になっています", @@ -819,7 +819,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "このエンドポイントで light-object-detect が実行されていることを確認してください", "streamsConfig.customApiEndpointUrl": "カスタム API エンドポイント URL", "streamsConfig.useDefaultEndpoint": "デフォルトのエンドポイントを使用する", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "カスタム検出 API エンドポイントに完全な URL を入力します", "streamsConfig.overrideWithCustomEndpoint": "カスタムエンドポイントによるオーバーライド", "streamsConfig.detectionThreshold": "検出閾値", @@ -1056,7 +1056,7 @@ "settings.detectionModelsPath": "検出モデルのパス", "settings.detectionModelsPathHelp": "検出モデルが保存されるディレクトリ", "settings.apiDetectionUrl": "API 検出 URL", - "settings.apiDetectionUrlHelp": "外部物体検出 API エンドポイントの URL", + "settings.apiDetectionUrlHelp": "light-object-detect エンドポイント(例: http://localhost:8000/api/v1/detect)。スナップショットはマルチパートフォームデータとしてアップロードされ、backend と confidence_threshold のクエリパラメータが付加されます。", "settings.apiDetectionBackend": "API 検出バックエンド", "settings.apiDetectionBackendOnnx": "ONNX ランタイム", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1156,5 +1156,1492 @@ "settings.discoveryIntervalSecondsRangeHelp": "カメラをスキャンする頻度 (30 ~ 3600 秒)", "settings.discoveryNetwork": "ディスカバリーネットワーク", "settings.discoveryNetworkExamples": "例: 192.168.1.0/24、10.0.0.0/16、自動", - "settings.saveSettings": "設定を保存" + "settings.saveSettings": "設定を保存", + "live.navigator.title": "ナビゲーター", + "live.navigator.subtitle": "場所、レイアウト、アクティビティ", + "live.navigator.cameras": "カメラ", + "live.navigator.plans": "プラン", + "live.navigator.views": "ビュー", + "live.navigator.events": "イベント", + "live.navigator.search": "カメラを検索…", + "live.navigator.allCameras": "すべてのカメラ", + "live.navigator.unassigned": "未割り当て", + "live.navigator.noCameras": "この範囲に一致するカメラはありません。", + "live.navigator.saveCurrent": "現在のレイアウトを保存", + "live.navigator.noLayouts": "保存済みのレイアウトはありません。", + "live.navigator.layoutNamePrompt": "このライブレイアウトに名前を付ける", + "live.navigator.shareLayoutPrompt": "このレイアウトを他のオペレーターと共有しますか?", + "live.navigator.layoutSaved": "{name} を保存しました", + "live.navigator.layoutLoaded": "{name} を読み込みました", + "live.navigator.deleteLayoutConfirm": "{name} を削除しますか?", + "live.navigator.shared": "共有済み", + "live.navigator.loadingEvents": "最近のイベントを読み込み中…", + "live.navigator.noRecentEvents": "過去1時間の検出はありません。", + "live.navigator.expand": "ナビゲーターを展開", + "live.navigator.collapse": "ナビゲーターを折りたたむ", + "live.plan.navigatorHelp": "建物またはフロアを選択してください。カメラプレビューはリクエスト時のみ表示されます。", + "live.plan.noPlans": "建物プランはまだありません。プランワークスペースで作成してください。", + "live.plan.emptyTitle": "空間カメラビューを作成", + "live.plan.emptyDescription": "プランではサイト全体のステータスマーカーを表示し、オペレーターが要求したときのみ映像を開きます。ここで部屋や壁を描画するか、スキャンしたフロアプラン、サイト図面、NVRソフトウェアのスナップショットをアップロードして、カメラを実際の部屋にマッピングしてください。", + "live.plan.sketch.tools": "レイアウトツール", + "live.plan.sketch.tool.select": "選択", + "live.plan.sketch.tool.room": "部屋", + "live.plan.sketch.tool.wall": "壁", + "live.plan.sketch.tool.area": "エリア", + "live.plan.sketch.tool.label": "ラベル", + "live.plan.sketch.undo": "描画を取り消す", + "live.plan.sketch.redo": "描画をやり直す", + "live.plan.sketch.snap": "グリッドにスナップ", + "live.plan.sketch.hint.select": "図形やカメラをドラッグして移動します。図形をクリックして編集、Altキーでグリッドを無視できます。", + "live.plan.sketch.hint.room": "プラン上でドラッグして部屋や建物の輪郭を描画します。", + "live.plan.sketch.hint.wall": "クリックして壁の点を追加します。ダブルクリックまたはEnterで完了、Escapeでキャンセル。", + "live.plan.sketch.hint.area": "クリックしてエリアの輪郭を描画します。最初の点をクリックまたはEnterで閉じます。", + "live.plan.sketch.hint.label": "プランをクリックしてテキストラベルを配置します。", + "live.plan.sketch.type.rect": "部屋", + "live.plan.sketch.type.wall": "壁", + "live.plan.sketch.type.area": "エリア", + "live.plan.sketch.type.label": "ラベル", + "live.plan.sketch.pointCount": "{count} 点", + "live.plan.sketch.defaultLabel": "ラベル", + "live.plan.sketch.shapes": "レイアウト図形", + "live.plan.sketch.noShapes": "まだ何も描画されていません。プラン上のツールを選択して開始してください。", + "live.plan.sketch.tone": "色", + "live.plan.sketch.tone.slate": "スレート", + "live.plan.sketch.tone.blue": "ブルー", + "live.plan.sketch.tone.green": "グリーン", + "live.plan.sketch.tone.amber": "アンバー", + "live.plan.sketch.tone.red": "レッド", + "live.plan.sketch.tone.violet": "バイオレット", + "live.plan.sketch.labelText": "ラベル", + "live.plan.sketch.text": "テキスト", + "live.plan.sketch.size": "サイズ", + "live.plan.sketch.size.sm": "小", + "live.plan.sketch.size.md": "中", + "live.plan.sketch.size.lg": "大", + "live.plan.sketch.filled": "部屋を塗りつぶす", + "live.plan.sketch.left": "左 %", + "live.plan.sketch.top": "上 %", + "live.plan.sketch.width": "幅 %", + "live.plan.sketch.height": "高さ %", + "live.plan.sketch.points": "ポイント", + "live.plan.sketch.point": "ポイント {index}", + "live.plan.sketch.delete": "図形を削除", + "live.plan.sketch.duplicate": "複製", + "live.plan.sketch.deselect": "完了", + "live.plan.sketch.emptyTitle": "このプランにはまだ何もありません", + "live.plan.sketch.emptyBody": "ここで部屋、壁、ラベルを描画するか、スキャンした平面図、現場図、PNG/JPEG出力(最大768 KB)をアップロードしてください。", + "live.plan.sketch.emptyBodyReadOnly": "管理者がレイアウトを描画するか、実際の建物の平面図をアップロードできます。", + "live.plan.sketch.drawLayout": "レイアウトを描画", + "live.plan.sketch.uploadImage": "画像をアップロード", + "live.plan.sketch.limitReached": "図形の上限に達しました({max})", + "live.plan.sketch.discardDrawing": "描画をキャンセルしました", + "live.favorites": "お気に入り", + "live.favoritesOnly": "お気に入りのカメラのみ表示", + "live.addFavorite": "{stream}をお気に入りに追加", + "live.removeFavorite": "{stream}をお気に入りから削除", + "live.noFavorites": "お気に入りのカメラはまだありません。カメラタイルの星アイコンで追加できます。", + "live.favoriteUpdateError": "お気に入りを更新できませんでした: {message}", + "live.resetZoom": "ズームをリセット", + "live.audioPlaybackBlocked": "ブラウザがカメラの音声をブロックしました。スピーカーボタンを再度クリックして再試行してください。", + "live.fullscreenSubStreamFallback": "{stream}: フルスクリーンでフル解像度ストリームに十分な帯域幅がありません — サブストリームに切り替えました。", + "live.tileActions": "カメラ操作", + "live.takeSnapshot": "スナップショットを撮影", + "live.openStreamRecordings": "このストリームの録画を開く", + "live.enterReorderMode": "カメラの並び替え", + "live.pullToRefresh": "引っ張ってストリームを更新", + "live.releaseToRefresh": "離してストリームを更新", + "live.refreshingStreams": "ストリームを更新中…", + "live.streamsRefreshed": "ストリームを更新しました", + "live.refreshStreamsFailed": "ストリームを更新できませんでした: {message}", + "live.tipDoubleTapFullscreen": "ヒント: タイルをダブルタップすると全画面表示になります。", + "live.dayNightControl": "デイ/ナイトモード", + "live.dayNightLoading": "読み込み中…", + "live.dayNightApplying": "適用中…", + "live.dayNightMode_auto": "自動", + "live.dayNightMode_day": "デイ", + "live.dayNightMode_night": "ナイト", + "live.dayNightMode_unknown": "不明", + "live.dayNightApplied": "デイ/ナイトモードを{mode}に設定しました", + "live.dayNightApplyFailed": "デイ/ナイトモードの設定に失敗しました", + "live.dayNightLoadFailed": "デイ/ナイトモードの読み込みに失敗しました", + "live.playbackFallbackUsed": "フォールバック: {transport}", + "live.playbackTransportUnavailable": "このストリームではサーバー側で{transport}が無効になっています。", + "live.recordingMode.constant": "常時録画", + "live.recordingMode.detection": "動体検知録画", + "live.recordingMode.schedule": "スケジュール録画", + "live.recordingMode.none": "録画なし", + "live.health.healthy": "ストリーム正常", + "live.health.degraded": "ストリームはバッファリング中/復旧中", + "live.health.offline": "ストリーム利用不可", + "live.enterPictureInPicture": "ピクチャーインピクチャーを開く", + "live.exitPictureInPicture": "ピクチャーインピクチャーを閉じる", + "live.pictureInPictureError": "ピクチャーインピクチャーに失敗しました: {message}", + "live.alwaysFullscreenOnTapEnable": "タイルの1回タップで全画面表示を有効にする", + "live.alwaysFullscreenOnTapDisable": "タイルの1回タップで全画面表示を無効化", + "live.displayMode": "表示モード", + "live.displayModeFit": "フィット", + "live.displayModeFill": "フィル", + "live.displayModeFitDescription": "フィット:レターボックス付きでフレーム全体を表示", + "live.displayModeFillDescription": "フィル:タイルを埋め尽くし、フレームの端をトリミング", + "live.slideshowStartCameras": "スライドショー開始:カメラを切り替え", + "live.slideshowStartPages": "スライドショー開始:グリッドページを切り替え", + "live.slideshowStop": "スライドショー停止", + "live.slideshowInterval": "スライドショー間隔", + "live.slideshowSeconds": "{seconds}秒", + "live.plan.previewUnavailable": "カメラプレビューを利用できません", + "live.plan.previewAlt": "{name}の現在の映像", + "live.plan.degreesValue": "{value}度", + "live.plan.inDegrees": "{label}(度)", + "live.plan.imageDimensionsError": "画像の寸法を読み取れませんでした", + "live.plan.loading": "フロアプランを読み込み中…", + "live.plan.created": "{name}を作成しました", + "live.plan.renamed": "{name}に名前を変更しました", + "live.plan.deleted": "{name}を削除しました", + "live.plan.backgroundType": "背景はPNGまたはJPEG画像である必要があります", + "live.plan.backgroundTooLarge": "背景画像が大きすぎます。最大768 KBです", + "live.plan.backgroundAspect": "アップロードされましたが、画像のアスペクト比が有効なキャンバスサイズに適合しません", + "live.plan.backgroundUpdatedSave": "{name}の背景を更新しました。レイアウトを保存してキャンバスサイズを適用してください", + "live.plan.backgroundNotResized": "背景をアップロードしましたが、キャンバスはリサイズされませんでした: {error}", + "live.plan.backgroundUpdated": "{name} の背景を更新しました", + "live.plan.backgroundRemoved": "背景を削除しました", + "live.plan.saved": "{name} を保存しました", + "live.plan.createTitle": "建物プランを作成", + "live.plan.createDescription": "この建物やフロアに分かりやすい名前を付けます。レイアウトを描画するか、フロアプラン画像をアップロードしてカメラを配置します。", + "live.plan.nameLabel": "プラン名", + "live.plan.namePlaceholder": "本館 · 1階", + "live.plan.createConfirm": "プランを作成", + "live.plan.eyebrow": "建物プラン", + "live.plan.placedSummary": "{placed} 台配置 · {live} 台ライブ中", + "live.plan.zoomAndPan": "プランのズームとパン", + "live.plan.panLeft": "左にパン", + "live.plan.panUp": "上にパン", + "live.plan.panDown": "下にパン", + "live.plan.panRight": "右にパン", + "live.plan.zoomOut": "ズームアウト", + "live.plan.zoomIn": "ズームイン", + "live.plan.fitTitle": "プランに合わせる", + "live.plan.fit": "合わせる", + "live.plan.backgroundMenu": "背景…", + "live.plan.save": "プランを保存", + "live.plan.uploadBackgroundTitle": "PNGまたはJPEG画像をプランの背景としてアップロード", + "live.plan.replaceBackground": "背景を置き換える", + "live.plan.uploadBackground": "背景をアップロード", + "live.plan.removeBackground": "背景を削除", + "live.plan.rename": "名前を変更", + "live.plan.newPlan": "新規プラン", + "live.plan.editLayout": "レイアウトを編集", + "live.plan.placementHint": "プランをクリックして{name}を配置", + "live.plan.clusterLabel": "{count}台のカメラ;拡大", + "live.plan.markerLabel": "{name};{availability};{rotation}°方向、視野角{fov}°", + "live.plan.cameraFallback": "カメラ", + "live.plan.legendLive": "ライブ", + "live.plan.canvas": "プランキャンバス", + "live.plan.width": "幅", + "live.plan.height": "高さ", + "live.plan.canvasHint": "背景画像をアップロードすると、キャンバスが画像に合わせてリサイズされます。", + "live.plan.canvasInvalid": "幅は400~4000、高さは300~4000の範囲で指定してください。", + "live.plan.openLive": "ライブカメラを開く", + "live.plan.direction": "カメラ方向", + "live.plan.fov": "視野角", + "live.plan.coverageNote": "扇形は方向と角度のみを示します。プラン上の距離は校正されていません。", + "live.plan.removeCamera": "プランから削除", + "live.plan.selectCamera": "カメラを選択", + "live.plan.selectHintEditing": "配置済みマーカーをドラッグして微調整できます。ステータスを確認し、必要に応じてライブ表示を開いてください。", + "live.plan.selectHint": "ステータスを確認し、必要に応じてライブ表示を開いてください。", + "live.plan.cameras": "プランカメラ", + "live.plan.findPlaceholder": "このプラン内で検索…", + "live.plan.findLabel": "このプラン内のカメラを検索", + "live.plan.unplaced": "未配置のカメラ", + "live.plan.unplacedHint": "カメラを選択し、プラン上の位置をクリックしてください。", + "live.plan.renameTitle": "プラン名を変更", + "live.plan.renameDescription": "プランはこのサイトのすべてのオペレーターと共有されます。", + "live.plan.deleteTitle": "プランを削除", + "live.plan.deleteMessage": "「{name}」とアップロードされた背景を削除しますか?このプラン上のカメラ配置は削除されますが、カメラ自体は影響を受けません。", + "setupWizard.welcomeTitle": "LightNVRへようこそ", + "setupWizard.welcomeIntro": "いくつかの簡単なステップでNVRを設定します。設定ページからいつでもこれらの設定を変更できます。", + "setupWizard.welcomeStorage": "ストレージパスとサイズ制限", + "setupWizard.welcomePerformance": "カメラ台数に応じたパフォーマンス制限", + "setupWizard.welcomeSecurity": "管理者サインインのセキュリティ", + "setupWizard.storageTitle": "ストレージとデータベース", + "setupWizard.storageIntro": "録画データとデータベースの保存先を設定してください。", + "setupWizard.storagePath": "録画保存パス", + "setupWizard.storagePathHint": "動画ファイルの書き込み先(絶対パス)。", + "setupWizard.maxStorage": "最大ストレージサイズ(GB)", + "setupWizard.maxStorageHint": "0 = 無制限。", + "setupWizard.dbPath": "データベースパス", + "setupWizard.dbPathHint": "SQLiteデータベースファイルの場所。", + "setupWizard.performanceTitle": "パフォーマンス", + "setupWizard.performanceIntro": "これらの設定は容量を制御するもので、画質には影響しません。ほとんどの場合はデフォルトのままで問題ありません。", + "setupWizard.threadPool": "ワーカースレッドプールサイズ", + "setupWizard.threadPoolInfo": "バックグラウンドのWeb/サーバー処理に影響します。パフォーマンス調整を行わない限り、推奨デフォルト値が最適です。", + "setupWizard.maxStreams": "最大同時ストリーム数", + "setupWizard.maxStreamsInfo": "は、この実行インスタンスのカメラ容量上限です。追加予定のカメラ数に余裕を持たせた値を設定してください。", + "setupWizard.important": "重要:", + "setupWizard.restartWarning": "いずれかの設定を変更した場合、新しい値は保存されますが、LightNVRの再起動後に反映されます。例えば、現在のストリーム上限が1で32に変更した場合、旧上限を超えるカメラを追加する前に再起動が必要です。", + "setupWizard.threadPoolHintCores": "推奨: {recommended}({cores}コアCPUの2倍)。libuvのバックグラウンドワーカースレッド数を制御します。範囲: 2–128。", + "setupWizard.threadPoolHint": "推奨: {recommended}(CPUコア数の2倍)。libuvのバックグラウンドワーカースレッド数を制御します。範囲: 2–128。", + "setupWizard.maxStreamsHint": "LightNVRが同時にアクティブにできるカメラ数です。デフォルト32、最大{max}。8台のカメラを想定する場合は8以上を選択してください。反映には再起動が必要です。", + "setupWizard.completeTitle": "セットアップ完了!", + "setupWizard.saved": "設定が正常に保存されました。", + "setupWizard.notSaved": "設定は変更されていません。デフォルト値が使用されます。", + "setupWizard.restartRequired": "再起動が必要です", + "setupWizard.restartRequiredInfo": "スレッドプールサイズおよび/または最大ストリーム数の変更は保存されましたが、サービスの再起動後に反映されます。カメラを追加する前に、または新しい容量上限を適用する前に再起動してください。", + "setupWizard.saveFailed": "設定の保存に失敗しました: {error}", + "setupWizard.back": "戻る", + "setupWizard.saving": "保存中…", + "setupWizard.saveContinue": "保存して続行", + "setupWizard.next": "次へ →", + "setupWizard.finish": "ダッシュボードへ", + "setupWizard.skip": "セットアップウィザードをスキップ", + "live.eptzCanvasLabel": "フィッシュアイ電子PTZビュー", + "live.eptzCanvasHint": "ドラッグでパン・チルト、ホイールまたはピンチでズーム、Homeでリセット", + "live.eptzReset": "ePTZビューをリセット", + "live.autoShort": "自動", + "live.webrtcShort": "WebRTC", + "nav.investigation": "調査", + "availability.label": "カメラの稼働状況", + "availability.live": "現在ライブ", + "availability.offline": "オフライン(以前接続済み)", + "availability.neverConnected": "未接続", + "availability.disabled": "無効", + "availability.all": "すべてのカメラ", + "streams.inventory": "一覧", + "streams.configuration": "設定", + "events.tab": "イベント", + "events.eyebrow": "イベント駆動型連携", + "events.title": "イベントとルーティング", + "events.description": "カメラおよびシステムイベントを永続的なMQTTストリームに変換し、自動化、通知サービス、外部処理に活用します。LightNVRはイベントインターフェースを提供し、メールやSMSの配信は下流サービスが担当します。", + "events.routes": "ルート", + "events.destinations": "宛先", + "events.catalog": "イベントカタログ", + "events.enable": "有効にする", + "events.loadError": "イベントルーティング設定を読み込めませんでした", + "events.accessDenied": "アクセス拒否 - 権限が不足しています", + "events.summary.routes": "ルート", + "events.summary.enabled": "{count} 件有効", + "events.summary.destinations": "宛先", + "events.summary.managedActive": "{count} 件管理・稼働中", + "events.summary.types": "登録済みタイプ", + "events.summary.registry": "バージョン管理イベントカタログ", + "events.summary.interface": "インターフェース", + "events.summary.interfaceHelp": "永続的イベント出力", + "events.route.add": "ルートを追加", + "events.route.addTitle": "イベントルートを作成", + "events.route.editTitle": "イベントルートを編集", + "events.route.create": "ルートを作成", + "events.route.editorDescription": "対象イベント、対象カメラ、送信先、ノイズの多いソースの制御方法を選択します。", + "events.route.emptyTitle": "イベントルートが設定されていません", + "events.route.emptyDescription": "イベントタイプ、カメラ範囲、スケジュール、抑制ポリシー、MQTT送信先を選択するルートを作成します。", + "events.route.enabled": "ルート有効", + "events.route.enabledHelp": "一致したイベントは永続的な配信のために受け付けられます", + "events.route.destination": "送信先", + "events.route.destinationHelp": "一致したイベントは各送信先ごとに1回永続化されます。", + "events.route.eventTypes": "イベントタイプ", + "events.route.eventTypesHelp": "レジストリから1つ以上のバージョン付きイベントコントラクトを選択します。", + "events.route.detectionFilters": "物体検出をフィルタリング", + "events.route.detectionFiltersHelp": "物体検出イベントに対してラベル、ゾーン、または最小信頼度を任意で要求します。", + "events.route.healthFilters": "システムヘルスイベントをフィルタリング", + "events.route.healthFiltersHelp": "登録済みのヘルス条件コードまたは重大度を任意で一致させます。利用可能な値はこのレコーダーから取得されます。", + "events.route.healthConditions": "ヘルス条件(いずれか)", + "events.route.healthSeverities": "重大度(いずれか)", + "events.route.healthRegistryUnavailable": "ヘルス条件レジストリが利用できません。条件フィルタを設定する前に再読み込みしてください。", + "events.route.labels": "ラベル(いずれか)", + "events.route.zones": "ゾーンID(いずれか)", + "events.route.listHelp": "値はカンマで区切ってください。", + "events.route.minConfidence": "最小信頼度", + "events.route.confidenceHelp": "0から1の値。", + "events.route.cameraScope": "カメラ範囲", + "events.route.cameraScopeHelp": "フリート全体を読み込まずに、フリートロケーション、タグ、属性コレクション、または明示的なカメラを再利用します。", + "events.route.allCameras": "すべてのカメラ", + "events.route.dynamicScope": "動的カメラセレクタ", + "events.route.systemScopeHelp": "システムイベントはカメラではありません。このルートにシステムスコープのイベントが含まれる場合、カメラセレクタは利用できません。", + "events.route.schedule": "スケジュール", + "events.route.scheduleHelp": "IANAタイムゾーンでイベント発生時刻を使用します。深夜をまたぐ時間帯もサポートされています。", + "events.route.restrictSchedule": "設定された時間帯のみ", + "events.route.suppression": "ノイズと配信ポリシー", + "events.route.suppressionHelp": "0に設定するとコントロールが無効になります。抑制は、その送信先が永続イベントを受け入れた後にのみ進行します。", + "events.route.debounce": "デバウンス秒数", + "events.route.debounceHelp": "繰り返し観測されるとこの静穏期間が延長されます。", + "events.route.cooldown": "クールダウン秒数", + "events.route.cooldownHelp": "イベント受理後の最小間隔。", + "events.route.grouping": "グループ化ウィンドウ秒数", + "events.route.groupingHelp": "最初のイベントを保持し、重複を統合します。", + "events.route.rateLimit": "毎分のイベント数", + "events.route.rateLimitHelp": "ルートとカメラごとの固定ウィンドウ上限。", + "events.route.deliveryPolicy": "配信ポリシー", + "events.route.suppressionActive": "ノイズ制御が有効", + "events.route.everyMatch": "すべての一致", + "events.route.preview": "ルートプレビュー", + "events.route.previewing": "プレビュー中…", + "events.route.previewResult": "ルートプレビュー", + "events.route.cameraMatches": "{count} 台のカメラが一致", + "events.route.previewNoPublish": "プレビューは完全なルールを検証し、カメラサンプルを解決しますが、イベントを公開することはありません。", + "events.route.systemPreviewHelp": "システムイベントはカメラ選択をバイパスするため、このプレビューでは一致するカメラがゼロと表示されます。", + "events.route.created": "イベントルートを作成しました", + "events.route.updated": "イベントルートを更新しました", + "events.route.deleted": "イベントルートを削除しました", + "events.route.disabled": "イベントルートを無効化しました", + "events.route.enabledMessage": "イベントルートを有効化しました", + "events.route.deleteConfirm": "イベントルート「{name}」を削除しますか?", + "events.route.validation.name": "ルート名を入力してください。", + "events.route.validation.destination": "配信先を選択してください。", + "events.route.validation.event_types": "イベントタイプを1つ以上選択してください。", + "events.route.validation.selector": "カメラセレクターを完了または修正してください。", + "events.route.validation.system_scope": "システムスコープのイベントではカメラセレクターを使用できません。", + "events.route.validation.detection_type": "検出フィルターには物体検出イベントタイプが必要です。", + "events.route.validation.detection_filter": "検出ラベル、ゾーン、信頼度しきい値を1つ以上追加してください。", + "events.route.validation.confidence": "最小信頼度は0から1の範囲で指定してください。", + "events.route.validation.predicate_mix": "検出フィルターとヘルスフィルターを1つのルートで組み合わせることはできません。", + "events.route.validation.health_type": "ヘルスフィルターには登録済みのシステムヘルスイベントタイプのみ使用できます。", + "events.route.validation.health_filter": "登録済みのヘルス条件または重大度を1つ以上選択してください。", + "events.route.validation.health_condition": "レコーダーのヘルスレジストリが返す条件コードのみを選択してください。", + "events.route.validation.health_severity": "選択したヘルスイベントタイプでサポートされる重大度のみを選択してください。", + "events.route.validation.timezone": "UTC や America/New_York など、インストール済みの IANA タイムゾーンを入力してください。", + "events.route.validation.schedule_window": "各スケジュールウィンドウには少なくとも1日と、異なる有効な開始時刻と終了時刻が必要です。", + "events.route.validation.suppression": "抑制値は許容範囲内の整数である必要があります。", + "events.schedule.timezone": "タイムゾーン", + "events.schedule.timezoneHelp": "レコーダーのタイムゾーンデータベースに存在する必要があります。", + "events.schedule.addWindow": "時間ウィンドウを追加", + "events.schedule.windowNumber": "ウィンドウ {number}", + "events.schedule.start": "開始", + "events.schedule.end": "終了", + "events.schedule.sunday": "日", + "events.schedule.monday": "月", + "events.schedule.tuesday": "火", + "events.schedule.wednesday": "水", + "events.schedule.thursday": "木", + "events.schedule.friday": "金", + "events.schedule.saturday": "土", + "events.destination.add": "配信先を追加", + "events.destination.addTitle": "MQTT 配信先を追加", + "events.destination.editTitle": "MQTT 配信先を編集", + "events.destination.create": "配信先を作成", + "events.destination.editorDescription": "永続的なイベント出力を設定します。認証情報は書き込み専用で、API からは返されません。", + "events.destination.default": "デフォルト MQTT 設定", + "events.destination.settingsManaged": "設定管理済み", + "events.destination.defaultDescription": "既存の MQTT 設定は mqtt:default として引き続き利用可能で、{count} 個のルートで使用されています。", + "events.destination.openSettings": "MQTT 設定を開く", + "events.destination.emptyTitle": "管理対象の配信先はありません", + "events.destination.emptyDescription": "クラウドコネクタ、自動化システム、通知サービスへの独立したイベント配信のために、別の MQTT ブローカーを追加します。", + "events.destination.identity": "配信先の識別子", + "events.destination.enabled": "配信先を有効にする", + "events.destination.enabledHelp": "接続して永続キューを処理する", + "events.destination.active": "アクティブ", + "events.destination.paused": "一時停止中", + "events.destination.pause": "一時停止", + "events.destination.broker": "ブローカー", + "events.destination.host": "ブローカーホスト", + "events.destination.hostHelp": "ホスト名またはIPアドレスのみ入力してください。URLスキームは含めないでください。", + "events.destination.port": "ポート", + "events.destination.clientId": "クライアントID", + "events.destination.clientIdHelp": "このブローカー接続に対して一意である必要があります。", + "events.destination.topic": "トピック", + "events.destination.topicTemplate": "トピックテンプレート", + "events.destination.topicHelp": "イベントタイプとサブジェクトIDのトークンを含める必要があります。MQTTワイルドカードは使用できません。", + "events.destination.keepalive": "キープアライブ秒数", + "events.destination.statusTopicTemplate": "プレゼンスステータストピック", + "events.destination.statusTopicHelp": "任意。{installation_uuid}を含める必要があります。{destination_uuid}も使用可能です。MQTTワイルドカードは使用できません。", + "events.destination.statusTopicEnabled": "この宛先ではプレゼンスが明示的に有効になっています。トピックはイベントトピックから推論されません。", + "events.destination.statusTopicDisabled": "この宛先ではプレゼンスが無効になっています。無効のままにするにはこのフィールドを空にしてください。", + "events.destination.qos": "QoS(サービス品質)", + "events.destination.qos0": "1回送信", + "events.destination.qos1": "最低1回", + "events.destination.qos2": "正確に1回", + "events.destination.authentication": "認証", + "events.destination.passwordPreserved": "保存されている書き込み専用パスワードを保持するには空のままにしてください。", + "events.destination.passwordOptional": "ブローカーが匿名クライアントを許可する場合は任意です。", + "events.destination.clearPassword": "保存されたパスワードをクリア", + "events.destination.transportSecurity": "通信セキュリティ", + "events.destination.tlsMode": "TLSモード", + "events.destination.tlsSystem": "システム信頼ストア", + "events.destination.tlsCustomCa": "カスタム認証局", + "events.destination.tlsMutual": "相互TLS", + "events.destination.tlsDisabled": "無効(平文)", + "events.destination.tlsHelp.system": "ブローカー証明書をオペレーティングシステムの信頼ストアで検証します。", + "events.destination.tlsHelp.custom_ca": "明示的なPEM形式の証明書局(CA)ファイルでブローカーを検証します。", + "events.destination.tlsHelp.mutual": "明示的なCAでブローカーを検証し、クライアント証明書と鍵を提示します。", + "events.destination.tlsHelp.disabled": "トランスポート暗号化およびブローカーの身元検証は行われません。", + "events.destination.caFile": "CAファイル", + "events.destination.certFile": "クライアント証明書ファイル", + "events.destination.keyFile": "クライアント鍵ファイル", + "events.destination.absolutePathHelp": "LightNVRサービスが読み取り可能な絶対パスを指定してください。", + "events.destination.plaintextWarning": "平文MQTTではイベントメタデータや認証情報が漏洩する可能性があります。信頼できる隔離ネットワークでのみ使用してください。", + "events.destination.security": "セキュリティ", + "events.destination.tls.system": "システム信頼", + "events.destination.tls.custom_ca": "カスタムCA", + "events.destination.tls.mutual": "相互TLS", + "events.destination.tls.disabled": "平文", + "events.destination.routes": "ルート", + "events.destination.presence": "プレゼンストピック", + "events.destination.deleteInUse": "この宛先を削除する前に、ルートを削除またはリダイレクトしてください。", + "events.destination.created": "MQTT宛先を作成しました", + "events.destination.updated": "MQTT宛先を更新しました", + "events.destination.deleted": "MQTT宛先を削除しました", + "events.destination.pausedMessage": "MQTT宛先を一時停止しました。キュー内のイベントは有効期限まで保持されます。", + "events.destination.enabledMessage": "MQTT宛先を有効にしました", + "events.destination.deleteConfirm": "MQTT宛先「{name}」を削除しますか?", + "events.destination.validation.name": "宛先名を入力してください。", + "events.destination.validation.host": "ブローカーのホスト名またはIPアドレスを入力してください。", + "events.destination.validation.client_id": "ブローカーのクライアントIDを入力してください。", + "events.destination.validation.topic": "トピックにはイベントタイプとサブジェクトIDのトークンを含める必要があり、MQTTワイルドカードは使用できません。", + "events.destination.validation.status_topic": "オプションのプレゼンストピックにはインストールUUIDトークンを含め、サポートされているトークンのみを使用し、MQTTワイルドカードは使用できません。", + "events.destination.validation.port": "ポートは1~65535の整数で入力してください。", + "events.destination.validation.keepalive": "キープアライブは5~3600秒の整数で入力してください。", + "events.destination.validation.qos": "MQTT QoSは0、1、または2を選択してください。", + "events.destination.validation.username": "パスワードを設定する場合はユーザー名が必要です。", + "events.destination.validation.ca_file": "このTLSモードではCAファイルの絶対パスが必要です。", + "events.destination.validation.mutual_files": "相互TLSには、CA、クライアント証明書、クライアントキーの絶対パスが必要です。", + "fleet.eyebrow": "カメラ操作", + "fleet.title": "カメラ一覧", + "fleet.description": "大規模展開において、全カメラ情報をブラウザに読み込まずに、カメラの検索・評価・整理ができます。", + "fleet.summary": "全体状態サマリー", + "fleet.totalCameras": "該当カメラ", + "fleet.needsAttention": "劣化", + "fleet.searchLabel": "カメラを検索", + "fleet.searchPlaceholder": "名前、アドレス、場所、タグ、ベンダー、モデルで検索…", + "fleet.resultCount": "{count}台のカメラ", + "fleet.filters": "フィルター", + "fleet.clearFilters": "フィルターをクリア", + "fleet.filter.health": "状態", + "fleet.filter.enabled": "カメラ状態", + "fleet.filter.anyState": "すべての状態", + "fleet.filter.recording": "録画モード", + "fleet.filter.location": "場所のサブツリー", + "fleet.filter.allLocations": "すべての場所", + "fleet.filter.tags": "タグ(いずれかに一致)", + "fleet.filter.collection": "カメラコレクション", + "fleet.health.unknown": "不明", + "fleet.health.up": "オンライン", + "fleet.health.degraded": "劣化", + "fleet.health.down": "オフライン", + "fleet.health.disabled": "無効", + "fleet.recording.off": "オフ", + "fleet.recording.continuous": "常時", + "fleet.recording.detection": "検知", + "fleet.recordingActive": "録画中", + "fleet.recordingInactive": "録画していません", + "fleet.column.camera": "カメラ", + "fleet.column.health": "状態", + "fleet.column.location": "ロケーション", + "fleet.column.tags": "タグ", + "fleet.column.recording": "録画", + "fleet.viewLive": "ライブ", + "fleet.lastFrame": "最終フレーム", + "fleet.noAddress": "アドレスが利用できません", + "fleet.unassigned": "未割り当て", + "fleet.loading": "カメラフリートを読み込み中…", + "fleet.refreshing": "更新中…", + "fleet.loadError": "カメラフリートを読み込めませんでした", + "fleet.emptyTitle": "カメラが設定されていません", + "fleet.emptyDescription": "ストリームを追加してフリートワークスペースで利用可能にしてください。", + "fleet.emptyFilteredTitle": "このビューに一致するカメラはありません", + "fleet.emptyFilteredDescription": "検索条件を広げるか、フィルターを解除してください。", + "fleet.paginationSummary": "{total}件中 {first}–{last}件を表示", + "fleet.perPage": "ページあたり", + "fleet.pageOf": "{pages}ページ中 {page}ページ目", + "fleet.selectPage": "このページのすべてのカメラを選択", + "fleet.selectCamera": "{name}を選択", + "fleet.selectedCount": "{count}台のカメラを選択中", + "fleet.organizeSelected": "選択項目を整理", + "fleet.clearSelection": "選択を解除", + "fleet.organization.manage": "組織を管理", + "fleet.organization.title": "カメラの組織管理", + "fleet.organization.description": "カメラフリート用の再利用可能なロケーション階層と正規化されたタグ辞書を管理します。", + "fleet.organization.locations": "ロケーション", + "fleet.organization.tags": "タグ", + "fleet.organization.locationsDescription": "拠点、建物、フロア、運用エリアを階層構造でモデル化します。", + "fleet.organization.tagsDescription": "一貫性のない自由記述のラベルの代わりに、管理されたタグ辞書を使用します。", + "fleet.organization.addRoot": "最上位ロケーションを追加", + "fleet.organization.addLocation": "ロケーションを追加", + "fleet.organization.editLocation": "ロケーションを編集", + "fleet.organization.addChild": "子を追加", + "fleet.organization.type": "種類", + "fleet.organization.parent": "親ロケーション", + "fleet.organization.topLevel": "トップレベル", + "fleet.organization.sortOrder": "並び順", + "fleet.organization.contents": "内容", + "fleet.organization.cameras": "カメラ", + "fleet.organization.system": "システム", + "fleet.organization.contentCounts": "{cameras}台のカメラ · {children}個の子", + "fleet.organization.locationNotEmpty": "先にカメラを移動し、子ロケーションを削除してください", + "fleet.organization.noLocations": "ロケーションが設定されていません。", + "fleet.organization.locationCreated": "ロケーションを作成しました", + "fleet.organization.locationUpdated": "ロケーションを更新しました", + "fleet.organization.locationDeleted": "ロケーションを削除しました", + "fleet.organization.deleteLocationConfirm": "ロケーション「{name}」を削除しますか?", + "fleet.organization.addTag": "タグを追加", + "fleet.organization.editTag": "タグを編集", + "fleet.organization.tagLabel": "タグ", + "fleet.organization.color": "色 (#RRGGBB)", + "fleet.organization.tagDescription": "説明", + "fleet.organization.noTags": "正規化されたタグが設定されていません。", + "fleet.organization.tagCreated": "タグを作成しました", + "fleet.organization.tagUpdated": "タグを更新しました", + "fleet.organization.tagDeleted": "タグを削除しました", + "fleet.organization.deleteTagConfirm": "「{name}」を削除しますか?現在{count}台のカメラに割り当てられています。", + "fleet.organization.merge": "統合", + "fleet.organization.mergeTagNamed": "「{name}」を統合", + "fleet.organization.mergeInto": "統合先", + "fleet.organization.chooseTag": "保持するタグを選択", + "fleet.organization.mergeWarning": "すべてのカメラの割り当ては保持するタグに移動し、元のタグは削除されます。", + "fleet.organization.tagsMerged": "タグを統合しました", + "fleet.organization.saveError": "保存できませんでした: {message}", + "fleet.organization.deleteError": "削除できませんでした: {message}", + "fleet.locationType.site": "サイト", + "fleet.locationType.building": "建物", + "fleet.locationType.floor": "フロア", + "fleet.locationType.area": "エリア", + "fleet.locationType.zone": "ゾーン", + "fleet.locationType.system": "システム", + "fleet.bulk.title": "選択したカメラを整理", + "fleet.bulk.description": "並行処理を制限し、{count}台のカメラに位置とタグの変更を適用します。", + "fleet.bulk.location": "位置の割り当て", + "fleet.bulk.locationHelp": "選択したすべてのカメラを選択した位置に移動します。", + "fleet.bulk.keepLocations": "現在の位置を維持", + "fleet.bulk.tags": "タグの割り当て", + "fleet.bulk.tagsHelp": "他の割り当てに影響を与えずにタグを追加・削除、またはタグセット全体を明示的に置き換えます。", + "fleet.bulk.tagOperation.none": "維持", + "fleet.bulk.tagOperation.add": "追加", + "fleet.bulk.tagOperation.remove": "削除", + "fleet.bulk.tagOperation.replace": "すべて置き換え", + "fleet.bulk.replaceWarning": "すべて置き換えでは、選択を適用する前に現在のすべてのタグを削除します。選択が空の場合、すべてのタグがクリアされます。", + "fleet.bulk.apply": "変更を適用", + "fleet.bulk.working": "変更を適用中…", + "fleet.bulk.success": "{count}台のカメラを更新しました", + "fleet.bulk.partial": "{succeeded}台のカメラを更新しました。{failed}台が失敗しました", + "fleet.bulk.error": "カメラを整理できませんでした: {message}", + "fleet.bulk.failures": "更新できなかったカメラ", + "fleet.queues.degraded": "ストリーム劣化", + "fleet.queues.offline": "オフラインのカメラ", + "fleet.queues.oldest": "最古: {time}", + "fleet.queues.noneActive": "アクティブな条件はありません", + "fleet.views.title": "保存済みビュー", + "fleet.views.choose": "保存済みビューを選択", + "fleet.views.none": "保存済みビューはまだありません", + "fleet.views.shared": "共有", + "fleet.views.saveCurrent": "現在のビューを保存", + "fleet.views.name": "ビュー名", + "fleet.views.share": "すべてのオペレーターと共有", + "fleet.views.saved": "フリートビューを保存しました", + "fleet.views.saveError": "ビューを保存できませんでした: {message}", + "fleet.views.deleted": "フリートビューを削除しました", + "fleet.views.deleteConfirm": "保存済みのビュー「{name}」を削除しますか?", + "fleet.views.deleteError": "ビューを削除できませんでした: {message}", + "fleet.views.unsupported": "この保存済みセレクターは現在のフィルターコントロールでは表示できません。", + "collections.manage": "コレクション", + "collections.all": "すべてのコレクション", + "collections.filter": "コレクション", + "collections.loadMembersError": "コレクションのカメラを読み込めませんでした: {message}", + "collections.title": "カメラコレクション", + "collections.subtitle": "運用、保存済みビュー、後続ワークフローで再利用可能なカメラグループを作成します。", + "collections.listDescription": "静的コレクションは明示的なメンバーシップを保持し、スマートコレクションはフリートルールを継続的に評価します。", + "collections.create": "コレクションを作成", + "collections.edit": "コレクションを編集", + "collections.editorDescription": "コレクション定義には、安定したカメラ、場所、タグのUUIDを使用します。", + "collections.backToList": "コレクションに戻る", + "collections.type": "コレクションタイプ", + "collections.type.static": "静的", + "collections.type.smart": "スマート", + "collections.description": "説明", + "collections.shared": "共有コレクション", + "collections.sharedHelp": "他の権限付きユーザーがこのコレクションを閲覧できるようにします。カメラのアクセスルールは引き続き適用されます。", + "collections.typeChangeWarning": "コレクションタイプを変更するとメンバーシップモデルが置き換えられます。以前のタイプの静的メンバーまたはスマートルールは適用されなくなります。", + "collections.selectorError": "セレクターが無効です: {message}", + "collections.created": "コレクションを作成しました", + "collections.updated": "コレクションを更新しました", + "collections.saveError": "コレクションを保存できませんでした: {message}", + "collections.loadError": "コレクションを読み込めませんでした: {message}", + "collections.cameras": "カメラ", + "collections.visibility.shared": "共有", + "collections.visibility.private": "プライベート", + "collections.selectorRedacted": "プライベートルール", + "collections.emptyTitle": "コレクションはまだありません", + "collections.emptyAdmin": "カメラの選択を再利用するために、静的グループまたはスマートルールベースのビューを作成します。", + "collections.emptyViewer": "カメラスコープに利用可能な共有コレクションはありません。", + "collections.deleteConfirm": "コレクション「{name}」を削除しますか?", + "collections.deleted": "コレクションを削除しました", + "collections.deleteError": "コレクションを削除できませんでした: {message}", + "collections.preview.title": "ルールプレビュー", + "collections.preview.matches": "{count}台のカメラが一致", + "collections.preview.action": "プレビュー", + "collections.preview.hide": "プレビューを非表示", + "collections.preview.loading": "評価中…", + "collections.preview.empty": "現在一致するカメラはありません。", + "collections.preview.sample": "{total}件の一致のうち{count}台のカメラを表示しています。", + "collections.preview.error": "コレクションをプレビューできませんでした: {message}", + "collections.members.title": "静的メンバー", + "collections.members.selected": "全ページで{count}台のカメラを選択中", + "collections.members.search": "カメラを検索…", + "collections.members.selectPage": "このページを選択", + "collections.members.empty": "この検索に一致するカメラはありません。", + "collections.builder.title": "スマートルール", + "collections.builder.description": "ルールはカメラの構成、設定、機能、状態に基づいて評価されます。", + "collections.builder.match": "一致条件", + "collections.builder.allRules": "すべてのルール", + "collections.builder.anyRule": "いずれかのルール", + "collections.builder.addRule": "ルールを追加", + "collections.builder.removeRule": "ルールを削除", + "collections.builder.matchesAll": "ルールが設定されていない場合、このコレクションはユーザーの権限範囲内のすべてのカメラに一致します。", + "collections.builder.incompleteRule": "保存前にすべてのルールを完了または削除してください。", + "collections.builder.chooseLocation": "場所のサブツリーを選択", + "collections.builder.vendorPlaceholder": "ベンダー名(カンマ区切り)", + "collections.builder.modelPlaceholder": "モデル名(カンマ区切り)", + "collections.builder.advancedMode": "高度なJSON", + "collections.builder.visualMode": "ビジュアルビルダー", + "collections.builder.cannotVisualize": "このセレクターには、ビジュアルビルダーで安全に表現できないネストまたは高度なロジックが含まれています。", + "collections.rule.location_subtree": "場所が以下に含まれる", + "collections.rule.camera_uuid": "特定のカメラ", + "collections.rule.tag_any": "いずれかのタグを持つ", + "collections.rule.tag_all": "すべてのタグを持つ", + "collections.rule.tag_none": "いずれのタグも持たない", + "collections.rule.health": "状態が", + "collections.rule.enabled": "カメラが", + "collections.rule.recording_mode": "録画モードが", + "collections.rule.capability_any": "いずれかの機能を持つ", + "collections.rule.capability_all": "すべての機能を持つ", + "collections.rule.vendor": "ベンダーが", + "collections.rule.model": "モデルが", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "オーディオバックチャネル", + "streamHealth.observedFps": "観測FPS", + "streamHealth.expectedFps": "期待値", + "streamHealth.fpsHelp": "LightNVRが観測した値です。期待値はカメラのストリームメタデータから取得されます。", + "login.passwordChanged": "パスワードが正常に変更されました。新しいパスワードでサインインしてください。", + "passwordChangeRequired.title": "デフォルトパスワードを変更", + "passwordChangeRequired.description": "このインストールではまだデフォルトの管理者パスワードが使用されています。LightNVRを続行する前に変更してください。MFAが有効な場合、次回のサインイン時に確認されます。", + "passwordChangeRequired.currentPassword": "現在のパスワード", + "passwordChangeRequired.newPassword": "新しいパスワード", + "passwordChangeRequired.confirmPassword": "新しいパスワードの確認", + "passwordChangeRequired.passwordHelp": "8文字以上で入力してください。パスワードにadminは使用できません。", + "passwordChangeRequired.submit": "パスワードを変更", + "passwordChangeRequired.saving": "パスワードを変更中...", + "passwordChangeRequired.error.currentRequired": "現在のパスワードを入力してください。", + "passwordChangeRequired.error.tooShort": "新しいパスワードは8文字以上である必要があります。", + "passwordChangeRequired.error.defaultPassword": "新しいパスワードに「admin」は使用できません。", + "passwordChangeRequired.error.mismatch": "新しいパスワードが一致しません。", + "passwordChangeRequired.error.generic": "パスワードを変更できませんでした。もう一度お試しください。", + "settings.tab.health": "ヘルス", + "settings.tab.workspaces": "ワークスペース", + "settings.health.title": "ホストとハードウェアのヘルス", + "settings.health.description": "デバイスパスやシークレットを公開せずに、OSおよびハードウェアの監視を設定します。", + "settings.health.enabled": "ヘルス監視を有効にする", + "settings.health.enabledHelp": "対応するホスト、サービス、ストレージ、ネットワーク、ハードウェアのシグナルを収集します。", + "settings.health.profile": "ポリシープロファイル", + "settings.health.profileHelp": "「バランス」が通常のデフォルトです。「保守的」はアラート前により強い根拠を必要とします。", + "settings.health.profile.balanced": "バランス", + "settings.health.profile.conservative": "保守的", + "settings.health.hardwareProvider": "ハードウェアプロバイダー", + "settings.health.provider.auto": "自動(カーネルプロバイダー)", + "settings.health.provider.smartctl": "smartctl(明示的)", + "settings.health.providerHelp.auto": "制限付きのsysfs、NVMe、カーネルプロバイダーのみを使用します。smartctlは推論されません。", + "settings.health.providerHelp.smartctl": "検出されたデバイスに対して、オプションの制限付きsmartctl JSONプロバイダーを明示的に有効にします。", + "settings.health.providerHelp.disabled": "オプションのハードウェアプロバイダーを無効にし、ポータブルなヘルス監視は利用可能なままにします。", + "settings.health.writeProbe": "ストレージ書き込みプローブを有効にする", + "settings.health.writeProbeHelp": "設定された録画ターゲットの制限付きプローブを定期的に実行します。", + "settings.health.cadences": "サンプリング間隔", + "settings.health.cadencesHelp": "間隔は高速からデバイスサンプリングまで順序を保ち、サーバーの制限内に収める必要があります。", + "settings.health.fastInterval": "高速間隔", + "settings.health.normalInterval": "通常間隔", + "settings.health.slowInterval": "低速間隔", + "settings.health.deviceInterval": "デバイス間隔", + "settings.health.presenceInterval": "存在確認間隔", + "settings.health.retention": "インシデント保持期間", + "settings.health.conditions": "条件オーバーライド", + "settings.health.conditionsHelp": "有効ポリシーレジストリが返す条件コードと単位のみを上書きできます。", + "settings.health.conditionOverride": "条件オーバーライド", + "settings.health.overrideMode": "オーバーライドモード", + "settings.health.overrideModeHelp": "選択中のプロファイルを継承、別の制限付きプロファイルを選択、条件を無効化、または検証済みしきい値を設定します。", + "settings.health.profileDefault": "選択中のプロファイルを使用", + "settings.health.custom": "カスタムしきい値", + "settings.health.warning": "警告しきい値", + "settings.health.critical": "重大しきい値", + "settings.health.recovery": "回復しきい値", + "settings.health.warning_for_seconds": "警告滞留秒数", + "settings.health.critical_for_seconds": "重大滞留秒数", + "settings.health.recovery_for_seconds": "回復滞留秒数", + "settings.health.clearOverrides": "オーバーライドをクリア", + "settings.health.registryUnavailable": "サーバーから条件レジストリが返されませんでした。オーバーライドを編集する前に再読み込みしてください。", + "settings.health.resetDefaults": "ヘルス設定をデフォルトにリセット", + "settings.health.reloadGuidance": "保存はアトミックです。保存成功後に再読み込みして有効ポリシーを確認してください。サーバーが明示的に要求した場合のみ再起動してください。", + "settings.health.validation.profile": "サポートされているヘルスプロファイルを選択してください。", + "settings.health.validation.provider": "サポートされているハードウェアプロバイダーを選択してください。", + "settings.health.validation.healthFastIntervalSeconds": "高速間隔は5〜60秒の整数で入力してください。", + "settings.health.validation.healthNormalIntervalSeconds": "通常間隔は15〜600秒の整数で入力してください。", + "settings.health.validation.healthSlowIntervalSeconds": "低速間隔は60〜3600秒の整数で入力してください。", + "settings.health.validation.healthDeviceIntervalSeconds": "デバイス間隔は300〜86400秒の整数で入力してください。", + "settings.health.validation.healthPresenceIntervalSeconds": "存在検知間隔は15〜3600秒の整数で入力してください。", + "settings.health.validation.healthIncidentRetentionDays": "インシデント保持期間は7〜3650日の整数で入力してください。", + "settings.health.validation.ordered": "サンプリング間隔は高速、通常、低速、デバイスの順にしてください。", + "settings.health.validation.overrides": "条件オーバーライドにはサーバーレジストリの一意なコードとサポートされているプロファイルを使用してください。", + "settings.health.validation.thresholds": "カスタムしきい値は条件の単位範囲内の有限値である必要があります。", + "settings.health.validation.thresholdOrder": "警告、重大、回復の各しきい値は条件のアラート方向とヒステリシスを維持する必要があります。", + "settings.health.validation.dwell": "滞留時間は7日以内の整数秒である必要があります。警告と回復の滞留時間はゼロにできません。", + "workspaces.title": "オペレーターワークスペース", + "workspaces.description": "ナビゲーションとページUIに表示するワークスペースを選択してください。", + "workspaces.saved": "ワークスペースの設定を保存しました", + "workspaces.saveError": "ワークスペースの設定を保存できませんでした: {message}", + "workspaces.loadError": "ワークスペースの設定を読み込めませんでした。", + "workspaces.showWorkspace": "{name}を表示", + "workspaces.authorizationNote": "これは表示のみを制御します。直接URLおよびAPIアクセスは引き続き認可ポリシーに従います。", + "workspaces.liveNavigator": "拡張ライブナビゲーター", + "workspaces.liveNavigatorDescription": "ロケーションツリー、可用性フィルター、保存済みレイアウト、最近のイベント。", + "workspaces.investigation": "調査", + "workspaces.investigationDescription": "録画データの検索、相関分析、保護、エクスポート。", + "settings.reduceMotion": "モーションを軽減", + "settings.reduceMotionHelp": "不要なアニメーションとトランジションを無効にします。自動はOSの設定に従います。", + "settings.reduceMotionPreference": "モーション軽減の設定", + "settings.reduceMotionAuto": "自動", + "settings.reduceMotionOn": "オン", + "settings.reduceMotionOff": "オフ", + "settings.audioCompliance": "音声コンプライアンス", + "settings.disableAudioGlobally": "このインスタンス全体で音声を無効にする", + "settings.audioDisabled": "音声はグローバルで無効です", + "settings.audioComplianceHelp": "このインスタンス全体でライブ聴取、双方向通話、新規録画の音声を防止します。保存するとアクティブなgo2rtcメディアセッションが再起動されます。既存の録画は変更されません。", + "tokens.manage": "APIアクセスの管理", + "tokens.title": "APIアクセス — {username}", + "tokens.description": "インテグレーション用にスコープを絞った認証情報を作成し、個別に失効させることができます。", + "tokens.recommendedTitle": "スコープ付きトークンを推奨します", + "tokens.recommendedDescription": "すべてのトークンには有効期限があり、明示的なアクションとカメラスコープが設定され、ユーザーの現在のアクセスポリシーを超えることはできません。", + "tokens.coverageNotice": "利用可能な権限はこのサーバーが適用するものを反映しています。トークンはユーザーが既に持つ権限のみを使用できます。", + "tokens.createTitle": "スコープ付きトークンを作成", + "tokens.createDescription": "インテグレーションごとに1つのトークンを使用すると、他のものに影響を与えずに識別、ローテーション、失効ができます。", + "tokens.name": "インテグレーション名", + "tokens.namePlaceholder": "例: 北ガレージPTZブリッジ", + "tokens.expiry": "有効期限", + "tokens.expiryDays": "{days}日", + "tokens.actions": "許可するアクション", + "tokens.actionsHelp": "この連携に必要なものだけを選択してください。破壊的なアクションには専用のトークンを使用してください。", + "tokens.destructive": "破壊的", + "tokens.noEnforcedActions": "このサーバーバージョンでは、トークンで有効化できるアクションはありません。", + "tokens.scope.label": "カメラスコープ", + "tokens.scope.all": "全カメラ", + "tokens.scope.collection": "共有コレクション", + "tokens.scope.selector": "カスタムセレクター", + "tokens.scope.chooseCollection": "共有カメラコレクション", + "tokens.scope.allValue": "全カメラ", + "tokens.scope.collectionValue": "コレクション: {name}", + "tokens.scope.selectorValue": "カスタム動的セレクター", + "tokens.create": "トークンを作成", + "tokens.creating": "トークンを作成中…", + "tokens.createdSuccess": "スコープ付きAPIトークンを作成しました", + "tokens.createError": "APIトークンを作成できませんでした: {message}", + "tokens.invalidResponse": "サーバーから不完全な認証情報レスポンスが返されました。", + "tokens.existingTitle": "既存のトークン", + "tokens.existingDescription": "作成後はプレフィックスとメタデータのみが利用可能です。", + "tokens.emptyTitle": "アクティブなトークンはありません", + "tokens.emptyDescription": "APIアクセスが必要な最初の連携用にスコープ付きトークンを作成してください。", + "tokens.showInactive": "非アクティブ {count}件を表示", + "tokens.status.active": "アクティブ", + "tokens.status.expired": "期限切れ", + "tokens.status.revoked": "失効済み", + "tokens.expires": "有効期限", + "tokens.expiresValue": "有効期限: {date}", + "tokens.created": "作成日", + "tokens.lastUsed": "最終使用日", + "tokens.revoke": "失効させる", + "tokens.revoking": "失効中…", + "tokens.revokeConfirm": "「{description}」を失効させますか?このトークンを使用しているリクエストは直ちに停止します。", + "tokens.revokedSuccess": "APIトークンを失効させました", + "tokens.revokeError": "APIトークンを失効できませんでした: {message}", + "tokens.validation.missing_description": "このトークンを使用するインテグレーションの名前を入力してください。", + "tokens.validation.description_too_long": "インテグレーション名は128文字以内で入力してください。", + "tokens.validation.invalid_expiry": "トークンの有効期間は1〜365日で選択してください。", + "tokens.validation.missing_actions": "許可するアクションを1つ以上選択してください。", + "tokens.validation.invalid_action": "選択したアクションの一部は、このサーバーでトークン対応されていません。", + "tokens.validation.invalid_scope": "有効なカメラスコープを選択してください。", + "tokens.validation.requires_all_scope": "カメラ以外の権限には「全カメラ」スコープが必要です。そのスコープを選択するか、該当する権限を削除してください。", + "tokens.validation.missing_collection": "利用可能な共有コレクションを選択してください。", + "tokens.validation.invalid_selector": "カスタムカメラセレクターを完了または修正してください。", + "tokens.secret.oneTime": "一度のみ表示", + "tokens.secret.scopedTitle": "このスコープ付きトークンを今すぐ保存してください", + "tokens.secret.legacyTitle": "このレガシーAPIキーを今すぐ保存してください", + "tokens.secret.scopedDescription": "lightNVRにはこのトークンのハッシュのみが保存されます。紛失した場合は失効させて再作成してください。", + "tokens.secret.legacyDescription": "この互換性キーはここでのみ一度表示されます。別のキーを生成すると無効になります。", + "tokens.secret.value": "API認証情報", + "tokens.secret.copied": "コピーしました", + "tokens.secret.copySuccess": "API認証情報をコピーしました", + "tokens.secret.copyError": "自動的にコピーできませんでした。認証情報を選択して手動でコピーしてください。", + "tokens.secret.savedConfirm": "この認証情報を安全に保存しました", + "tokens.secret.savedHelp": "確認するとこのダイアログが閉じます。完全な値は再度表示できません。", + "tokens.legacy.title": "レガシー互換性キー", + "tokens.legacy.description": "レガシーキーはこのユーザーのすべての権限を持ち、有効期限がなく、カメラやアクションによるスコープ制限ができません。", + "tokens.legacy.warning": "エンドポイントがスコープ付きトークン強制に移行していない既存のインテグレーションに対してのみ生成してください。生成すると直ちに以前のレガシーキーは無効になります。", + "tokens.legacy.generate": "レガシーキーを生成", + "tokens.legacy.confirm": "新しいレガシーキーを生成しますか?このユーザーの現在のレガシーキーは直ちに無効になります。", + "tokens.legacy.createdSuccess": "レガシーAPIキーを生成しました", + "tokens.legacy.createError": "レガシーAPIキーを生成できませんでした: {message}", + "audit.manage": "監査履歴", + "audit.title": "セキュリティとアクセス監査", + "audit.description": "認証情報を公開せずに、ログイン結果、アクセス判断、機微なポリシー変更を追跡します。", + "audit.retention": "保持期間", + "audit.retentionDescription": "イベントは現在{days}日間保持されています。この値を下げると、古い履歴がすぐに削除されます。", + "audit.retentionDays": "日数", + "audit.retentionInvalid": "保持期間は1日から3650日の範囲で選択してください。", + "audit.retentionSaved": "監査保持期間を保存しました。期限切れのイベント{count}件を削除しました", + "audit.retentionError": "監査保持期間を保存できませんでした: {message}", + "audit.filters": "フィルター", + "audit.clearFilters": "フィルターをクリア", + "audit.applyFilters": "フィルターを適用", + "audit.actor": "実行者", + "audit.unauthenticated": "未認証", + "audit.outcome": "結果", + "audit.action": "完全一致のアクション", + "audit.filterToAction": "このアクションで絞り込む", + "audit.since": "開始", + "audit.until": "終了", + "audit.invalidDateRange": "開始日は終了日より前にしてください。", + "audit.source": "ソースアドレス", + "audit.target": "対象", + "audit.targetUuid": "対象UUID", + "audit.noTarget": "システム全体", + "audit.requestId": "リクエストID", + "audit.apiToken": "スコープ付きトークンID", + "audit.showDetails": "詳細を表示", + "audit.hideDetails": "詳細を非表示", + "audit.pageSize": "表示件数", + "audit.resultRange": "{total}件中{start}–{end}件を表示", + "audit.empty": "一致する監査イベントがありません", + "audit.emptyDescription": "一部のフィルターをクリアするか、新しいセキュリティアクティビティをお待ちください。", + "audit.exportPage": "このページをエクスポート", + "audit.exporting": "エクスポート中…", + "audit.exported": "監査ページをエクスポートしました", + "audit.exportError": "監査イベントをエクスポートできませんでした: {message}", + "audit.pagination": "監査履歴ページ", + "audit.page": "{page} ページ", + "audit.modesTitle": "許可された判断", + "audit.modesDescription": "読み取り専用のアクセスが許可された場合の記録方法を選択します。変更を伴うリクエスト、拒否、エラー、サインインは常に記録されます。「要約」では、ユーザー・カメラ・クライアントごとに {minutes} 分間隔で1件のエントリに集約し、回数を記録します。", + "audit.mode.record": "個別に記録", + "audit.mode.summarize": "要約", + "audit.mode.off": "オフ", + "audit.modeOffWarning": "このアクションの許可アクセスは監査履歴に表示されなくなります。", + "audit.modesSaved": "監査判断モードを保存しました", + "audit.modesError": "監査判断モードを保存できませんでした: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "イベントタイプ", + "audit.eventTypeSummary": "要約", + "audit.eventTypeDecision": "個別の判断", + "access.cameraSearch": "カメラを検索", + "access.cameraSearchPlaceholder": "2文字以上入力して検索…", + "access.cameraSearchHint": "カメラ名、UUID、アドレス、場所、タグ、ベンダー、モデルで検索。", + "access.cameraSelected": "選択済み", + "access.cameraAdd": "追加", + "access.cameraLimit": "セレクターには最大64台のカメラを明示的に指定できます。より広い範囲には場所またはタグのルールを使用してください。", + "access.roles.manage": "ロールの管理", + "access.roles.title": "認可ロール", + "access.roles.description": "アクションを再利用可能なロールにまとめ、カメラスコープに対してロールを付与します。", + "access.roles.create": "ロールを作成", + "access.roles.newRole": "新規ロール", + "access.roles.copyName": "{name} のコピー", + "access.roles.clone": "複製", + "access.roles.builtin": "組み込み", + "access.roles.builtinHelp": "組み込みロールはアップグレードを安全に行うための固定テンプレートです。複製してカスタマイズしてください。", + "access.roles.actionCount": "{count} 件のアクション", + "access.roles.destructive": "機密アクション", + "access.roles.notEnforced": "どのエンドポイントでもまだ適用されていません", + "access.roles.destructiveWarning": "このロールは設定や証拠の変更が可能です。その権限が必要なスコープでのみ付与してください。", + "access.roles.created": "ロールを作成しました", + "access.roles.updated": "ロールを更新しました", + "access.roles.deleted": "ロールを削除しました", + "access.roles.saveError": "ロールを保存できませんでした: {message}", + "access.roles.deleteError": "ロールを削除できませんでした: {message}", + "access.roles.deleteConfirm": "ロール「{name}」を削除しますか?権限付与で参照されているロールは削除できません。", + "access.policy.manage": "アクセス管理", + "access.policy.column": "アクセス", + "access.policy.scopedShort": "スコープ付き", + "access.policy.title": "アクセスポリシー — {username}", + "access.policy.description": "デフォルト拒否のロール権限付与を管理し、カメラスコープをプレビューします。", + "access.policy.tab.grants": "権限付与", + "access.policy.tab.test": "アクセステスト", + "access.policy.scopedWarning": "一致する権限付与とカメラスコープで許可された操作のみ実行できます。", + "access.policy.grants": "ロール権限付与", + "access.policy.grantsDescription": "権限付与では、1つのロールを全カメラ、共有コレクション、またはカスタムカメラセレクターと組み合わせて設定します。", + "access.policy.addGrant": "権限付与を追加", + "access.policy.noGrants": "権限付与が設定されていません", + "access.policy.noGrantsHelp": "このユーザーにアクセス権限を持たせない場合を除き、スコープ付きポリシーを有効化する前に少なくとも1つの権限付与を追加してください。", + "access.policy.role": "ロール", + "access.policy.chooseRole": "ロールを選択", + "access.policy.scope": "カメラスコープ", + "access.policy.allCameras": "全カメラ", + "access.policy.collectionScope": "共有コレクション", + "access.policy.collection": "カメラコレクション", + "access.policy.chooseCollection": "共有コレクションを選択", + "access.policy.collectionHelp": "カメラの追加、削除、またはルールの一致に応じて、アクセスがコレクションに追従します。", + "access.policy.dynamicScope": "動的セレクター", + "access.policy.activateConfirm": "{username} のデフォルト拒否スコープ付きポリシーを有効化しますか?一致する権限付与がない操作は拒否されます。", + "access.policy.emptyConfirm": "権限付与なしで {username} のスコープ付きポリシーを有効化しますか?これによりポリシー管理下のすべてのアクセスが意図的に削除されます。", + "access.policy.saved": "アクセスポリシーを保存しました", + "access.policy.saveError": "アクセスポリシーを保存できませんでした: {message}", + "access.policy.version": "ポリシーバージョン {version}", + "access.policy.unsaved": "未保存の変更", + "access.policy.validation.invalid_mode": "有効な評価モードを選択してください。", + "access.policy.validation.missing_role": "すべての権限付与は利用可能なロールを参照する必要があります。", + "access.policy.validation.invalid_scope": "すべての権限付与は、全カメラ、共有コレクション、またはセレクタースコープを使用する必要があります。", + "access.policy.validation.invalid_selector": "保存前にすべてのカメラセレクターを完了または修正してください。", + "access.policy.validation.missing_collection": "すべてのコレクション権限付与に利用可能な共有コレクションを選択してください。", + "access.policy.validation.duplicate_grant": "保存前に重複するロールとスコープの権限付与を削除してください。", + "access.test.title": "実効アクセスをテスト", + "access.test.description": "{username} として保存済みのアクションとカメラを実行せずに評価します。", + "access.test.saveFirst": "テスト前に権限付与の変更を保存または破棄してください。結果はここに表示されているポリシーを反映します。", + "access.test.action": "アクション", + "access.test.camera": "カメラ", + "access.test.run": "アクセスをテスト", + "access.test.running": "テスト中…", + "access.test.allowed": "許可", + "access.test.denied": "拒否", + "access.test.version": "バージョン {version}", + "access.test.source": "ソース: {source} · ロール: {role}", + "recordings.pullToRefresh": "引っ張って録画を更新", + "recordings.releaseToRefresh": "離して録画を更新", + "recordings.refreshing": "録画を更新中…", + "recordings.refreshed": "録画を更新しました", + "recordings.refreshFailed": "録画を更新できませんでした: {message}", + "recordings.download": "ダウンロード", + "recordings.tags": "タグ", + "recordings.selectRecording": "録画を選択", + "timeline.legend.recording": "録画", + "timeline.legend.detection": "検知イベント", + "timeline.detectionEvent": "検知イベント", + "streams.showCredentials": "認証情報表示", + "streams.hideCredentials": "認証情報を隠す", + "streams.streamSuccessfullyEnabled": "ストリームを有効化しました。", + "streams.errorEnablingStream": "ストリームの有効化に失敗しました: {message}", + "system.health.tab": "ヘルス", + "system.health.operatorView": "運用状況", + "system.health.title": "システムヘルス", + "system.health.loading": "システムヘルスを読み込み中…", + "system.health.loadError": "システムヘルスを読み込めませんでした。", + "system.health.refreshing": "更新中…", + "system.health.activeIncidentCount": "{count} 件のアクティブなインシデント", + "system.health.coverage": "カバレッジ", + "system.health.monitoringDisabled": "ヘルス監視が無効です", + "system.health.lastRecordedValue": "最終記録値", + "system.health.monitoringDisabledHelp": "現在のヘルス情報は収集されていません。設定 → ヘルスでヘルス監視を有効にし、保存後に再起動が求められた場合は再起動してください。インシデント履歴は過去のイベントを表示しており、現在のリソース使用状況ではありません。", + "system.health.monitoringRestartRequired": "保存された設定ではヘルス監視が有効ですが、実行中のサンプラーはまだ無効です。LightNVRを再起動して変更を適用してください。インシデント履歴は過去のイベントを表示しています。", + "system.health.containerCoverage": "ホストカバレッジが制限されています", + "system.health.hostHardwareUnavailable": "このインストールではコンテナおよびマウント済みリソースのヘルスは確認できますが、ホストのハードウェア情報にはアクセスできません。欠落したホスト値は「不明」であり、「正常」ではありません。", + "system.health.coverageUnknown": "完了したヘルススナップショットはまだありません。収集が完了するまで値は不明のままです。", + "system.health.coverageComplete": "このインストールで確認可能なすべてのヘルス情報が正常に収集されました。", + "system.health.coveragePartial": "カバレッジは部分的です。{count} 件の観測または収集チェックが利用不可、古い、または不完全です。", + "system.health.effectiveScope": "有効範囲", + "system.health.activeIncidents": "アクティブなインシデント", + "system.health.noActiveIncidents": "表示対象のカバレッジにアクティブなインシデントは報告されていません。", + "system.health.duration": "持続時間", + "system.health.currentValue": "現在値", + "system.health.thresholds": "しきい値と滞留時間", + "system.health.thresholdSummary": "警告 {warning}、重大 {critical}、回復 {recovery} {unit};警告滞留 {seconds}s", + "system.health.remediation": "推奨対応", + "system.health.facts": "ヘルス情報", + "system.health.group.resources": "リソース", + "system.health.group.storage": "ストレージ", + "system.health.group.hardware": "ハードウェア", + "system.health.group.network": "ネットワーク", + "system.health.group.clock": "時計", + "system.health.group.components": "コンポーネント", + "system.health.noFacts": "このグループに表示できる情報はありません。", + "system.health.observationState": "機能と鮮度", + "system.health.valueUnavailable": "1つ以上の値が不明です", + "system.health.componentStatus": "監視コンポーネント", + "system.health.collectors": "コレクター", + "system.health.collectorSummary": "{total} 登録済み · {attention} 要確認", + "system.health.collectorsNeedingAttention": "要確認のコレクター", + "system.health.collectionFailures": "{count} 件の障害またはタイムアウト", + "system.health.stale": "期限切れ", + "system.health.eventDelivery": "イベント配信", + "system.health.degraded": "劣化", + "system.health.circularDelivery": "これは唯一設定されたアラート経路のため、自身の障害を独立して報告できません。", + "system.health.incidentPersistence": "インシデント永続化", + "system.health.persistenceSummary": "{pending} 保留中 · {failures} 障害 · {retries} リトライ", + "system.health.recentSamples": "最近の収集アクティビティ", + "system.health.recentSamplesHelp": "サーバー側の生成サマリーを最大{count}件まで表示。これはカバレッジアクティビティであり、値のチャートではありません。", + "system.health.sampleSequence": "生成 {sequence}", + "system.health.sampleCoverage": "{observations} 件の観測 · {dropped} 件破棄", + "system.health.noSamples": "完了した収集世代がありません。", + "system.health.incidentHistory": "インシデント履歴", + "system.health.incidentHistoryHelp": "新しいインシデントから表示。履歴はページ単位で読み込まれます。", + "system.health.loadingHistory": "インシデント履歴を読み込み中…", + "system.health.historyError": "インシデント履歴を読み込めませんでした。", + "system.health.emptyHistory": "インシデントは記録されていません。", + "system.health.firstSeen": "初回検出", + "system.health.lastSeen": "最終検出", + "system.health.deliveryState": "配信状態", + "system.health.historyPagination": "インシデント履歴ページ", + "system.health.pageCount": "ページ上のインシデント {count}件", + "system.health.remediation.memory": "メモリ圧力を軽減し、プロセスとcgroupの制限を確認し、最近のOOM活動を確認してください。", + "system.health.remediation.cpu": "持続的なCPU消費プロセスを特定し、制限を変更する前にサービスのスループットを確認してください。", + "system.health.remediation.io": "ストレージの遅延とアクティブな書き込みを確認し、障害を伴うメンテナンスの前に録画を保護してください。", + "system.health.remediation.filesystem": "指定された論理ファイルシステム、空き容量またはinodeを確認し、書き込み可能であることを検証してください。", + "system.health.remediation.thermal": "冷却を改善し負荷を軽減してください。温度がシャットダウン制限に達する前にファンと通気口を点検してください。", + "system.health.remediation.network": "独立したネットワーク経路から、表示されているインターフェース、リンク、スイッチ、エラーカウンタを確認してください。", + "system.health.remediation.clock": "イベントのタイムスタンプに依存する前に、時刻同期を復元し、ホストのクロックソースを確認してください。", + "system.health.remediation.process": "LightNVRのリソース制限とログを確認し、負荷を軽減するか検証済みの制限を引き上げてください。", + "system.health.remediation.storage": "交換または修理の前に、重要な映像をバックアップし、マッピングされたストレージデバイスを点検してください。", + "system.health.remediation.hardware": "影響を受けるハードウェアとプラットフォームログを点検し、状態が継続する場合はメンテナンスを計画してください。", + "system.health.remediation.health": "不足しているヘルス情報を評価できるよう、コレクターのアクセスと権限を復元してください。", + "system.health.remediation.system": "前回の実行とホストログを確認し、プロセスの再起動とホストの再起動を区別してください。", + "system.health.remediation.event": "ローカルAPIまたはメトリクスビューを使用し、永続キューの圧力を解消し、独立したアラート先を復元してください。", + "system.health.remediation.default": "影響を受けるコンポーネントと最近のログを確認し、新しいヘルス生成で回復を検証してください。", + "system.capacityTarget": "容量目標", + "system.capacityTargetValue": "{pct}%以上の空きを維持", + "system.fillRate": "充填率", + "system.fillRateValue": "{value} / 日", + "system.projectedToTarget": "目標までの推定時間", + "system.projectedNow": "現在目標に到達/超過", + "system.projectedDays": "約{count}日", + "system.projectedHours": "約{count}時間", + "system.projectedUnknown": "—", + "common.description": "説明", + "common.remove": "削除", + "streams.selectStream": "{name}を選択", + "streams.search": "ストリームを検索", + "streams.searchPlaceholder": "カメラ、場所、タグを検索", + "streams.noStreamsMatchFilters": "現在のフィルターに一致するストリームはありません。", + "streamHealth.sourceConnected": "ソース接続済み", + "streamHealth.videoAdvancing": "映像進行中", + "streamHealth.recorderWriting": "レコーダー書き込み中", + "streamHealth.detectorOperating": "検出器稼働中", + "streamHealth.lastSegment": "最終完了セグメント", + "streams.disablingStreamsProgress": "ストリームを無効化中…", + "streams.onvifInvalidAddress": "ONVIFデバイスのIPアドレスが未設定または無効です。", + "streams.warningFallingBackToHttp": "HTTPS接続に失敗しました。HTTPで再試行しています。認証情報が平文で送信される可能性があります。", + "streamsConfig.playbackTransport": "再生トランスポート", + "streamsConfig.playbackTransportHelp": "このカメラのブラウザ再生方法と、選択した場合はそのフォールバック順序を選択してください。", + "streamsConfig.playbackTransportUnavailable": "サーバーで利用不可: {transports}。トランスポートをグローバルで有効にするか、別のプロファイルを選択してください。", + "streamsConfig.audioDisabledByPolicy": "インスタンスポリシーによりオーディオが無効です", + "streamsConfig.audioDisabledByPolicyHelp": "グローバル音声コンプライアンスポリシーが有効な間、録音、ライブ聴取、双方向通話は利用できません。", + "streamsConfig.audioVoiceEnhancement": "音声強調(録音)", + "streamsConfig.customApiModel": "カスタムAPI検出", + "streamsConfig.modelNotSupportedByBuild": "このビルドではサポートされていません", + "streamsConfig.tierCriticalMultiplier": "重要度: 最高 ×", + "streamsConfig.tierImportantMultiplier": "重要度: 高 ×", + "streamsConfig.tierEphemeralMultiplier": "重要度: 低 ×", + "streamsConfig.tierMultipliersHelp": "基本保持期間に対するティア別倍率。上位ティアの映像はより長く保持され、ディスク容量逼迫時に最後に削除されます。", + "streamsConfig.storagePriority": "ストレージ優先度(1-10)", + "streamsConfig.storagePriorityHelp": "容量回収時のこのストリーム映像の相対的な重要度。優先度が高いほど長く保持されます。", + "streamsConfig.restream": "リストリーム / 配信(RTMP)", + "streamsConfig.publishUrl": "配信URL(RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "go2rtc経由でYouTube Liveなどのサービスにこのカメラをリストリームします。ストリームキーを含む完全なRTMPインジェストURLを貼り付けてください(例: rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx)。複数のサービスに同時にリストリームする場合は、URLをカンマで区切ってください。YouTubeはH264映像とAAC音声が必要ですが、LightNVRは自動的にトランスコードするため(非H264カメラにはH264、非AAC音声にはAAC)、ほとんどのカメラはそのまま動作します。注意: YouTubeは音声トラックも必須のため、音声が一切ないカメラは拒否されます。空欄の場合は無効になります。", + "streams.lastSeen": "最終確認: {time}", + "streams.claimed": "クレーム済み", + "streams.duplicateSuspected": "重複の可能性", + "streams.duplicateSuspectedHelp": "安定したIDまたはエンドポイント情報が別の検出レコードと競合しています。", + "streams.onvifClaimWarning": "ストリームは追加されましたが、検出レコードをクレーム済みとしてマークできませんでした: {message}", + "common.online": "オンライン", + "common.offline": "オフライン", + "settings.storageTargets.title": "録画ストレージターゲット", + "settings.storageTargets.description": "ローカルディスクおよび管理者がマウントしたNFSまたはSMBファイルシステムを、個別に監視される録画先として登録します。", + "settings.storageTargets.foundationNotice": "キャプチャはファイルシステムターゲットを使用します。S3バケットやマウント済みのNFS/SANターゲットに検証済みアーカイブコピーを保存できます。ホットストレージの圧力下でも、論理保持期間が満了するまでアーカイブ済み録画は保持されます。", + "settings.storageTargets.add": "ストレージターゲットを追加", + "settings.storageTargets.edit": "ストレージターゲットを編集", + "settings.storageTargets.editorHelp": "有効なターゲットは既に存在し、書き込み・fsync・クリーンアップテストに合格する必要があります。利用不可の将来のマウントは無効として保存し、マウント後に有効にしてください。", + "settings.storageTargets.name": "ターゲット名", + "settings.storageTargets.root": "マウント済みルートパス", + "settings.storageTargets.rootLocked": "デフォルトまたは空でないターゲットは不変のルートを保持し、既存の映像が孤立しないようにします。", + "settings.storageTargets.class": "パフォーマンスクラス", + "settings.storageTargets.hot": "ホット — アクティブ録画", + "settings.storageTargets.warm": "ウォーム — マウント済みアーカイブ", + "settings.storageTargets.cold": "コールド — 低頻度アクセス", + "settings.storageTargets.reserveGb": "予約空き容量 (GB)", + "settings.storageTargets.lowWatermark": "低水位 (%使用)", + "settings.storageTargets.highWatermark": "高水位 (%使用)", + "settings.storageTargets.migrationBandwidth": "ライフサイクル帯域幅 (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0は無制限です。制限は移動またはコピージョブの作成時にスナップショットされます。", + "settings.storageTargets.archiveStart": "アーカイブウィンドウ開始", + "settings.storageTargets.archiveEnd": "アーカイブウィンドウ終了", + "settings.storageTargets.archiveWindowHelp": "ローカルタイム。開始と終了が同じ場合は終日ライフサイクルジョブが実行されます。夜間ウィンドウは日付をまたぐ場合があります。", + "settings.storageTargets.enabled": "有効(配置ポリシーがこのターゲットを選択する可能性があります)", + "settings.storageTargets.notRouted": "有効な配置ポリシーがこのターゲットにカメラをルーティングしていません。ポリシーがこのターゲットをプライマリ、プールメンバー、またはアーカイブターゲットとして指定するまで、新しい録画はデフォルトターゲットに保存されます。", + "settings.storageTargets.degradedNotice": "高水位を超えているか、予約領域内です。空き容量が解放されるまで配置ポリシーはこのターゲットをスキップします。", + "settings.storageTargets.probePassedIneligible": "書き込みテストは合格しましたが、ターゲットは{status}です:配置ポリシーは選択しません。", + "settings.storageTargets.mountRequired": "マウント済みファイルシステムを要求", + "settings.storageTargets.mountRequiredHelp": "このターゲットを現在の非ルートマウントポイントに固定します。NFS、SMB、バインド、またはPVCマウントが消失した場合、ホストディレクトリへの書き込みを避けて録画を一時停止します。", + "settings.storageTargets.mountGuard": "必須マウント", + "settings.storageTargets.mountPending": "ターゲット有効時に検出されます", + "settings.storageTargets.default": "デフォルト", + "settings.storageTargets.capacity": "容量", + "settings.storageTargets.available": "利用可能", + "settings.storageTargets.recordings": "インデックス済み録画", + "settings.storageTargets.replicas": "検証済みコピー {count} 件 · {bytes}", + "settings.storageTargets.reserve": "予約済み", + "settings.storageTargets.pressure.normal": "圧力正常", + "settings.storageTargets.pressure.high": "高水位", + "settings.storageTargets.pressure.reserve": "予約領域超過", + "settings.storageTargets.pressure.unavailable": "圧力情報取得不可", + "settings.storageTargets.cleanupActive": "ターゲットスコープのクリーンアップが有効です。他のターゲットに割り当てられた録画を削除せずに、{target} の空き容量を確保します。", + "settings.storageTargets.test": "テスト対象", + "settings.storageTargets.probing": "テスト中…", + "settings.storageTargets.probePassed": "ストレージターゲット書き込みテスト合格", + "settings.storageTargets.duplicateFilesystem": "このルートは別のターゲットと同じファイルシステムを共有しています。配置が有効な場合、容量を二重に計上しないでください。", + "settings.storageTargets.deleteLocked": "デフォルトおよび空でないターゲットは削除できません。", + "settings.storageTargets.deleteConfirm": "空のストレージターゲット「{name}」を削除しますか? ファイルは削除されません。", + "settings.storageTargets.created": "ストレージターゲットを作成しました", + "settings.storageTargets.updated": "ストレージターゲットを更新しました", + "settings.storageTargets.deleted": "ストレージターゲットを削除しました", + "settings.storageTargets.invalidThresholds": "水位、予約領域、ライフサイクル帯域幅、アーカイブウィンドウ時間を確認してください。", + "settings.storageTargets.loadError": "ストレージターゲットを読み込めませんでした", + "settings.storagePools.title": "ストレージプール", + "settings.storagePools.description": "自動スプールオーバーと別ターゲットレプリケーションのために、正常なターゲットをグループ化します。", + "settings.storagePools.add": "プールを追加", + "settings.storagePools.strategy": "割り当て戦略", + "settings.storagePools.mostFree": "空き容量最大", + "settings.storagePools.roundRobin": "ラウンドロビン", + "settings.storagePools.priority": "明示的優先度", + "settings.storagePools.members": "ターゲット(表示順が割り当て優先度)", + "settings.storagePools.enabled": "プール有効", + "settings.storagePools.active": "有効", + "settings.storagePools.inactive": "無効", + "settings.storagePools.strategyValue.most_free": "空き最大", + "settings.storagePools.strategyValue.round_robin": "ラウンドロビン", + "settings.storagePools.strategyValue.priority": "優先順", + "settings.storagePools.created": "ストレージプールを作成しました", + "settings.storagePools.updated": "ストレージプールを更新しました", + "settings.storagePools.deleted": "ストレージプールを削除しました", + "settings.storagePools.deleteConfirm": "ストレージプール「{name}」を削除しますか?", + "settings.storagePools.empty": "ストレージプールはまだありません。", + "settings.storageMigrations.title": "録画移行ジョブ", + "settings.storageMigrations.description": "永続的な移動と保持コピーは、各ターゲットのアーカイブ期間と帯域幅制限を遵守し、SHA-256を検証し、再起動後も安全に復旧します。", + "settings.storageMigrations.empty": "録画移行ジョブはまだありません。", + "settings.storageMigrations.loadError": "録画移行ジョブを読み込めませんでした", + "settings.storageMigrations.recording": "録画 #{id}", + "settings.storageMigrations.attempt": "試行 {current}/{max}", + "settings.storageMigrations.operation.move": "移動", + "settings.storageMigrations.operation.copy": "保持コピー", + "settings.storageMigrations.cancelled": "移行のキャンセルを受け付けました", + "settings.storageMigrations.cancelling": "キャンセル中…", + "settings.storageMigrations.retried": "再試行のために移行をキューに追加しました", + "settings.storageMigrations.state.queued": "キュー待ち", + "settings.storageMigrations.state.copying": "コピー中", + "settings.storageMigrations.state.verifying": "検証中", + "settings.storageMigrations.state.committing": "コミット中", + "settings.storageMigrations.state.cleanup_pending": "ソースをクリーンアップ中", + "settings.storageMigrations.state.retry_wait": "再試行待ち", + "settings.storageMigrations.state.completed": "完了", + "settings.storageMigrations.state.failed": "失敗", + "settings.storageMigrations.state.cancelled": "キャンセル済み", + "settings.storagePolicies.title": "カメラ配置ポリシー", + "settings.storagePolicies.description": "優先順位に従って、一致するカメラをプライマリ録画ターゲットにルーティングします。カメラは最初に一致した有効なポリシーを使用します。", + "settings.storagePolicies.add": "配置ポリシーを追加", + "settings.storagePolicies.edit": "配置ポリシーを編集", + "settings.storagePolicies.editorHelp": "ポリシーは新しいセグメントに対して再評価されます。変更は既存の録画には影響しません。", + "settings.storagePolicies.priority": "優先度(高い順)", + "settings.storagePolicies.priorityValue": "優先度 {priority}", + "settings.storagePolicies.primary": "プライマリターゲット", + "settings.storagePolicies.primaryPool": "プレースメントプール(任意)", + "settings.storagePolicies.exactTarget": "一次ターゲットを厳密に使用", + "settings.storagePolicies.fallback": "一次ターゲットが利用不可の場合", + "settings.storagePolicies.fallbackDefault": "デフォルトターゲットを使用", + "settings.storagePolicies.fallbackTarget": "名前付きフォールバックターゲットを使用", + "settings.storagePolicies.fallbackPause": "録画を一時停止", + "settings.storagePolicies.fallbackFail": "録画開始を失敗として扱う", + "settings.storagePolicies.namedFallback": "フォールバックターゲット", + "settings.storagePolicies.chooseTarget": "ターゲットを選択", + "settings.storagePolicies.choosePool": "プールを選択", + "settings.storagePolicies.minimumDays": "最小保持期間(日)", + "settings.storagePolicies.desiredDays": "希望保持期間(日)", + "settings.storagePolicies.maximumDays": "最大保持期間(日)", + "settings.storagePolicies.copyCount": "必要な検証済みコピー数", + "settings.storagePolicies.replicationPool": "レプリケーションプール", + "settings.storagePolicies.migrateAfter": "経過後に移動(日)", + "settings.storagePolicies.migrationTarget": "アーカイブターゲット", + "settings.storagePolicies.pressurePriority": "圧迫削除優先度(低い順)", + "settings.storagePolicies.disabledTarget": "無効", + "settings.storagePolicies.enabled": "ポリシー有効", + "settings.storagePolicies.selector": "一致するカメラ", + "settings.storagePolicies.preview": "プレビュー優先順位", + "settings.storagePolicies.previewing": "評価中…", + "settings.storagePolicies.previewRequired": "保存前に現在のドラフトをプレビューして、カメラの重複と有効な優先ポリシーを確認できます。", + "settings.storagePolicies.previewSummary": "{matched}台のカメラに一致。このドラフトは{effective}に有効です。", + "settings.storagePolicies.previewShadowed": "より優先度の高いポリシーが{count}台の一致カメラに適用されます。", + "settings.storagePolicies.previewWins": "{count}台のカメラで「{policy}」(優先度 {priority})に優先します。", + "settings.storagePolicies.previewLoses": "{count}台のカメラで「{policy}」(優先度 {priority})に劣後します。", + "settings.storagePolicies.previewNoMatches": "このセレクターは現在、どのカメラにも一致しません。", + "settings.storagePolicies.invalidPriority": "優先度は -1,000,000 から 1,000,000 の整数である必要があります。", + "settings.storagePolicies.invalidLifecycle": "保持順序、コピー数とレプリケーションプール、移行経過日数とターゲットを確認してください。", + "settings.storagePolicies.created": "プレースメントポリシーを作成しました", + "settings.storagePolicies.updated": "配置ポリシーを更新しました", + "settings.storagePolicies.deleted": "配置ポリシーを削除しました", + "settings.storagePolicies.deleteConfirm": "配置ポリシー「{name}」を削除しますか?既存の録画には影響しません。", + "settings.storagePolicies.active": "有効", + "settings.storagePolicies.inactive": "無効", + "settings.storagePolicies.routesTo": "主保存先: {target}", + "settings.storagePolicies.lifecycleSummary": "保持期間 最小/希望/最大: {minimum}/{desired}/{maximum}日 · 検証済みコピー {copies}個", + "settings.storagePolicies.fallsBackTo": "フォールバック先: {target}", + "settings.storagePolicies.mode.default": "フォールバック: 既定の保存先", + "settings.storagePolicies.mode.pause": "フォールバック: 録画を一時停止", + "settings.storagePolicies.mode.fail": "フォールバック: 録画開始を失敗させる", + "settings.storagePolicies.empty": "配置ポリシーがありません。カメラは既定の保存先を使用し続けます。ポリシーでカメラを割り当てるまで、他の保存先には何も書き込まれません。", + "settings.storagePolicies.archiveNoTrigger": "アーカイブ先が設定されていますが、移動のトリガーがありません。「経過日数で移動」、アーカイブ経過日数、またはアーカイブオプションを設定してください。設定しない場合、録画は移動されません。", + "settings.storageCompliance.title": "容量とポリシー準拠", + "settings.storageCompliance.description": "30日間の観測レートに基づき、保存先の圧迫状況と達成された保持期間を予測しています。アクティブなライフサイクル違反は解決されるまで表示されます。", + "settings.storageCompliance.loadError": "ストレージ準拠状況を読み込めませんでした", + "settings.storageCompliance.unknown": "不明", + "settings.storageCompliance.days": "{days}日", + "settings.storageCompliance.day": "日", + "settings.storageCompliance.targetForecasts": "保存先予測", + "settings.storageCompliance.target": "保存先", + "settings.storageCompliance.dailyRate": "観測レート", + "settings.storageCompliance.toHigh": "高水位までの余裕", + "settings.storageCompliance.expected": "予測保持期間", + "settings.storageCompliance.confidence": "信頼度", + "settings.storageCompliance.policyCompliance": "ポリシー準拠", + "settings.storageCompliance.compliant": "アクティブな違反はありません", + "settings.storageCompliance.violationCount": "{count}件の違反", + "settings.storageCompliance.policyForecast": "達成 {achieved}日; 予測 {expected}日; 希望 {desired}日。", + "settings.storageCompliance.copyDeficits": "{count}件の録画に追加の検証済みコピーが必要です。", + "settings.storageCompliance.activeViolations": "アクティブな違反", + "settings.storageCompliance.type.copy_count": "コピー数", + "settings.storageCompliance.type.minimum_retention": "最小保持容量", + "settings.storageCompliance.type.target_unavailable": "ターゲットが利用できません", + "settings.storageCompliance.type.migration_failed": "ライフサイクルジョブが失敗しました", + "settings.recordingDirectoryFormat": "録画フォルダのレイアウト", + "settings.recordingDirectoryFormatHelp": "各カメラフォルダ配下に新しいMP4録画を分割して保存します。既存の録画は移動されません。", + "settings.recordingDirectoryFlat": "フラット(カメラフォルダのみ)", + "settings.recordingDirectoryMonth": "月別(YYYY/MM)", + "settings.recordingDirectoryDay": "日別(YYYY/MM/DD)", + "settings.minFreePct": "最小空き容量(%)", + "settings.minFreePctHelp": "保持日数に関係なく、最も古い録画を自動的に削除して、ボリュームの空き容量がこの割合を下回らないようにします。ディスク容量の上限を設定でき、ディスクが満杯になることはありません。0で容量上限を無効化します。", + "settings.pressureThresholds": "ディスク逼迫しきい値(%)", + "settings.pressureThresholdsHelp": "自動クリーンアップを段階的に強化する空き容量のしきい値です。緊急 < 危険 < 警告 の関係を満たす必要があります。", + "settings.pressureWarningPct": "警告(空き容量が以下の場合)", + "settings.pressureCriticalPct": "危険(空き容量が以下の場合)", + "settings.pressureEmergencyPct": "緊急(空き容量が以下の場合)", + "settings.databaseBackupVerify": "バックアップ検証", + "settings.databaseBackupVerifyFull": "フル(integrity_check、すべてのインデックスを相互チェック)", + "settings.databaseBackupVerifyQuick": "クイック(quick_check、ページ構造のみ)", + "settings.databaseBackupVerifyOff": "オフ(コピー後のスキャンなし)", + "settings.databaseBackupVerifyHelp": "各バックアップのコピーを公開する前に適用されるスキャンです。フルは機械式ディスク上の大規模データベースではコピーより時間がかかり、30分のセーフティバルブに達してそのバックアップが破棄される場合があります。クイックでもシーク回数を大幅に抑えつつ、破損や切り詰められたページを検出できます。", + "settings.viewMethodAuto": "自動 — カメラごとの設定(フォールバック付き)", + "settings.resetWizardPending": "ウィザードを開始しています…", + "settings.apiDetectionFormat": "APIリクエスト形式", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect(マルチパート画像アップロード)", + "settings.apiDetectionFormatDoods2": "DOODS2(base64画像を含むJSONボディ)", + "settings.apiDetectionFormatHelp": "LightNVRが検出APIにスナップショットを送信する際に使用する通信形式です。light-object-detectまたはその契約を実装したサーバーではlight-object-detectを、DOODS2サーバーではDOODS2を選択してください。", + "settings.apiDetectionUrlHelpDoods2": "DOODS2の/detectエンドポイント(例: http://localhost:8080/detect)。リクエストはJSONで送信され、クエリパラメータは追加されません。", + "settings.apiDetectionDetectorName": "DOODS2検出器名", + "settings.apiDetectionDetectorNameHelp": "各リクエストのdetector_nameとして送信されます。サーバーのGET /detectorsで一覧される検出器と一致する必要があります。\"default\"はサーバーのデフォルト検出器を使用します。", + "settings.defaultPlaybackTransport": "デフォルト再生トランスポート", + "settings.defaultPlaybackTransportHelp": "新規作成されるストリームに適用される再生プロファイルです。既存のストリームは各自の設定を維持します。", + "playbackTransport.auto": "自動(推奨)", + "playbackTransport.webrtcOnly": "WebRTCのみ", + "playbackTransport.mseOnly": "MSEのみ", + "playbackTransport.hlsOnly": "HLSのみ", + "playbackTransport.webrtcThenMse": "WebRTC、次にMSE", + "playbackTransport.mseThenHls": "MSE、次にHLS", + "investigation.experimental": "実験的ワークスペース", + "investigation.title": "調査", + "investigation.description": "映像のギャップを隠さず、複数のカメラを共通のUTCカーソルで確認できます。", + "investigation.query": "調査ウィンドウ", + "investigation.queryHelp": "最大16台のカメラを選択できます。同時にアクティブになる動画プレイヤーは最大4台です。", + "investigation.cameras": "カメラ", + "investigation.cameraSelection": "カメラ選択", + "investigation.start": "開始", + "investigation.end": "終了", + "investigation.load": "調査を読み込む", + "investigation.applyWindow": "時間範囲を適用", + "investigation.loading": "調査を読み込み中…", + "investigation.eventType": "イベントタイプ", + "investigation.anyEventType": "すべてのイベントタイプ", + "investigation.eventType.detection": "検出", + "investigation.eventType.motion": "モーション", + "investigation.location": "場所", + "investigation.anyLocation": "すべての場所", + "investigation.objectLabel": "オブジェクトラベル", + "investigation.anyLabel": "すべてのラベル", + "investigation.zone": "ゾーン", + "investigation.anyZone": "すべてのゾーン", + "investigation.source": "検出ソース", + "investigation.anySource": "すべてのソース", + "investigation.captureMethod": "キャプチャ方法", + "investigation.anyCaptureMethod": "すべてのキャプチャ方法", + "investigation.recordingTag": "録画タグ", + "investigation.anyRecordingTag": "録音タグ(すべて)", + "investigation.protection": "保護", + "investigation.anyProtection": "保護(すべて)", + "investigation.protected": "保護済み", + "investigation.unprotected": "未保護", + "investigation.minimumConfidence": "最小信頼度", + "investigation.confidenceError": "最小信頼度は0から1の間で入力してください。", + "investigation.metadataRegionSearch": "メタデータ領域検索", + "investigation.regionSearchHelp": "映像のあるカメラを選択し、動画の上に領域を描画してください。", + "investigation.regionActive": "{camera}の保存済みボックスを検索中。結果がないことは、領域を通過したものがなかったことの証明ではありません。", + "investigation.regionMatch": "ボックス照合", + "investigation.regionMatch.center": "中心が内側", + "investigation.regionMatch.intersects": "交差あり", + "investigation.regionMatch.minimumIntersection": "最小重複率", + "investigation.regionMinimumOverlap": "最小重複率 (%)", + "investigation.regionLeft": "左 (%)", + "investigation.regionTop": "上 (%)", + "investigation.regionWidth": "幅 (%)", + "investigation.regionHeight": "高さ (%)", + "investigation.drawRegion": "検索領域を描画", + "investigation.drawingRegion": "検索領域を描画中…", + "investigation.clearRegion": "領域をクリア", + "investigation.useFullFrame": "フレーム全体を使用", + "investigation.drawRegionPrompt": "動画の上をドラッグして検索領域を定義", + "investigation.applyFilters": "フィルターを適用", + "investigation.searching": "イベントを検索中…", + "investigation.searchResults": "イベント結果", + "investigation.searchHelp": "調査を読み込んで、保存されたイベントメタデータを検索してください。", + "investigation.resultCount": "{count}件の一致イベント", + "investigation.results": "件の結果", + "investigation.resultHistogram": "イベントヒストグラム", + "investigation.histogramHelp": "バーを選択して共有カーソルを移動。", + "investigation.previousResult": "前のイベント", + "investigation.nextResult": "次のイベント", + "investigation.previousResultShortcut": "前のイベント ([)", + "investigation.nextResultShortcut": "次のイベント (])", + "investigation.noResults": "このカメラ、時間、フィルター条件に一致する保存済みイベントはありません。", + "investigation.noThumbnail": "サムネイルなし", + "investigation.exploreThumbnails": "サムネイルを閲覧", + "investigation.exploreSelectedThumbnails": "イベント周辺を閲覧", + "investigation.thumbnailDrilldown": "サムネイルの詳細表示", + "investigation.thumbnailDrilldownHelp": "任意の時点(間隔を含む)を選択すると、共有カーソルが移動し、より狭い範囲のサンプルが再生成されます。", + "investigation.selectThumbnailSample": "{time} 周辺を確認", + "investigation.loadingThumbnail": "サムネイルを読み込み中…", + "investigation.thumbnailUnavailable": "サムネイルを利用できません", + "investigation.loadingSamples": "サムネイルサンプルを読み込み中…", + "investigation.thumbnailCoverageTruncated": "この区間にはサンプラーが確認できる以上の録画が含まれています。時間範囲を狭めて全範囲をカバーしてください。", + "investigation.bookmarks.save": "ブックマークを保存", + "investigation.bookmarks.open": "ブックマーク", + "investigation.bookmarks.saveTitle": "調査ブックマークを保存", + "investigation.bookmarks.listTitle": "調査ブックマーク", + "investigation.bookmarks.notHold": "ブックマークはこのビューを復元しますが、通常の保持ポリシーや削除から録画を保護するものではありません。", + "investigation.bookmarks.title": "ブックマーク名", + "investigation.bookmarks.note": "プライベートメモ(任意)", + "investigation.bookmarks.titleRequired": "ブックマーク名を入力してください。", + "investigation.bookmarks.empty": "保存済みの調査ブックマークはありません。", + "investigation.bookmarks.cameraCount": "{count} 台のカメラ", + "investigation.bookmarks.restore": "開く", + "investigation.bookmarks.confirmDelete": "ブックマークを削除しますか?", + "investigation.actions.open": "保護 / ダウンロード", + "investigation.actions.title": "調査用録画", + "investigation.actions.notEvidenceExport": "保護により通常の保持ポリシーによる削除が防止されます。ZIPダウンロードは利便性のためのエクスポートであり、検証済みの証拠パッケージではありません。", + "investigation.actions.scope": "録画範囲", + "investigation.actions.selectedResult": "選択中のイベントとカメラ", + "investigation.actions.fullWindow": "調査ウィンドウ内の全カメラ", + "investigation.actions.preview": "録画をプレビュー", + "investigation.actions.previewing": "重複する録画を検索中…", + "investigation.actions.invalidRange": "終了時刻が開始時刻より後の有効な時間範囲を選択してください。", + "investigation.actions.recordingCount": "{count}件の重複する録画", + "investigation.actions.protectedCount": "{count}件は既に保護済み", + "investigation.actions.noRecordings": "このカメラと時間選択に重複する完了した録画はありません。", + "investigation.actions.protectDenied": "{count}件の未保護の録画は保護対象範囲外のため、この操作から除外されます。", + "investigation.actions.exportDenied": "{count}件の録画にエクスポート権限がありません。ダウンロードは全件一括のため、この選択はエクスポートできません。", + "investigation.actions.camera": "カメラ", + "investigation.actions.recording": "録画", + "investigation.actions.size": "サイズ", + "investigation.actions.notPermitted": "権限なし", + "investigation.actions.protectButton": "{count}件を保護", + "investigation.actions.protecting": "保護中…", + "investigation.actions.protectUnavailable": "保護可能な未保護の録画がありません。", + "investigation.actions.protectResult": "保護完了:{success}件成功、{failed}件失敗。", + "investigation.actions.downloadButton": "{count}件をダウンロード", + "investigation.actions.downloadUnavailable": "ZIPを作成するにはすべての録画にエクスポート権限が必要です。", + "investigation.actions.buildingArchive": "ZIPを作成中…", + "investigation.actions.downloadFailed": "サーバーでZIPの作成に失敗しました。", + "investigation.actions.downloadTimedOut": "ZIPの作成が5分以内に完了しませんでした。より狭い間隔でお試しください。", + "investigation.actions.downloadStarted": "ZIPのダウンロードを開始しました。", + "investigation.backOneLevel": "1つ上のレベルに戻る", + "investigation.thumbnailMinimumWindow": "これは利用可能な最小の1秒間隔です。共有カーソルは選択した位置に移動しました。", + "investigation.localSource": "ローカル", + "investigation.mediaAvailable": "メディア利用可能", + "investigation.durationSeconds": "再生時間 {count}秒", + "investigation.pageNumber": "{count}ページ目", + "investigation.incompleteCoverage": "{count}件のレガシーイベント行を不変のカメラIDに紐付けできませんでした。", + "investigation.spatialCoverageGap": "{count}件の対象イベント行にバウンディングボックスがなく、空間検索の対象外でした。", + "investigation.noSpatialMetadata": "このメタデータ検索に対応する対象イベントにバウンディングボックスがありません。", + "investigation.selectCameraError": "カメラを1台以上選択してください。", + "investigation.selectRecordingError": "録画を1件以上選択してください。", + "investigation.investigateSelectedCount": "選択した{count}件の録画を調査", + "investigation.missingCameraIdentity": "調査できません: 選択した{count}件の録画にカメラIDがありません。", + "investigation.recordingTimeError": "選択した録画に有効な時間範囲がありません。", + "investigation.windowLimit": "選択した録画が調査上限の31日を超えています。", + "investigation.timeRangeError": "終了時刻は開始時刻より後にしてください。", + "investigation.cameraLimit": "調査には最大{count}台のカメラを含められます。", + "investigation.decoderLimit": "同時にアクティブにできるカメラプレイヤーは{count}台までです。", + "investigation.playbackControls": "同期再生コントロール", + "investigation.play": "再生", + "investigation.pause": "一時停止", + "investigation.mode": "再生モード", + "investigation.wallClock": "リアルタイム", + "investigation.skipCommonGaps": "共通ギャップをスキップ", + "investigation.speed": "速度", + "investigation.sharedCursor": "共有UTCカーソル", + "investigation.activePlayers": "アクティブプレイヤー", + "investigation.timeline": "共有タイムライン", + "investigation.segments": "セグメント", + "investigation.truncated": "切り詰め済み", + "investigation.gap": "映像なし", + "investigation.players": "同期カメラプレイヤー", + "investigation.activateCamera": "タイムラインの行を1つ以上有効にして動画を読み込んでください。", + "investigation.noFootage": "映像なし", + "investigation.noFootageAtTime": "共有時刻に映像がありません", + "investigation.primaryAudio": "プライマリ音声", + "investigation.makePrimary": "プライマリに設定", + "investigation.status.loading": "メディアを読み込み中", + "investigation.status.synchronizing": "同期中", + "investigation.status.ready": "同期済み", + "investigation.status.late": "遅延 — 復旧中", + "investigation.status.error": "メディアを利用できません", + "investigation.status.paused-by-browser": "再生を選択してメディアを許可", + "streamsConfig.eptzTitle": "フィッシュアイ ePTZ", + "streamsConfig.eptzEnable": "ブラウザ側でフィッシュアイ ePTZ を有効にする", + "streamsConfig.eptzHelp": "ライブ表示、タイムライン再生、調査で元のフィッシュアイ映像を歪み補正します。録画やカメラ出力には影響しません。", + "streamsConfig.eptzModelHelp": "投影方式: 等距離円形フィッシュアイ · マウント: 天井。中心と半径は正規化されたソース画像座標を使用します。", + "streamsConfig.eptzCenterX": "光学中心 X", + "streamsConfig.eptzCenterY": "光学中心 Y", + "streamsConfig.eptzRadius": "イメージサークル半径", + "streamsConfig.eptzLensFov": "レンズ FOV(度)", + "streamsConfig.eptzRotation": "レンズ回転(度)", + "streamsConfig.eptzDefaultYaw": "デフォルトパン(度)", + "streamsConfig.eptzDefaultTilt": "デフォルトチルト(度)", + "streamsConfig.eptzViewFov": "デフォルト表示 FOV", + "streamsConfig.eptzCalibrationHelp": "ドラッグで視点移動、ホイールまたはピンチでズーム、Home キーで仮想カメラをリセットします。イメージサークルの縁が一致しない場合は中心と半径を微調整してください。", + "settings.archive.targetType": "ストレージタイプ", + "settings.archive.filesystem": "ローカルまたはマウント済みファイルシステム(NFS/SAN)", + "settings.archive.s3": "S3 互換アーカイブバケット", + "settings.archive.endpoint": "HTTPS エンドポイント", + "settings.archive.region": "リージョン", + "settings.archive.bucket": "専用バケット", + "settings.archive.credential_ref": "認証情報参照", + "settings.archive.budget": "アーカイブ予算(GiB、0 = 無制限)", + "settings.archive.connectionHelp": "プライベートでバージョニングなし、ライフサイクル期限ルールのないバケットを使用してください。認証情報参照はサーバーにマウントされたシークレットファイルを指定します。管理先は s3://bucket/instance-prefix の形式で入力してください。", + "settings.archive.policy": "外部アーカイブポリシー", + "settings.archive.archive_after_seconds": "キャプチャ後のアーカイブ(秒、-1 = 無効)", + "settings.archive.hot_residency_seconds": "ホットコピー保持(秒、-1 = アーカイブ後に移動)", + "settings.archive.archive_protected": "保護された録画のアーカイブを優先", + "settings.archive.archive_on_pressure": "ホットストレージの容量が逼迫した場合に早期アーカイブ", + "settings.archive.policyHelp": "アーカイブタイミングはキャプチャ経過時間に基づき、完了した録画が対象です。-1 は経過時間ベースのアーカイブを無効にするか、ホット保持の最小時間を解除します。0 は即時を意味します。編集は新しい録画に適用されます。既存の録画に新しい改訂を適用するには確認してください。", + "settings.archive.deletion_pending": "削除保留中", + "settings.archive.archived": "アーカイブ済み", + "settings.archive.hot": "ホット", + "settings.archive.hot_and_archive": "ホット + アーカイブ", + "settings.archive.archiving": "アーカイブ中", + "settings.archive.preparing": "再生の準備中", + "settings.archive.unavailable": "利用不可", + "settings.archive.operations": "アーカイブ操作", + "settings.archive.readOnly": "リカバリモード: 録画の移行と削除は一時停止中です。", + "settings.archive.disabledBuild": "このビルドではS3サポートは無効です。マウントされたファイルシステムターゲットは引き続き利用可能です。", + "settings.archive.stored": "バケットに保存済み", + "settings.archive.backlog": "転送バックログ", + "settings.archive.cache": "取得キャッシュ", + "settings.archive.objectsRemaining": "件のオブジェクトが残っています", + "settings.archive.waitingForReaders": "キュー投入済み、またはアクティブなリーダーの待機中。", + "settings.archive.applied": "既存の録画に適用されるポリシー改訂", + "settings.archive.reviewExisting": "既存の録画を確認", + "settings.archive.applySummary": "{count}件の録画({bytes})がこの改訂を使用します。{expired}件はすでに保持期間を超過しています。", + "settings.archive.applyHelp": "保護および録画の上書き設定は引き続き適用されます。ストリームおよびシステムの保持設定も適用されます。新しいアーカイブのタイミングと保存先は、次のライフサイクルスキャンで有効になります。", + "settings.archive.applyBlocked": "この改訂を適用する前に、関連する転送を完了または解決してください。", + "settings.archive.apply": "既存の録画に適用", + "common.fullscreenUnsupported": "このブラウザではフルスクリーンモードはサポートされていません。", + "recordings.viewInTimelineTitle": "タイムラインビューでこの時点のストリームを表示", + "recordings.clickToRetry": "クリックして再試行", + "timeline.previousDay": "前日", + "timeline.nextDay": "翌日", + "timeline.previousMonth": "前月", + "timeline.nextMonth": "翌月", + "settings.searchLabel": "設定を検索", + "settings.clearSearch": "検索をクリア", + "recordings.addTagPlaceholder": "タグを追加...", + "recordings.addNewTagPlaceholder": "新しいタグを追加..." } diff --git a/web/public/locales/ko.json b/web/public/locales/ko.json index 0050be99..1bfceeb8 100644 --- a/web/public/locales/ko.json +++ b/web/public/locales/ko.json @@ -821,7 +821,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "이 엔드포인트에서 light-object-detect가 실행 중인지 확인하세요.", "streamsConfig.customApiEndpointUrl": "사용자 지정 API 엔드포인트 URL", "streamsConfig.useDefaultEndpoint": "기본 엔드포인트 사용", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "사용자 지정 감지 API 엔드포인트의 전체 URL을 입력하세요.", "streamsConfig.overrideWithCustomEndpoint": "사용자 지정 엔드포인트로 재정의", "streamsConfig.detectionThreshold": "감지 임계값", @@ -881,7 +881,7 @@ "streamsConfig.segmentDurationHelp": "각 녹화 세그먼트의 길이", "streamsConfig.motionTriggerSource": "모션 트리거 소스 스트림", "streamsConfig.motionTriggerSourcePlaceholder": "예: fixed_wide_lens", - "streamsConfig.motionTriggerSourceHelp": "선택사항. ONVIF 모션 이벤트로 이 스트림의 녹화를 트리거할 다른 스트림 이름을 입력하세요. 한 렌즈는 모션 이벤트를 제공하고 다른 렌즈는 제공하지 않는 듀얼 렌즈 카메라에 유용합니다. 이 스트림의 모션 이벤트를 사용하려면 비워 두세요.", + "streamsConfig.motionTriggerSourceHelp": "선택사항. ONVIF 모션 이벤트로 이 스트림의 녹화를 트리거할 다른 스트림 이름을 입력하세요. 한 렌즈(예: 고정 광각)가 모션 이벤트를 제공하고 다른 렌즈(예: PTZ)는 제공하지 않는 듀얼 렌즈 카메라에 유용합니다. 이 스트림의 모션 이벤트를 사용하려면 비워 두세요.", "streamsConfig.go2rtcSourceOverride": "go2rtc 소스 재정의", "streamsConfig.go2rtcSourceOverrideLabel": "사용자 지정 go2rtc 소스", "streamsConfig.go2rtcSourceOverrideHelp": "고급: 이 스트림의 go2rtc 소스 URL을 재정의합니다 (단일 URL 또는 장애 조치/트랜스코딩을 위한 다중 소스 YAML 목록). 설정하면 자격 증명 및 전송 매개변수가 자동으로 주입되지 않습니다. 계정 수준 모듈 구성 (wyze:, homekit: 등)은 설정 → go2rtc 구성 재정의를 사용하세요. 자동 구성을 위해 비워 두세요. 변경 시 go2rtc가 재시작됩니다.", @@ -1058,7 +1058,7 @@ "settings.detectionModelsPath": "감지 모델 경로", "settings.detectionModelsPathHelp": "감지 모델이 저장된 디렉터리", "settings.apiDetectionUrl": "API 감지 URL", - "settings.apiDetectionUrlHelp": "외부 개체 감지 API 엔드포인트의 URL", + "settings.apiDetectionUrlHelp": "light-object-detect 엔드포인트, 예: http://localhost:8000/api/v1/detect. 스냅샷은 multipart form data로 업로드되며, backend 및 confidence_threshold 쿼리 매개변수가 추가됩니다.", "settings.apiDetectionBackend": "API 감지 백엔드", "settings.apiDetectionBackendOnnx": "ONNX Runtime", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1158,5 +1158,1490 @@ "settings.discoveryIntervalSecondsRangeHelp": "카메라 검색 빈도 (30~3600초)", "settings.discoveryNetwork": "검색 네트워크", "settings.discoveryNetworkExamples": "예: 192.168.1.0/24, 10.0.0.0/16, auto", - "settings.saveSettings": "설정 저장" + "settings.saveSettings": "설정 저장", + "live.navigator.title": "내비게이터", + "live.navigator.subtitle": "위치, 레이아웃 및 활동", + "live.navigator.cameras": "카메라", + "live.navigator.plans": "평면도", + "live.navigator.views": "뷰", + "live.navigator.events": "이벤트", + "live.navigator.search": "카메라 검색…", + "live.navigator.allCameras": "모든 카메라", + "live.navigator.unassigned": "미할당", + "live.navigator.noCameras": "이 범위에 해당하는 카메라가 없습니다.", + "live.navigator.saveCurrent": "현재 레이아웃 저장", + "live.navigator.noLayouts": "저장된 레이아웃이 없습니다.", + "live.navigator.layoutNamePrompt": "이 라이브 레이아웃 이름 지정", + "live.navigator.shareLayoutPrompt": "이 레이아웃을 다른 운영자와 공유하시겠습니까?", + "live.navigator.layoutSaved": "{name} 저장됨", + "live.navigator.layoutLoaded": "{name} 불러옴", + "live.navigator.deleteLayoutConfirm": "{name}을(를) 삭제하시겠습니까?", + "live.navigator.shared": "공유됨", + "live.navigator.loadingEvents": "최근 이벤트 불러오는 중…", + "live.navigator.noRecentEvents": "최근 1시간 내 감지된 항목이 없습니다.", + "live.navigator.expand": "내비게이터 펼치기", + "live.navigator.collapse": "내비게이터 접기", + "live.plan.navigatorHelp": "건물 또는 층을 선택하세요. 카메라 미리보기는 요청 시에만 열립니다.", + "live.plan.noPlans": "건물 평면도가 없습니다. 평면 작업 공간에서 생성하세요.", + "live.plan.emptyTitle": "공간 기반 카메라 뷰 만들기", + "live.plan.emptyDescription": "평면도는 전체 사이트의 상태 마커를 표시하며, 운영자가 요청할 때만 영상을 엽니다. 여기서 방과 벽을 직접 그리거나, 스캔한 도면, 현장 배치도, NVR 소프트웨어의 스냅샷을 업로드한 후 카메라를 실제 방에 매핑하세요.", + "live.plan.sketch.tools": "레이아웃 도구", + "live.plan.sketch.tool.select": "선택", + "live.plan.sketch.tool.room": "방", + "live.plan.sketch.tool.wall": "벽", + "live.plan.sketch.tool.area": "영역", + "live.plan.sketch.tool.label": "라벨", + "live.plan.sketch.undo": "그리기 취소", + "live.plan.sketch.redo": "그리기 다시 실행", + "live.plan.sketch.snap": "그리드에 스냅", + "live.plan.sketch.hint.select": "도형이나 카메라를 드래그하여 이동합니다. 도형을 클릭하여 편집하고, Alt를 누르면 그리드를 무시합니다.", + "live.plan.sketch.hint.room": "평면도에서 드래그하여 방 또는 건물 외곽선을 그립니다.", + "live.plan.sketch.hint.wall": "클릭하여 벽 지점을 추가합니다. 더블클릭 또는 Enter로 완료, Escape로 취소합니다.", + "live.plan.sketch.hint.area": "클릭하여 영역 외곽선을 그립니다. 첫 번째 지점을 클릭하거나 Enter를 눌러 닫습니다.", + "live.plan.sketch.hint.label": "평면도를 클릭하여 텍스트 라벨을 배치합니다.", + "live.plan.sketch.type.rect": "방", + "live.plan.sketch.type.wall": "벽", + "live.plan.sketch.type.area": "영역", + "live.plan.sketch.type.label": "라벨", + "live.plan.sketch.pointCount": "{count}개 지점", + "live.plan.sketch.defaultLabel": "라벨", + "live.plan.sketch.shapes": "레이아웃 도형", + "live.plan.sketch.noShapes": "아직 그려진 것이 없습니다. 평면도 위의 도구를 선택하여 시작하세요.", + "live.plan.sketch.tone": "색상", + "live.plan.sketch.tone.slate": "슬레이트", + "live.plan.sketch.tone.blue": "파랑", + "live.plan.sketch.tone.green": "초록", + "live.plan.sketch.tone.amber": "앰버", + "live.plan.sketch.tone.red": "빨강", + "live.plan.sketch.tone.violet": "보라", + "live.plan.sketch.labelText": "라벨", + "live.plan.sketch.text": "텍스트", + "live.plan.sketch.size": "크기", + "live.plan.sketch.size.sm": "작게", + "live.plan.sketch.size.md": "보통", + "live.plan.sketch.size.lg": "크게", + "live.plan.sketch.filled": "실내 채우기", + "live.plan.sketch.left": "왼쪽 %", + "live.plan.sketch.top": "위 %", + "live.plan.sketch.width": "너비 %", + "live.plan.sketch.height": "높이 %", + "live.plan.sketch.points": "포인트", + "live.plan.sketch.point": "포인트 {index}", + "live.plan.sketch.delete": "도형 삭제", + "live.plan.sketch.duplicate": "복제", + "live.plan.sketch.deselect": "완료", + "live.plan.sketch.emptyTitle": "이 평면에 아직 아무것도 없습니다", + "live.plan.sketch.emptyBody": "여기서 방, 벽, 라벨을 그리거나 스캔한 평면도, 현장 도면, PNG/JPEG 내보내기 파일을 업로드하세요 (최대 768 KB).", + "live.plan.sketch.emptyBodyReadOnly": "관리자가 레이아웃을 그리거나 실제 건물의 평면도를 업로드할 수 있습니다.", + "live.plan.sketch.drawLayout": "레이아웃 그리기", + "live.plan.sketch.uploadImage": "이미지 업로드", + "live.plan.sketch.limitReached": "도형 개수 제한에 도달했습니다 ({max})", + "live.plan.sketch.discardDrawing": "작업 취소됨", + "live.favorites": "즐겨찾기", + "live.favoritesOnly": "즐겨찾기 카메라만 표시", + "live.addFavorite": "{stream}을(를) 즐겨찾기에 추가", + "live.removeFavorite": "{stream}을(를) 즐겨찾기에서 제거", + "live.noFavorites": "즐겨찾기한 카메라가 없습니다. 카메라 타일의 별 아이콘을 눌러 추가하세요.", + "live.favoriteUpdateError": "즐겨찾기를 업데이트할 수 없습니다: {message}", + "live.resetZoom": "확대/축소 초기화", + "live.fullscreenSubStreamFallback": "{stream}: 전체 화면에서 전체 해상도 스트림을 표시할 대역폭이 부족합니다 — 서브 스트림으로 전환했습니다.", + "live.tileActions": "카메라 작업", + "live.takeSnapshot": "스냅샷 촬영", + "live.openStreamRecordings": "이 스트림의 녹화 열기", + "live.enterReorderMode": "카메라 순서 변경", + "live.pullToRefresh": "당겨서 스트림 새로고침", + "live.releaseToRefresh": "놓아서 스트림 새로고침", + "live.refreshingStreams": "스트림 새로고침 중…", + "live.streamsRefreshed": "스트림 새로고침 완료", + "live.refreshStreamsFailed": "스트림을 새로고침할 수 없습니다: {message}", + "live.tipDoubleTapFullscreen": "팁: 타일을 두 번 탭하면 전체 화면으로 열립니다.", + "live.dayNightControl": "주간/야간 모드", + "live.dayNightLoading": "불러오는 중…", + "live.dayNightApplying": "적용 중…", + "live.dayNightMode_auto": "자동", + "live.dayNightMode_day": "주간", + "live.dayNightMode_night": "야간", + "live.dayNightMode_unknown": "알 수 없음", + "live.dayNightApplied": "주간/야간 모드를 {mode}(으)로 설정했습니다", + "live.dayNightApplyFailed": "주간/야간 모드 설정에 실패했습니다", + "live.dayNightLoadFailed": "주간/야간 모드 조회에 실패했습니다", + "live.playbackFallbackUsed": "대체: {transport}", + "live.playbackTransportUnavailable": "이 스트림에 대해 서버에서 {transport}이(가) 비활성화되어 있습니다.", + "live.recordingMode.constant": "상시 녹화", + "live.recordingMode.detection": "감지 녹화", + "live.recordingMode.schedule": "예약 녹화", + "live.recordingMode.none": "녹화 안 함", + "live.health.healthy": "스트림 정상", + "live.health.degraded": "스트림 버퍼링 또는 복구 중", + "live.health.offline": "스트림 사용 불가", + "live.enterPictureInPicture": "픽처 인 픽처 열기", + "live.exitPictureInPicture": "픽처 인 픽처 닫기", + "live.pictureInPictureError": "픽처 인 픽처 실패: {message}", + "live.alwaysFullscreenOnTapEnable": "타일 한 번 탭으로 전체 화면 활성화", + "live.alwaysFullscreenOnTapDisable": "타일 한 번 탭으로 전체 화면 비활성화", + "live.displayMode": "표시 모드", + "live.displayModeFit": "맞춤", + "live.displayModeFill": "채우기", + "live.displayModeFitDescription": "맞춤: 레터박스로 전체 프레임을 표시", + "live.displayModeFillDescription": "채우기: 타일을 채우고 프레임 가장자리를 잘라냄", + "live.slideshowStartCameras": "슬라이드쇼 시작: 카메라 순환", + "live.slideshowStartPages": "슬라이드쇼 시작: 그리드 페이지 순환", + "live.slideshowStop": "슬라이드쇼 중지", + "live.slideshowInterval": "슬라이드쇼 간격", + "live.slideshowSeconds": "{seconds}초", + "live.plan.previewUnavailable": "카메라 미리보기를 사용할 수 없음", + "live.plan.previewAlt": "{name}의 현재 뷰", + "live.plan.degreesValue": "{value}도", + "live.plan.inDegrees": "{label} (도 단위)", + "live.plan.imageDimensionsError": "이미지 크기를 읽을 수 없음", + "live.plan.loading": "건물 평면도 불러오는 중…", + "live.plan.created": "{name} 생성됨", + "live.plan.renamed": "{name}(으)로 이름 변경됨", + "live.plan.deleted": "{name} 삭제됨", + "live.plan.backgroundType": "배경은 PNG 또는 JPEG 이미지여야 합니다", + "live.plan.backgroundTooLarge": "배경 이미지가 너무 큼. 최대 768 KB", + "live.plan.backgroundAspect": "업로드되었지만 이미지 비율이 유효한 캔버스 크기에 맞지 않음", + "live.plan.backgroundUpdatedSave": "{name}의 배경이 업데이트됨. 레이아웃을 저장하여 캔버스 크기를 적용하세요", + "live.plan.backgroundNotResized": "배경이 업로드되었지만 캔버스 크기가 조정되지 않음: {error}", + "live.plan.backgroundUpdated": "{name}의 배경이 업데이트되었습니다", + "live.plan.backgroundRemoved": "배경 제거됨", + "live.plan.saved": "{name} 저장됨", + "live.plan.createTitle": "건물 평면도 만들기", + "live.plan.createDescription": "이 건물이나 층에 명확한 이름을 지정하세요. 레이아웃을 그리거나 평면도 이미지를 업로드한 후 카메라를 배치합니다.", + "live.plan.nameLabel": "평면도 이름", + "live.plan.namePlaceholder": "본관 · 1층", + "live.plan.createConfirm": "평면도 만들기", + "live.plan.eyebrow": "건물 평면도", + "live.plan.placedSummary": "{placed}개 배치 · {live}개 라이브 중", + "live.plan.zoomAndPan": "평면도 확대/축소 및 이동", + "live.plan.panLeft": "왼쪽으로 이동", + "live.plan.panUp": "위로 이동", + "live.plan.panDown": "아래로 이동", + "live.plan.panRight": "오른쪽으로 이동", + "live.plan.zoomOut": "축소", + "live.plan.zoomIn": "확대", + "live.plan.fitTitle": "평면도 맞춤", + "live.plan.fit": "맞춤", + "live.plan.backgroundMenu": "배경…", + "live.plan.save": "평면도 저장", + "live.plan.uploadBackgroundTitle": "PNG 또는 JPEG 이미지를 평면도 배경으로 업로드", + "live.plan.replaceBackground": "배경 교체", + "live.plan.uploadBackground": "배경 업로드", + "live.plan.removeBackground": "배경 제거", + "live.plan.rename": "이름 변경", + "live.plan.newPlan": "새 플랜", + "live.plan.editLayout": "레이아웃 편집", + "live.plan.placementHint": "플랜을 클릭하여 {name} 배치", + "live.plan.clusterLabel": "카메라 {count}대; 확대", + "live.plan.markerLabel": "{name}; {availability}; {rotation}° 방향, {fov}° 시야", + "live.plan.cameraFallback": "카메라", + "live.plan.legendLive": "라이브", + "live.plan.canvas": "플랜 캔버스", + "live.plan.width": "너비", + "live.plan.height": "높이", + "live.plan.canvasHint": "배경 이미지를 업로드하면 캔버스가 이미지에 맞게 조정됩니다.", + "live.plan.canvasInvalid": "너비는 400–4000, 높이는 300–4000이어야 합니다.", + "live.plan.openLive": "라이브 카메라 열기", + "live.plan.direction": "카메라 방향", + "live.plan.fov": "시야각", + "live.plan.coverageNote": "부채꼴은 방향과 각도만 표시하며, 플랜상의 거리는 보정되지 않습니다.", + "live.plan.removeCamera": "플랜에서 제거", + "live.plan.selectCamera": "카메라 선택", + "live.plan.selectHintEditing": "배치된 마커를 드래그하여 미세 조정하세요. 상태를 확인하고 필요 시 라이브 뷰를 여세요.", + "live.plan.selectHint": "상태를 확인하고 필요 시 라이브 뷰를 여세요.", + "live.plan.cameras": "플랜 카메라", + "live.plan.findPlaceholder": "이 플랜에서 찾기…", + "live.plan.findLabel": "이 플랜에서 카메라 찾기", + "live.plan.unplaced": "배치되지 않은 카메라", + "live.plan.unplacedHint": "카메라를 선택한 후 플랜에서 위치를 클릭하세요.", + "live.plan.renameTitle": "플랜 이름 변경", + "live.plan.renameDescription": "플랜은 이 사이트의 모든 운영자에게 공유됩니다.", + "live.plan.deleteTitle": "플랜 삭제", + "live.plan.deleteMessage": "“{name}”과 업로드된 배경을 삭제하시겠습니까? 이 플랜의 카메라 배치는 제거되지만, 카메라 자체는 영향을 받지 않습니다.", + "setupWizard.welcomeTitle": "LightNVR에 오신 것을 환영합니다", + "setupWizard.welcomeIntro": "몇 가지 간단한 단계로 NVR을 설정해 보세요. 설정 페이지에서 언제든지 다시 변경할 수 있습니다.", + "setupWizard.welcomeStorage": "저장 경로 및 용량 제한", + "setupWizard.welcomePerformance": "카메라 수에 따른 성능 제한", + "setupWizard.welcomeSecurity": "관리자 로그인 보안", + "setupWizard.storageTitle": "저장소 및 데이터베이스", + "setupWizard.storageIntro": "녹화 파일과 데이터베이스를 어디에 저장하시겠습니까?", + "setupWizard.storagePath": "녹화 저장 경로", + "setupWizard.storagePathHint": "비디오 파일이 저장되는 절대 경로입니다.", + "setupWizard.maxStorage": "최대 저장 용량 (GB)", + "setupWizard.maxStorageHint": "0 = 제한 없음.", + "setupWizard.dbPath": "데이터베이스 경로", + "setupWizard.dbPathHint": "SQLite 데이터베이스 파일 위치입니다.", + "setupWizard.performanceTitle": "성능", + "setupWizard.performanceIntro": "이 설정은 용량을 제어하며, 비디오 품질에는 영향을 주지 않습니다. 대부분의 사용자는 기본값을 유지하면 됩니다.", + "setupWizard.threadPool": "워커 스레드 풀 크기", + "setupWizard.threadPoolInfo": "백그라운드 웹/서버 작업에 영향을 줍니다. 성능 튜닝이 아닌 경우 권장 기본값을 사용하는 것이 일반적입니다.", + "setupWizard.maxStreams": "최대 동시 스트림 수", + "setupWizard.maxStreamsInfo": "은 현재 실행 중인 인스턴스의 카메라 용량 제한입니다. 추가할 카메라 수보다 약간 여유를 두고 설정하세요.", + "setupWizard.important": "중요:", + "setupWizard.restartWarning": "두 설정 중 하나를 변경하면 새 값은 지금 저장되지만 LightNVR이 재시작될 때까지 적용되지 않습니다. 예를 들어 현재 스트림 제한이 1이고 32로 올리면, 이전 제한을 초과하는 카메라를 추가하기 전에 재시작해야 합니다.", + "setupWizard.threadPoolHintCores": "권장: {recommended} ({cores}코어 CPU의 2배). libuv 백그라운드 워커 스레드를 제어합니다. 범위: 2–128.", + "setupWizard.threadPoolHint": "권장: {recommended} (CPU 코어의 2배). libuv 백그라운드 워커 스레드를 제어합니다. 범위: 2–128.", + "setupWizard.maxStreamsHint": "LightNVR이 동시에 활성화할 수 있는 카메라 수입니다. 기본값 32, 최대 {max}. 8대의 카메라를 사용하려면 최소 8로 설정하세요. 재시작 후 적용됩니다.", + "setupWizard.completeTitle": "설정 완료!", + "setupWizard.saved": "설정이 성공적으로 저장되었습니다.", + "setupWizard.notSaved": "설정이 변경되지 않았습니다 — 기본값이 사용됩니다.", + "setupWizard.restartRequired": "재시작 필요", + "setupWizard.restartRequiredInfo": "스레드 풀 크기 및/또는 최대 스트림 변경 사항이 저장되었지만, 서비스가 재시작될 때까지 적용되지 않습니다. 카메라를 추가하거나 새 용량 제한을 적용하기 전에 재시작하세요.", + "setupWizard.saveFailed": "설정 저장 실패: {error}", + "setupWizard.back": "이전", + "setupWizard.saving": "저장 중…", + "setupWizard.saveContinue": "저장 후 계속", + "setupWizard.next": "다음 →", + "setupWizard.finish": "대시보드로 이동", + "setupWizard.skip": "설정 마법사 건너뛰기", + "live.eptzCanvasLabel": "어안 전자식 팬/틸트/줌 뷰", + "live.eptzCanvasHint": "드래그하여 팬/틸트, 휠 또는 핀치로 줌, Home으로 초기화", + "live.eptzReset": "ePTZ 뷰 초기화", + "live.autoShort": "자동", + "live.webrtcShort": "WebRTC", + "nav.investigation": "조사", + "availability.label": "카메라 가용성", + "availability.live": "라이브", + "availability.offline": "오프라인 (이전에 연결됨)", + "availability.neverConnected": "연결된 적 없음", + "availability.disabled": "비활성화됨", + "availability.all": "모든 카메라", + "streams.inventory": "인벤토리", + "streams.configuration": "구성", + "events.tab": "이벤트", + "events.eyebrow": "이벤트 기반 통합", + "events.title": "이벤트 및 라우팅", + "events.description": "카메라 및 시스템 이벤트를 자동화, 알림 서비스, 외부 처리를 위한 신뢰성 있는 MQTT 스트림으로 변환합니다. LightNVR은 이벤트 인터페이스를 제공하며, 이메일 및 SMS 전송은 다운스트림 서비스에서 처리됩니다.", + "events.routes": "라우트", + "events.destinations": "목적지", + "events.catalog": "이벤트 카탈로그", + "events.enable": "활성화", + "events.loadError": "이벤트 라우팅 구성을 불러올 수 없습니다", + "events.accessDenied": "접근 거부 - 권한 부족", + "events.summary.routes": "라우트", + "events.summary.enabled": "{count}개 활성화됨", + "events.summary.destinations": "목적지", + "events.summary.managedActive": "{count}개 관리 중 및 활성", + "events.summary.types": "등록된 유형", + "events.summary.registry": "버전 관리 이벤트 카탈로그", + "events.summary.interface": "인터페이스", + "events.summary.interfaceHelp": "신뢰성 있는 이벤트 출력", + "events.route.add": "라우트 추가", + "events.route.addTitle": "이벤트 라우트 생성", + "events.route.editTitle": "이벤트 라우트 편집", + "events.route.create": "라우트 생성", + "events.route.editorDescription": "대상 이벤트, 범위 내 카메라, 전송 목적지 및 소음 제어 방식을 선택합니다.", + "events.route.emptyTitle": "이벤트 라우트가 구성되어 없습니다", + "events.route.emptyDescription": "이벤트 유형, 카메라 범위, 일정, 억제 정책 및 MQTT 대상을 선택하여 라우트를 만드세요.", + "events.route.enabled": "라우트 활성화됨", + "events.route.enabledHelp": "일치하는 이벤트가 영구 전달을 위해 수락됩니다", + "events.route.destination": "대상", + "events.route.destinationHelp": "일치하는 이벤트는 각 고유 대상에 대해 한 번 저장됩니다.", + "events.route.eventTypes": "이벤트 유형", + "events.route.eventTypesHelp": "레지스트리에서 하나 이상의 버전 관리 이벤트 계약을 선택하세요.", + "events.route.detectionFilters": "객체 감지 필터", + "events.route.detectionFiltersHelp": "객체 감지 이벤트에 대해 레이블, 구역 또는 최소 신뢰도를 선택적으로 요구합니다.", + "events.route.healthFilters": "시스템 상태 이벤트 필터", + "events.route.healthFiltersHelp": "등록된 상태 조건 코드 또는 심각도를 선택적으로 일치시킵니다. 사용 가능한 값은 이 레코더에서 제공됩니다.", + "events.route.healthConditions": "상태 조건 (하나라도 해당)", + "events.route.healthSeverities": "심각도 (하나라도 해당)", + "events.route.healthRegistryUnavailable": "상태 조건 레지스트리를 사용할 수 없습니다. 조건 필터를 구성하기 전에 새로고침하세요.", + "events.route.labels": "레이블 (하나라도 해당)", + "events.route.zones": "구역 ID (하나라도 해당)", + "events.route.listHelp": "값은 쉼표로 구분하세요.", + "events.route.minConfidence": "최소 신뢰도", + "events.route.confidenceHelp": "0에서 1 사이의 값.", + "events.route.cameraScope": "카메라 범위", + "events.route.cameraScopeHelp": "전체 플릿을 로드하지 않고 플릿 위치, 태그, 속성 컬렉션 또는 명시적 카메라를 재사용합니다.", + "events.route.allCameras": "모든 카메라", + "events.route.dynamicScope": "동적 카메라 선택기", + "events.route.systemScopeHelp": "시스템 이벤트는 카메라가 아닙니다. 이 라우트에 시스템 범위 이벤트가 포함된 경우 카메라 선택기를 사용할 수 없습니다.", + "events.route.schedule": "일정", + "events.route.scheduleHelp": "IANA 시간대의 이벤트 발생 시간을 사용하며, 자정을 넘는 시간대도 지원합니다.", + "events.route.restrictSchedule": "구성된 시간대 동안에만", + "events.route.suppression": "노이즈 및 전달 정책", + "events.route.suppressionHelp": "0이면 해당 제어가 비활성화됩니다. 억제는 해당 대상이 영구 이벤트를 수락한 후에만 진행됩니다.", + "events.route.debounce": "디바운스 시간(초)", + "events.route.debounceHelp": "반복된 관측은 이 대기 시간을 연장합니다.", + "events.route.cooldown": "쿨다운 시간(초)", + "events.route.cooldownHelp": "수락된 이벤트 이후 최소 간격입니다.", + "events.route.grouping": "그룹화 창(초)", + "events.route.groupingHelp": "첫 번째 이벤트를 유지하고 반복 이벤트를 병합합니다.", + "events.route.rateLimit": "분당 이벤트 수", + "events.route.rateLimitHelp": "라우트 및 카메라별 고정 창 최대값입니다.", + "events.route.deliveryPolicy": "전달 정책", + "events.route.suppressionActive": "노이즈 제어 활성", + "events.route.everyMatch": "모든 일치", + "events.route.preview": "라우트 미리보기", + "events.route.previewing": "미리보기 중…", + "events.route.previewResult": "라우트 미리보기", + "events.route.cameraMatches": "{count}개 카메라 일치", + "events.route.previewNoPublish": "미리보기는 전체 규칙을 검증하고 카메라 샘플을 확인합니다. 이벤트는 게시되지 않습니다.", + "events.route.systemPreviewHelp": "시스템 이벤트는 카메라 선택을 거치지 않으므로 이 미리보기에서 일치하는 카메라 수가 0으로 표시됩니다.", + "events.route.created": "이벤트 라우트 생성됨", + "events.route.updated": "이벤트 라우트 업데이트됨", + "events.route.deleted": "이벤트 라우트 삭제됨", + "events.route.disabled": "이벤트 라우트 비활성화됨", + "events.route.enabledMessage": "이벤트 라우트 활성화됨", + "events.route.deleteConfirm": "이벤트 라우트 \"{name}\"을(를) 삭제하시겠습니까?", + "events.route.validation.name": "라우트 이름을 입력하세요.", + "events.route.validation.destination": "대상을 선택하세요.", + "events.route.validation.event_types": "이벤트 유형을 하나 이상 선택하세요.", + "events.route.validation.selector": "카메라 선택기를 완성하거나 수정하세요.", + "events.route.validation.system_scope": "카메라 선택기는 시스템 범위 이벤트와 함께 사용할 수 없습니다.", + "events.route.validation.detection_type": "감지 필터에는 객체 감지 이벤트 유형이 필요합니다.", + "events.route.validation.detection_filter": "감지 레이블, 영역 또는 신뢰도 임계값을 하나 이상 추가하세요.", + "events.route.validation.confidence": "최소 신뢰도는 0에서 1 사이여야 합니다.", + "events.route.validation.predicate_mix": "감지 필터와 상태 필터는 하나의 라우트에서 함께 사용할 수 없습니다.", + "events.route.validation.health_type": "상태 필터에는 등록된 시스템 상태 이벤트 유형만 사용할 수 있습니다.", + "events.route.validation.health_filter": "등록된 상태 조건 또는 심각도를 하나 이상 선택하세요.", + "events.route.validation.health_condition": "녹화기의 상태 레지스트리가 반환하는 조건 코드만 선택하세요.", + "events.route.validation.health_severity": "선택한 상태 이벤트 유형에서 지원하는 심각도만 선택하세요.", + "events.route.validation.timezone": "UTC 또는 America/New_York와 같이 설치된 IANA 시간대를 입력하세요.", + "events.route.validation.schedule_window": "각 일정 창에는 최소 하루와 서로 다른 유효한 시작 및 종료 시간이 필요합니다.", + "events.route.validation.suppression": "억제 값은 허용 범위 내의 정수여야 합니다.", + "events.schedule.timezone": "시간대", + "events.schedule.timezoneHelp": "녹화기의 시간대 데이터베이스에 있어야 합니다.", + "events.schedule.addWindow": "시간 창 추가", + "events.schedule.windowNumber": "창 {number}", + "events.schedule.start": "시작", + "events.schedule.end": "종료", + "events.schedule.sunday": "일", + "events.schedule.monday": "월", + "events.schedule.tuesday": "화", + "events.schedule.wednesday": "수", + "events.schedule.thursday": "목", + "events.schedule.friday": "금", + "events.schedule.saturday": "토", + "events.destination.add": "대상 추가", + "events.destination.addTitle": "MQTT 대상 추가", + "events.destination.editTitle": "MQTT 대상 편집", + "events.destination.create": "대상 생성", + "events.destination.editorDescription": "영구 이벤트 출력을 구성합니다. 자격 증명은 쓰기 전용이며 API를 통해 반환되지 않습니다.", + "events.destination.default": "기본 MQTT 설정", + "events.destination.settingsManaged": "설정 관리됨", + "events.destination.defaultDescription": "기존 MQTT 구성은 mqtt:default로 계속 사용할 수 있으며 {count}개 라우트에서 사용됩니다.", + "events.destination.openSettings": "MQTT 설정 열기", + "events.destination.emptyTitle": "관리되는 대상 없음", + "events.destination.emptyDescription": "클라우드 커넥터, 자동화 시스템 또는 알림 서비스로 독립적인 이벤트 전달을 위해 다른 MQTT 브로커를 추가하세요.", + "events.destination.identity": "대상 식별자", + "events.destination.enabled": "대상 활성화됨", + "events.destination.enabledHelp": "연결하여 영구 큐 처리", + "events.destination.active": "활성", + "events.destination.paused": "일시 중지됨", + "events.destination.pause": "일시 중지", + "events.destination.broker": "브로커", + "events.destination.host": "브로커 호스트", + "events.destination.hostHelp": "호스트 이름 또는 IP 주소만 입력하세요. URL 스킴은 포함하지 마세요.", + "events.destination.port": "포트", + "events.destination.clientId": "클라이언트 ID", + "events.destination.clientIdHelp": "이 브로커 연결에 대해 고유해야 합니다.", + "events.destination.topic": "토픽", + "events.destination.topicTemplate": "토픽 템플릿", + "events.destination.topicHelp": "이벤트 유형 및 대상 ID 토큰을 포함해야 합니다. MQTT 와일드카드는 허용되지 않습니다.", + "events.destination.keepalive": "킵얼라이브(초)", + "events.destination.statusTopicTemplate": "온라인 상태 토픽", + "events.destination.statusTopicHelp": "선택 사항입니다. {installation_uuid}를 포함해야 합니다. {destination_uuid}도 사용할 수 있습니다. MQTT 와일드카드는 허용되지 않습니다.", + "events.destination.statusTopicEnabled": "이 대상에 대해 온라인 상태가 명시적으로 활성화되어 있습니다. 토픽은 이벤트 토픽에서 추론되지 않습니다.", + "events.destination.statusTopicDisabled": "이 대상에 대해 온라인 상태가 비활성화되어 있습니다. 비활성 상태를 유지하려면 이 필드를 비워 두세요.", + "events.destination.qos": "서비스 품질", + "events.destination.qos0": "한 번 전송", + "events.destination.qos1": "최소 한 번", + "events.destination.qos2": "정확히 한 번", + "events.destination.authentication": "인증", + "events.destination.passwordPreserved": "저장된 쓰기 전용 암호를 유지하려면 비워 두세요.", + "events.destination.passwordOptional": "브로커가 익명 클라이언트를 허용하는 경우 선택 사항입니다.", + "events.destination.clearPassword": "저장된 암호 지우기", + "events.destination.transportSecurity": "전송 보안", + "events.destination.tlsMode": "TLS 모드", + "events.destination.tlsSystem": "시스템 신뢰 저장소", + "events.destination.tlsCustomCa": "사용자 지정 인증 기관", + "events.destination.tlsMutual": "상호 TLS", + "events.destination.tlsDisabled": "비활성화(평문)", + "events.destination.tlsHelp.system": "운영 체제 신뢰 저장소를 사용하여 브로커 인증서를 검증합니다.", + "events.destination.tlsHelp.custom_ca": "브로커를 명시적인 PEM 인증 기관 파일로 검증합니다.", + "events.destination.tlsHelp.mutual": "명시적인 CA로 브로커를 검증하고 클라이언트 인증서 및 키를 제시합니다.", + "events.destination.tlsHelp.disabled": "전송 암호화 또는 브로커 신원 검증 없음.", + "events.destination.caFile": "CA 파일", + "events.destination.certFile": "클라이언트 인증서 파일", + "events.destination.keyFile": "클라이언트 키 파일", + "events.destination.absolutePathHelp": "LightNVR 서비스가 읽을 수 있는 절대 경로를 사용하세요.", + "events.destination.plaintextWarning": "평문 MQTT는 이벤트 메타데이터 및 자격 증명을 노출할 수 있습니다. 신뢰할 수 있는 격리된 네트워크에서만 사용하세요.", + "events.destination.security": "보안", + "events.destination.tls.system": "시스템 신뢰", + "events.destination.tls.custom_ca": "사용자 지정 CA", + "events.destination.tls.mutual": "상호 TLS", + "events.destination.tls.disabled": "평문", + "events.destination.routes": "라우트", + "events.destination.presence": "부재 감지 토픽", + "events.destination.deleteInUse": "이 대상을 삭제하기 전에 라우트를 제거하거나 리디렉션하세요.", + "events.destination.created": "MQTT 대상 생성됨", + "events.destination.updated": "MQTT 대상 업데이트됨", + "events.destination.deleted": "MQTT 대상 삭제됨", + "events.destination.pausedMessage": "MQTT 대상 일시 중지됨. 대기열의 이벤트는 만료까지 영구적으로 유지됩니다.", + "events.destination.enabledMessage": "MQTT 대상 활성화됨", + "events.destination.deleteConfirm": "MQTT 대상 \"{name}\"을(를) 삭제하시겠습니까?", + "events.destination.validation.name": "대상 이름을 입력하세요.", + "events.destination.validation.host": "브로커 호스트 이름 또는 IP 주소를 입력하세요.", + "events.destination.validation.client_id": "브로커 클라이언트 ID를 입력하세요.", + "events.destination.validation.topic": "토픽에는 이벤트 유형 및 대상 ID 토큰이 포함되어야 하며 MQTT 와일드카드를 포함할 수 없습니다.", + "events.destination.validation.status_topic": "선택적 부재 감지 토픽에는 설치 UUID 토큰이 포함되어야 하며, 지원되는 토큰만 사용해야 하고 MQTT 와일드카드를 포함할 수 없습니다.", + "events.destination.validation.port": "포트는 1에서 65535 사이의 정수여야 합니다.", + "events.destination.validation.keepalive": "킵얼라이브는 5에서 3600초 사이의 정수여야 합니다.", + "events.destination.validation.qos": "MQTT QoS 0, 1 또는 2를 선택하세요.", + "events.destination.validation.username": "비밀번호를 설정하려면 사용자 이름이 필요합니다.", + "events.destination.validation.ca_file": "이 TLS 모드에는 절대 CA 파일 경로가 필요합니다.", + "events.destination.validation.mutual_files": "상호 TLS에는 CA, 클라이언트 인증서, 클라이언트 키의 절대 경로가 필요합니다.", + "fleet.eyebrow": "카메라 작업", + "fleet.title": "카메라 인벤토리", + "fleet.description": "전체 인벤토리를 브라우저에 로드하지 않고 대규모 배포 환경에서 카메라를 검색, 평가 및 구성합니다.", + "fleet.summary": "전체 상태 요약", + "fleet.totalCameras": "일치하는 카메라", + "fleet.needsAttention": "성능 저하", + "fleet.searchLabel": "카메라 검색", + "fleet.searchPlaceholder": "이름, 주소, 위치, 태그, 제조사 또는 모델로 검색…", + "fleet.resultCount": "{count}대 카메라", + "fleet.filters": "필터", + "fleet.clearFilters": "필터 초기화", + "fleet.filter.health": "상태", + "fleet.filter.enabled": "카메라 상태", + "fleet.filter.anyState": "모든 상태", + "fleet.filter.recording": "녹화 모드", + "fleet.filter.location": "위치 하위 트리", + "fleet.filter.allLocations": "모든 위치", + "fleet.filter.tags": "태그 (하나라도 일치)", + "fleet.filter.collection": "카메라 컬렉션", + "fleet.health.unknown": "알 수 없음", + "fleet.health.up": "온라인", + "fleet.health.degraded": "성능 저하", + "fleet.health.down": "오프라인", + "fleet.health.disabled": "비활성화", + "fleet.recording.off": "꺼짐", + "fleet.recording.continuous": "연속", + "fleet.recording.detection": "감지", + "fleet.recordingActive": "녹화 중", + "fleet.recordingInactive": "녹화 안 함", + "fleet.column.camera": "카메라", + "fleet.column.health": "상태", + "fleet.column.location": "위치", + "fleet.column.tags": "태그", + "fleet.column.recording": "녹화", + "fleet.viewLive": "라이브", + "fleet.lastFrame": "마지막 프레임", + "fleet.noAddress": "주소 사용 불가", + "fleet.unassigned": "미할당", + "fleet.loading": "카메라 목록 불러오는 중…", + "fleet.refreshing": "새로고침 중…", + "fleet.loadError": "카메라 목록을 불러올 수 없습니다", + "fleet.emptyTitle": "구성된 카메라가 없습니다", + "fleet.emptyDescription": "스트림을 추가하여 작업 공간에서 사용할 수 있도록 하세요.", + "fleet.emptyFilteredTitle": "이 뷰에 해당하는 카메라가 없습니다", + "fleet.emptyFilteredDescription": "검색 범위를 넓히거나 필터를 해제해 보세요.", + "fleet.paginationSummary": "{total}개 중 {first}–{last} 표시", + "fleet.perPage": "페이지당", + "fleet.pageOf": "{pages}페이지 중 {page}페이지", + "fleet.selectPage": "이 페이지의 모든 카메라 선택", + "fleet.selectCamera": "{name} 선택", + "fleet.selectedCount": "{count}개 카메라 선택됨", + "fleet.organizeSelected": "선택 항목 정리", + "fleet.clearSelection": "선택 해제", + "fleet.organization.manage": "조직 관리", + "fleet.organization.title": "카메라 조직", + "fleet.organization.description": "카메라 목록을 위한 재사용 가능한 위치 계층 구조와 표준화된 태그 사전을 관리합니다.", + "fleet.organization.locations": "위치", + "fleet.organization.tags": "태그", + "fleet.organization.locationsDescription": "사이트, 건물, 층, 운영 구역을 탐색 가능한 계층 구조로 모델링합니다.", + "fleet.organization.tagsDescription": "일관성 없는 자유 형식 레이블 대신 관리되는 태그 사전을 사용하세요.", + "fleet.organization.addRoot": "최상위 위치 추가", + "fleet.organization.addLocation": "위치 추가", + "fleet.organization.editLocation": "위치 편집", + "fleet.organization.addChild": "하위 항목 추가", + "fleet.organization.type": "유형", + "fleet.organization.parent": "상위 위치", + "fleet.organization.topLevel": "최상위", + "fleet.organization.sortOrder": "정렬 순서", + "fleet.organization.contents": "콘텐츠", + "fleet.organization.cameras": "카메라", + "fleet.organization.system": "시스템", + "fleet.organization.contentCounts": "카메라 {cameras}대 · 하위 항목 {children}개", + "fleet.organization.locationNotEmpty": "카메라를 이동하고 하위 위치를 먼저 삭제하세요", + "fleet.organization.noLocations": "구성된 위치가 없습니다.", + "fleet.organization.locationCreated": "위치 생성됨", + "fleet.organization.locationUpdated": "위치 업데이트됨", + "fleet.organization.locationDeleted": "위치 삭제됨", + "fleet.organization.deleteLocationConfirm": "위치 \"{name}\"을(를) 삭제하시겠습니까?", + "fleet.organization.addTag": "태그 추가", + "fleet.organization.editTag": "태그 편집", + "fleet.organization.tagLabel": "태그", + "fleet.organization.color": "색상 (#RRGGBB)", + "fleet.organization.tagDescription": "설명", + "fleet.organization.noTags": "정규화된 태그가 구성되어 없습니다.", + "fleet.organization.tagCreated": "태그 생성됨", + "fleet.organization.tagUpdated": "태그 업데이트됨", + "fleet.organization.tagDeleted": "태그 삭제됨", + "fleet.organization.deleteTagConfirm": "\"{name}\"을(를) 삭제하시겠습니까? 현재 {count}대의 카메라에 할당되어 있습니다.", + "fleet.organization.merge": "병합", + "fleet.organization.mergeTagNamed": "\"{name}\" 병합", + "fleet.organization.mergeInto": "병합 대상", + "fleet.organization.chooseTag": "유지할 태그를 선택하세요", + "fleet.organization.mergeWarning": "모든 카메라 할당이 유지할 태그로 이동하며, 원본 태그는 삭제됩니다.", + "fleet.organization.tagsMerged": "태그 병합됨", + "fleet.organization.saveError": "저장할 수 없습니다: {message}", + "fleet.organization.deleteError": "삭제할 수 없습니다: {message}", + "fleet.locationType.site": "사이트", + "fleet.locationType.building": "건물", + "fleet.locationType.floor": "층", + "fleet.locationType.area": "구역", + "fleet.locationType.zone": "존", + "fleet.locationType.system": "시스템", + "fleet.bulk.title": "선택한 카메라 정리", + "fleet.bulk.description": "동시 처리 제한을 적용하여 {count}개 카메라에 위치 및 태그 변경 사항을 적용합니다.", + "fleet.bulk.location": "위치 할당", + "fleet.bulk.locationHelp": "선택한 모든 카메라가 선택한 위치로 이동합니다.", + "fleet.bulk.keepLocations": "현재 위치 유지", + "fleet.bulk.tags": "태그 할당", + "fleet.bulk.tagsHelp": "다른 할당을 변경하지 않고 태그를 추가 또는 제거하거나, 전체 태그 세트를 명시적으로 교체합니다.", + "fleet.bulk.tagOperation.none": "유지", + "fleet.bulk.tagOperation.add": "추가", + "fleet.bulk.tagOperation.remove": "제거", + "fleet.bulk.tagOperation.replace": "모두 교체", + "fleet.bulk.replaceWarning": "모두 교체는 선택 항목을 적용하기 전에 모든 현재 태그를 제거합니다. 선택 항목이 비어 있으면 모든 태그가 삭제됩니다.", + "fleet.bulk.apply": "변경 사항 적용", + "fleet.bulk.working": "변경 사항 적용 중…", + "fleet.bulk.success": "{count}개 카메라 업데이트됨", + "fleet.bulk.partial": "{succeeded}개 카메라 업데이트됨; {failed}개 실패", + "fleet.bulk.error": "카메라를 정리할 수 없습니다: {message}", + "fleet.bulk.failures": "업데이트할 수 없는 카메라", + "fleet.queues.degraded": "저하된 스트림", + "fleet.queues.offline": "오프라인 카메라", + "fleet.queues.oldest": "가장 오래됨: {time}", + "fleet.queues.noneActive": "활성 조건 없음", + "fleet.views.title": "저장된 뷰", + "fleet.views.choose": "저장된 뷰 선택", + "fleet.views.none": "저장된 뷰가 없습니다", + "fleet.views.shared": "공유됨", + "fleet.views.saveCurrent": "현재 뷰 저장", + "fleet.views.name": "뷰 이름", + "fleet.views.share": "모든 운영자와 공유", + "fleet.views.saved": "플릿 뷰 저장됨", + "fleet.views.saveError": "뷰를 저장할 수 없습니다: {message}", + "fleet.views.deleted": "플릿 뷰 삭제됨", + "fleet.views.deleteConfirm": "저장된 뷰 \"{name}\"을(를) 삭제하시겠습니까?", + "fleet.views.deleteError": "뷰를 삭제할 수 없습니다: {message}", + "fleet.views.unsupported": "이 저장된 셀렉터는 현재 필터 컨트롤로 표현할 수 없습니다.", + "collections.manage": "컬렉션", + "collections.all": "모든 컬렉션", + "collections.filter": "컬렉션", + "collections.loadMembersError": "컬렉션 카메라를 불러올 수 없습니다: {message}", + "collections.title": "카메라 컬렉션", + "collections.subtitle": "운영, 저장된 뷰 및 후속 워크플로우를 위해 재사용 가능한 카메라 그룹을 만드세요.", + "collections.listDescription": "정적 컬렉션은 명시적 구성을 유지하며, 스마트 컬렉션은 플릿 규칙을 지속적으로 평가합니다.", + "collections.create": "컬렉션 생성", + "collections.edit": "컬렉션 편집", + "collections.editorDescription": "컬렉션 정의는 안정적인 카메라, 위치 및 태그 UUID를 사용합니다.", + "collections.backToList": "컬렉션으로 돌아가기", + "collections.type": "컬렉션 유형", + "collections.type.static": "정적", + "collections.type.smart": "스마트", + "collections.description": "설명", + "collections.shared": "공유 컬렉션", + "collections.sharedHelp": "다른 권한이 있는 사용자가 이 컬렉션을 볼 수 있도록 허용합니다. 카메라 접근 규칙은 계속 적용됩니다.", + "collections.typeChangeWarning": "컬렉션 유형을 변경하면 구성 모델이 대체됩니다. 이전 유형의 정적 멤버 또는 스마트 규칙은 더 이상 적용되지 않습니다.", + "collections.selectorError": "셀렉터가 유효하지 않습니다: {message}", + "collections.created": "컬렉션 생성됨", + "collections.updated": "컬렉션 업데이트됨", + "collections.saveError": "컬렉션을 저장할 수 없습니다: {message}", + "collections.loadError": "컬렉션을 불러올 수 없습니다: {message}", + "collections.cameras": "카메라", + "collections.visibility.shared": "공유", + "collections.visibility.private": "비공개", + "collections.selectorRedacted": "규칙 비공개", + "collections.emptyTitle": "아직 컬렉션이 없습니다", + "collections.emptyAdmin": "카메라 선택을 재사용하려면 정적 그룹 또는 스마트 규칙 기반 뷰를 만드세요.", + "collections.emptyViewer": "카메라 범위에서 사용할 수 있는 공유 컬렉션이 없습니다.", + "collections.deleteConfirm": "컬렉션 \"{name}\"을(를) 삭제하시겠습니까?", + "collections.deleted": "컬렉션이 삭제되었습니다", + "collections.deleteError": "컬렉션을 삭제할 수 없습니다: {message}", + "collections.preview.title": "규칙 미리보기", + "collections.preview.matches": "일치하는 카메라 {count}대", + "collections.preview.action": "미리보기", + "collections.preview.hide": "미리보기 숨기기", + "collections.preview.loading": "평가 중…", + "collections.preview.empty": "현재 일치하는 카메라가 없습니다.", + "collections.preview.sample": "{total}개 일치 항목 중 {count}개 카메라 샘플 표시 중.", + "collections.preview.error": "컬렉션을 미리볼 수 없습니다: {message}", + "collections.members.title": "정적 구성원", + "collections.members.selected": "모든 페이지에서 {count}대 카메라 선택됨", + "collections.members.search": "카메라 검색…", + "collections.members.selectPage": "이 페이지 선택", + "collections.members.empty": "검색과 일치하는 카메라가 없습니다.", + "collections.builder.title": "스마트 규칙", + "collections.builder.description": "규칙은 현재 카메라 구성, 설정, 기능 및 상태를 기준으로 평가됩니다.", + "collections.builder.match": "일치", + "collections.builder.allRules": "모든 규칙", + "collections.builder.anyRule": "임의의 규칙", + "collections.builder.addRule": "규칙 추가", + "collections.builder.removeRule": "규칙 제거", + "collections.builder.matchesAll": "완전한 규칙이 없으면 이 컬렉션은 사용자의 권한 범위 내 모든 카메라와 일치합니다.", + "collections.builder.incompleteRule": "저장 전에 모든 규칙을 완료하거나 삭제하세요.", + "collections.builder.chooseLocation": "위치 하위 트리 선택", + "collections.builder.vendorPlaceholder": "제조사 이름, 쉼표로 구분", + "collections.builder.modelPlaceholder": "모델 이름, 쉼표로 구분", + "collections.builder.advancedMode": "고급 JSON", + "collections.builder.visualMode": "시각적 빌더", + "collections.builder.cannotVisualize": "이 선택기에는 시각적 빌더로 안전하게 표현할 수 없는 중첩 또는 고급 로직이 포함되어 있습니다.", + "collections.rule.location_subtree": "위치가 다음 범위 내", + "collections.rule.camera_uuid": "특정 카메라", + "collections.rule.tag_any": "태그가 하나라도 있음", + "collections.rule.tag_all": "모든 태그 포함", + "collections.rule.tag_none": "태그 없음", + "collections.rule.health": "상태가", + "collections.rule.enabled": "카메라가", + "collections.rule.recording_mode": "녹화 모드가", + "collections.rule.capability_any": "기능 중 하나 이상 보유", + "collections.rule.capability_all": "모든 기능 보유", + "collections.rule.vendor": "제조사", + "collections.rule.model": "모델", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "오디오 백채널", + "streamHealth.observedFps": "관측 FPS", + "streamHealth.expectedFps": "예상", + "streamHealth.fpsHelp": "LightNVR에서 관측한 값이며, 예상 값은 카메라 스트림 메타데이터에서 가져옵니다.", + "login.passwordChanged": "비밀번호가 변경되었습니다. 새 비밀번호로 로그인하세요.", + "passwordChangeRequired.title": "기본 비밀번호 변경", + "passwordChangeRequired.description": "이 설치 환경은 여전히 기본 관리자 비밀번호를 사용 중입니다. LightNVR을 계속 사용하려면 비밀번호를 변경하세요. MFA가 활성화된 경우 다음 로그인 시 확인됩니다.", + "passwordChangeRequired.currentPassword": "현재 비밀번호", + "passwordChangeRequired.newPassword": "새 비밀번호", + "passwordChangeRequired.confirmPassword": "새 비밀번호 확인", + "passwordChangeRequired.passwordHelp": "8자 이상 입력하세요. 비밀번호는 admin일 수 없습니다.", + "passwordChangeRequired.submit": "비밀번호 변경", + "passwordChangeRequired.saving": "비밀번호 변경 중...", + "passwordChangeRequired.error.currentRequired": "현재 비밀번호를 입력하세요.", + "passwordChangeRequired.error.tooShort": "새 비밀번호는 8자 이상이어야 합니다.", + "passwordChangeRequired.error.defaultPassword": "새 비밀번호는 admin일 수 없습니다.", + "passwordChangeRequired.error.mismatch": "새 비밀번호가 일치하지 않습니다.", + "passwordChangeRequired.error.generic": "비밀번호를 변경할 수 없습니다. 다시 시도하세요.", + "settings.tab.health": "상태", + "settings.tab.workspaces": "작업 공간", + "settings.health.title": "호스트 및 하드웨어 상태", + "settings.health.description": "디바이스 경로 또는 비밀 정보를 노출하지 않고 운영 체제 및 하드웨어 모니터링을 설정합니다.", + "settings.health.enabled": "상태 모니터링 활성화", + "settings.health.enabledHelp": "지원되는 호스트, 서비스, 저장소, 네트워크 및 하드웨어 신호를 수집합니다.", + "settings.health.profile": "정책 프로필", + "settings.health.profileHelp": "Balanced는 기본값이며, Conservative는 알림 전에 더 강한 근거를 요구합니다.", + "settings.health.profile.balanced": "Balanced", + "settings.health.profile.conservative": "Conservative", + "settings.health.hardwareProvider": "하드웨어 제공자", + "settings.health.provider.auto": "자동 (커널 제공자)", + "settings.health.provider.smartctl": "smartctl (명시적)", + "settings.health.providerHelp.auto": "제한된 sysfs, NVMe 및 커널 제공자만 사용하며, smartctl은 추론하지 않습니다.", + "settings.health.providerHelp.smartctl": "발견된 디바이스에 대해 선택적 제한 smartctl JSON 제공자를 명시적으로 활성화합니다.", + "settings.health.providerHelp.disabled": "선택적 하드웨어 제공자를 비활성화하되 이식 가능한 상태 모니터링은 유지합니다.", + "settings.health.writeProbe": "저장소 쓰기 프로브 활성화", + "settings.health.writeProbeHelp": "구성된 제한 녹화 대상 프로브를 주기적으로 수행합니다.", + "settings.health.cadences": "샘플링 주기", + "settings.health.cadencesHelp": "간격은 빠른 것부터 디바이스 샘플링까지 순서를 유지하며 서버 한계 내에 있어야 합니다.", + "settings.health.fastInterval": "빠른 간격", + "settings.health.normalInterval": "일반 간격", + "settings.health.slowInterval": "느린 간격", + "settings.health.deviceInterval": "디바이스 간격", + "settings.health.presenceInterval": "존재 확인 간격", + "settings.health.retention": "사고 보관 기간", + "settings.health.conditions": "조건 재정의", + "settings.health.conditionsHelp": "유효 정책 레지스트리가 반환한 조건 코드와 단위만 재정의할 수 있습니다.", + "settings.health.conditionOverride": "조건 재정의", + "settings.health.overrideMode": "재정의 모드", + "settings.health.overrideModeHelp": "선택한 프로파일을 상속하거나, 다른 제한된 프로파일을 선택하거나, 조건을 비활성화하거나, 검증된 임계값을 설정합니다.", + "settings.health.profileDefault": "선택한 프로파일 사용", + "settings.health.custom": "사용자 지정 임계값", + "settings.health.warning": "경고 임계값", + "settings.health.critical": "치명 임계값", + "settings.health.recovery": "복구 임계값", + "settings.health.warning_for_seconds": "경고 지속 시간(초)", + "settings.health.critical_for_seconds": "치명 지속 시간(초)", + "settings.health.recovery_for_seconds": "복구 지속 시간(초)", + "settings.health.clearOverrides": "재정의 삭제", + "settings.health.registryUnavailable": "서버가 조건 레지스트리를 반환하지 않았습니다. 재정의 편집 전에 새로고침하십시오.", + "settings.health.resetDefaults": "상태 기본값으로 재설정", + "settings.health.reloadGuidance": "저장은 원자적으로 수행됩니다. 저장 성공 후 새로고침하여 유효 정책을 확인하십시오. 서버가 명시적으로 요청할 때만 재시작하십시오.", + "settings.health.validation.profile": "지원되는 상태 프로파일을 선택하십시오.", + "settings.health.validation.provider": "지원되는 하드웨어 공급자를 선택하십시오.", + "settings.health.validation.healthFastIntervalSeconds": "빠른 간격은 5~60초 사이의 정수여야 합니다.", + "settings.health.validation.healthNormalIntervalSeconds": "일반 간격은 15~600초 사이의 정수여야 합니다.", + "settings.health.validation.healthSlowIntervalSeconds": "느린 간격은 60~3600초 사이의 정수여야 합니다.", + "settings.health.validation.healthDeviceIntervalSeconds": "장치 간격은 300~86400초 사이의 정수여야 합니다.", + "settings.health.validation.healthPresenceIntervalSeconds": "존재 감지 간격은 15~3600초 사이의 정수여야 합니다.", + "settings.health.validation.healthIncidentRetentionDays": "사고 보관 기간은 7~3650일 사이의 정수여야 합니다.", + "settings.health.validation.ordered": "샘플링 간격은 빠른, 일반, 느린, 장치 순서로 정렬되어야 합니다.", + "settings.health.validation.overrides": "조건 재정의는 서버 레지스트리의 고유 코드와 지원되는 프로파일을 사용해야 합니다.", + "settings.health.validation.thresholds": "사용자 지정 임계값은 조건의 단위 범위 내의 유한한 값이어야 합니다.", + "settings.health.validation.thresholdOrder": "경고, 치명, 복구 임계값은 조건의 알림 방향과 히스테리시스를 유지해야 합니다.", + "settings.health.validation.dwell": "지속 시간은 7일 이내의 정수 초여야 하며, 경고 및 복구 지속 시간은 0일 수 없습니다.", + "workspaces.title": "운영자 작업 공간", + "workspaces.description": "내비게이션 및 페이지 UI에 표시할 전문 작업 공간을 선택하세요.", + "workspaces.saved": "작업 공간 환경 설정이 저장되었습니다", + "workspaces.saveError": "작업 공간 환경 설정을 저장할 수 없습니다: {message}", + "workspaces.loadError": "작업 공간 환경 설정을 불러올 수 없습니다.", + "workspaces.showWorkspace": "{name} 표시", + "workspaces.authorizationNote": "이 설정은 표시에만 영향을 줍니다. 직접 URL 및 API 접근은 여전히 권한 정책에 따릅니다.", + "workspaces.liveNavigator": "향상된 라이브 내비게이터", + "workspaces.liveNavigatorDescription": "위치 트리, 가용성 필터, 저장된 레이아웃, 최근 이벤트.", + "workspaces.investigation": "조사", + "workspaces.investigationDescription": "녹화 증거 검색, 상관 분석, 보호 및 내보내기.", + "settings.reduceMotion": "모션 감소", + "settings.reduceMotionHelp": "필수적이지 않은 애니메이션 및 전환을 비활성화합니다. 자동은 운영체제 설정을 따릅니다.", + "settings.reduceMotionPreference": "모션 감소 환경 설정", + "settings.reduceMotionAuto": "자동", + "settings.reduceMotionOn": "켜기", + "settings.reduceMotionOff": "끄기", + "settings.audioCompliance": "오디오 규정 준수", + "settings.disableAudioGlobally": "이 인스턴스에서 오디오 비활성화", + "settings.audioDisabled": "오디오가 전역으로 비활성화됨", + "settings.audioComplianceHelp": "이 인스턴스에서 실시간 청취, 양방향 통화 및 새 녹화의 오디오를 차단합니다. 저장 시 활성 go2rtc 미디어 세션이 재시작됩니다. 기존 녹화물은 수정되지 않습니다.", + "tokens.manage": "API 접근 관리", + "tokens.title": "API 접근 — {username}", + "tokens.description": "통합을 위해 범위를 좁게 지정한 자격 증명을 만들고 각각 독립적으로 폐기할 수 있습니다.", + "tokens.recommendedTitle": "범위 지정 토큰을 권장합니다", + "tokens.recommendedDescription": "모든 토큰은 만료일이 있으며, 명시적 작업과 카메라 범위를 가지고 있고, 사용자의 현재 접근 정책을 초과할 수 없습니다.", + "tokens.coverageNotice": "사용 가능한 권한은 이 서버에서 적용하는 권한을 반영합니다. 토큰은 해당 사용자가 이미 보유한 권한만 사용할 수 있습니다.", + "tokens.createTitle": "범위 지정 토큰 생성", + "tokens.createDescription": "통합별로 하나의 토큰을 사용하면 식별, 회전 및 폐기가 다른 것에 방해 없이 가능합니다.", + "tokens.name": "통합 이름", + "tokens.namePlaceholder": "예: 북쪽 차고 PTZ 브리지", + "tokens.expiry": "만료 기간", + "tokens.expiryDays": "{days}일", + "tokens.actions": "허용된 작업", + "tokens.actionsHelp": "이 통합에 필요한 항목만 선택하세요. 파괴적 작업은 별도의 토큰을 사용해야 합니다.", + "tokens.destructive": "파괴적", + "tokens.noEnforcedActions": "이 서버 버전에서는 토큰으로 사용할 수 있는 작업이 없습니다.", + "tokens.scope.label": "카메라 범위", + "tokens.scope.all": "전체 카메라", + "tokens.scope.collection": "공유 컬렉션", + "tokens.scope.selector": "사용자 지정 선택기", + "tokens.scope.chooseCollection": "공유 카메라 컬렉션", + "tokens.scope.allValue": "전체 카메라", + "tokens.scope.collectionValue": "컬렉션: {name}", + "tokens.scope.selectorValue": "사용자 지정 동적 선택기", + "tokens.create": "토큰 생성", + "tokens.creating": "토큰 생성 중…", + "tokens.createdSuccess": "범위 지정 API 토큰이 생성되었습니다", + "tokens.createError": "API 토큰을 생성할 수 없습니다: {message}", + "tokens.invalidResponse": "서버에서 불완전한 자격 증명 응답을 반환했습니다.", + "tokens.existingTitle": "기존 토큰", + "tokens.existingDescription": "생성 후 접두사와 메타데이터만 사용할 수 있습니다.", + "tokens.emptyTitle": "활성 토큰 없음", + "tokens.emptyDescription": "API 접근이 필요한 첫 통합을 위해 범위 지정 토큰을 생성하세요.", + "tokens.showInactive": "비활성 {count}개 표시", + "tokens.status.active": "활성", + "tokens.status.expired": "만료됨", + "tokens.status.revoked": "폐기됨", + "tokens.expires": "만료일", + "tokens.expiresValue": "만료일: {date}", + "tokens.created": "생성일", + "tokens.lastUsed": "마지막 사용", + "tokens.revoke": "폐기", + "tokens.revoking": "폐기 중…", + "tokens.revokeConfirm": "“{description}”을(를) 폐기하시겠습니까? 이 토큰을 사용하는 요청은 즉시 중단됩니다.", + "tokens.revokedSuccess": "API 토큰이 폐기되었습니다", + "tokens.revokeError": "API 토큰을 폐기할 수 없습니다: {message}", + "tokens.validation.missing_description": "이 토큰을 사용할 통합 이름을 입력하세요.", + "tokens.validation.description_too_long": "통합 이름은 128자 이내로 입력하세요.", + "tokens.validation.invalid_expiry": "토큰 유효 기간을 1일에서 365일 사이로 선택하세요.", + "tokens.validation.missing_actions": "허용된 작업을 하나 이상 선택하세요.", + "tokens.validation.invalid_action": "선택한 작업 중 하나 이상이 이 서버에서 토큰 사용이 허용되지 않습니다.", + "tokens.validation.invalid_scope": "유효한 카메라 범위를 선택하세요.", + "tokens.validation.requires_all_scope": "카메라 외 권한은 전체 카메라 플릿 범위가 필요합니다. 해당 범위를 선택하거나 해당 권한을 제거하세요.", + "tokens.validation.missing_collection": "사용 가능한 공유 컬렉션을 선택하세요.", + "tokens.validation.invalid_selector": "사용자 지정 카메라 선택기를 완성하거나 수정하세요.", + "tokens.secret.oneTime": "한 번만 표시됨", + "tokens.secret.scopedTitle": "이 범위 지정 토큰을 지금 저장하세요", + "tokens.secret.legacyTitle": "이 레거시 API 키를 지금 저장하세요", + "tokens.secret.scopedDescription": "lightNVR은 이 토큰의 해시만 저장합니다. 분실 시 폐기하고 새로 생성하세요.", + "tokens.secret.legacyDescription": "이 호환 키는 여기에 한 번만 표시됩니다. 다른 키를 생성하면 이 키는 무효화됩니다.", + "tokens.secret.value": "API 자격 증명", + "tokens.secret.copied": "복사됨", + "tokens.secret.copySuccess": "API 자격 증명이 복사되었습니다", + "tokens.secret.copyError": "자동으로 복사할 수 없습니다. 자격 증명을 수동으로 선택하여 복사하세요.", + "tokens.secret.savedConfirm": "이 자격 증명을 안전하게 저장했습니다", + "tokens.secret.savedHelp": "확인 시 이 대화 상자가 닫힙니다. 전체 값은 다시 표시할 수 없습니다.", + "tokens.legacy.title": "레거시 호환 키", + "tokens.legacy.description": "레거시 키는 이 사용자의 모든 권한을 가지며, 만료되지 않고, 카메라 또는 작업별로 범위를 지정할 수 없습니다.", + "tokens.legacy.warning": "엔드포인트가 범위 지정 토큰 적용으로 이전되지 않은 기존 통합에만 생성하세요. 생성 시 이전 레거시 키는 즉시 무효화됩니다.", + "tokens.legacy.generate": "레거시 키 생성", + "tokens.legacy.confirm": "새 레거시 키를 생성하시겠습니까? 현재 사용자의 레거시 키는 즉시 무효화됩니다.", + "tokens.legacy.createdSuccess": "레거시 API 키가 생성되었습니다", + "tokens.legacy.createError": "레거시 API 키를 생성할 수 없습니다: {message}", + "audit.manage": "감사 이력", + "audit.title": "보안 및 접근 감사", + "audit.description": "자격 증명을 노출하지 않고 로그인 결과, 접근 결정 및 민감한 정책 변경을 추적합니다.", + "audit.retention": "보존", + "audit.retentionDescription": "이벤트는 현재 {days}일 동안 보존됩니다. 이 값을 줄이면 이전 기록이 즉시 삭제됩니다.", + "audit.retentionDays": "일", + "audit.retentionInvalid": "1일에서 3650일 사이의 보존 기간을 선택하세요.", + "audit.retentionSaved": "감사 보존 설정이 저장되었습니다. 만료된 이벤트 {count}개가 삭제되었습니다.", + "audit.retentionError": "감사 보존 설정을 저장할 수 없습니다: {message}", + "audit.filters": "필터", + "audit.clearFilters": "필터 초기화", + "audit.applyFilters": "필터 적용", + "audit.actor": "행위자", + "audit.unauthenticated": "미인증", + "audit.outcome": "결과", + "audit.action": "정확한 작업", + "audit.filterToAction": "이 작업으로 필터링", + "audit.since": "시작일", + "audit.until": "종료일", + "audit.invalidDateRange": "시작일은 종료일보다 이전이어야 합니다.", + "audit.source": "소스 주소", + "audit.target": "대상", + "audit.targetUuid": "대상 UUID", + "audit.noTarget": "시스템 전체", + "audit.requestId": "요청 ID", + "audit.apiToken": "범위 토큰 ID", + "audit.showDetails": "상세 보기", + "audit.hideDetails": "상세 숨기기", + "audit.pageSize": "페이지당", + "audit.resultRange": "{total}개 중 {start}–{end} 표시", + "audit.empty": "일치하는 감사 이벤트 없음", + "audit.emptyDescription": "하나 이상의 필터를 초기화하거나 새로운 보안 활동을 기다리세요.", + "audit.exportPage": "이 페이지 내보내기", + "audit.exporting": "내보내는 중…", + "audit.exported": "감사 페이지가 내보내졌습니다", + "audit.exportError": "감사 이벤트를 내보낼 수 없습니다: {message}", + "audit.pagination": "감사 이력 페이지", + "audit.page": "{page} 페이지", + "audit.modesTitle": "허용된 결정", + "audit.modesDescription": "허용된 읽기 전용 접근이 각 작업에 대해 어떻게 기록되는지 선택하세요. 변경을 수반하는 요청, 거부, 오류, 로그인은 항상 기록됩니다. 요약 모드는 {minutes}분마다 사용자, 카메라, 클라이언트별로 카운트와 함께 한 항목만 기록합니다.", + "audit.mode.record": "각각 기록", + "audit.mode.summarize": "요약", + "audit.mode.off": "끄기", + "audit.modeOffWarning": "이 작업에 대한 허용 접근이 감사 이력에 표시되지 않습니다.", + "audit.modesSaved": "감사 결정 모드가 저장되었습니다", + "audit.modesError": "감사 결정 모드를 저장할 수 없습니다: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "이벤트 유형", + "audit.eventTypeSummary": "요약", + "audit.eventTypeDecision": "개별 결정", + "access.cameraSearch": "카메라 검색", + "access.cameraSearchPlaceholder": "검색하려면 두 글자 이상 입력하세요…", + "access.cameraSearchHint": "카메라 이름, UUID, 주소, 위치, 태그, 제조사 또는 모델로 검색하세요.", + "access.cameraSelected": "선택됨", + "access.cameraAdd": "추가", + "access.cameraLimit": "선택기에는 최대 64개의 명시적 카메라를 포함할 수 있습니다. 더 큰 범위는 위치 또는 태그 규칙을 사용하세요.", + "access.roles.manage": "역할 관리", + "access.roles.title": "권한 역할", + "access.roles.description": "작업을 재사용 가능한 역할로 묶고 카메라 범위에 해당 역할을 부여하세요.", + "access.roles.create": "역할 생성", + "access.roles.newRole": "새 역할", + "access.roles.copyName": "{name} 복사본", + "access.roles.clone": "복제", + "access.roles.builtin": "기본 제공", + "access.roles.builtinHelp": "기본 제공 역할은 업그레이드 시에도 안전한 고정 템플릿입니다. 복제하여 사용자 지정하세요.", + "access.roles.actionCount": "{count}개 작업", + "access.roles.destructive": "민감한 작업", + "access.roles.notEnforced": "아직 어떤 엔드포인트에서도 적용되지 않음", + "access.roles.destructiveWarning": "이 역할은 구성 또는 증거를 변경할 수 있습니다. 해당 권한이 필요한 범위에만 부여하세요.", + "access.roles.created": "역할 생성됨", + "access.roles.updated": "역할 업데이트됨", + "access.roles.deleted": "역할 삭제됨", + "access.roles.saveError": "역할을 저장할 수 없습니다: {message}", + "access.roles.deleteError": "역할을 삭제할 수 없습니다: {message}", + "access.roles.deleteConfirm": "역할 \"{name}\"을(를) 삭제하시겠습니까? 권한 부여에서 참조되는 역할은 삭제할 수 없습니다.", + "access.policy.manage": "접근 관리", + "access.policy.column": "접근", + "access.policy.scopedShort": "범위 지정됨", + "access.policy.title": "접근 정책 — {username}", + "access.policy.description": "기본 거부 역할 권한 부여를 관리하고 카메라 범위를 미리 봅니다.", + "access.policy.tab.grants": "권한 부여", + "access.policy.tab.test": "접근 테스트", + "access.policy.scopedWarning": "일치하는 권한 부여 및 카메라 범위에서 허용된 작업만 실행됩니다.", + "access.policy.grants": "역할 권한 부여", + "access.policy.grantsDescription": "권한 부여는 하나의 역할과 전체 카메라, 공유 컬렉션 또는 사용자 지정 카메라 선택기를 조합합니다.", + "access.policy.addGrant": "권한 부여 추가", + "access.policy.noGrants": "권한 부여가 구성되지 않음", + "access.policy.noGrantsHelp": "이 사용자가 접근 권한이 없어야 하는 경우가 아니라면, 범위 지정 정책을 활성화하기 전에 최소 하나의 권한 부여를 추가하세요.", + "access.policy.role": "역할", + "access.policy.chooseRole": "역할 선택", + "access.policy.scope": "카메라 범위", + "access.policy.allCameras": "전체 카메라", + "access.policy.collectionScope": "공유 컬렉션", + "access.policy.collection": "카메라 컬렉션", + "access.policy.chooseCollection": "공유 컬렉션 선택", + "access.policy.collectionHelp": "카메라가 추가, 제거되거나 규칙에 따라 매칭될 때 접근이 컬렉션을 추적합니다.", + "access.policy.dynamicScope": "동적 선택기", + "access.policy.activateConfirm": "{username}에 대해 기본 거부 범위 지정 정책을 활성화하시겠습니까? 일치하는 권한 부여가 없는 작업은 거부됩니다.", + "access.policy.emptyConfirm": "권한 부여 없이 {username}에 대해 범위 지정 정책을 활성화하시겠습니까? 이는 정책으로 제어되는 모든 접근을 의도적으로 제거합니다.", + "access.policy.saved": "액세스 정책이 저장되었습니다", + "access.policy.saveError": "액세스 정책을 저장할 수 없습니다: {message}", + "access.policy.version": "정책 버전 {version}", + "access.policy.unsaved": "저장되지 않은 변경 사항", + "access.policy.validation.invalid_mode": "유효한 평가 모드를 선택하세요.", + "access.policy.validation.missing_role": "모든 권한 부여는 사용 가능한 역할을 참조해야 합니다.", + "access.policy.validation.invalid_scope": "모든 권한 부여는 전체 플릿, 공유 컬렉션 또는 선택기 범위를 사용해야 합니다.", + "access.policy.validation.invalid_selector": "저장하기 전에 모든 카메라 선택기를 완료하거나 수정하세요.", + "access.policy.validation.missing_collection": "모든 컬렉션 권한 부여에 사용 가능한 공유 컬렉션을 선택하세요.", + "access.policy.validation.duplicate_grant": "저장하기 전에 중복된 역할 및 범위 권한 부여를 제거하세요.", + "access.test.title": "실효 액세스 테스트", + "access.test.description": "{username}(으)로 저장된 작업과 카메라를 실행하지 않고 평가합니다.", + "access.test.saveFirst": "테스트 전에 권한 부여 변경 사항을 저장하거나 폐기하여 결과가 여기에 표시된 정책을 반영하도록 하세요.", + "access.test.action": "작업", + "access.test.camera": "카메라", + "access.test.run": "액세스 테스트", + "access.test.running": "테스트 중…", + "access.test.allowed": "허용", + "access.test.denied": "거부", + "access.test.version": "버전 {version}", + "access.test.source": "소스: {source} · 역할: {role}", + "recordings.pullToRefresh": "당겨서 녹화 새로고침", + "recordings.releaseToRefresh": "놓아서 녹화 새로고침", + "recordings.refreshing": "녹화 새로고침 중…", + "recordings.refreshed": "녹화가 새로고침되었습니다", + "recordings.refreshFailed": "녹화를 새로고침할 수 없습니다: {message}", + "recordings.download": "다운로드", + "recordings.tags": "태그", + "recordings.selectRecording": "녹화 선택", + "timeline.legend.recording": "녹화", + "timeline.legend.detection": "감지 이벤트", + "timeline.detectionEvent": "감지 이벤트", + "streams.showCredentials": "자격 증명 표시", + "streams.hideCredentials": "자격 증명 숨기기", + "streams.streamSuccessfullyEnabled": "스트림이 성공적으로 활성화되었습니다.", + "streams.errorEnablingStream": "스트림 활성화 오류: {message}", + "system.health.tab": "상태", + "system.health.operatorView": "운영 상태", + "system.health.title": "시스템 상태", + "system.health.loading": "시스템 상태 불러오는 중…", + "system.health.loadError": "시스템 상태를 불러올 수 없습니다.", + "system.health.refreshing": "새로고침 중…", + "system.health.activeIncidentCount": "활성 장애 {count}건", + "system.health.coverage": "범위", + "system.health.monitoringDisabled": "상태 모니터링이 비활성화되었습니다", + "system.health.lastRecordedValue": "마지막 기록 값", + "system.health.monitoringDisabledHelp": "현재 상태 정보가 수집되지 않고 있습니다. 설정 → 상태 에서 상태 모니터링을 활성화하고, 저장 후 재시작이 요청되면 재시작하세요. 장애 이력은 과거 이벤트를 표시하며 현재 리소스 사용량을 나타내지 않습니다.", + "system.health.monitoringRestartRequired": "저장된 구성에서 상태 모니터링이 활성화되어 있지만, 실행 중인 샘플러는 아직 비활성화 상태입니다. 변경 사항을 적용하려면 LightNVR을 재시작하세요. 장애 이력은 과거 이벤트를 표시합니다.", + "system.health.containerCoverage": "호스트 범위 제한", + "system.health.hostHardwareUnavailable": "이 설치 환경에서는 컨테이너 및 마운트된 리소스의 상태를 확인할 수 있지만, 호스트 하드웨어는 사용할 수 없습니다. 누락된 호스트 값은 상태 양호가 아닌 알 수 없음입니다.", + "system.health.coverageUnknown": "완료된 상태 스냅샷이 아직 없습니다. 수집이 완료될 때까지 값은 알 수 없음으로 표시됩니다.", + "system.health.coverageComplete": "이 설치 환경에서 확인할 수 있는 모든 상태 정보가 성공적으로 수집되었습니다.", + "system.health.coveragePartial": "범위가 부분적입니다. {count}개의 관측 또는 수집 검사를 사용할 수 없거나, 오래되었거나, 불완전합니다.", + "system.health.effectiveScope": "실효 범위", + "system.health.activeIncidents": "활성 장애", + "system.health.noActiveIncidents": "표시된 범위에서 보고된 활성 장애가 없습니다.", + "system.health.duration": "지속 시간", + "system.health.currentValue": "현재 값", + "system.health.thresholds": "임계값 및 지속 시간", + "system.health.thresholdSummary": "경고 {warning}, 심각 {critical}, 복구 {recovery} {unit}; 경고 지속 {seconds}초", + "system.health.remediation": "권장 조치", + "system.health.facts": "상태 정보", + "system.health.group.resources": "리소스", + "system.health.group.storage": "저장소", + "system.health.group.hardware": "하드웨어", + "system.health.group.network": "네트워크", + "system.health.group.clock": "시계", + "system.health.group.components": "구성 요소", + "system.health.noFacts": "이 그룹에 표시할 정보가 없습니다.", + "system.health.observationState": "기능 및 최신 상태", + "system.health.valueUnavailable": "하나 이상의 값을 알 수 없습니다", + "system.health.componentStatus": "모니터링 구성 요소", + "system.health.collectors": "수집기", + "system.health.collectorSummary": "{total}개 등록됨 · {attention}개 확인 필요", + "system.health.collectorsNeedingAttention": "확인이 필요한 수집기", + "system.health.collectionFailures": "{count}개 실패 또는 시간 초과", + "system.health.stale": "만료됨", + "system.health.eventDelivery": "이벤트 전달", + "system.health.degraded": "성능 저하", + "system.health.circularDelivery": "유일한 알림 경로이므로 자체 장애를 독립적으로 보고할 수 없습니다.", + "system.health.incidentPersistence": "사고 저장", + "system.health.persistenceSummary": "{pending}개 대기 중 · {failures}개 실패 · {retries}개 재시도", + "system.health.recentSamples": "최근 수집 활동", + "system.health.recentSamplesHelp": "최대 {count}개의 서버 측 생성 요약입니다. 이는 커버리지 활동이며 값 차트가 아닙니다.", + "system.health.sampleSequence": "생성 {sequence}", + "system.health.sampleCoverage": "{observations}개 관측됨 · {dropped}개 유실됨", + "system.health.noSamples": "완료된 수집 생성이 없습니다.", + "system.health.incidentHistory": "사고 이력", + "system.health.incidentHistoryHelp": "최신 사고부터 표시됩니다. 이력은 제한된 페이지 단위로 로드됩니다.", + "system.health.loadingHistory": "사고 이력 로드 중…", + "system.health.historyError": "사고 이력을 로드할 수 없습니다.", + "system.health.emptyHistory": "기록된 사고가 없습니다.", + "system.health.firstSeen": "최초 감지", + "system.health.lastSeen": "마지막 감지", + "system.health.deliveryState": "전달 상태", + "system.health.historyPagination": "사고 이력 페이지", + "system.health.pageCount": "이 페이지의 {count}개 이벤트", + "system.health.remediation.memory": "메모리 압력을 줄이고, 프로세스 및 cgroup 제한을 확인하며, 최근 OOM 활동을 검토하세요.", + "system.health.remediation.cpu": "지속적인 CPU 사용량을 식별하고, 제한을 변경하기 전에 서비스 처리량을 확인하세요.", + "system.health.remediation.io": "저장소 지연 시간과 활성 쓰기 작업을 확인하고, 장애를 유발할 수 있는 유지보수 전에 녹화 파일을 보존하세요.", + "system.health.remediation.filesystem": "해당 논리 파일 시스템의 여유 공간 또는 inode를 확인하고, 쓰기 가능한 상태를 유지하는지 검증하세요.", + "system.health.remediation.thermal": "냉각을 개선하고 부하를 줄이세요. 온도가 종료 한도에 도달하기 전에 팬과 통풍구를 점검하세요.", + "system.health.remediation.network": "독립적인 네트워크 경로에서 인터페이스, 링크, 스위치 및 오류 카운터를 확인하세요.", + "system.health.remediation.clock": "이벤트 타임스탬프를 신뢰하기 전에 시간 동기화를 복원하고 호스트 클럭 소스를 확인하세요.", + "system.health.remediation.process": "LightNVR 리소스 제한 및 로그를 확인한 후, 부하를 줄이거나 검증된 제한을 상향 조정하세요.", + "system.health.remediation.storage": "교체 또는 수리 전에 중요한 영상을 백업하고 매핑된 저장 장치를 점검하세요.", + "system.health.remediation.hardware": "영향을 받은 하드웨어 및 플랫폼 로그를 점검하고, 상태가 지속되면 유지보수를 예약하세요.", + "system.health.remediation.health": "누락된 상태 정보를 평가할 수 있도록 수집기 접근 권한을 복원하세요.", + "system.health.remediation.system": "이전 실행 및 호스트 로그를 검토하여 프로세스 재시작과 호스트 재부팅을 구분하세요.", + "system.health.remediation.event": "로컬 API 또는 메트릭 뷰를 사용하고, 영구 큐 압력을 해소하며, 독립적인 알림 대상을 복원하세요.", + "system.health.remediation.default": "영향을 받은 구성 요소와 최근 로그를 검토한 후, 새로운 상태 생성에서 복구를 확인하세요.", + "system.capacityTarget": "용량 목표", + "system.capacityTargetValue": "{pct}% 여유 공간 유지", + "system.fillRate": "채워지는 속도", + "system.fillRateValue": "{value} / 일", + "system.projectedToTarget": "목표까지 예상 시간", + "system.projectedNow": "현재 목표 도달/초과", + "system.projectedDays": "~{count}일", + "system.projectedHours": "~{count}시간", + "system.projectedUnknown": "—", + "common.description": "설명", + "common.remove": "삭제", + "streams.selectStream": "{name} 선택", + "streams.search": "스트림 검색", + "streams.searchPlaceholder": "카메라, 위치 또는 태그 검색", + "streams.noStreamsMatchFilters": "현재 필터와 일치하는 스트림이 없습니다.", + "streamHealth.sourceConnected": "소스 연결됨", + "streamHealth.videoAdvancing": "비디오 진행 중", + "streamHealth.recorderWriting": "녹화기 기록 중", + "streamHealth.detectorOperating": "감지기 작동 중", + "streamHealth.lastSegment": "마지막 완료 세그먼트", + "streams.disablingStreamsProgress": "스트림 비활성화 중…", + "streams.onvifInvalidAddress": "ONVIF 기기 IP 주소가 없거나 올바르지 않습니다.", + "streams.warningFallingBackToHttp": "HTTPS 연결 실패; HTTP로 재시도합니다. 자격 증명이 평문으로 전송될 수 있습니다.", + "streamsConfig.playbackTransport": "재생 전송 방식", + "streamsConfig.playbackTransportHelp": "이 카메라의 브라우저 재생 방식과, 선택된 경우 대체 순서를 지정합니다.", + "streamsConfig.playbackTransportUnavailable": "서버에서 사용 불가: {transports}. 해당 전송 방식을 전역으로 활성화하거나 다른 프로필을 선택하세요.", + "streamsConfig.audioDisabledByPolicy": "인스턴스 정책에 따라 오디오가 비활성화됨", + "streamsConfig.audioDisabledByPolicyHelp": "전역 오디오 준수 정책이 활성화되어 있는 동안 녹화, 라이브 청취, 양방향 통화가 사용 불가합니다.", + "streamsConfig.customApiModel": "사용자 지정 API 감지", + "streamsConfig.modelNotSupportedByBuild": "이 빌드에서 지원되지 않음", + "streamsConfig.tierCriticalMultiplier": "중요 등급 ×", + "streamsConfig.tierImportantMultiplier": "우선 등급 ×", + "streamsConfig.tierEphemeralMultiplier": "일시적 등급 ×", + "streamsConfig.tierMultipliersHelp": "기본 보존 기간에 대한 등급별 배수입니다. 상위 등급의 영상은 더 오래 보존되며 디스크 공간이 부족할 때 가장 나중에 삭제됩니다.", + "streamsConfig.storagePriority": "저장소 우선순위 (1-10)", + "streamsConfig.storagePriorityHelp": "공간 회수 시 이 스트림 영상의 상대적 중요도입니다. 우선순위가 높을수록 더 오래 보존됩니다.", + "streamsConfig.restream": "재전송 / 게시 (RTMP)", + "streamsConfig.publishUrl": "게시 URL (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "go2rtc를 통해 YouTube Live와 같은 서비스로 이 카메라를 재전송합니다. 스트림 키를 포함한 전체 RTMP 인제스트 URL을 붙여넣으세요 (예: rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). 여러 서비스로 동시에 재전송하려면 URL을 쉼표로 구분하세요. YouTube는 H264 비디오와 AAC 오디오가 필요하며, LightNVR이 자동으로 트랜스코딩합니다 (비 H264 카메라는 H264로, 비 AAC 오디오는 AAC로 변환)하므로 대부분의 카메라가 그대로 작동합니다. 참고: YouTube는 오디오 트랙도 필요하므로 오디오가 전혀 없는 카메라는 거부됩니다. 비워 두면 비활성화됩니다.", + "streams.lastSeen": "마지막 확인 {time}", + "streams.claimed": "소유 확인됨", + "streams.duplicateSuspected": "중복 가능성", + "streams.duplicateSuspectedHelp": "안정적인 식별자 또는 엔드포인트 정보가 다른 검색 기록과 충돌합니다.", + "streams.onvifClaimWarning": "스트림이 추가되었지만 검색 기록을 소유 확인으로 표시할 수 없습니다: {message}", + "common.online": "온라인", + "common.offline": "오프라인", + "settings.storageTargets.title": "녹화 저장 대상", + "settings.storageTargets.description": "로컬 디스크 및 관리자 마운트된 NFS 또는 SMB 파일 시스템을 독립적으로 모니터링되는 녹화 대상으로 등록합니다.", + "settings.storageTargets.foundationNotice": "캡처는 파일 시스템 대상을 사용합니다. S3 버킷 및 마운트된 NFS/SAN 대상에 검증된 아카이브 사본을 보관할 수 있습니다. 디스크 공간 압박 시 아카이브된 녹화물은 논리적 보존 기간이 만료될 때까지 보존됩니다.", + "settings.storageTargets.add": "저장 대상 추가", + "settings.storageTargets.edit": "저장 대상 편집", + "settings.storageTargets.editorHelp": "활성화된 대상은 이미 존재하며 쓰기, fsync, 정리 테스트를 통과해야 합니다. 사용할 수 없는 미래 마운트는 비활성 상태로 저장한 후, 마운트 후에 활성화하세요.", + "settings.storageTargets.name": "대상 이름", + "settings.storageTargets.root": "마운트된 루트 경로", + "settings.storageTargets.rootLocked": "기본 또는 비어 있지 않은 대상은 기존 영상 데이터가 고아 상태로 남지 않도록 변경할 수 없는 루트를 유지합니다.", + "settings.storageTargets.class": "성능 등급", + "settings.storageTargets.hot": "핫 — 활성 녹화", + "settings.storageTargets.warm": "웜 — 마운트된 아카이브", + "settings.storageTargets.cold": "콜드 — 드문 접근", + "settings.storageTargets.reserveGb": "예약 여유 공간 (GB)", + "settings.storageTargets.lowWatermark": "낮은 워터마크 (사용률 %)", + "settings.storageTargets.highWatermark": "높은 워터마크 (사용률 %)", + "settings.storageTargets.migrationBandwidth": "수명 주기 대역폭 (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0은 무제한입니다. 이동 또는 복사 작업 생성 시 제한이 스냅샷으로 저장됩니다.", + "settings.storageTargets.archiveStart": "아카이브 창 시작", + "settings.storageTargets.archiveEnd": "아카이브 창 종료", + "settings.storageTargets.archiveWindowHelp": "로컬 시간입니다. 시작과 종료 시간이 같으면 하루 종일 수명 주기 작업이 허용되며, 야간 창은 자정을 넘길 수 있습니다.", + "settings.storageTargets.enabled": "활성화됨 (배치 정책이 이 대상을 선택할 수 있음)", + "settings.storageTargets.notRouted": "활성화된 배치 정책이 이 대상을 라우팅하지 않습니다. 정책이 이 대상을 기본, 풀 멤버 또는 아카이브 대상으로 지정할 때까지 새 녹화는 기본 대상으로 계속 저장됩니다.", + "settings.storageTargets.degradedNotice": "높은 워터마크를 초과하거나 예약 공간 내에 있습니다. 공간이 확보될 때까지 배치 정책이 이 대상을 건너뜁니다.", + "settings.storageTargets.probePassedIneligible": "쓰기 테스트를 통과했지만 대상 상태가 {status}입니다: 배치 정책이 이 대상을 선택하지 않습니다.", + "settings.storageTargets.mountRequired": "마운트된 파일 시스템 필수", + "settings.storageTargets.mountRequiredHelp": "이 대상을 현재 비루트 마운트 지점에 고정합니다. 해당 NFS, SMB, 바인드 또는 PVC 마운트가 사라지면 호스트 디렉터리에 쓰는 대신 녹화가 일시 중지됩니다.", + "settings.storageTargets.mountGuard": "필수 마운트", + "settings.storageTargets.mountPending": "대상 활성화 시 감지됩니다", + "settings.storageTargets.default": "기본", + "settings.storageTargets.capacity": "용량", + "settings.storageTargets.available": "사용 가능", + "settings.storageTargets.recordings": "인덱싱된 녹화", + "settings.storageTargets.replicas": "{count}개 검증된 복사본 · {bytes}", + "settings.storageTargets.reserve": "예약됨", + "settings.storageTargets.pressure.normal": "저장소 압력 정상", + "settings.storageTargets.pressure.high": "높은 워터마크", + "settings.storageTargets.pressure.reserve": "예약 공간 초과", + "settings.storageTargets.pressure.unavailable": "압력 상태 확인 불가", + "settings.storageTargets.cleanupActive": "대상 범위 정리가 활성화되어 있으며, 다른 대상에 할당된 녹화 파일을 삭제하지 않고 {target} 가용 공간을 확보합니다.", + "settings.storageTargets.test": "대상 테스트", + "settings.storageTargets.probing": "테스트 중…", + "settings.storageTargets.probePassed": "저장소 대상 쓰기 테스트 통과", + "settings.storageTargets.duplicateFilesystem": "이 루트는 다른 대상과 동일한 파일 시스템을 공유합니다. 배치가 활성화된 경우 용량을 중복 계산하면 안 됩니다.", + "settings.storageTargets.deleteLocked": "기본 대상 및 비어 있지 않은 대상은 삭제할 수 없습니다.", + "settings.storageTargets.deleteConfirm": "비어 있는 저장소 대상 \"{name}\"을(를) 삭제하시겠습니까? 파일은 삭제되지 않습니다.", + "settings.storageTargets.created": "저장소 대상 생성됨", + "settings.storageTargets.updated": "저장소 대상 업데이트됨", + "settings.storageTargets.deleted": "저장소 대상 삭제됨", + "settings.storageTargets.invalidThresholds": "워터마크, 예약 공간, 수명 주기 대역폭, 아카이브 창 시간을 확인하세요.", + "settings.storageTargets.loadError": "저장소 대상을 불러올 수 없습니다", + "settings.storagePools.title": "저장소 풀", + "settings.storagePools.description": "자동 스플오버 및 대상 간 복제를 위해 정상 대상을 그룹화합니다.", + "settings.storagePools.add": "풀 추가", + "settings.storagePools.strategy": "할당 전략", + "settings.storagePools.mostFree": "여유 공간 최대", + "settings.storagePools.roundRobin": "라운드 로빈", + "settings.storagePools.priority": "명시적 우선순위", + "settings.storagePools.members": "대상 (표시 순서가 할당 우선순위)", + "settings.storagePools.enabled": "풀 활성화", + "settings.storagePools.active": "활성", + "settings.storagePools.inactive": "비활성화", + "settings.storagePools.strategyValue.most_free": "여유 공간 최대", + "settings.storagePools.strategyValue.round_robin": "라운드 로빈", + "settings.storagePools.strategyValue.priority": "우선순위 순서", + "settings.storagePools.created": "저장소 풀 생성됨", + "settings.storagePools.updated": "저장소 풀 업데이트됨", + "settings.storagePools.deleted": "스토리지 풀이 삭제되었습니다", + "settings.storagePools.deleteConfirm": "스토리지 풀 \"{name}\"을(를) 삭제하시겠습니까?", + "settings.storagePools.empty": "스토리지 풀이 없습니다.", + "settings.storageMigrations.title": "녹화 마이그레이션 작업", + "settings.storageMigrations.description": "영구 이동 및 보존 복사본은 각 대상의 아카이브 기간과 대역폭 제한을 준수하며, SHA-256을 검증하고 재시작 후 안전하게 복구합니다.", + "settings.storageMigrations.empty": "녹화 마이그레이션 작업이 없습니다.", + "settings.storageMigrations.loadError": "녹화 마이그레이션 작업을 불러올 수 없습니다", + "settings.storageMigrations.recording": "녹화 #{id}", + "settings.storageMigrations.attempt": "시도 {current}/{max}", + "settings.storageMigrations.operation.move": "이동", + "settings.storageMigrations.operation.copy": "보존 복사본", + "settings.storageMigrations.cancelled": "마이그레이션 취소가 접수되었습니다", + "settings.storageMigrations.cancelling": "취소 중…", + "settings.storageMigrations.retried": "마이그레이션이 재시도 대기열에 추가되었습니다", + "settings.storageMigrations.state.queued": "대기 중", + "settings.storageMigrations.state.copying": "복사 중", + "settings.storageMigrations.state.verifying": "검증 중", + "settings.storageMigrations.state.committing": "커밋 중", + "settings.storageMigrations.state.cleanup_pending": "소스 정리 중", + "settings.storageMigrations.state.retry_wait": "재시도 대기 중", + "settings.storageMigrations.state.completed": "완료", + "settings.storageMigrations.state.failed": "실패", + "settings.storageMigrations.state.cancelled": "취소됨", + "settings.storagePolicies.title": "카메라 배치 정책", + "settings.storagePolicies.description": "일치하는 카메라를 우선순위 순서에 따라 기본 녹화 대상으로 라우팅합니다. 카메라는 일치하는 첫 번째 활성화된 정책을 사용합니다.", + "settings.storagePolicies.add": "배치 정책 추가", + "settings.storagePolicies.edit": "배치 정책 편집", + "settings.storagePolicies.editorHelp": "정책은 새 세그먼트에 대해 재평가됩니다. 변경 사항은 이미 존재하는 녹화를 이동하지 않습니다.", + "settings.storagePolicies.priority": "우선순위 (높은 순)", + "settings.storagePolicies.priorityValue": "우선순위 {priority}", + "settings.storagePolicies.primary": "기본 대상", + "settings.storagePolicies.primaryPool": "배치 풀 (선택)", + "settings.storagePolicies.exactTarget": "주 대상 정확히 사용", + "settings.storagePolicies.fallback": "주 대상 사용 불가 시", + "settings.storagePolicies.fallbackDefault": "기본 대상 사용", + "settings.storagePolicies.fallbackTarget": "지정된 대체 대상 사용", + "settings.storagePolicies.fallbackPause": "녹화 일시 정지", + "settings.storagePolicies.fallbackFail": "녹화 시작 실패 처리", + "settings.storagePolicies.namedFallback": "대체 대상", + "settings.storagePolicies.chooseTarget": "대상 선택", + "settings.storagePolicies.choosePool": "풀 선택", + "settings.storagePolicies.minimumDays": "최소 보관 기간 (일)", + "settings.storagePolicies.desiredDays": "희망 보관 기간 (일)", + "settings.storagePolicies.maximumDays": "최대 보관 기간 (일)", + "settings.storagePolicies.copyCount": "필요한 검증된 사본 수", + "settings.storagePolicies.replicationPool": "복제 풀", + "settings.storagePolicies.migrateAfter": "이동 대기 기간 (일)", + "settings.storagePolicies.migrationTarget": "아카이브 대상", + "settings.storagePolicies.pressurePriority": "압축 삭제 우선순위 (낮은 순)", + "settings.storagePolicies.disabledTarget": "비활성화", + "settings.storagePolicies.enabled": "정책 활성화됨", + "settings.storagePolicies.selector": "일치하는 카메라", + "settings.storagePolicies.preview": "우선순위 미리보기", + "settings.storagePolicies.previewing": "평가 중…", + "settings.storagePolicies.previewRequired": "저장 전에 현재 초안을 미리보여 카메라 중복 및 적용되는 우선 정책을 확인하세요.", + "settings.storagePolicies.previewSummary": "{matched}개 카메라와 일치; 이 초안은 {effective}에 적용됩니다.", + "settings.storagePolicies.previewShadowed": "더 높은 우선순위의 정책이 {count}개 일치하는 카메라에 적용됩니다.", + "settings.storagePolicies.previewWins": "{count}개 카메라에서 \"{policy}\" (우선순위 {priority})보다 우선합니다.", + "settings.storagePolicies.previewLoses": "{count}개 카메라에서 \"{policy}\" (우선순위 {priority})에 밀립니다.", + "settings.storagePolicies.previewNoMatches": "현재 이 선택기와 일치하는 카메라가 없습니다.", + "settings.storagePolicies.invalidPriority": "우선순위는 -1,000,000에서 1,000,000 사이의 정수여야 합니다.", + "settings.storagePolicies.invalidLifecycle": "보관 기간 순서, 사본 수 및 복제 풀, 이동 대기 기간 및 대상을 확인하세요.", + "settings.storagePolicies.created": "배치 정책 생성됨", + "settings.storagePolicies.updated": "배치 정책 업데이트됨", + "settings.storagePolicies.deleted": "배치 정책이 삭제되었습니다", + "settings.storagePolicies.deleteConfirm": "배치 정책 \"{name}\"을(를) 삭제하시겠습니까? 기존 녹화에는 영향을 주지 않습니다.", + "settings.storagePolicies.active": "활성", + "settings.storagePolicies.inactive": "비활성화", + "settings.storagePolicies.routesTo": "기본 대상: {target}", + "settings.storagePolicies.lifecycleSummary": "보존 최소/원하는/최대: {minimum}/{desired}/{maximum}일 · 검증된 복사본 {copies}개", + "settings.storagePolicies.fallsBackTo": "대체 대상: {target}", + "settings.storagePolicies.mode.default": "대체: 기본 대상", + "settings.storagePolicies.mode.pause": "대체: 녹화 일시 중지", + "settings.storagePolicies.mode.fail": "대체: 녹화 시작 실패 처리", + "settings.storagePolicies.empty": "배치 정책이 없습니다. 카메라는 계속 기본 대상을 사용하며, 정책이 카메라를 라우팅하기 전까지 다른 대상에는 아무것도 전송되지 않습니다.", + "settings.storagePolicies.archiveNoTrigger": "아카이브 대상이 설정되어 있지만 이동을 트리거하는 항목이 없습니다. '경과 후 이동(일)', 아카이브 경과 기간 또는 아카이브 옵션을 설정하세요. 그렇지 않으면 녹화 파일이 이동되지 않습니다.", + "settings.storageCompliance.title": "용량 및 정책 준수", + "settings.storageCompliance.description": "30일 관측률로 대상 압력과 달성된 보존 기간을 예측합니다. 활성 수명 주기 위반은 해결될 때까지 표시됩니다.", + "settings.storageCompliance.loadError": "저장소 준수 상태를 불러올 수 없습니다", + "settings.storageCompliance.unknown": "알 수 없음", + "settings.storageCompliance.days": "{days}일", + "settings.storageCompliance.day": "일", + "settings.storageCompliance.targetForecasts": "대상 예측", + "settings.storageCompliance.target": "대상", + "settings.storageCompliance.dailyRate": "관측률", + "settings.storageCompliance.toHigh": "고수위까지", + "settings.storageCompliance.expected": "예상 보존 기간", + "settings.storageCompliance.confidence": "신뢰도", + "settings.storageCompliance.policyCompliance": "정책 준수", + "settings.storageCompliance.compliant": "활성 위반 없음", + "settings.storageCompliance.violationCount": "위반 {count}건", + "settings.storageCompliance.policyForecast": "달성 {achieved}일; 예측 {expected}일; 원하는 {desired}일.", + "settings.storageCompliance.copyDeficits": "녹화 {count}건에 추가 검증된 복사본이 필요합니다.", + "settings.storageCompliance.activeViolations": "활성 위반", + "settings.storageCompliance.type.copy_count": "복사본 수", + "settings.storageCompliance.type.minimum_retention": "최소 보존 용량", + "settings.storageCompliance.type.target_unavailable": "대상 사용 불가", + "settings.storageCompliance.type.migration_failed": "수명 주기 작업 실패", + "settings.recordingDirectoryFormat": "녹화 폴더 구조", + "settings.recordingDirectoryFormatHelp": "새 MP4 녹화 파일을 각 카메라 폴더 아래에 구분하여 저장합니다. 기존 녹화 파일은 이동되지 않습니다.", + "settings.recordingDirectoryFlat": "평면 (카메라 폴더만)", + "settings.recordingDirectoryMonth": "월별 (YYYY/MM)", + "settings.recordingDirectoryDay": "일별 (YYYY/MM/DD)", + "settings.minFreePct": "최소 여유 공간 (%)", + "settings.minFreePctHelp": "보관 일수와 관계없이 가장 오래된 녹화 파일을 자동으로 삭제하여 볼륨의 최소 이 비율을 유지합니다. 디스크 용량에 따라 사용량이 제한되므로 설정하면 디스크가 가득 차지 않습니다. 0이면 용량 상한을 비활성화합니다.", + "settings.pressureThresholds": "디스크 압력 임계값 (%)", + "settings.pressureThresholdsHelp": "자동 정리 단계를 높이는 여유 공간 구간입니다. 비상 < 심각 < 경고 순서를 만족해야 합니다.", + "settings.pressureWarningPct": "경고 이하 (% 여유)", + "settings.pressureCriticalPct": "심각 이하 (% 여유)", + "settings.pressureEmergencyPct": "비상 이하 (% 여유)", + "settings.databaseBackupVerify": "백업 검증", + "settings.databaseBackupVerifyFull": "전체 (integrity_check, 모든 인덱스 교차 검증)", + "settings.databaseBackupVerifyQuick": "빠른 (quick_check, 페이지 구조만)", + "settings.databaseBackupVerifyOff": "끄기 (복사 후 스캔 없음)", + "settings.databaseBackupVerifyHelp": "백업이 게시되기 전에 각 복사된 백업에 적용되는 스캔입니다. 전체 스캔은 대용량 데이터베이스에서 기계식 디스크를 사용할 경우 복사보다 오래 걸릴 수 있으며 30분 안전 밸브에 도달하여 해당 백업이 폐기될 수 있습니다. 빠른 스캔은 훨씬 적은 시크로 손상되거나 잘린 페이지를 감지합니다.", + "settings.viewMethodAuto": "자동 — 카메라별 설정 및 폴백", + "settings.resetWizardPending": "마법사 시작 중…", + "settings.apiDetectionFormat": "API 요청 형식", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (멀티파트 이미지 업로드)", + "settings.apiDetectionFormatDoods2": "DOODS2 (base64 이미지 포함 JSON 본문)", + "settings.apiDetectionFormatHelp": "LightNVR이 감지 API에 스냅샷을 전송할 때 사용하는 전송 형식입니다. light-object-detect 또는 해당 계약을 구현한 서버에는 light-object-detect를 유지하고, DOODS2 서버에는 DOODS2를 선택하세요.", + "settings.apiDetectionUrlHelpDoods2": "DOODS2 /detect 엔드포인트, 예: http://localhost:8080/detect. 요청은 JSON으로 전송되며 쿼리 매개변수는 추가되지 않습니다.", + "settings.apiDetectionDetectorName": "DOODS2 감지기 이름", + "settings.apiDetectionDetectorNameHelp": "각 요청에서 detector_name으로 전송됩니다. 서버의 GET /detectors에 나열된 감지기와 일치해야 합니다. \"default\"는 서버의 기본 감지기를 사용합니다.", + "settings.defaultPlaybackTransport": "기본 재생 전송 방식", + "settings.defaultPlaybackTransportHelp": "새로 생성된 스트림에 적용되는 재생 프로필입니다. 기존 스트림은 자체 선택을 유지합니다.", + "playbackTransport.auto": "자동 (권장)", + "playbackTransport.webrtcOnly": "WebRTC 전용", + "playbackTransport.mseOnly": "MSE 전용", + "playbackTransport.hlsOnly": "HLS 전용", + "playbackTransport.webrtcThenMse": "WebRTC, 그 다음 MSE", + "playbackTransport.mseThenHls": "MSE, 그 다음 HLS", + "investigation.experimental": "실험적 작업 공간", + "investigation.title": "조사", + "investigation.description": "여러 카메라를 하나의 공유된 UTC 커서 기준으로 검토하며, 영상 공백을 숨기지 않습니다.", + "investigation.query": "조사 창", + "investigation.queryHelp": "최대 16개 카메라를 선택하세요. 동시에 최대 4개의 비디오 플레이어만 활성화됩니다.", + "investigation.cameras": "카메라", + "investigation.cameraSelection": "카메라 선택", + "investigation.start": "시작", + "investigation.end": "종료", + "investigation.load": "조사 불러오기", + "investigation.applyWindow": "시간 범위 적용", + "investigation.loading": "조사 불러오는 중…", + "investigation.eventType": "이벤트 유형", + "investigation.anyEventType": "모든 이벤트 유형", + "investigation.eventType.detection": "감지", + "investigation.eventType.motion": "모션", + "investigation.location": "위치", + "investigation.anyLocation": "모든 위치", + "investigation.objectLabel": "객체 레이블", + "investigation.anyLabel": "모든 레이블", + "investigation.zone": "구역", + "investigation.anyZone": "모든 구역", + "investigation.source": "감지 소스", + "investigation.anySource": "모든 소스", + "investigation.captureMethod": "캡처 방식", + "investigation.anyCaptureMethod": "모든 캡처 방식", + "investigation.recordingTag": "녹화 태그", + "investigation.anyRecordingTag": "모든 녹화 태그", + "investigation.protection": "보호", + "investigation.anyProtection": "모든 보호 상태", + "investigation.protected": "보호됨", + "investigation.unprotected": "보호되지 않음", + "investigation.minimumConfidence": "최소 신뢰도", + "investigation.confidenceError": "최소 신뢰도는 0에서 1 사이여야 합니다.", + "investigation.metadataRegionSearch": "메타데이터 영역 검색", + "investigation.regionSearchHelp": "녹화 영상이 있는 주 카메라를 선택한 후 영상 위에 영역을 그리세요.", + "investigation.regionActive": "{camera}의 저장된 박스를 검색 중입니다. 결과가 없는 것은 영역을 통과한 것이 없다는 증거가 아닙니다.", + "investigation.regionMatch": "박스 매칭", + "investigation.regionMatch.center": "중심이 내부에", + "investigation.regionMatch.intersects": "교차 시", + "investigation.regionMatch.minimumIntersection": "최소 겹침", + "investigation.regionMinimumOverlap": "최소 겹침 (%)", + "investigation.regionLeft": "왼쪽 (%)", + "investigation.regionTop": "위쪽 (%)", + "investigation.regionWidth": "너비 (%)", + "investigation.regionHeight": "높이 (%)", + "investigation.drawRegion": "검색 영역 그리기", + "investigation.drawingRegion": "검색 영역 그리는 중…", + "investigation.clearRegion": "영역 지우기", + "investigation.useFullFrame": "전체 프레임 사용", + "investigation.drawRegionPrompt": "영상을 드래그하여 검색 영역을 지정하세요", + "investigation.applyFilters": "필터 적용", + "investigation.searching": "이벤트 검색 중…", + "investigation.searchResults": "이벤트 결과", + "investigation.searchHelp": "조사를 불러와 저장된 이벤트 메타데이터를 검색하세요.", + "investigation.resultCount": "일치하는 이벤트 {count}개", + "investigation.results": "결과", + "investigation.resultHistogram": "이벤트 히스토그램", + "investigation.histogramHelp": "막대를 선택하여 공유 커서를 이동하세요.", + "investigation.previousResult": "이전 이벤트", + "investigation.nextResult": "다음 이벤트", + "investigation.previousResultShortcut": "이전 이벤트 ([)", + "investigation.nextResultShortcut": "다음 이벤트 (])", + "investigation.noResults": "선택한 카메라, 시간, 필터 조건에 맞는 저장된 이벤트가 없습니다.", + "investigation.noThumbnail": "썸네일 없음", + "investigation.exploreThumbnails": "썸네일 탐색", + "investigation.exploreSelectedThumbnails": "이벤트 주변 탐색", + "investigation.thumbnailDrilldown": "썸네일 상세 보기", + "investigation.thumbnailDrilldownHelp": "공통 커서를 이동하고 더 좁은 범위의 샘플을 다시 생성하려면 간격을 포함해 원하는 시점을 선택하세요.", + "investigation.selectThumbnailSample": "{time} 주변 확인", + "investigation.loadingThumbnail": "썸네일 불러오는 중…", + "investigation.thumbnailUnavailable": "썸네일 사용 불가", + "investigation.loadingSamples": "썸네일 샘플 불러오는 중…", + "investigation.thumbnailCoverageTruncated": "이 구간에 샘플러가 확인할 수 있는 것보다 많은 녹화 파일이 있습니다. 전체를 확인하려면 시간 범위를 좁히세요.", + "investigation.bookmarks.save": "북마크 저장", + "investigation.bookmarks.open": "북마크", + "investigation.bookmarks.saveTitle": "조사 북마크 저장", + "investigation.bookmarks.listTitle": "조사 북마크", + "investigation.bookmarks.notHold": "북마크는 이 뷰를 복원하지만, 녹화 파일을 일반적인 보관 정책이나 삭제로부터 보호하지는 않습니다.", + "investigation.bookmarks.title": "북마크 이름", + "investigation.bookmarks.note": "개인 메모 (선택 사항)", + "investigation.bookmarks.titleRequired": "북마크 이름을 입력하세요.", + "investigation.bookmarks.empty": "저장된 조사 북마크가 없습니다.", + "investigation.bookmarks.cameraCount": "카메라 {count}대", + "investigation.bookmarks.restore": "열기", + "investigation.bookmarks.confirmDelete": "북마크를 삭제하시겠습니까?", + "investigation.actions.open": "보호 / 다운로드", + "investigation.actions.title": "조사 녹화 파일", + "investigation.actions.notEvidenceExport": "보호 설정은 일반적인 보관 기간 만료 삭제를 방지합니다. ZIP 다운로드는 편의용 내보내기이며, 검증된 증거 패키지가 아닙니다.", + "investigation.actions.scope": "녹화 범위", + "investigation.actions.selectedResult": "선택한 이벤트 및 카메라", + "investigation.actions.fullWindow": "조사 구간의 모든 카메라", + "investigation.actions.preview": "녹화 미리보기", + "investigation.actions.previewing": "중복 녹화 검색 중…", + "investigation.actions.invalidRange": "종료 시간이 시작 시간 이후인 유효한 시간 범위를 선택하세요.", + "investigation.actions.recordingCount": "중복 녹화 {count}개", + "investigation.actions.protectedCount": "이미 보호됨 {count}개", + "investigation.actions.noRecordings": "선택한 카메라 및 시간 범위와 중복되는 완료된 녹화가 없습니다.", + "investigation.actions.protectDenied": "보호 범위를 벗어난 보호되지 않은 녹화 {count}개가 이 작업에서 제외됩니다.", + "investigation.actions.exportDenied": "녹화 {count}개에 대한 내보내기 권한이 없습니다. 다운로드는 전체 또는 전무 방식이므로 이 선택 항목을 내보낼 수 없습니다.", + "investigation.actions.camera": "카메라", + "investigation.actions.recording": "녹화", + "investigation.actions.size": "크기", + "investigation.actions.notPermitted": "권한 없음", + "investigation.actions.protectButton": "{count}개 보호", + "investigation.actions.protecting": "보호 중…", + "investigation.actions.protectUnavailable": "보호 권한이 있는 보호되지 않은 녹화가 없습니다.", + "investigation.actions.protectResult": "보호 완료: 성공 {success}개, 실패 {failed}개.", + "investigation.actions.downloadButton": "{count}개 다운로드", + "investigation.actions.downloadUnavailable": "ZIP 파일을 생성하려면 모든 녹화에 내보내기 권한이 필요합니다.", + "investigation.actions.buildingArchive": "ZIP 생성 중…", + "investigation.actions.downloadFailed": "서버에서 ZIP 생성에 실패했습니다.", + "investigation.actions.downloadTimedOut": "ZIP 생성이 5분 이내에 완료되지 않았습니다. 더 좁은 간격을 시도하세요.", + "investigation.actions.downloadStarted": "ZIP 다운로드가 시작되었습니다.", + "investigation.backOneLevel": "한 단계 위로", + "investigation.thumbnailMinimumWindow": "이미 최소 간격인 1초입니다. 공유 커서는 선택한 시점으로 이동했습니다.", + "investigation.localSource": "로컬", + "investigation.mediaAvailable": "미디어 사용 가능", + "investigation.durationSeconds": "{count}초", + "investigation.pageNumber": "{count}페이지", + "investigation.incompleteCoverage": "레거시 이벤트 {count}행을 변경 불가능한 카메라 식별자에 연결할 수 없습니다.", + "investigation.spatialCoverageGap": "범위 내 이벤트 {count}행에 경계 상자가 없어 공간 검색이 수행되지 않았습니다.", + "investigation.noSpatialMetadata": "이 메타데이터 검색에 사용할 수 있는 경계 상자가 있는 범위 내 이벤트가 없습니다.", + "investigation.selectCameraError": "카메라를 하나 이상 선택하세요.", + "investigation.selectRecordingError": "녹화를 하나 이상 선택하세요.", + "investigation.investigateSelectedCount": "선택한 녹화 {count}건 조사", + "investigation.missingCameraIdentity": "조사 불가: 선택한 녹화 {count}건에 카메라 식별 정보가 없습니다.", + "investigation.recordingTimeError": "선택한 녹화에 유효한 시간 범위가 없습니다.", + "investigation.windowLimit": "선택한 녹화가 31일 조사 제한을 초과합니다.", + "investigation.timeRangeError": "종료 시간은 시작 시간 이후여야 합니다.", + "investigation.cameraLimit": "조사는 최대 {count}대의 카메라를 포함할 수 있습니다.", + "investigation.decoderLimit": "동시에 최대 {count}대의 카메라 플레이어만 활성화할 수 있습니다.", + "investigation.playbackControls": "동기화 재생 제어", + "investigation.play": "재생", + "investigation.pause": "일시 정지", + "investigation.mode": "재생 모드", + "investigation.wallClock": "실시간", + "investigation.skipCommonGaps": "공통 간격 건너뛰기", + "investigation.speed": "배속", + "investigation.sharedCursor": "공유 UTC 커서", + "investigation.activePlayers": "활성 플레이어", + "investigation.timeline": "공유 타임라인", + "investigation.segments": "세그먼트", + "investigation.truncated": "잘림", + "investigation.gap": "영상 없음", + "investigation.players": "동기화 카메라 플레이어", + "investigation.activateCamera": "영상을 불러오려면 타임라인 행을 하나 이상 활성화하세요.", + "investigation.noFootage": "영상 없음", + "investigation.noFootageAtTime": "공유 시간에 영상이 없습니다", + "investigation.primaryAudio": "기본 오디오", + "investigation.makePrimary": "기본으로 설정", + "investigation.status.loading": "미디어 불러오는 중", + "investigation.status.synchronizing": "동기화 중", + "investigation.status.ready": "동기화됨", + "investigation.status.late": "지연 — 복구 중", + "investigation.status.error": "미디어 사용 불가", + "investigation.status.paused-by-browser": "미디어 재생을 허용하려면 재생을 선택하세요", + "streamsConfig.eptzTitle": "어안 ePTZ", + "streamsConfig.eptzEnable": "브라우저 측 어안 ePTZ 활성화", + "streamsConfig.eptzHelp": "라이브 뷰, 타임라인 재생 및 조사에서 원본 어안 스트림의 왜곡을 보정합니다. 녹화 또는 카메라 출력에는 영향을 주지 않습니다.", + "streamsConfig.eptzModelHelp": "투영: 등거리 원형 어안 · 설치: 천장. 중심 및 반지름은 정규화된 원본 이미지 좌표를 사용합니다.", + "streamsConfig.eptzCenterX": "광학 중심 X", + "streamsConfig.eptzCenterY": "광학 중심 Y", + "streamsConfig.eptzRadius": "이미지 서클 반지름", + "streamsConfig.eptzLensFov": "렌즈 시야각(도)", + "streamsConfig.eptzRotation": "렌즈 회전(도)", + "streamsConfig.eptzDefaultYaw": "기본 팬(도)", + "streamsConfig.eptzDefaultTilt": "기본 틸트(도)", + "streamsConfig.eptzViewFov": "기본 뷰 시야각", + "streamsConfig.eptzCalibrationHelp": "드래그하여 시야를 이동하고, 휠 또는 핀치로 확대/축소하며, Home 키를 눌러 가상 카메라를 초기화합니다. 이미지 서클 가장자리가 정렬되지 않으면 중심과 반지름을 미세 조정하세요.", + "settings.archive.targetType": "저장소 유형", + "settings.archive.filesystem": "로컬 또는 마운트된 파일 시스템(NFS/SAN)", + "settings.archive.s3": "S3 호환 아카이브 버킷", + "settings.archive.endpoint": "HTTPS 엔드포인트", + "settings.archive.region": "리전", + "settings.archive.bucket": "전용 버킷", + "settings.archive.credential_ref": "자격 증명 참조", + "settings.archive.budget": "아카이브 예산(GiB, 0 = 무제한)", + "settings.archive.connectionHelp": "수명 주기 만료 규칙이 없는 비공개 비버전 버킷을 사용하세요. 자격 증명 참조는 서버에 마운트된 시크릿 파일을 선택합니다. 관리 위치를 s3://bucket/instance-prefix 형식으로 입력하세요.", + "settings.archive.policy": "외부 아카이브 정책", + "settings.archive.archive_after_seconds": "캡처 후 아카이브(초, -1 = 비활성화)", + "settings.archive.hot_residency_seconds": "핫 사본 유지(초, -1 = 아카이브 후 이동)", + "settings.archive.archive_protected": "보호된 녹화의 아카이브 우선 처리", + "settings.archive.archive_on_pressure": "핫 저장소 용량 압박 시 조기 아카이브", + "settings.archive.policyHelp": "아카이브 시점은 캡처 경과 시간을 사용하며 완료된 녹화가 필요합니다. -1은 경과 시간 기반 아카이브를 비활성화하거나 핫 보관 최소 시간을 제거하며, 0은 즉시 아카이브를 의미합니다. 편집은 새 녹화에 적용됩니다. 기존 녹화에 새 개정을 적용하려면 녹화를 검토하세요.", + "settings.archive.deletion_pending": "삭제 대기 중", + "settings.archive.archived": "아카이브됨", + "settings.archive.hot": "핫", + "settings.archive.hot_and_archive": "핫 + 아카이브", + "settings.archive.archiving": "아카이빙", + "settings.archive.preparing": "재생 준비 중", + "settings.archive.unavailable": "사용 불가", + "settings.archive.operations": "아카이브 작업", + "settings.archive.readOnly": "복구 모드: 녹화 마이그레이션 및 삭제가 일시 중지되었습니다.", + "settings.archive.disabledBuild": "이 빌드에서는 S3 지원이 비활성화되어 있습니다. 마운트된 파일 시스템 대상은 계속 사용할 수 있습니다.", + "settings.archive.stored": "버킷에 저장됨", + "settings.archive.backlog": "전송 대기열", + "settings.archive.cache": "검색 캐시", + "settings.archive.objectsRemaining": "개 객체 남음", + "settings.archive.waitingForReaders": "대기 중이거나 활성 리더를 기다리는 중입니다.", + "settings.archive.applied": "기존 녹화에 적용된 정책 개정", + "settings.archive.reviewExisting": "기존 녹화 검토", + "settings.archive.applySummary": "{count}개 녹화({bytes})에 이 개정이 적용됩니다. {expired}개는 이미 보존 기간을 초과했습니다.", + "settings.archive.applyHelp": "보호 및 녹화 재정의는 계속 적용됩니다. 스트림 및 시스템 보존도 적용됩니다. 새 아카이브 타이밍 및 대상은 다음 라이프사이클 스캔에서 적용됩니다.", + "settings.archive.applyBlocked": "이 개정을 적용하기 전에 관련 전송을 완료하거나 해결하십시오.", + "settings.archive.apply": "기존 녹화에 적용", + "common.fullscreenUnsupported": "이 브라우저에서는 전체 화면 모드를 지원하지 않습니다.", + "recordings.viewInTimelineTitle": "타임라인 뷰에서 이 시점의 스트림 보기", + "recordings.clickToRetry": "클릭하여 재시도", + "timeline.previousDay": "이전 일", + "timeline.nextDay": "다음 일", + "timeline.previousMonth": "이전 달", + "timeline.nextMonth": "다음 달", + "settings.searchLabel": "검색 설정", + "settings.clearSearch": "검색 지우기", + "recordings.addTagPlaceholder": "태그 추가...", + "recordings.addNewTagPlaceholder": "새 태그 추가..." } diff --git a/web/public/locales/nl.json b/web/public/locales/nl.json index c70eb213..800335aa 100644 --- a/web/public/locales/nl.json +++ b/web/public/locales/nl.json @@ -9,6 +9,84 @@ "nav.timeline": "Tijdlijn", "nav.health": "Status", "nav.toggleMenu": "Menu tonen/verbergen", + "live.navigator.title": "Navigator", + "live.navigator.subtitle": "Locaties, indelingen en activiteit", + "live.navigator.cameras": "Camera's", + "live.navigator.plans": "Plattegrond", + "live.navigator.views": "Weergaven", + "live.navigator.events": "Gebeurtenissen", + "live.navigator.search": "Camera zoeken…", + "live.navigator.allCameras": "Alle camera's", + "live.navigator.unassigned": "Niet toegewezen", + "live.navigator.noCameras": "Geen camera's vallen binnen dit bereik.", + "live.navigator.saveCurrent": "Huidige indeling opslaan", + "live.navigator.noLayouts": "Nog geen opgeslagen indelingen.", + "live.navigator.layoutNamePrompt": "Geef deze live-indeling een naam", + "live.navigator.shareLayoutPrompt": "Deze indeling delen met andere bedieners?", + "live.navigator.layoutSaved": "{name} opgeslagen", + "live.navigator.layoutLoaded": "{name} geladen", + "live.navigator.deleteLayoutConfirm": "{name} verwijderen?", + "live.navigator.shared": "Gedeeld", + "live.navigator.loadingEvents": "Recente gebeurtenissen laden…", + "live.navigator.noRecentEvents": "Geen detecties in het afgelopen uur.", + "live.navigator.expand": "Navigator uitklappen", + "live.navigator.collapse": "Navigator inklappen", + "live.plan.navigatorHelp": "Kies een gebouw of verdieping. Cameravoorbeelden worden alleen op verzoek geopend.", + "live.plan.noPlans": "Nog geen plattegronden. Maak er een in de plattegrondwerkruimte.", + "live.plan.emptyTitle": "Bouw een ruimtelijke cameraweergave", + "live.plan.emptyDescription": "Een plattegrond toont statusmarkers voor het hele terrein en opent video alleen wanneer een bediener dat vraagt. Teken hier de kamers en muren, of upload een gescande plattegrond, een tekening van het terrein of een schermafbeelding van je NVR-software, en wijs camera's vervolgens toe aan de echte kamers.", + "live.plan.sketch.tools": "Indelingshulpmiddelen", + "live.plan.sketch.tool.select": "Selecteren", + "live.plan.sketch.tool.room": "Kamer", + "live.plan.sketch.tool.wall": "Muur", + "live.plan.sketch.tool.area": "Gebied", + "live.plan.sketch.tool.label": "Label", + "live.plan.sketch.undo": "Tekening ongedaan maken", + "live.plan.sketch.redo": "Tekening herstellen", + "live.plan.sketch.snap": "Op raster uitlijnen", + "live.plan.sketch.hint.select": "Sleep vormen of camera's om ze te verplaatsen. Klik op een vorm om deze te bewerken; houd Alt ingedrukt om het raster over te slaan.", + "live.plan.sketch.hint.room": "Sleep op de plattegrond om een kamer of gebouwomtrek te tekenen.", + "live.plan.sketch.hint.wall": "Klik om muurpunten toe te voegen. Dubbelklik of Enter om te voltooien, Escape om te annuleren.", + "live.plan.sketch.hint.area": "Klik om een gebied te omlijnen. Klik op het eerste punt of druk op Enter om het te sluiten.", + "live.plan.sketch.hint.label": "Klik op de plattegrond om een tekstlabel te plaatsen.", + "live.plan.sketch.type.rect": "Kamer", + "live.plan.sketch.type.wall": "Muur", + "live.plan.sketch.type.area": "Gebied", + "live.plan.sketch.type.label": "Label", + "live.plan.sketch.pointCount": "{count} punten", + "live.plan.sketch.defaultLabel": "Label", + "live.plan.sketch.shapes": "Indelingsvormen", + "live.plan.sketch.noShapes": "Nog niets getekend. Kies een hulpmiddel boven de plattegrond om te beginnen.", + "live.plan.sketch.tone": "Kleur", + "live.plan.sketch.tone.slate": "Leigrijs", + "live.plan.sketch.tone.blue": "Blauw", + "live.plan.sketch.tone.green": "Groen", + "live.plan.sketch.tone.amber": "Amber", + "live.plan.sketch.tone.red": "Rood", + "live.plan.sketch.tone.violet": "Violet", + "live.plan.sketch.labelText": "Label", + "live.plan.sketch.text": "Tekst", + "live.plan.sketch.size": "Grootte", + "live.plan.sketch.size.sm": "Klein", + "live.plan.sketch.size.md": "Middelgroot", + "live.plan.sketch.size.lg": "Groot", + "live.plan.sketch.filled": "Kamer vullen", + "live.plan.sketch.left": "Links %", + "live.plan.sketch.top": "Boven %", + "live.plan.sketch.width": "Breedte %", + "live.plan.sketch.height": "Hoogte %", + "live.plan.sketch.points": "Punten", + "live.plan.sketch.point": "Punt {index}", + "live.plan.sketch.delete": "Vorm verwijderen", + "live.plan.sketch.duplicate": "Dupliceren", + "live.plan.sketch.deselect": "Klaar", + "live.plan.sketch.emptyTitle": "Nog niets op deze plattegrond", + "live.plan.sketch.emptyBody": "Teken hier kamers, muren en labels, of upload een gescande plattegrond, een terreintekening of een PNG/JPEG-export (tot 768 KB).", + "live.plan.sketch.emptyBodyReadOnly": "Een beheerder kan de indeling tekenen of een plattegrond van het echte gebouw uploaden.", + "live.plan.sketch.drawLayout": "Indeling tekenen", + "live.plan.sketch.uploadImage": "Afbeelding uploaden", + "live.plan.sketch.limitReached": "Vormlimiet bereikt ({max})", + "live.plan.sketch.discardDrawing": "Tekening geannuleerd", "streamHealth.title": "Streamstatus", "streamHealth.loading": "Statusgegevens laden...", "streamHealth.error": "Kan statusgegevens niet laden", @@ -405,6 +483,12 @@ "live.errorProcessingStreams": "Fout bij het verwerken van streams: {message}", "live.couldNotEnableFullscreen": "Kon de modus Volledig scherm niet inschakelen: {message}", "live.allTags": "Alle labels", + "live.favorites": "Favorieten", + "live.favoritesOnly": "Alleen favoriete camera's weergeven", + "live.addFavorite": "{stream} aan favorieten toevoegen", + "live.removeFavorite": "{stream} uit favorieten verwijderen", + "live.noFavorites": "Nog geen favoriete camera's. Gebruik de ster op een camerategel om er een toe te voegen.", + "live.favoriteUpdateError": "Favorieten konden niet worden bijgewerkt: {message}", "live.tags": "Labels", "live.stream": "Stream", "live.filterByTag": "Filter op tag: {tag}", @@ -589,6 +673,7 @@ "live.forceRefreshWarning": "Hierdoor wordt de go2rtc-verbinding kortstondig onderbroken, waardoor de actieve opname wordt verbroken. De opname wordt automatisch hervat.", "live.viewInTimeline": "Bekijk in tijdlijn", "live.toggleFullscreen": "Volledig scherm schakelen", + "live.resetZoom": "Zoom herstellen", "live.streamStarting": "Stream begint...", "live.go2rtcNotRespondingRetry": "go2rtc is ingeschakeld maar reageert niet. Controleer de servicestatus van go2rtc. Klik op Opnieuw proberen om het opnieuw te proberen.", "live.go2rtcHlsFailedRetry": "go2rtc HLS streamen mislukt. Klik op Opnieuw proberen om het opnieuw te proberen.", @@ -603,12 +688,14 @@ "live.failedToCreateMediaBuffer": "Kan mediabuffer niet maken", "live.webSocketConnectionError": "WebSocket verbindingsfout", "live.webrtcAutoplayBlocked": "Klik om video af te spelen (autoplay geblokkeerd)", + "live.audioPlaybackBlocked": "De browser heeft cameregeluid geblokkeerd. Klik opnieuw op de luidsprekerknop om het opnieuw te proberen.", "live.webrtcConnectionLostRetry": "WebRTC verbinding verbroken. Klik op Opnieuw proberen om opnieuw verbinding te maken.", "live.streamConnectedNoVideoDataRetry": "Stream verbonden maar geen videogegevens. Klik op Opnieuw proberen om opnieuw verbinding te maken.", "live.failedToLoadVideo": "Kan video niet laden", "live.webrtcIceConnectionFailed": "WebRTC ICE-verbinding mislukt", "live.webrtcConnectionLostPleaseRetry": "WebRTC verbinding verbroken. Probeer het opnieuw.", "live.autoRetryingIn": "Opnieuw proberen over {seconds} s…", + "live.fullscreenSubStreamFallback": "{stream}: niet genoeg bandbreedte voor de stream op volledige resolutie op volledig scherm — overgeschakeld naar de substream.", "live.connectionTimeoutCheckNetwork": "Time-out voor verbinding. Controleer de netwerk-/firewallinstellingen.", "live.failedToEstablishWebrtcConnection": "Kan geen WebRTC-verbinding tot stand brengen", "live.cannotConnectToSource": "Kan geen verbinding maken met de camerabron", @@ -622,6 +709,16 @@ "live.connectionQuality.bad": "Slecht", "live.muteCameraAudio": "Camerageluid dempen", "live.unmuteCameraAudio": "Schakel het dempen van het camerageluid in", + "live.tileActions": "Camera-acties", + "live.takeSnapshot": "Momentopname maken", + "live.openStreamRecordings": "Opnames van deze stream openen", + "live.enterReorderMode": "Camera's opnieuw ordenen", + "live.pullToRefresh": "Trek om streams te vernieuwen", + "live.releaseToRefresh": "Laat los om streams te vernieuwen", + "live.refreshingStreams": "Streams vernieuwen…", + "live.streamsRefreshed": "Streams vernieuwd", + "live.refreshStreamsFailed": "Streams konden niet worden vernieuwd: {message}", + "live.tipDoubleTapFullscreen": "Tip: tik dubbel op een tegel om deze op volledig scherm te openen.", "live.switchToToggleMode": "Schakel over naar de schakelmodus", "live.switchToPushToTalkMode": "Schakel over naar Push-to-Talk", "live.releaseToStopTalking": "Laat los om te stoppen met praten", @@ -636,6 +733,40 @@ "live.pauseForPrivacyConfirm": "Deze stream pauzeren vanwege privacy? De opname en liveweergave stoppen, maar de stream blijft zichtbaar op deze pagina met een privacy-overlay. Klik op Hervatten als u klaar bent.", "live.streamPausedForPrivacy": "Stream onderbroken vanwege privacy", "live.resumeStream": "Stream hervatten", + "live.dayNightControl": "Dag/nachtmodus", + "live.dayNightLoading": "Laden…", + "live.dayNightApplying": "Toepassen…", + "live.dayNightMode_auto": "Auto", + "live.dayNightMode_day": "Dag", + "live.dayNightMode_night": "Nacht", + "live.dayNightMode_unknown": "Onbekend", + "live.dayNightApplied": "Dag/nachtmodus ingesteld op {mode}", + "live.dayNightApplyFailed": "Dag/nachtmodus kon niet worden ingesteld", + "live.dayNightLoadFailed": "Dag/nachtmodus kon niet worden gelezen", + "live.playbackFallbackUsed": "Terugval: {transport}", + "live.playbackTransportUnavailable": "{transport} is op de server uitgeschakeld voor deze stream.", + "live.recordingMode.constant": "Continue opname", + "live.recordingMode.detection": "Opname bij detectie", + "live.recordingMode.schedule": "Geplande opname", + "live.recordingMode.none": "Geen opname", + "live.health.healthy": "Stream gezond", + "live.health.degraded": "Stream buffert of herstelt", + "live.health.offline": "Stream onbeschikbaar", + "live.enterPictureInPicture": "Beeld-in-beeld openen", + "live.exitPictureInPicture": "Beeld-in-beeld sluiten", + "live.pictureInPictureError": "Beeld-in-beeld mislukt: {message}", + "live.alwaysFullscreenOnTapEnable": "Volledig scherm inschakelen bij één tik op een tegel", + "live.alwaysFullscreenOnTapDisable": "Volledig scherm uitschakelen bij één tik op een tegel", + "live.displayMode": "Weergavemodus", + "live.displayModeFit": "Passend", + "live.displayModeFill": "Vullend", + "live.displayModeFitDescription": "Passend: het hele beeld tonen met zwarte balken", + "live.displayModeFillDescription": "Vullend: de tegel vullen en de beeldranden bijsnijden", + "live.slideshowStartCameras": "Diavoorstelling starten: camera's doorlopen", + "live.slideshowStartPages": "Diavoorstelling starten: rasterpagina's doorlopen", + "live.slideshowStop": "Diavoorstelling stoppen", + "live.slideshowInterval": "Interval diavoorstelling", + "live.slideshowSeconds": "{seconds} s", "streams.toggleDisable": "Stream uitschakelen", "streams.toggleEnable": "Stream inschakelen", "streams.readOnlyInsufficientPermissions": "Alleen-lezen (onvoldoende rechten om te wijzigen)", @@ -819,7 +950,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "Zorg ervoor dat light-object-detect op dit eindpunt actief is", "streamsConfig.customApiEndpointUrl": "Aangepast API Eindpunt URL", "streamsConfig.useDefaultEndpoint": "Gebruik standaardeindpunt", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "Voer de volledige URL in voor uw aangepaste detectie-API-eindpunt", "streamsConfig.overrideWithCustomEndpoint": "Overschrijven met aangepast eindpunt", "streamsConfig.detectionThreshold": "Detectiedrempel", @@ -1056,7 +1187,7 @@ "settings.detectionModelsPath": "Pad voor detectiemodellen", "settings.detectionModelsPathHelp": "Directory waarin detectiemodellen zijn opgeslagen", "settings.apiDetectionUrl": "API Detectie URL", - "settings.apiDetectionUrlHelp": "URL van het externe objectdetectie API eindpunt", + "settings.apiDetectionUrlHelp": "light-object-detect endpoint, bijv. http://localhost:8000/api/v1/detect. De snapshot wordt als multipart form data geüpload met backend en confidence_threshold queryparameters toegevoegd.", "settings.apiDetectionBackend": "API Detectie-backend", "settings.apiDetectionBackendOnnx": "ONNX Looptijd", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1156,5 +1287,1361 @@ "settings.discoveryIntervalSecondsRangeHelp": "Hoe vaak scannen naar camera's (30–3600 seconden)", "settings.discoveryNetwork": "Zoeknetwerk", "settings.discoveryNetworkExamples": "Voorbeelden: 192.168.1.0/24, 10.0.0.0/16, automatisch", - "settings.saveSettings": "Instellingen opslaan" + "settings.saveSettings": "Instellingen opslaan", + "live.plan.previewUnavailable": "Cameravoorbeeld niet beschikbaar", + "live.plan.previewAlt": "Huidige weergave van {name}", + "live.plan.degreesValue": "{value} graden", + "live.plan.inDegrees": "{label} in graden", + "live.plan.imageDimensionsError": "Afbeeldingsdimensies konden niet worden gelezen", + "live.plan.loading": "Plattegronden laden…", + "live.plan.created": "{name} aangemaakt", + "live.plan.renamed": "Hernoemd naar {name}", + "live.plan.deleted": "{name} verwijderd", + "live.plan.backgroundType": "De achtergrond moet een PNG- of JPEG-afbeelding zijn", + "live.plan.backgroundTooLarge": "Achtergrondafbeelding te groot; maximaal 768 KB", + "live.plan.backgroundAspect": "Geüpload, maar de beeldverhouding van de afbeelding past bij geen enkele geldige canvasgrootte", + "live.plan.backgroundUpdatedSave": "Achtergrond bijgewerkt voor {name}; sla de indeling op om de canvasgrootte toe te passen", + "live.plan.backgroundNotResized": "Achtergrond geüpload, maar het canvas is niet aangepast: {error}", + "live.plan.backgroundUpdated": "Achtergrond bijgewerkt voor {name}", + "live.plan.backgroundRemoved": "Achtergrond verwijderd", + "live.plan.saved": "{name} opgeslagen", + "live.plan.createTitle": "Plattegrond aanmaken", + "live.plan.createDescription": "Geef dit gebouw of deze verdieping een duidelijke naam. Teken de indeling of upload een plattegrondafbeelding en plaats vervolgens camera's.", + "live.plan.nameLabel": "Naam plattegrond", + "live.plan.namePlaceholder": "Hoofdgebouw · Begane grond", + "live.plan.createConfirm": "Plattegrond aanmaken", + "live.plan.eyebrow": "Plattegrond", + "live.plan.placedSummary": "{placed} geplaatst · {live} nu live", + "live.plan.zoomAndPan": "Zoomen en schuiven van de plattegrond", + "live.plan.panLeft": "Naar links schuiven", + "live.plan.panUp": "Omhoog schuiven", + "live.plan.panDown": "Omlaag schuiven", + "live.plan.panRight": "Naar rechts schuiven", + "live.plan.zoomOut": "Uitzoomen", + "live.plan.zoomIn": "Inzoomen", + "live.plan.fitTitle": "Plattegrond passend maken", + "live.plan.fit": "Passend", + "live.plan.backgroundMenu": "Achtergrond…", + "live.plan.save": "Plattegrond opslaan", + "live.plan.uploadBackgroundTitle": "Een PNG- of JPEG-afbeelding als plattegrondachtergrond uploaden", + "live.plan.replaceBackground": "Achtergrond vervangen", + "live.plan.uploadBackground": "Achtergrond uploaden", + "live.plan.removeBackground": "Achtergrond verwijderen", + "live.plan.rename": "Hernoemen", + "live.plan.newPlan": "Nieuwe plattegrond", + "live.plan.editLayout": "Indeling bewerken", + "live.plan.placementHint": "Klik op de plattegrond om {name} te positioneren", + "live.plan.clusterLabel": "{count} camera's; zoom in", + "live.plan.markerLabel": "{name}; {availability}; gericht op {rotation}° met een gezichtsveld van {fov}°", + "live.plan.cameraFallback": "Camera", + "live.plan.legendLive": "Live", + "live.plan.canvas": "Canvas plattegrond", + "live.plan.width": "Breedte", + "live.plan.height": "Hoogte", + "live.plan.canvasHint": "Bij het uploaden van een achtergrondafbeelding wordt het canvas daaraan aangepast.", + "live.plan.canvasInvalid": "De breedte moet 400–4000 zijn en de hoogte 300–4000.", + "live.plan.openLive": "Livecamera openen", + "live.plan.direction": "Camerarichting", + "live.plan.fov": "Gezichtsveld", + "live.plan.coverageNote": "Wiggen tonen alleen richting en hoek; de afstand op de plattegrond is niet gekalibreerd.", + "live.plan.removeCamera": "Van plattegrond verwijderen", + "live.plan.selectCamera": "Selecteer een camera", + "live.plan.selectHintEditing": "Sleep geplaatste markers voor fijne afstelling. Bekijk de status en open op aanvraag één liveweergave.", + "live.plan.selectHint": "Bekijk de status en open op aanvraag één liveweergave.", + "live.plan.cameras": "Plattegrondcamera's", + "live.plan.findPlaceholder": "Op deze plattegrond zoeken…", + "live.plan.findLabel": "Camera op deze plattegrond zoeken", + "live.plan.unplaced": "Niet geplaatste camera's", + "live.plan.unplacedHint": "Selecteer een camera en klik vervolgens op de positie op de plattegrond.", + "live.plan.renameTitle": "Plattegrond hernoemen", + "live.plan.renameDescription": "Plattegronden worden gedeeld met elke bediener van deze locatie.", + "live.plan.deleteTitle": "Plattegrond verwijderen", + "live.plan.deleteMessage": "“{name}” en de geüploade achtergrond verwijderen? Cameraplaatsingen op deze plattegrond worden verwijderd; de camera's zelf blijven ongewijzigd.", + "setupWizard.welcomeTitle": "Welkom bij LightNVR", + "setupWizard.welcomeIntro": "Laten we je NVR in een paar snelle stappen configureren. Je kunt deze instellingen later altijd opnieuw bekijken op de instellingenpagina.", + "setupWizard.welcomeStorage": "Opslagpad en omvanglimieten", + "setupWizard.welcomePerformance": "Prestatielimieten voor jouw aantal camera's", + "setupWizard.welcomeSecurity": "Veilig beheerdersaanmelden", + "setupWizard.storageTitle": "Opslag en database", + "setupWizard.storageIntro": "Waar moeten opnames en de database worden opgeslagen?", + "setupWizard.storagePath": "Opslagpad voor opnames", + "setupWizard.storagePathHint": "Absoluut pad waar videobestanden worden geschreven.", + "setupWizard.maxStorage": "Maximale opslagruimte (GB)", + "setupWizard.maxStorageHint": "0 = onbeperkt.", + "setupWizard.dbPath": "Databasepad", + "setupWizard.dbPathHint": "Locatie van het SQLite-databasebestand.", + "setupWizard.performanceTitle": "Prestaties", + "setupWizard.performanceIntro": "Deze instellingen bepalen de capaciteit, niet de videokwaliteit. De meeste gebruikers kunnen de standaardwaarden aanhouden.", + "setupWizard.threadPool": "Grootte van de worker-threadpool", + "setupWizard.threadPoolInfo": "is van invloed op achtergrondwerk van web/server. De aanbevolen standaardwaarde is doorgaans het best, tenzij je prestaties aan het afstemmen bent.", + "setupWizard.maxStreams": "Maximaal aantal gelijktijdige streams", + "setupWizard.maxStreamsInfo": "is de capaciteitslimiet voor camera's van deze draaiende instantie. Stel het minstens in op het aantal camera's dat je wilt toevoegen, plus wat extra ruimte.", + "setupWizard.important": "Belangrijk:", + "setupWizard.restartWarning": "als je een van beide instellingen wijzigt, wordt de nieuwe waarde nu opgeslagen, maar pas gebruikt nadat LightNVR opnieuw is opgestart. Als de huidige streamlimiet bijvoorbeeld 1 is en je verhoogt die naar 32, dan moet je herstarten voordat je meer camera's toevoegt dan de oude limiet toelaat.", + "setupWizard.threadPoolHintCores": "Aanbevolen: {recommended} (2× je CPU van {cores} kernen). Dit regelt de achtergrond-workerthreads van libuv. Bereik: 2–128.", + "setupWizard.threadPoolHint": "Aanbevolen: {recommended} (2× je CPU-kernen). Dit regelt de achtergrond-workerthreads van libuv. Bereik: 2–128.", + "setupWizard.maxStreamsHint": "Hoeveel camera's LightNVR tegelijk actief kan houden. Standaard 32, maximaal {max}. Verwacht je 8 camera's, kies dan minstens 8. Opnieuw opstarten vereist om van kracht te worden.", + "setupWizard.completeTitle": "Configuratie voltooid!", + "setupWizard.saved": "Je instellingen zijn succesvol opgeslagen.", + "setupWizard.notSaved": "Er zijn geen instellingen gewijzigd — de standaardwaarden worden gebruikt.", + "setupWizard.restartRequired": "Opnieuw opstarten vereist", + "setupWizard.restartRequiredInfo": "wijzigingen in de threadpoolgrootte en/of het maximaal aantal streams zijn opgeslagen, maar worden pas van kracht nadat de service opnieuw is opgestart. Herstart voordat je meer camera's toevoegt of het nieuwe capaciteitslimiet verwacht.", + "setupWizard.saveFailed": "Instellingen opslaan mislukt: {error}", + "setupWizard.back": "Terug", + "setupWizard.saving": "Opslaan…", + "setupWizard.saveContinue": "Opslaan en doorgaan", + "setupWizard.next": "Volgende →", + "setupWizard.finish": "Naar het dashboard", + "setupWizard.skip": "Installatiewizard overslaan", + "live.eptzCanvasLabel": "Elektronisch panorama-, tilt- en zoombeeld voor fisheye", + "live.eptzCanvasHint": "Sleep om te schuiven en te kantelen; wiel of knijpen om te zoomen; Home herstelt", + "live.eptzReset": "ePTZ-weergave herstellen", + "live.autoShort": "Auto", + "live.webrtcShort": "WebRTC", + "nav.investigation": "Onderzoek", + "availability.label": "Beschikbaarheid camera's", + "availability.live": "Nu live", + "availability.offline": "Offline (eerder verbonden)", + "availability.neverConnected": "Nooit verbonden", + "availability.disabled": "Uitgeschakeld", + "availability.all": "Alle camera's", + "streams.inventory": "Inventaris", + "streams.configuration": "Configuratie", + "events.tab": "Gebeurtenissen", + "events.eyebrow": "Gebeurtenisgestuurde integraties", + "events.title": "Gebeurtenissen en routing", + "events.description": "Zet camera- en systeemgebeurtenissen om in duurzame MQTT-streams voor automatisering, notificatiediensten en externe verwerking. LightNVR biedt de gebeurtenisinterface; e-mail- en sms-bezorging blijven bij downstream services.", + "events.routes": "Routes", + "events.destinations": "Bestemmingen", + "events.catalog": "Gebeurteniscatalogus", + "events.enable": "Inschakelen", + "events.loadError": "Gebeurtenisroutingconfiguratie kon niet worden geladen", + "events.accessDenied": "Toegang geweigerd - onvoldoende rechten", + "events.summary.routes": "Routes", + "events.summary.enabled": "{count} ingeschakeld", + "events.summary.destinations": "Bestemmingen", + "events.summary.managedActive": "{count} beheerd en actief", + "events.summary.types": "Geregistreerde typen", + "events.summary.registry": "Versiebeheerde gebeurteniscatalogus", + "events.summary.interface": "Interface", + "events.summary.interfaceHelp": "Duurzame gebeurtenisuitvoer", + "events.route.add": "Route toevoegen", + "events.route.addTitle": "Gebeurtenisroute aanmaken", + "events.route.editTitle": "Gebeurtenisroute bewerken", + "events.route.create": "Route aanmaken", + "events.route.editorDescription": "Kies welke gebeurtenissen in aanmerking komen, welke camera's binnen het bereik vallen, waar ze naartoe gaan en hoe drukke bronnen worden beheerst.", + "events.route.emptyTitle": "Geen eventroutes geconfigureerd", + "events.route.emptyDescription": "maak een route aan om eventtypes, camerabereik, planning, onderdrukkingsbeleid en MQTT-bestemming te selecteren.", + "events.route.enabled": "Route ingeschakeld", + "events.route.enabledHelp": "Overeenkomende events worden geaccepteerd voor duurzame levering", + "events.route.destination": "Bestemming", + "events.route.destinationHelp": "Een overeenkomend event wordt eenmaal opgeslagen voor elke unieke bestemming.", + "events.route.eventTypes": "Eventtypes", + "events.route.eventTypesHelp": "Selecteer een of meer versiebeheerde eventcontracten uit het register.", + "events.route.detectionFilters": "Objectdetecties filteren", + "events.route.detectionFiltersHelp": "Optioneel labels, zones of een minimale betrouwbaarheid vereisen voor objectdetectie-events.", + "events.route.healthFilters": "Systeemgezondheidsevents filteren", + "events.route.healthFiltersHelp": "Optioneel geregistreerde gezondheidsconditiecodes of ernstniveaus matchen. De beschikbare waarden komen van deze recorder.", + "events.route.healthConditions": "Gezondheidscondities (willekeurig)", + "events.route.healthSeverities": "Ernstniveaus (willekeurig)", + "events.route.healthRegistryUnavailable": "Het gezondheidsconditieregister is niet beschikbaar. Herlaad voordat u conditiefilters configureert.", + "events.route.labels": "Labels (willekeurig)", + "events.route.zones": "Zone-ID's (willekeurig)", + "events.route.listHelp": "Scheid waarden met komma's.", + "events.route.minConfidence": "Minimale betrouwbaarheid", + "events.route.confidenceHelp": "Een waarde van 0 tot 1.", + "events.route.cameraScope": "Camerabereik", + "events.route.cameraScopeHelp": "Hergebruik vlootlocaties, tags, collecties van attributen of expliciete camera's zonder de volledige vloot te laden.", + "events.route.allCameras": "Alle camera's", + "events.route.dynamicScope": "Dynamische cameraselector", + "events.route.systemScopeHelp": "Systeemevents zijn geen camera's. Cameraselectors zijn niet beschikbaar wanneer deze route systeemevents bevat.", + "events.route.schedule": "Planning", + "events.route.scheduleHelp": "Gebruik de eventgebeurtenistijd in een IANA-tijdzone; overnachtelijke vensters worden ondersteund.", + "events.route.restrictSchedule": "Alleen tijdens geconfigureerde vensters", + "events.route.suppression": "Ruis- en leveringsbeleid", + "events.route.suppressionHelp": "Nul schakelt een besturing uit. Onderdrukking wordt pas doorgevoerd nadat die bestemming het duurzame event accepteert.", + "events.route.debounce": "Debounce-seconden", + "events.route.debounceHelp": "Herhaalde waarnemingen verlengen dit rustinterval.", + "events.route.cooldown": "Afkoelperiode (seconden)", + "events.route.cooldownHelp": "Minimuminterval na een geaccepteerd evenement.", + "events.route.grouping": "Groeperingsvenster (seconden)", + "events.route.groupingHelp": "Behoud het eerste evenement en voeg herhalingen samen.", + "events.route.rateLimit": "Evenementen per minuut", + "events.route.rateLimitHelp": "Vast-venstermaximum per route en camera.", + "events.route.deliveryPolicy": "Bezorgbeleid", + "events.route.suppressionActive": "Ruisbeheer actief", + "events.route.everyMatch": "Elke overeenkomst", + "events.route.preview": "Route voorvertonen", + "events.route.previewing": "Voorvertonen…", + "events.route.previewResult": "Route-voorvertoning", + "events.route.cameraMatches": "{count} camera's komen overeen", + "events.route.previewNoPublish": "De voorvertoning valideert de volledige regel en lost een cameramonster op; er wordt nooit een evenement gepubliceerd.", + "events.route.systemPreviewHelp": "Systeemgebeurtenissen omzeilen de cameraselectie en melden daarom nul overeenkomende camera's in deze voorvertoning.", + "events.route.created": "Evenementroute aangemaakt", + "events.route.updated": "Evenementroute bijgewerkt", + "events.route.deleted": "Evenementroute verwijderd", + "events.route.disabled": "Evenementroute uitgeschakeld", + "events.route.enabledMessage": "Evenementroute ingeschakeld", + "events.route.deleteConfirm": "Evenementroute \"{name}\" verwijderen?", + "events.route.validation.name": "Voer een routenaam in.", + "events.route.validation.destination": "Kies een bestemming.", + "events.route.validation.event_types": "Selecteer minimaal één evenementtype.", + "events.route.validation.selector": "Voltooi of corrigeer de cameraselector.", + "events.route.validation.system_scope": "Cameraselectors kunnen niet worden gebruikt met systeemgebeurtenissen.", + "events.route.validation.detection_type": "Detectiefilters vereisen het objectdetectie-evenementtype.", + "events.route.validation.detection_filter": "Voeg minimaal één detectielabel, zone of vertrouwensdrempel toe.", + "events.route.validation.confidence": "Minimale vertrouwenswaarde moet tussen 0 en 1 liggen.", + "events.route.validation.predicate_mix": "Detectie- en healthfilters kunnen niet in één route worden gecombineerd.", + "events.route.validation.health_type": "Healthfilters vereisen alleen geregistreerde systeemhealth-evenementtypes.", + "events.route.validation.health_filter": "Selecteer minimaal één geregistreerde healthvoorwaarde of ernst.", + "events.route.validation.health_condition": "Selecteer alleen conditiecodes die door de gezondheidsregistratie van de recorder worden geretourneerd.", + "events.route.validation.health_severity": "Selecteer alleen ernstniveaus die door de geselecteerde gezondheidsgebeurtenistypen worden ondersteund.", + "events.route.validation.timezone": "Voer een geïnstalleerde IANA-tijdzone in, zoals UTC of America/New_York.", + "events.route.validation.schedule_window": "Elk planningsvenster heeft minimaal één dag en verschillende geldige start- en eindtijden nodig.", + "events.route.validation.suppression": "Onderdrukkingswaarden moeten gehele getallen binnen de toegestane bereiken zijn.", + "events.schedule.timezone": "Tijdzone", + "events.schedule.timezoneHelp": "Moet aanwezig zijn in de tijdzonedatabase van de recorder.", + "events.schedule.addWindow": "Tijdvenster toevoegen", + "events.schedule.windowNumber": "Venster {number}", + "events.schedule.start": "Start", + "events.schedule.end": "Einde", + "events.schedule.sunday": "Zon", + "events.schedule.monday": "Maa", + "events.schedule.tuesday": "Din", + "events.schedule.wednesday": "Woe", + "events.schedule.thursday": "Don", + "events.schedule.friday": "Vri", + "events.schedule.saturday": "Zat", + "events.destination.add": "Bestemming toevoegen", + "events.destination.addTitle": "MQTT-bestemming toevoegen", + "events.destination.editTitle": "MQTT-bestemming bewerken", + "events.destination.create": "Bestemming aanmaken", + "events.destination.editorDescription": "Configureer een duurzame gebeurtenisuitvoer. Inloggegevens blijven alleen-schrijven en worden nooit door de API geretourneerd.", + "events.destination.default": "Standaard MQTT-instellingen", + "events.destination.settingsManaged": "Instellingen beheerd", + "events.destination.defaultDescription": "De bestaande MQTT-configuratie blijft beschikbaar als mqtt:default en wordt gebruikt door {count} routes.", + "events.destination.openSettings": "MQTT-instellingen openen", + "events.destination.emptyTitle": "Geen beheerde bestemmingen", + "events.destination.emptyDescription": "Voeg een extra MQTT-broker toe voor onafhankelijke gebeurtenisbezorging aan een cloudconnector, automatiseringssysteem of notificatiedienst.", + "events.destination.identity": "Bestemmingsidentiteit", + "events.destination.enabled": "Bestemming ingeschakeld", + "events.destination.enabledHelp": "Verbinden en de duurzame wachtrij leeghalen", + "events.destination.active": "Actief", + "events.destination.paused": "Gepauzeerd", + "events.destination.pause": "Pauze", + "events.destination.broker": "Broker", + "events.destination.host": "Brokerhost", + "events.destination.hostHelp": "Alleen hostnaam of IP-adres; voeg geen URL-scheme toe.", + "events.destination.port": "Poort", + "events.destination.clientId": "Client-ID", + "events.destination.clientIdHelp": "Moet uniek zijn voor deze brokerverbinding.", + "events.destination.topic": "Onderwerp", + "events.destination.topicTemplate": "Onderwerpsjabloon", + "events.destination.topicHelp": "Moet de tokens voor evenementtype en onderwerp-ID bevatten; MQTT-wildcards zijn niet toegestaan.", + "events.destination.keepalive": "Keepalive-seconden", + "events.destination.statusTopicTemplate": "Aanwezigheidsstatusonderwerp", + "events.destination.statusTopicHelp": "Optioneel. Moet {installation_uuid} bevatten; {destination_uuid} is ook beschikbaar. MQTT-wildcards zijn niet toegestaan.", + "events.destination.statusTopicEnabled": "Aanwezigheid is expliciet ingeschakeld voor dit doel. Het onderwerp wordt nooit afgeleid van het evenementonderwerp.", + "events.destination.statusTopicDisabled": "Aanwezigheid is uitgeschakeld voor dit doel. Laat dit veld leeg om het uitgeschakeld te houden.", + "events.destination.qos": "Quality of Service", + "events.destination.qos0": "één keer verzenden", + "events.destination.qos1": "minstens één keer", + "events.destination.qos2": "precies één keer", + "events.destination.authentication": "Verificatie", + "events.destination.passwordPreserved": "Laat leeg om het opgeslagen alleen-schrijf-wachtwoord te behouden.", + "events.destination.passwordOptional": "Optioneel wanneer de broker anonieme clients toestaat.", + "events.destination.clearPassword": "Wis het opgeslagen wachtwoord", + "events.destination.transportSecurity": "Transportbeveiliging", + "events.destination.tlsMode": "TLS-modus", + "events.destination.tlsSystem": "Systeemvertrouwensopslag", + "events.destination.tlsCustomCa": "Aangepaste certificeringsinstantie", + "events.destination.tlsMutual": "Wedzijdige TLS", + "events.destination.tlsDisabled": "Uitgeschakeld (platte tekst)", + "events.destination.tlsHelp.system": "Verifieer het certificaat van de broker tegen de vertrouwensopslag van het besturingssysteem.", + "events.destination.tlsHelp.custom_ca": "Verifieer de broker met een expliciet PEM-certificaatautoriteitbestand.", + "events.destination.tlsHelp.mutual": "Verifieer de broker met een expliciete CA en presenteer een clientcertificaat en -sleutel.", + "events.destination.tlsHelp.disabled": "Geen transportversleuteling of verificatie van brokeridentiteit.", + "events.destination.caFile": "CA-bestand", + "events.destination.certFile": "Clientcertificaatbestand", + "events.destination.keyFile": "Clientsleutelbestand", + "events.destination.absolutePathHelp": "Gebruik een absoluut pad dat leesbaar is voor de LightNVR-service.", + "events.destination.plaintextWarning": "Onversleutelde MQTT kan evenementmetadata en aanmeldgegevens blootstellen. Gebruik dit alleen op een vertrouwd, geïsoleerd netwerk.", + "events.destination.security": "Beveiliging", + "events.destination.tls.system": "Systeemvertrouwen", + "events.destination.tls.custom_ca": "Aangepaste CA", + "events.destination.tls.mutual": "Wederzijdse TLS", + "events.destination.tls.disabled": "Onversleuteld", + "events.destination.routes": "Routes", + "events.destination.presence": "Aanwezigheidsonderwerp", + "events.destination.deleteInUse": "Verwijder of leid routes om voordat u deze bestemming verwijdert.", + "events.destination.created": "MQTT-bestemming aangemaakt", + "events.destination.updated": "MQTT-bestemming bijgewerkt", + "events.destination.deleted": "MQTT-bestemming verwijderd", + "events.destination.pausedMessage": "MQTT-bestemming gepauzeerd; wachtrijgebeurtenissen blijven behouden tot het verlopen.", + "events.destination.enabledMessage": "MQTT-bestemming ingeschakeld", + "events.destination.deleteConfirm": "MQTT-bestemming \"{name}\" verwijderen?", + "events.destination.validation.name": "Voer een bestemmingsnaam in.", + "events.destination.validation.host": "Voer een broker-hostnaam of IP-adres in.", + "events.destination.validation.client_id": "Voer een broker-client-ID in.", + "events.destination.validation.topic": "Het onderwerp moet de tokens voor evenementtype en onderwerp-ID bevatten en mag geen MQTT-wildcards bevatten.", + "events.destination.validation.status_topic": "Het optionele aanwezigheidsonderwerp moet het installatie-UUID-token bevatten, alleen ondersteunde tokens gebruiken en mag geen MQTT-wildcards bevatten.", + "events.destination.validation.port": "Poort moet een geheel getal zijn van 1 tot 65535.", + "events.destination.validation.keepalive": "Keepalive moet een geheel getal zijn van 5 tot 3600 seconden.", + "events.destination.validation.qos": "Kies MQTT QoS 0, 1 of 2.", + "events.destination.validation.username": "Een ingesteld wachtwoord vereist een gebruikersnaam.", + "events.destination.validation.ca_file": "Deze TLS-modus vereist een absoluut CA-bestandspad.", + "events.destination.validation.mutual_files": "Mutual TLS vereist absolute paden voor CA, clientcertificaat en clientsleutel.", + "fleet.eyebrow": "Cameraacties", + "fleet.title": "Cameraoverzicht", + "fleet.description": "Vind, beoordeel en organiseer camera's in grote implementaties zonder de volledige inventaris in de browser te laden.", + "fleet.summary": "Samenvatting fleetstatus", + "fleet.totalCameras": "Overeenkomende camera's", + "fleet.needsAttention": "Gedegradeerd", + "fleet.searchLabel": "Camera's zoeken", + "fleet.searchPlaceholder": "Zoek op naam, adres, locatie, tag, leverancier of model…", + "fleet.resultCount": "{count} camera's", + "fleet.filters": "Filters", + "fleet.clearFilters": "Filters wissen", + "fleet.filter.health": "Status", + "fleet.filter.enabled": "Camerastatus", + "fleet.filter.anyState": "Alle statussen", + "fleet.filter.recording": "Opnamemodus", + "fleet.filter.location": "Locatieboom", + "fleet.filter.allLocations": "Alle locaties", + "fleet.filter.tags": "Tags (elke overeenkomst)", + "fleet.filter.collection": "Cameraverzameling", + "fleet.health.unknown": "Onbekend", + "fleet.health.up": "Online", + "fleet.health.degraded": "Gedegradeerd", + "fleet.health.down": "Offline", + "fleet.health.disabled": "Uitgeschakeld", + "fleet.recording.off": "Uit", + "fleet.recording.continuous": "Continu", + "fleet.recording.detection": "Detectie", + "fleet.recordingActive": "Nu aan het opnemen", + "fleet.recordingInactive": "Niet aan het opnemen", + "fleet.column.camera": "Camera", + "fleet.column.health": "Status", + "fleet.column.location": "Locatie", + "fleet.column.tags": "Tags", + "fleet.column.recording": "Opname", + "fleet.viewLive": "Livebeeld", + "fleet.lastFrame": "Laatste frame", + "fleet.noAddress": "Adres niet beschikbaar", + "fleet.unassigned": "Niet toegewezen", + "fleet.loading": "Cameravloot laden…", + "fleet.refreshing": "Vernieuwen…", + "fleet.loadError": "Cameravloot kon niet worden geladen", + "fleet.emptyTitle": "Geen camera's geconfigureerd", + "fleet.emptyDescription": "Voeg een stream toe om deze beschikbaar te maken in de werkruimte.", + "fleet.emptyFilteredTitle": "Geen camera's gevonden voor dit overzicht", + "fleet.emptyFilteredDescription": "Probeer de zoekopdracht te verbreden of een of meer filters te wissen.", + "fleet.paginationSummary": "{first}–{last} van {total} weergegeven", + "fleet.perPage": "Per pagina", + "fleet.pageOf": "Pagina {page} van {pages}", + "fleet.selectPage": "Alle camera's op deze pagina selecteren", + "fleet.selectCamera": "{name} selecteren", + "fleet.selectedCount": "{count} camera's geselecteerd", + "fleet.organizeSelected": "Selectie organiseren", + "fleet.clearSelection": "Selectie wissen", + "fleet.organization.manage": "Organisatie beheren", + "fleet.organization.title": "Cameraorganisatie", + "fleet.organization.description": "Beheer een herbruikbare locatiehiërarchie en genormaliseerde tagwoordenlijst voor de cameravloot.", + "fleet.organization.locations": "Locaties", + "fleet.organization.tags": "Tags", + "fleet.organization.locationsDescription": "Stel locaties, gebouwen, verdiepingen en operationele zones voor als een navigeerbare hiërarchie.", + "fleet.organization.tagsDescription": "Gebruik een beheerde tagwoordenlijst in plaats van inconsistente vrije labels.", + "fleet.organization.addRoot": "Bovenliggende locatie toevoegen", + "fleet.organization.addLocation": "Locatie toevoegen", + "fleet.organization.editLocation": "Locatie bewerken", + "fleet.organization.addChild": "Onderliggende locatie toevoegen", + "fleet.organization.type": "Type", + "fleet.organization.parent": "Bovenliggende locatie", + "fleet.organization.topLevel": "Hoofdniveau", + "fleet.organization.sortOrder": "Sorteervolgorde", + "fleet.organization.contents": "Inhoud", + "fleet.organization.cameras": "Camera's", + "fleet.organization.system": "Systeem", + "fleet.organization.contentCounts": "{cameras} camera's · {children} onderliggende locaties", + "fleet.organization.locationNotEmpty": "Verplaats eerst de camera's en verwijder de onderliggende locaties", + "fleet.organization.noLocations": "Er zijn geen locaties geconfigureerd.", + "fleet.organization.locationCreated": "Locatie aangemaakt", + "fleet.organization.locationUpdated": "Locatie bijgewerkt", + "fleet.organization.locationDeleted": "Locatie verwijderd", + "fleet.organization.deleteLocationConfirm": "Locatie \"{name}\" verwijderen?", + "fleet.organization.addTag": "Tag toevoegen", + "fleet.organization.editTag": "Tag bewerken", + "fleet.organization.tagLabel": "Tag", + "fleet.organization.color": "Kleur (#RRGGBB)", + "fleet.organization.tagDescription": "Beschrijving", + "fleet.organization.noTags": "Er zijn geen genormaliseerde tags geconfigureerd.", + "fleet.organization.tagCreated": "Tag aangemaakt", + "fleet.organization.tagUpdated": "Tag bijgewerkt", + "fleet.organization.tagDeleted": "Tag verwijderd", + "fleet.organization.deleteTagConfirm": "\"{name}\" verwijderen? Deze is momenteel toegewezen aan {count} camera's.", + "fleet.organization.merge": "Samenvoegen", + "fleet.organization.mergeTagNamed": "\"{name}\" samenvoegen", + "fleet.organization.mergeInto": "Samenvoegen met", + "fleet.organization.chooseTag": "Kies de tag die behouden blijft", + "fleet.organization.mergeWarning": "Alle cameratoewijzingen worden verplaatst naar de behouden tag; de brontag wordt vervolgens verwijderd.", + "fleet.organization.tagsMerged": "Tags samengevoegd", + "fleet.organization.saveError": "Opslaan mislukt: {message}", + "fleet.organization.deleteError": "Kan niet verwijderen: {message}", + "fleet.locationType.site": "Site", + "fleet.locationType.building": "Gebouw", + "fleet.locationType.floor": "Verdieping", + "fleet.locationType.area": "Gebied", + "fleet.locationType.zone": "Zone", + "fleet.locationType.system": "Systeem", + "fleet.bulk.title": "Geselecteerde camera's organiseren", + "fleet.bulk.description": "Locatie- en tagwijzigingen toepassen op {count} camera's met beperkte gelijktijdigheid.", + "fleet.bulk.location": "Locatietoewijzing", + "fleet.bulk.locationHelp": "Alle geselecteerde camera's worden verplaatst naar de gekozen locatie.", + "fleet.bulk.keepLocations": "Huidige locaties behouden", + "fleet.bulk.tags": "Tagtoewijzing", + "fleet.bulk.tagsHelp": "Tags toevoegen of verwijderen zonder andere toewijzingen te wijzigen, of de volledige tagset expliciet vervangen.", + "fleet.bulk.tagOperation.none": "Behouden", + "fleet.bulk.tagOperation.add": "Toevoegen", + "fleet.bulk.tagOperation.remove": "Verwijderen", + "fleet.bulk.tagOperation.replace": "Alles vervangen", + "fleet.bulk.replaceWarning": "Alles vervangen verwijdert alle huidige tags voordat deze selectie wordt toegepast. Een lege selectie wist alle tags.", + "fleet.bulk.apply": "Wijzigingen toepassen", + "fleet.bulk.working": "Wijzigingen toepassen…", + "fleet.bulk.success": "{count} camera's bijgewerkt", + "fleet.bulk.partial": "{succeeded} camera's bijgewerkt; {failed} mislukt", + "fleet.bulk.error": "Kan camera's niet organiseren: {message}", + "fleet.bulk.failures": "Camera's die niet bijgewerkt konden worden", + "fleet.queues.degraded": "Gedegradeerde streams", + "fleet.queues.offline": "Offline camera's", + "fleet.queues.oldest": "Oudste: {time}", + "fleet.queues.noneActive": "Geen actieve voorwaarden", + "fleet.views.title": "Opgeslagen weergaven", + "fleet.views.choose": "Kies een opgeslagen weergave", + "fleet.views.none": "Nog geen opgeslagen weergaven", + "fleet.views.shared": "Gedeeld", + "fleet.views.saveCurrent": "Huidige weergave opslaan", + "fleet.views.name": "Weergavenaam", + "fleet.views.share": "Delen met alle operators", + "fleet.views.saved": "Vlootweergave opgeslagen", + "fleet.views.saveError": "Weergave kon niet worden opgeslagen: {message}", + "fleet.views.deleted": "Vlootweergave verwijderd", + "fleet.views.deleteConfirm": "Opgeslagen weergave \"{name}\" verwijderen?", + "fleet.views.deleteError": "Weergave kon niet worden verwijderd: {message}", + "fleet.views.unsupported": "Deze opgeslagen selector kan niet worden weergegeven door de huidige filteropties.", + "collections.manage": "Verzamelingen", + "collections.all": "Alle verzamelingen", + "collections.filter": "Verzameling", + "collections.loadMembersError": "Cameraverzamelingen konden niet worden geladen: {message}", + "collections.title": "Cameraverzamelingen", + "collections.subtitle": "Maak herbruikbare cameragroepen voor operaties, opgeslagen weergaven en downstream-workflows.", + "collections.listDescription": "Statische verzamelingen behouden expliciete lidmaatschappen; slimme verzamelingen evalueren continu vlootregels.", + "collections.create": "Verzameling aanmaken", + "collections.edit": "Verzameling bewerken", + "collections.editorDescription": "Verzamelingsdefinities gebruiken stabiele UUID's voor camera's, locaties en tags.", + "collections.backToList": "Terug naar verzamelingen", + "collections.type": "Verzamelingstype", + "collections.type.static": "Statisch", + "collections.type.smart": "Slim", + "collections.description": "Beschrijving", + "collections.shared": "Gedeelde verzameling", + "collections.sharedHelp": "Sta andere bevoegde gebruikers toe deze verzameling te zien; cameratoegangsregels blijven van toepassing.", + "collections.typeChangeWarning": "Het wijzigen van het verzamelingstype vervangt het lidmaatschapsmodel. Statische leden of slimme regels van het vorige type zijn niet langer van toepassing.", + "collections.selectorError": "Selector is niet geldig: {message}", + "collections.created": "Verzameling aangemaakt", + "collections.updated": "Verzameling bijgewerkt", + "collections.saveError": "Verzameling kon niet worden opgeslagen: {message}", + "collections.loadError": "Kan collectie niet laden: {message}", + "collections.cameras": "camera's", + "collections.visibility.shared": "Gedeeld", + "collections.visibility.private": "Privé", + "collections.selectorRedacted": "Regels privé", + "collections.emptyTitle": "Nog geen collecties", + "collections.emptyAdmin": "maak een statische groep of een slimme regelgebaseerde weergave om cameraselecties opnieuw te gebruiken.", + "collections.emptyViewer": "Er zijn geen gedeelde collecties beschikbaar voor uw camerabereik.", + "collections.deleteConfirm": "Collectie \"{name}\" verwijderen?", + "collections.deleted": "Collectie verwijderd", + "collections.deleteError": "Kan collectie niet verwijderen: {message}", + "collections.preview.title": "Regelvoorbeeld", + "collections.preview.matches": "{count} overeenkomende camera's", + "collections.preview.action": "Voorbeeld", + "collections.preview.hide": "Voorbeeld verbergen", + "collections.preview.loading": "Evalueren…", + "collections.preview.empty": "Er komen momenteel geen camera's overeen.", + "collections.preview.sample": "Voorbeeld van {count} camera's van {total} overeenkomsten weergegeven.", + "collections.preview.error": "Kan collectie niet voorvertonen: {message}", + "collections.members.title": "Statische leden", + "collections.members.selected": "{count} camera's geselecteerd op alle pagina's", + "collections.members.search": "Camera's zoeken…", + "collections.members.selectPage": "Deze pagina selecteren", + "collections.members.empty": "Geen camera's gevonden voor deze zoekopdracht.", + "collections.builder.title": "Slimme regels", + "collections.builder.description": "Regels worden geëvalueerd op basis van de huidige cameraorganisatie, configuratie, mogelijkheden en status.", + "collections.builder.match": "Overeenkomst", + "collections.builder.allRules": "alle regels", + "collections.builder.anyRule": "een regel", + "collections.builder.addRule": "Regel toevoegen", + "collections.builder.removeRule": "Regel verwijderen", + "collections.builder.matchesAll": "Zonder volledige regels komt deze collectie overeen met elke camera binnen het bevoegde bereik van de gebruiker.", + "collections.builder.incompleteRule": "Voltooi of verwijder elke regel voordat u opslaat.", + "collections.builder.chooseLocation": "Kies een locatie-subtree", + "collections.builder.vendorPlaceholder": "Namen van fabrikanten, gescheiden door komma's", + "collections.builder.modelPlaceholder": "Namen van modellen, gescheiden door komma's", + "collections.builder.advancedMode": "Geavanceerde JSON", + "collections.builder.visualMode": "Visuele builder", + "collections.builder.cannotVisualize": "Deze selector bevat geneste of geavanceerde logica die de visuele builder niet veilig kan weergeven.", + "collections.rule.location_subtree": "Locatie is binnen", + "collections.rule.camera_uuid": "Specifieke camera's", + "collections.rule.tag_any": "Heeft een van de tags", + "collections.rule.tag_all": "Heeft alle tags", + "collections.rule.tag_none": "Heeft geen van de tags", + "collections.rule.health": "Status is", + "collections.rule.enabled": "Camera is", + "collections.rule.recording_mode": "Opnamemodus is", + "collections.rule.capability_any": "Heeft een van de functionaliteiten", + "collections.rule.capability_all": "Heeft alle functionaliteiten", + "collections.rule.vendor": "Fabrikant is", + "collections.rule.model": "Model is", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Audio-backchannel", + "streamHealth.observedFps": "Waargenomen FPS", + "streamHealth.expectedFps": "Verwacht", + "streamHealth.fpsHelp": "Waargenomen door LightNVR; verwacht komt uit de metadata van de camerastream.", + "login.passwordChanged": "Wachtwoord succesvol gewijzigd. Meld u aan met uw nieuwe wachtwoord.", + "passwordChangeRequired.title": "Wijzig het standaardwachtwoord", + "passwordChangeRequired.description": "Deze installatie gebruikt nog steeds het standaardbeheerderswachtwoord. Vervang het voordat u doorgaat naar LightNVR. MFA wordt, indien ingeschakeld, bij uw volgende aanmelding gecontroleerd.", + "passwordChangeRequired.currentPassword": "Huidig wachtwoord", + "passwordChangeRequired.newPassword": "Nieuw wachtwoord", + "passwordChangeRequired.confirmPassword": "Bevestig nieuw wachtwoord", + "passwordChangeRequired.passwordHelp": "Gebruik minimaal 8 tekens. Het wachtwoord mag niet admin zijn.", + "passwordChangeRequired.submit": "Wachtwoord wijzigen", + "passwordChangeRequired.saving": "Wachtwoord wijzigen…", + "passwordChangeRequired.error.currentRequired": "Voer je huidige wachtwoord in.", + "passwordChangeRequired.error.tooShort": "Het nieuwe wachtwoord moet minimaal 8 tekens bevatten.", + "passwordChangeRequired.error.defaultPassword": "Het nieuwe wachtwoord mag niet admin zijn.", + "passwordChangeRequired.error.mismatch": "De nieuwe wachtwoorden komen niet overeen.", + "passwordChangeRequired.error.generic": "Het wachtwoord kon niet worden gewijzigd. Probeer het opnieuw.", + "settings.tab.health": "Status", + "settings.tab.workspaces": "Werkruimtes", + "settings.health.title": "Status van host en hardware", + "settings.health.description": "Configureer beperkte besturingssysteem- en hardwarebewaking zonder apparaatpaden of geheimen bloot te stellen.", + "settings.health.enabled": "Statusbewaking inschakelen", + "settings.health.enabledHelp": "Verzamel ondersteunde host-, service-, opslag-, netwerk- en hardware-signalen.", + "settings.health.profile": "Beleidsprofiel", + "settings.health.profileHelp": "Gebalanceerd is de standaard; conservatief vereist sterker bewijs voordat er een waarschuwing wordt gegeven.", + "settings.health.profile.balanced": "Gebalanceerd", + "settings.health.profile.conservative": "Conservatief", + "settings.health.hardwareProvider": "Hardwareprovider", + "settings.health.provider.auto": "Automatisch (kernelproviders)", + "settings.health.provider.smartctl": "smartctl (expliciet)", + "settings.health.providerHelp.auto": "Gebruikt alleen beperkte sysfs-, NVMe- en kernelproviders; smartctl wordt nooit afgeleid.", + "settings.health.providerHelp.smartctl": "Schakelt de optionele beperkte smartctl JSON-provider expliciet in voor gevonden apparaten.", + "settings.health.providerHelp.disabled": "Schakelt optionele hardwareproviders uit, terwijl draagbare statusbewaking beschikbaar blijft.", + "settings.health.writeProbe": "Schrijfproef voor opslag inschakelen", + "settings.health.writeProbeHelp": "Voert periodiek de beperkte geconfigureerde proef op de opnamebestemming uit.", + "settings.health.cadences": "Bemonsteringsintervallen", + "settings.health.cadencesHelp": "Intervallen moeten geordend blijven van snel tot apparaatbemonstering en binnen de servergrenzen.", + "settings.health.fastInterval": "Snel interval", + "settings.health.normalInterval": "Normaal interval", + "settings.health.slowInterval": "Langzaam interval", + "settings.health.deviceInterval": "Apparaatinterval", + "settings.health.presenceInterval": "Aanwezigheidsinterval", + "settings.health.retention": "Incidentbewaring", + "settings.health.conditions": "Conditieoverschrijvingen", + "settings.health.conditionsHelp": "Overschrijf alleen conditiecodes en eenheden die door de effectieve-beleidsregistratie worden geretourneerd.", + "settings.health.conditionOverride": "conditieoverschrijving", + "settings.health.overrideMode": "Overschrijvingsmodus", + "settings.health.overrideModeHelp": "Erf het geselecteerde profiel over, selecteer een ander beperkt profiel, schakel de conditie uit of stel gevalideerde drempelwaarden in.", + "settings.health.profileDefault": "Geselecteerd profiel gebruiken", + "settings.health.custom": "Aangepaste drempelwaarden", + "settings.health.warning": "Waarschuwingsdrempel", + "settings.health.critical": "Kritieke drempel", + "settings.health.recovery": "Hersteldrempel", + "settings.health.warning_for_seconds": "Waarschuwingsverblijftijd (seconden)", + "settings.health.critical_for_seconds": "Kritieke verblijftijd (seconden)", + "settings.health.recovery_for_seconds": "Herstelverblijftijd (seconden)", + "settings.health.clearOverrides": "Overschrijvingen wissen", + "settings.health.registryUnavailable": "De server heeft geen conditieregistratie geretourneerd. Herlaad voordat u overschrijvingen bewerkt.", + "settings.health.resetDefaults": "Standaardgezondheidswaarden herstellen", + "settings.health.reloadGuidance": "Opslaan is atomair. Herlaad na een succesvolle opslag om het effectieve beleid te bevestigen; herstart alleen wanneer de server dit expliciet vraagt.", + "settings.health.validation.profile": "Kies een ondersteund gezondheidsprofiel.", + "settings.health.validation.provider": "Kies een ondersteunde hardwareprovider.", + "settings.health.validation.healthFastIntervalSeconds": "Het snelle interval moet een geheel getal van 5 tot 60 seconden zijn.", + "settings.health.validation.healthNormalIntervalSeconds": "Het normale interval moet een geheel getal van 15 tot 600 seconden zijn.", + "settings.health.validation.healthSlowIntervalSeconds": "Het langzame interval moet een geheel getal van 60 tot 3600 seconden zijn.", + "settings.health.validation.healthDeviceIntervalSeconds": "Het apparaatinterval moet een geheel getal van 300 tot 86400 seconden zijn.", + "settings.health.validation.healthPresenceIntervalSeconds": "Het aanwezigheidsinterval moet een geheel getal van 15 tot 3600 seconden zijn.", + "settings.health.validation.healthIncidentRetentionDays": "De incidentbewaring moet een geheel getal van 7 tot 3650 dagen zijn.", + "settings.health.validation.ordered": "Bemonsteringsintervallen moeten in volgorde zijn: snel, normaal, langzaam, dan apparaat.", + "settings.health.validation.overrides": "Conditieoverschrijvingen moeten unieke codes en ondersteunde profielen uit de serverregistratie gebruiken.", + "settings.health.validation.thresholds": "Aangepaste drempelwaarden moeten eindige waarden binnen de eenheidsgrenzen van de conditie zijn.", + "settings.health.validation.thresholdOrder": "Waarschuwings-, kritieke en hersteldrempels moeten de alarmrichting en hysterese van de conditie behouden.", + "settings.health.validation.dwell": "Verblijftijden moeten gehele seconden binnen zeven dagen zijn; waarschuwings- en herstelverblijftijd mogen niet nul zijn.", + "workspaces.title": "Operatorwerkruimtes", + "workspaces.description": "Kies welke gespecialiseerde werkruimtes verschijnen in je navigatie en paginakader.", + "workspaces.saved": "Werkruimtevoorkeuren opgeslagen", + "workspaces.saveError": "Kan werkruimtevoorkeuren niet opslaan: {message}", + "workspaces.loadError": "Kan werkruimtevoorkeuren niet laden.", + "workspaces.showWorkspace": "{name} tonen", + "workspaces.authorizationNote": "Dit bepaalt alleen de weergave. Directe URL's en API-toegang volgen nog steeds je autorisatiebeleid.", + "workspaces.liveNavigator": "Uitgebreide Live Navigator", + "workspaces.liveNavigatorDescription": "Locatieboom, beschikbaarheidsfilters, opgeslagen lay-outs en recente gebeurtenissen.", + "workspaces.investigation": "Onderzoek", + "workspaces.investigationDescription": "Zoek, koppel, beveilig en exporteer opgenomen bewijsmateriaal.", + "settings.reduceMotion": "Beweging beperken", + "settings.reduceMotionHelp": "Schakelt niet-essentiële animaties en overgangen uit. Automatisch volgt je besturingssysteemvoorkeur.", + "settings.reduceMotionPreference": "Voorkeur bewegingsbeperking", + "settings.reduceMotionAuto": "Automatisch", + "settings.reduceMotionOn": "Aan", + "settings.reduceMotionOff": "Uit", + "settings.audioCompliance": "Audio-naleving", + "settings.disableAudioGlobally": "Audio uitschakelen op deze instantie", + "settings.audioDisabled": "Audio is wereldwijd uitgeschakeld", + "settings.audioComplianceHelp": "Voorkomt live luisteren, tweerichtingsgesprek en audio in nieuwe opnames op deze instantie. Opslaan start actieve go2rtc-mediasessies opnieuw. Bestaande opnames worden niet aangepast.", + "tokens.manage": "API-toegang beheren", + "tokens.title": "API-toegang — {username}", + "tokens.description": "Maak aanmeldgegevens met beperkt bereik voor integraties en herroep ze onafhankelijk van elkaar.", + "tokens.recommendedTitle": "Tokens met beperkt bereik aanbevolen", + "tokens.recommendedDescription": "Elk token verloopt, heeft expliciete acties en een camerabereik, en kan nooit het huidige toegangsbeleid van de gebruiker overschrijden.", + "tokens.coverageNotice": "Beschikbare machtigingen weerspiegelen wat deze server afdwingt. Een token kan alleen machtigingen gebruiken die de gebruiker al heeft.", + "tokens.createTitle": "Token met beperkt bereik aanmaken", + "tokens.createDescription": "Gebruik één token per integratie zodat het geïdentificeerd, vernieuwd en herroepen kan worden zonder iets anders te verstoren.", + "tokens.name": "Integratienaam", + "tokens.namePlaceholder": "bijv. PTZ-bridge Noordgarage", + "tokens.expiry": "Verloopt na", + "tokens.expiryDays": "{days} dagen", + "tokens.actions": "Toegestane acties", + "tokens.actionsHelp": "Kies alleen wat deze integratie nodig heeft. Destructieve acties verdienen een eigen token.", + "tokens.destructive": "Destructief", + "tokens.noEnforcedActions": "Er zijn geen token-acties beschikbaar in deze serverversie.", + "tokens.scope.label": "Camerabereik", + "tokens.scope.all": "Hele cameravloot", + "tokens.scope.collection": "Gedeelde collectie", + "tokens.scope.selector": "Aangepaste selector", + "tokens.scope.chooseCollection": "Gedeelde cameracollectie", + "tokens.scope.allValue": "Hele vloot", + "tokens.scope.collectionValue": "Collectie: {name}", + "tokens.scope.selectorValue": "Aangepaste dynamische selector", + "tokens.create": "Token aanmaken", + "tokens.creating": "Token aanmaken…", + "tokens.createdSuccess": "API-token met bereik aangemaakt", + "tokens.createError": "API-token kon niet worden aangemaakt: {message}", + "tokens.invalidResponse": "De server heeft een onvolledig referentieantwoord teruggegeven.", + "tokens.existingTitle": "Bestaande tokens", + "tokens.existingDescription": "Na het aanmaken zijn alleen voorvoegsels en metadata beschikbaar.", + "tokens.emptyTitle": "Geen actieve tokens", + "tokens.emptyDescription": "Maak een token met bereik aan voor de eerste integratie die API-toegang nodig heeft.", + "tokens.showInactive": "{count} inactieve weergeven", + "tokens.status.active": "Actief", + "tokens.status.expired": "Verlopen", + "tokens.status.revoked": "Ingetrokken", + "tokens.expires": "Verloopt", + "tokens.expiresValue": "Verloopt {date}", + "tokens.created": "Aangemaakt", + "tokens.lastUsed": "Laatst gebruikt", + "tokens.revoke": "Intrekken", + "tokens.revoking": "Intrekken…", + "tokens.revokeConfirm": "\"{description}\" intrekken? Verzoeken die het gebruiken, werken onmiddellijk niet meer.", + "tokens.revokedSuccess": "API-token ingetrokken", + "tokens.revokeError": "Kan API-token niet intrekken: {message}", + "tokens.validation.missing_description": "Geef de integratie een naam die dit token zal gebruiken.", + "tokens.validation.description_too_long": "Houd de integratienaam onder 128 tekens.", + "tokens.validation.invalid_expiry": "Kies een geldigheidsduur van 1 tot 365 dagen.", + "tokens.validation.missing_actions": "Kies minimaal één toegestane actie.", + "tokens.validation.invalid_action": "Een of meer geselecteerde acties zijn op deze server niet token-ondersteund.", + "tokens.validation.invalid_scope": "Kies een geldig camerabereik.", + "tokens.validation.requires_all_scope": "Rechten buiten camera's vereisen het bereik 'Hele cameravloot'. Kies dat bereik of verwijder die rechten.", + "tokens.validation.missing_collection": "Kies een beschikbare gedeelde collectie.", + "tokens.validation.invalid_selector": "Voltooi of corrigeer de aangepaste cameraselector.", + "tokens.secret.oneTime": "Eén keer weergegeven", + "tokens.secret.scopedTitle": "Sla dit beperkte token nu op", + "tokens.secret.legacyTitle": "Sla deze verouderde API-sleutel nu op", + "tokens.secret.scopedDescription": "lightNVR bewaart alleen een hash van dit token. Als het verloren gaat, trek het dan in en maak een nieuw aan.", + "tokens.secret.legacyDescription": "Deze compatibiliteitssleutel wordt hier slechts één keer weergegeven. Het genereren van een nieuwe sleutel maakt deze ongeldig.", + "tokens.secret.value": "API-referentie", + "tokens.secret.copied": "Gekopieerd", + "tokens.secret.copySuccess": "API-referentie gekopieerd", + "tokens.secret.copyError": "Automatisch kopiëren mislukt; selecteer en kopieer de referentie handmatig.", + "tokens.secret.savedConfirm": "Ik heb deze referentie veilig opgeslagen", + "tokens.secret.savedHelp": "Bevestigen sluit dit venster. De volledige waarde kan niet opnieuw worden weergegeven.", + "tokens.legacy.title": "Verouderde compatibiliteitssleutel", + "tokens.legacy.description": "De verouderde sleutel heeft de volledige effectieve toegang van deze gebruiker, verloopt niet en kan niet worden beperkt per camera of actie.", + "tokens.legacy.warning": "Genereer deze alleen voor een bestaande integratie waarvan de eindpunten nog niet zijn overgestapt op afgedwongen beperkte tokens. Genereren maakt de vorige verouderde sleutel onmiddellijk ongeldig.", + "tokens.legacy.generate": "Verouderde sleutel genereren", + "tokens.legacy.confirm": "Nieuwe verouderde sleutel genereren? Dit maakt de huidige verouderde sleutel van de gebruiker onmiddellijk ongeldig.", + "tokens.legacy.createdSuccess": "Verouderde API-sleutel gegenereerd", + "tokens.legacy.createError": "Kan verouderde API-sleutel niet genereren: {message}", + "audit.manage": "Auditgeschiedenis", + "audit.title": "Beveiligings- en toegangsaudit", + "audit.description": "Volg inlogresultaten, toegangsbeslissingen en gevoelige beleidswijzigingen zonder referenties bloot te stellen.", + "audit.retention": "Bewaartermijn", + "audit.retentionDescription": "Gebeurtenissen worden momenteel {days} dagen bewaard. Het verlagen van deze waarde verwijdert direct oudere gegevens.", + "audit.retentionDays": "Dagen", + "audit.retentionInvalid": "Kies een bewaartermijn tussen 1 en 3650 dagen.", + "audit.retentionSaved": "Bewaartermijn voor audit opgeslagen; {count} verlopen gebeurtenissen verwijderd", + "audit.retentionError": "Bewaartermijn voor audit kon niet worden opgeslagen: {message}", + "audit.filters": "Filters", + "audit.clearFilters": "Filters wissen", + "audit.applyFilters": "Filters toepassen", + "audit.actor": "Acteur", + "audit.unauthenticated": "Niet geauthenticeerd", + "audit.outcome": "Resultaat", + "audit.action": "Exacte actie", + "audit.filterToAction": "Filteren op deze actie", + "audit.since": "Van", + "audit.until": "Tot", + "audit.invalidDateRange": "De begindatum moet vóór de einddatum liggen.", + "audit.source": "Bronadres", + "audit.target": "Doel", + "audit.targetUuid": "Doel-UUID", + "audit.noTarget": "Systeembreed", + "audit.requestId": "Aanvraag-ID", + "audit.apiToken": "Token-ID met bereik", + "audit.showDetails": "Details weergeven", + "audit.hideDetails": "Details verbergen", + "audit.pageSize": "Per pagina", + "audit.resultRange": "{start}–{end} van {total} weergegeven", + "audit.empty": "Geen overeenkomende auditgebeurtenissen", + "audit.emptyDescription": "Wis een of meer filters of wacht op nieuwe beveiligingsactiviteit.", + "audit.exportPage": "Deze pagina exporteren", + "audit.exporting": "Bezig met exporteren…", + "audit.exported": "Auditpagina geëxporteerd", + "audit.exportError": "Kan auditgebeurtenissen niet exporteren: {message}", + "audit.pagination": "Pagina's van auditgeschiedenis", + "audit.page": "Pagina {page}", + "audit.modesTitle": "Toegestane beslissingen", + "audit.modesDescription": "Kies hoe toegestane alleen-lezen-toegang per actie wordt vastgelegd. Verzoeken die iets wijzigen, weigeringen, fouten en aanmeldingen worden altijd vastgelegd. Samenvatten houdt één vermelding per gebruiker, camera en client bij elke {minutes} minuten aan met een telling.", + "audit.mode.record": "Elke afzonderlijk", + "audit.mode.summarize": "Samenvatten", + "audit.mode.off": "Uit", + "audit.modeOffWarning": "Toegestane toegang voor deze actie verschijnt niet meer in de auditgeschiedenis.", + "audit.modesSaved": "Auditbeslissingsmodi opgeslagen", + "audit.modesError": "Kan auditbeslissingsmodi niet opslaan: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Gebeurtenistype", + "audit.eventTypeSummary": "Samenvattingen", + "audit.eventTypeDecision": "Individuele beslissingen", + "access.cameraSearch": "Camera's zoeken", + "access.cameraSearchPlaceholder": "Typ minimaal twee tekens om te zoeken…", + "access.cameraSearchHint": "Zoek op cameranaam, UUID, adres, locatie, tag, leverancier of model.", + "access.cameraSelected": "Geselecteerd", + "access.cameraAdd": "Toevoegen", + "access.cameraLimit": "Een selector kan maximaal 64 expliciete camera's bevatten. Gebruik een locatie- of tagregel voor grotere scopes.", + "access.roles.manage": "Rollen beheren", + "access.roles.title": "Autorisatierollen", + "access.roles.description": "Bundel acties in herbruikbare rollen en wijs die rollen toe aan camerascopes.", + "access.roles.create": "Rol aanmaken", + "access.roles.newRole": "Nieuwe rol", + "access.roles.copyName": "{name} kopie", + "access.roles.clone": "Klonen", + "access.roles.builtin": "Ingebouwd", + "access.roles.builtinHelp": "Ingebouwde rollen zijn vaste, upgradeveilige sjablonen. Kloon er een om deze aan te passen.", + "access.roles.actionCount": "{count} acties", + "access.roles.destructive": "Gevoelige actie", + "access.roles.notEnforced": "Nog niet afgedwongen door een endpoint", + "access.roles.destructiveWarning": "Deze rol kan configuratie of bewijsmateriaal wijzigen. Verleen deze alleen over de scopes waar die bevoegdheid vereist is.", + "access.roles.created": "Rol aangemaakt", + "access.roles.updated": "Rol bijgewerkt", + "access.roles.deleted": "Rol verwijderd", + "access.roles.saveError": "Rol opslaan mislukt: {message}", + "access.roles.deleteError": "Rol verwijderen mislukt: {message}", + "access.roles.deleteConfirm": "Rol \"{name}\" verwijderen? Rollen die door toewijzingen worden gebruikt, kunnen niet worden verwijderd.", + "access.policy.manage": "Toegang beheren", + "access.policy.column": "Toegang", + "access.policy.scopedShort": "Scopebeperkt", + "access.policy.title": "Toegangsbeleid — {username}", + "access.policy.description": "Beheer standaard-weigeren roltoewijzingen en bekijk hun camerascopes.", + "access.policy.tab.grants": "Toewijzingen", + "access.policy.tab.test": "Toegang testen", + "access.policy.scopedWarning": "Alleen acties die zijn toegestaan door een overeenkomende toewijzing en camerascopes werken.", + "access.policy.grants": "Roltoewijzingen", + "access.policy.grantsDescription": "Een toewijzing combineert één rol met de volledige vloot, een gedeelde collectie of een aangepaste cameraselector.", + "access.policy.addGrant": "Toewijzing toevoegen", + "access.policy.noGrants": "Geen toewijzingen geconfigureerd", + "access.policy.noGrantsHelp": "Voeg minimaal één toewijzing toe voordat het scopebeleid wordt geactiveerd, tenzij deze gebruiker geen toegang moet hebben.", + "access.policy.role": "Rol", + "access.policy.chooseRole": "Kies een rol", + "access.policy.scope": "Camerascopes", + "access.policy.allCameras": "Volledige cameravloot", + "access.policy.collectionScope": "Gedeelde collectie", + "access.policy.collection": "Cameracollectie", + "access.policy.chooseCollection": "Kies een gedeelde collectie", + "access.policy.collectionHelp": "Toegang volgt de collectie wanneer camera's worden toegevoegd, verwijderd of door de regels worden gevonden.", + "access.policy.dynamicScope": "Dynamische selector", + "access.policy.activateConfirm": "Standaard-weigeren scopebeleid activeren voor {username}? Acties zonder overeenkomende toewijzing worden geweigerd.", + "access.policy.emptyConfirm": "Scopebeleid activeren voor {username} zonder toewijzingen? Dit verwijdert bewust alle beleidsgestuurde toegang.", + "access.policy.saved": "Toegangsbeleid opgeslagen", + "access.policy.saveError": "Toegangsbeleid kon niet worden opgeslagen: {message}", + "access.policy.version": "Beleidsversie {version}", + "access.policy.unsaved": "Niet-opgeslagen wijzigingen", + "access.policy.validation.invalid_mode": "Kies een geldige evaluatiemodus.", + "access.policy.validation.missing_role": "Elke toewijzing moet verwijzen naar een beschikbare rol.", + "access.policy.validation.invalid_scope": "Elke toewijzing moet een volledige-vloot-, gedeelde-collectie- of selectorbereik gebruiken.", + "access.policy.validation.invalid_selector": "Voltooi of corrigeer elke cameraselector voordat je opslaat.", + "access.policy.validation.missing_collection": "Kies een beschikbare gedeelde collectie voor elke collectietoewijzing.", + "access.policy.validation.duplicate_grant": "Verwijder dubbele rol- en bereiktoewijzingen voordat je opslaat.", + "access.test.title": "Effectieve toegang testen", + "access.test.description": "Evalueer een opgeslagen actie en camera als {username} zonder deze uit te voeren.", + "access.test.saveFirst": "Sla toewijzingswijzigingen op of verwerp ze voordat je test, zodat het resultaat het hier getoonde beleid weerspiegelt.", + "access.test.action": "Actie", + "access.test.camera": "Camera", + "access.test.run": "Toegang testen", + "access.test.running": "Testen…", + "access.test.allowed": "Toegestaan", + "access.test.denied": "Geweigerd", + "access.test.version": "Versie {version}", + "access.test.source": "Bron: {source} · Rol: {role}", + "recordings.pullToRefresh": "Trek om opnames te vernieuwen", + "recordings.releaseToRefresh": "Laat los om opnames te vernieuwen", + "recordings.refreshing": "Opnames vernieuwen…", + "recordings.refreshed": "Opnames vernieuwd", + "recordings.refreshFailed": "Opnames konden niet worden vernieuwd: {message}", + "recordings.download": "Downloaden", + "recordings.tags": "Tags", + "recordings.selectRecording": "Opname selecteren", + "timeline.legend.recording": "Opname", + "timeline.legend.detection": "Detectiegebeurtenis", + "timeline.detectionEvent": "Detectiegebeurtenis", + "streams.showCredentials": "Inloggegevens tonen", + "streams.hideCredentials": "Inloggegevens verbergen", + "streams.streamSuccessfullyEnabled": "Stream succesvol ingeschakeld.", + "streams.errorEnablingStream": "Fout bij inschakelen stream: {message}", + "system.health.tab": "Status", + "system.health.operatorView": "Operationele status", + "system.health.title": "Systeemstatus", + "system.health.loading": "Systeemstatus laden…", + "system.health.loadError": "Systeemstatus kon niet worden geladen.", + "system.health.refreshing": "Vernieuwen…", + "system.health.activeIncidentCount": "{count} actieve incidenten", + "system.health.coverage": "Dekking", + "system.health.monitoringDisabled": "Statusmonitoring is uitgeschakeld", + "system.health.lastRecordedValue": "Laatst vastgelegde waarde", + "system.health.monitoringDisabledHelp": "De huidige statusgegevens worden niet verzameld. Schakel statusmonitoring in bij Instellingen → Status; herstart indien gevraagd na het opslaan. De incidentgeschiedenis toont eerdere gebeurtenissen, niet het huidige resourcegebruik.", + "system.health.monitoringRestartRequired": "Statusmonitoring is ingeschakeld in de opgeslagen configuratie, maar de actieve sampler is nog uitgeschakeld. Herstart LightNVR om de wijziging toe te passen. De incidentgeschiedenis toont eerdere gebeurtenissen.", + "system.health.containerCoverage": "Beperkte hostdekking", + "system.health.hostHardwareUnavailable": "Deze installatie kan de status van containers en gekoppelde bronnen zien, maar hosthardware is niet beschikbaar. Ontbrekende hostwaarden zijn onbekend, niet gezond.", + "system.health.coverageUnknown": "Er is nog geen voltooide statusmomentopname beschikbaar. Waarden blijven onbekend totdat de verzameling is voltooid.", + "system.health.coverageComplete": "Alle voor deze installatie zichtbare gegevens zijn succesvol verzameld.", + "system.health.coveragePartial": "De dekking is gedeeltelijk. {count} waarnemingen of controlecontroles zijn niet beschikbaar, verouderd of onvolledig.", + "system.health.effectiveScope": "Effectieve reikwijdte", + "system.health.activeIncidents": "Actieve incidenten", + "system.health.noActiveIncidents": "Er worden geen actieve incidenten gerapporteerd voor de zichtbare dekking.", + "system.health.duration": "Duur", + "system.health.currentValue": "Huidige waarde", + "system.health.thresholds": "Drempel en verblijftijd", + "system.health.thresholdSummary": "Waarschuwing {warning}, kritiek {critical}, herstel {recovery} {unit}; waarschuwingsverblijftijd {seconds}s", + "system.health.remediation": "Voorgestelde actie", + "system.health.facts": "Statusgegevens", + "system.health.group.resources": "Bronnen", + "system.health.group.storage": "Opslag", + "system.health.group.hardware": "Hardware", + "system.health.group.network": "Netwerk", + "system.health.group.clock": "Klok", + "system.health.group.components": "Componenten", + "system.health.noFacts": "Er zijn geen feiten zichtbaar in deze groep.", + "system.health.observationState": "Mogelijkheden en actualiteit", + "system.health.valueUnavailable": "Een of meer waarden zijn onbekend", + "system.health.componentStatus": "Bewakingscomponenten", + "system.health.collectors": "Verzamelaars", + "system.health.collectorSummary": "{total} geregistreerd · {attention} vereisen aandacht", + "system.health.collectorsNeedingAttention": "Verzamelaars die aandacht vereisen", + "system.health.collectionFailures": "{count} fouten of time-outs", + "system.health.stale": "verouderd", + "system.health.eventDelivery": "Gebeurtenisbezorging", + "system.health.degraded": "Gedegradeerd", + "system.health.circularDelivery": "Dit is het enige geconfigureerde alarmkanaal, dus het kan niet onafhankelijk over zijn eigen storing rapporteren.", + "system.health.incidentPersistence": "Incidentopslag", + "system.health.persistenceSummary": "{pending} in behandeling · {failures} fouten · {retries} pogingen", + "system.health.recentSamples": "Recente verzamelactiviteit", + "system.health.recentSamplesHelp": "Tot {count} beperkte servergeneratiesamenvattingen; dit betreft dekkingsactiviteit, geen waardediagram.", + "system.health.sampleSequence": "Generatie {sequence}", + "system.health.sampleCoverage": "{observations} waarnemingen · {dropped} verworpen", + "system.health.noSamples": "Er zijn geen voltooide verzamelgeneraties beschikbaar.", + "system.health.incidentHistory": "Incidentgeschiedenis", + "system.health.incidentHistoryHelp": "Nieuwste incidenten eerst. Geschiedenis wordt in beperkte pagina's geladen.", + "system.health.loadingHistory": "Incidentgeschiedenis laden…", + "system.health.historyError": "Incidentgeschiedenis kon niet worden geladen.", + "system.health.emptyHistory": "Er zijn geen incidenten vastgelegd.", + "system.health.firstSeen": "Eerst gezien", + "system.health.lastSeen": "Laatst gezien", + "system.health.deliveryState": "Bezorgstatus", + "system.health.historyPagination": "Incidentgeschiedenispagina's", + "system.health.pageCount": "{count} incidenten op deze pagina", + "system.health.remediation.memory": "Verminder de geheugendruk, controleer proces- en cgroup-limieten, en bekijk recente OOM-activiteit.", + "system.health.remediation.cpu": "Identificeer aanhoudende CPU-verbruikers en controleer de service-doorvoer voordat u limieten wijzigt.", + "system.health.remediation.io": "Controleer opslaglatentie en actieve schrijvers; behoud opnames voordat u verstorend onderhoud uitvoert.", + "system.health.remediation.filesystem": "Controleer het genoemde logische bestandssysteem, vrije ruimte of inodes, en verifieer dat het schrijfbaar blijft.", + "system.health.remediation.thermal": "Verbeter de koeling en verminder de belasting; inspecteer ventilatoren en ventilatieopeningen voordat temperaturen de afsluitlimieten bereiken.", + "system.health.remediation.network": "Controleer de zichtbare interface, link, switch en fouttellers via een onafhankelijk netwerkpad.", + "system.health.remediation.clock": "Herstel de tijdsynchronisatie en verifieer de host-klokbron voordat u vertrouwt op tijdstempels van gebeurtenissen.", + "system.health.remediation.process": "Inspecteer LightNVR-bronlimieten en logbestanden, verminder vervolgens de belasting of verhoog gevalideerde limieten.", + "system.health.remediation.storage": "Maak een back-up van belangrijke beelden en inspecteer het gekoppelde opslagapparaat voordat u het vervangt of repareert.", + "system.health.remediation.hardware": "Inspecteer de betreffende hardware en platformlogbestanden; plan onderhoud als de situatie aanhoudt.", + "system.health.remediation.health": "Herstel de toegang en machtigingen van de collector zodat het ontbrekende gezondheidsbewijs kan worden geëvalueerd.", + "system.health.remediation.system": "Bekijk de vorige run en hostlogbestanden om een procesherstart te onderscheiden van een hostherstart.", + "system.health.remediation.event": "Gebruik de lokale API of metrikweergave, verlicht de druk op de persistente wachtrij en herstel een onafhankelijke alarmbestemming.", + "system.health.remediation.default": "Bekijk het betreffende onderdeel en recente logbestanden, verifieer vervolgens het herstel in een nieuwe gezondheidsgeneratie.", + "system.capacityTarget": "Capaciteitsdoel", + "system.capacityTargetValue": "{pct}% vrijhouden", + "system.fillRate": "Vulsnelheid", + "system.fillRateValue": "{value} / dag", + "system.projectedToTarget": "Verwachte tijd tot doel", + "system.projectedNow": "Nu op/boven doel", + "system.projectedDays": "~{count}d", + "system.projectedHours": "~{count}u", + "system.projectedUnknown": "—", + "common.description": "Beschrijving", + "common.remove": "Verwijderen", + "streams.selectStream": "{name} selecteren", + "streams.search": "Streams zoeken", + "streams.searchPlaceholder": "Camera's, locaties of tags zoeken", + "streams.noStreamsMatchFilters": "Geen streams gevonden die overeenkomen met de huidige filters.", + "streamHealth.sourceConnected": "Bron verbonden", + "streamHealth.videoAdvancing": "Video loopt door", + "streamHealth.recorderWriting": "Recorder schrijft", + "streamHealth.detectorOperating": "Detector actief", + "streamHealth.lastSegment": "Laatste voltooide segment", + "streams.disablingStreamsProgress": "Streams uitschakelen…", + "streams.onvifInvalidAddress": "ONVIF-apparaat heeft een ontbrekend of ongeldig IP-adres.", + "streams.warningFallingBackToHttp": "HTTPS-verbinding mislukt; opnieuw proberen via HTTP. Inloggegevens kunnen in platte tekst worden verzonden.", + "streamsConfig.playbackTransport": "Afspeeltransport", + "streamsConfig.playbackTransportHelp": "Kies de browser-afspeelmethode voor deze camera en, indien geselecteerd, de volgorde van terugvalopties.", + "streamsConfig.playbackTransportUnavailable": "Niet beschikbaar op de server: {transports}. Schakel het transport globaal in of kies een ander profiel.", + "streamsConfig.audioDisabledByPolicy": "Audio is uitgeschakeld door het instantiebeleid", + "streamsConfig.audioDisabledByPolicyHelp": "Opname, live luisteren en tweerichtingsgesprek zijn niet beschikbaar zolang het wereldwijde audio-compliancebeleid is ingeschakeld.", + "streamsConfig.audioVoiceEnhancement": "Stemverbetering (opnames)", + "streamsConfig.customApiModel": "Aangepaste API-detectie", + "streamsConfig.modelNotSupportedByBuild": "niet ondersteund door deze build", + "streamsConfig.tierCriticalMultiplier": "Kritieke laag ×", + "streamsConfig.tierImportantMultiplier": "Belangrijke laag ×", + "streamsConfig.tierEphemeralMultiplier": "Vluchtige laag ×", + "streamsConfig.tierMultipliersHelp": "Vermenigvuldigers per laag op de basisbewaartermijn. Beeldmateriaal van een hogere laag wordt langer bewaard en als laatste verwijderd bij schijfdruk.", + "streamsConfig.storagePriority": "Opslagprioriteit (1-10)", + "streamsConfig.storagePriorityHelp": "Relatief belang van het beeldmateriaal van deze stream bij het vrijmaken van ruimte; hogere prioriteit wordt langer behouden.", + "streamsConfig.restream": "Restream / Publiceren (RTMP)", + "streamsConfig.publishUrl": "Publiceer-URL (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "Restream deze camera naar een dienst zoals YouTube Live via go2rtc. Plak de volledige RTMP-ingest-URL inclusief de streamkey (bijv. rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Om naar meerdere diensten tegelijk te restreamen, scheidt u de URL's met komma's. YouTube vereist H264-video en AAC-audio; LightNVR transcodeert nu automatisch (H264 voor niet-H264-camera's, AAC voor niet-AAC-audio), zodat de meeste camera's direct werken. Let op: YouTube vereist ook een audiotrack — een camera zonder audio wordt nog steeds geweigerd. Laat leeg om uit te schakelen.", + "streams.lastSeen": "Laatst gezien {time}", + "streams.claimed": "Opgeëist", + "streams.duplicateSuspected": "Mogelijk duplicaat", + "streams.duplicateSuspectedHelp": "Stabiele identiteit of eindpuntaanduiding conflicteert met een ander detectieresultaat.", + "streams.onvifClaimWarning": "De stream is toegevoegd, maar het detectieresultaat kon niet als opgeëist worden gemarkeerd: {message}", + "common.online": "Online", + "common.offline": "Offline", + "settings.storageTargets.title": "Opslagdoelen voor opnames", + "settings.storageTargets.description": "Registreer lokale schijven en door de beheerder aangekoppelde NFS- of SMB-bestandssystemen als onafhankelijk bewaakte opnamedoelen.", + "settings.storageTargets.foundationNotice": "Opname gebruikt bestandssysteemdoelen. S3-buckets en gemounte NFS/SAN-doelen kunnen geverifieerde archiefkopieën bevatten. Hetedruk behoudt gearchiveerde opnames totdat hun logische bewaartermijn verloopt.", + "settings.storageTargets.add": "Opslagdoel toevoegen", + "settings.storageTargets.edit": "Opslagdoel bewerken", + "settings.storageTargets.editorHelp": "Ingeschakelde doelen moeten al bestaan en een schrijf-, fsync- en opruimtest doorstaan. Sla een niet-beschikbaar toekomstig mountpunt op als uitgeschakeld en schakel het in na het mounten.", + "settings.storageTargets.name": "Doelnaam", + "settings.storageTargets.root": "Gemount rootpad", + "settings.storageTargets.rootLocked": "Een standaard- of niet-leeg doel behoudt een onveranderbaar rootpad zodat bestaande beelden niet verweesd kunnen raken.", + "settings.storageTargets.class": "Prestatieklasse", + "settings.storageTargets.hot": "Hot — actieve opname", + "settings.storageTargets.warm": "Warm — gemount archief", + "settings.storageTargets.cold": "Cold — zelden gebruikt", + "settings.storageTargets.reserveGb": "Gereserveerde ruimte (GB)", + "settings.storageTargets.lowWatermark": "Lage watermerk (% gebruikt)", + "settings.storageTargets.highWatermark": "Hoge watermerk (% gebruikt)", + "settings.storageTargets.migrationBandwidth": "Levenscyclusbandbreedte (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 is onbeperkt. De limiet wordt vastgelegd wanneer een verplaats- of kopieertaak wordt aangemaakt.", + "settings.storageTargets.archiveStart": "Archiefvenster begint", + "settings.storageTargets.archiveEnd": "Archiefvenster eindigt", + "settings.storageTargets.archiveWindowHelp": "Lokale tijd. Gelijke begin- en eindtijden staan levenscyclustaken de hele dag toe; een overnight venster kan middernacht overschrijden.", + "settings.storageTargets.enabled": "Ingeschakeld (plaatsingsbeleid kan dit doel selecteren)", + "settings.storageTargets.notRouted": "Geen ingeschakeld plaatsingsbeleid stuurt camera's hierheen. Nieuwe opnames gaan naar het standaarddoel totdat een beleid dit doel als primair doel, pool-lid of archiefdoel aanwijst.", + "settings.storageTargets.degradedNotice": "Boven de hoge watermerk of binnen de reserve. Plaatsingsbeleid slaat dit doel over totdat er ruimte vrijkomt.", + "settings.storageTargets.probePassedIneligible": "Schrijftest geslaagd, maar het doel is {status}: plaatsingsbeleid zal het niet selecteren.", + "settings.storageTargets.mountRequired": "Vereist een gemount bestandssysteem", + "settings.storageTargets.mountRequiredHelp": "Zet dit doel vast op het huidige niet-root koppelpunt. Als die NFS-, SMB-, bind- of PVC-mount verdwijnt, pauzeert de opname in plaats van te schrijven naar de onderliggende hostmap.", + "settings.storageTargets.mountGuard": "Vereiste mount", + "settings.storageTargets.mountPending": "Wordt gedetecteerd wanneer het doel is ingeschakeld", + "settings.storageTargets.default": "Standaard", + "settings.storageTargets.capacity": "Capaciteit", + "settings.storageTargets.available": "Beschikbaar", + "settings.storageTargets.recordings": "Geïndexeerde opnames", + "settings.storageTargets.replicas": "{count} geverifieerde kopieën · {bytes}", + "settings.storageTargets.reserve": "Gereserveerd", + "settings.storageTargets.pressure.normal": "Opslagdruk normaal", + "settings.storageTargets.pressure.high": "Bovengrens", + "settings.storageTargets.pressure.reserve": "Reserve overschreden", + "settings.storageTargets.pressure.unavailable": "Opslagdruk niet beschikbaar", + "settings.storageTargets.cleanupActive": "Doelgebonden opschoning is actief en werkt naar {target} beschikbare ruimte toe zonder opnames te verwijderen die aan een ander doel zijn toegewezen.", + "settings.storageTargets.test": "Testdoel", + "settings.storageTargets.probing": "Testen…", + "settings.storageTargets.probePassed": "Schrijftest opslagdoel geslaagd", + "settings.storageTargets.duplicateFilesystem": "Deze root deelt hetzelfde onderliggende bestandssysteem als een ander doel. Capaciteit mag niet dubbel worden geteld wanneer plaatsing is ingeschakeld.", + "settings.storageTargets.deleteLocked": "Standaard- en niet-lege doelen kunnen niet worden verwijderd.", + "settings.storageTargets.deleteConfirm": "Leeg opslagdoel \"{name}\" verwijderen? Er worden geen bestanden verwijderd.", + "settings.storageTargets.created": "Opslagdoel aangemaakt", + "settings.storageTargets.updated": "Opslagdoel bijgewerkt", + "settings.storageTargets.deleted": "Opslagdoel verwijderd", + "settings.storageTargets.invalidThresholds": "Controleer grenswaarden, reserve, levenscyclusbandbreedte en archiefvenstertijden.", + "settings.storageTargets.loadError": "Kon opslagdoelen niet laden", + "settings.storagePools.title": "Opslagpools", + "settings.storagePools.description": "Groepeer gezonde doelen voor automatische overloop en replicatie naar afzonderlijke doelen.", + "settings.storagePools.add": "Pool toevoegen", + "settings.storagePools.strategy": "Toewijzingsstrategie", + "settings.storagePools.mostFree": "Meeste vrije ruimte", + "settings.storagePools.roundRobin": "Round robin", + "settings.storagePools.priority": "Expliciete prioriteit", + "settings.storagePools.members": "Doelen (weergavevolgorde is toewijzingsprioriteit)", + "settings.storagePools.enabled": "Pool ingeschakeld", + "settings.storagePools.active": "Actief", + "settings.storagePools.inactive": "Uitgeschakeld", + "settings.storagePools.strategyValue.most_free": "meeste vrij", + "settings.storagePools.strategyValue.round_robin": "round robin", + "settings.storagePools.strategyValue.priority": "prioriteitsvolgorde", + "settings.storagePools.created": "Opslagpool aangemaakt", + "settings.storagePools.updated": "Opslagpool bijgewerkt", + "settings.storagePools.deleted": "Opslagpool verwijderd", + "settings.storagePools.deleteConfirm": "Opslagpool \"{name}\" verwijderen?", + "settings.storagePools.empty": "Nog geen opslagpools.", + "settings.storageMigrations.title": "Migratietaken voor opnames", + "settings.storageMigrations.description": "Duurzame verplaatsingen en bewaarde kopieën houden rekening met het archiefvenster en de bandbreedtelimiet van elk doel, verifiëren SHA-256 en herstellen veilig na een herstart.", + "settings.storageMigrations.empty": "Nog geen migratietaken voor opnames.", + "settings.storageMigrations.loadError": "Migratietaken voor opnames konden niet worden geladen", + "settings.storageMigrations.recording": "Opname #{id}", + "settings.storageMigrations.attempt": "Poging {current}/{max}", + "settings.storageMigrations.operation.move": "Verplaatsen", + "settings.storageMigrations.operation.copy": "Bewaarde kopie", + "settings.storageMigrations.cancelled": "Migratieannulering geaccepteerd", + "settings.storageMigrations.cancelling": "Annuleren…", + "settings.storageMigrations.retried": "Migratie in wachtrij voor opnieuw proberen", + "settings.storageMigrations.state.queued": "In wachtrij", + "settings.storageMigrations.state.copying": "Kopiëren", + "settings.storageMigrations.state.verifying": "Verifiëren", + "settings.storageMigrations.state.committing": "Doorvoeren", + "settings.storageMigrations.state.cleanup_pending": "Bron opschonen", + "settings.storageMigrations.state.retry_wait": "Wachten op opnieuw proberen", + "settings.storageMigrations.state.completed": "Voltooid", + "settings.storageMigrations.state.failed": "Mislukt", + "settings.storageMigrations.state.cancelled": "Geannuleerd", + "settings.storagePolicies.title": "Beleidsregels voor cameraplaatsing", + "settings.storagePolicies.description": "Stuur overeenkomende camera's door naar een primair opnamedoel op volgorde van prioriteit. Een camera gebruikt het eerste ingeschakelde beleid dat overeenkomt.", + "settings.storagePolicies.add": "Beleidsregel voor plaatsing toevoegen", + "settings.storagePolicies.edit": "Beleidsregel voor plaatsing bewerken", + "settings.storagePolicies.editorHelp": "Het beleid wordt opnieuw geëvalueerd voor nieuwe segmenten. Wijzigingen verplaatsen bestaande opnames niet.", + "settings.storagePolicies.priority": "Prioriteit (hoogste eerst)", + "settings.storagePolicies.priorityValue": "Prioriteit {priority}", + "settings.storagePolicies.primary": "Primair doel", + "settings.storagePolicies.primaryPool": "Plaatsingspool (optioneel)", + "settings.storagePolicies.exactTarget": "Exact primair doel gebruiken", + "settings.storagePolicies.fallback": "Als het primaire doel niet beschikbaar is", + "settings.storagePolicies.fallbackDefault": "Standaarddoel gebruiken", + "settings.storagePolicies.fallbackTarget": "Benamed fallback-doel gebruiken", + "settings.storagePolicies.fallbackPause": "Opname pauzeren", + "settings.storagePolicies.fallbackFail": "Start van opname laten mislukken", + "settings.storagePolicies.namedFallback": "Fallback-doel", + "settings.storagePolicies.chooseTarget": "Doel kiezen", + "settings.storagePolicies.choosePool": "Pool kiezen", + "settings.storagePolicies.minimumDays": "Minimale bewaartijd (dagen)", + "settings.storagePolicies.desiredDays": "Gewenste bewaartijd (dagen)", + "settings.storagePolicies.maximumDays": "Maximale bewaartijd (dagen)", + "settings.storagePolicies.copyCount": "Vereiste geverifieerde kopieën", + "settings.storagePolicies.replicationPool": "Replicatiepool", + "settings.storagePolicies.migrateAfter": "Verplaatsen na leeftijd (dagen)", + "settings.storagePolicies.migrationTarget": "Archiefdoel", + "settings.storagePolicies.pressurePriority": "Drukverwijderingsprioriteit (laagste eerst)", + "settings.storagePolicies.disabledTarget": "uitgeschakeld", + "settings.storagePolicies.enabled": "Beleid ingeschakeld", + "settings.storagePolicies.selector": "Overeenkomende camera's", + "settings.storagePolicies.preview": "Voorbeeld van voorrang", + "settings.storagePolicies.previewing": "Evalueren…", + "settings.storagePolicies.previewRequired": "Bekijk het huidige concept vóór opslaan om camera-overlap en het effectieve winnende beleid te zien.", + "settings.storagePolicies.previewSummary": "Komt overeen met {matched} camera's; dit concept is effectief voor {effective}.", + "settings.storagePolicies.previewShadowed": "Een beleid met hogere voorrang wint voor {count} overeenkomende camera's.", + "settings.storagePolicies.previewWins": "Wint van \"{policy}\" (prioriteit {priority}) voor {count} camera's.", + "settings.storagePolicies.previewLoses": "Verliest van \"{policy}\" (prioriteit {priority}) voor {count} camera's.", + "settings.storagePolicies.previewNoMatches": "Deze selector komt momenteel niet overeen met camera's.", + "settings.storagePolicies.invalidPriority": "Prioriteit moet een geheel getal zijn tussen -1.000.000 en 1.000.000.", + "settings.storagePolicies.invalidLifecycle": "Controleer de volgorde van bewaartijden, het aantal kopieën en replicatiepool, en de migratieleeftijd en het doel.", + "settings.storagePolicies.created": "Plaatsingsbeleid aangemaakt", + "settings.storagePolicies.updated": "Plaatsingsbeleid bijgewerkt", + "settings.storagePolicies.deleted": "Plaatsingsbeleid verwijderd", + "settings.storagePolicies.deleteConfirm": "Plaatsingsbeleid \"{name}\" verwijderen? Bestaande opnames blijven ongewijzigd.", + "settings.storagePolicies.active": "Actief", + "settings.storagePolicies.inactive": "Uitgeschakeld", + "settings.storagePolicies.routesTo": "Primair doel: {target}", + "settings.storagePolicies.lifecycleSummary": "Behoud min/gewenst/max: {minimum}/{desired}/{maximum} dagen · {copies} geverifieerde kopieën", + "settings.storagePolicies.fallsBackTo": "Fallback-doel: {target}", + "settings.storagePolicies.mode.default": "Fallback: standaarddoel", + "settings.storagePolicies.mode.pause": "Fallback: opname pauzeren", + "settings.storagePolicies.mode.fail": "Fallback: opname starten mislukt", + "settings.storagePolicies.empty": "Geen plaatsingsbeleid. Camera's blijven het standaarddoel gebruiken; andere doelen ontvangen niets totdat een beleid camera's ernaar doorstuurt.", + "settings.storagePolicies.archiveNoTrigger": "Er is een archiefdoel ingesteld maar niets activeert een verplaatsing. Stel 'Verplaatsen na leeftijd (dagen)', een archiveringsleeftijd of een archiveeroptie in; anders worden er geen opnames verplaatst.", + "settings.storageCompliance.title": "Capaciteit en beleidsnaleving", + "settings.storageCompliance.description": "Waargenende 30-daagse snelheden voorspellen doeldruk en bereikt behoud; actieve levenscyclusovertredingen blijven zichtbaar totdat ze zijn opgelost.", + "settings.storageCompliance.loadError": "Opslagnaleving kon niet worden geladen", + "settings.storageCompliance.unknown": "Onbekend", + "settings.storageCompliance.days": "{days} dagen", + "settings.storageCompliance.day": "dag", + "settings.storageCompliance.targetForecasts": "Doelvoorspellingen", + "settings.storageCompliance.target": "Doel", + "settings.storageCompliance.dailyRate": "Waargenomen snelheid", + "settings.storageCompliance.toHigh": "Tot hoogwatermerk", + "settings.storageCompliance.expected": "Verwacht behoud", + "settings.storageCompliance.confidence": "Betrouwbaarheid", + "settings.storageCompliance.policyCompliance": "Beleidsnaleving", + "settings.storageCompliance.compliant": "Geen actieve overtredingen", + "settings.storageCompliance.violationCount": "{count} overtreding(en)", + "settings.storageCompliance.policyForecast": "Bereikt {achieved}; voorspeld {expected}; gewenst {desired} dagen.", + "settings.storageCompliance.copyDeficits": "{count} opname(s) heeft een extra geverifieerde kopie nodig.", + "settings.storageCompliance.activeViolations": "Actieve overtredingen", + "settings.storageCompliance.type.copy_count": "Kopieaantal", + "settings.storageCompliance.type.minimum_retention": "Minimale bewaarcapaciteit", + "settings.storageCompliance.type.target_unavailable": "Doel niet beschikbaar", + "settings.storageCompliance.type.migration_failed": "Levenscyclus-taak mislukt", + "settings.recordingDirectoryFormat": "Opnamemapstructuur", + "settings.recordingDirectoryFormatHelp": "Scheidt nieuwe MP4-opnames onder elke cameramap. Bestaande opnames worden niet verplaatst.", + "settings.recordingDirectoryFlat": "Plat (alleen cameramap)", + "settings.recordingDirectoryMonth": "Per maand (YYYY/MM)", + "settings.recordingDirectoryDay": "Per dag (YYYY/MM/DD)", + "settings.minFreePct": "Minimale vrije ruimte (%)", + "settings.minFreePctHelp": "Houd minimaal dit percentage van het volume vrij door automatisch de oudste opnames te verwijderen, ongeacht de bewaardagen. Dit beperkt het gebruik tot de schijfgrootte — stel het in en de schijf raakt nooit vol. 0 schakelt de capaciteitslimiet uit.", + "settings.pressureThresholds": "Schijfdrukdrempels (%)", + "settings.pressureThresholdsHelp": "Vrije-ruimtebanden die automatisch opschonen opvoeren. Moet voldoen aan noodsituatie < kritiek < waarschuwing.", + "settings.pressureWarningPct": "Waarschuwing onder (% vrij)", + "settings.pressureCriticalPct": "Kritiek onder (% vrij)", + "settings.pressureEmergencyPct": "Noodsituatie onder (% vrij)", + "settings.databaseBackupVerify": "Back-upverificatie", + "settings.databaseBackupVerifyFull": "Volledig (integrity_check, controleert elke index)", + "settings.databaseBackupVerifyQuick": "Snel (quick_check, alleen paginestructuur)", + "settings.databaseBackupVerifyOff": "Uit (geen scan na kopiëren)", + "settings.databaseBackupVerifyHelp": "Scan toegepast op elke gekopieerde back-up voordat deze wordt gepubliceerd. Volledig kan langer duren dan het kopiëren zelf bij een grote database op een mechanische schijf en kan de veiligheidsklep van 30 minuten raken, waardoor die back-up wordt verwijderd; Snel vangt nog steeds beschadigde of afgekapte pagina's op met veel minder seeks.", + "settings.viewMethodAuto": "Auto — voorkeur per camera met terugval", + "settings.resetWizardPending": "Wizard starten…", + "settings.apiDetectionFormat": "API-verzoekformaat", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (multipart afbeeldingsupload)", + "settings.apiDetectionFormatDoods2": "DOODS2 (JSON-body met base64-afbeelding)", + "settings.apiDetectionFormatHelp": "Wireformat die LightNVR gebruikt bij het versturen van snapshots naar de detectie-API. Houd light-object-detect aan voor light-object-detect of elke server die het contract implementeert; kies DOODS2 voor een DOODS2-server.", + "settings.apiDetectionUrlHelpDoods2": "DOODS2 /detect-endpoint, bijv. http://localhost:8080/detect. Het verzoek wordt als JSON verzonden en er worden geen queryparameters toegevoegd.", + "settings.apiDetectionDetectorName": "DOODS2-detectornaam", + "settings.apiDetectionDetectorNameHelp": "Verzonden als detector_name in elk verzoek. Moet overeenkomen met een detector die door de server wordt vermeld via GET /detectors; \"default\" gebruikt de standaarddetector van de server.", + "settings.defaultPlaybackTransport": "Standaard afspeeltransport", + "settings.defaultPlaybackTransportHelp": "Afspeelprofiel toegepast op nieuw aangemaakte streams. Bestaande streams behouden hun eigen selectie.", + "playbackTransport.auto": "Auto (aanbevolen)", + "playbackTransport.webrtcOnly": "Alleen WebRTC", + "playbackTransport.mseOnly": "Alleen MSE", + "playbackTransport.hlsOnly": "Alleen HLS", + "playbackTransport.webrtcThenMse": "WebRTC, dan MSE", + "playbackTransport.mseThenHls": "MSE, dan HLS", + "investigation.experimental": "Experimentele werkruimte", + "investigation.title": "Onderzoek", + "investigation.description": "Bekijk meerdere camera's met één gedeelde UTC-cursor zonder gaten in de beelden te verbergen.", + "investigation.query": "Onderzoeksvenster", + "investigation.queryHelp": "Kies maximaal 16 camera's. Er zijn maximaal vier videospelers tegelijk actief.", + "investigation.cameras": "camera's", + "investigation.cameraSelection": "Cameraselectie", + "investigation.start": "Start", + "investigation.end": "Einde", + "investigation.load": "Onderzoek laden", + "investigation.applyWindow": "Tijdvenster toepassen", + "investigation.loading": "Onderzoek laden…", + "investigation.eventType": "Gebeurtenistype", + "investigation.anyEventType": "Elk gebeurtenistype", + "investigation.eventType.detection": "Detectie", + "investigation.eventType.motion": "Beweging", + "investigation.location": "Locatie", + "investigation.anyLocation": "Elke locatie", + "investigation.objectLabel": "Objectlabel", + "investigation.anyLabel": "Elk label", + "investigation.zone": "Zone", + "investigation.anyZone": "Elke zone", + "investigation.source": "Detectiebron", + "investigation.anySource": "Elke bron", + "investigation.captureMethod": "Vastlegmethode", + "investigation.anyCaptureMethod": "Elke vastlegmethode", + "investigation.recordingTag": "Opnametag", + "investigation.anyRecordingTag": "Elke opnametag", + "investigation.protection": "Beveiliging", + "investigation.anyProtection": "Elke beveiliging", + "investigation.protected": "Beveiligd", + "investigation.unprotected": "Onbeveiligd", + "investigation.minimumConfidence": "Minimale betrouwbaarheid", + "investigation.confidenceError": "Minimale betrouwbaarheid moet tussen 0 en 1 liggen.", + "investigation.metadataRegionSearch": "Metadata-regio zoeken", + "investigation.regionSearchHelp": "Kies een primaire camera met beelden en teken een gebied over de video.", + "investigation.regionActive": "Zoeken in opgeslagen vakken van {camera}. Een ontbrekend resultaat is geen bewijs dat er niets door het gebied is gegaan.", + "investigation.regionMatch": "Vakvergelijking", + "investigation.regionMatch.center": "Midden binnen", + "investigation.regionMatch.intersects": "Elke doorsnijding", + "investigation.regionMatch.minimumIntersection": "Minimale overlapping", + "investigation.regionMinimumOverlap": "Minimale overlapping (%)", + "investigation.regionLeft": "Links (%)", + "investigation.regionTop": "Boven (%)", + "investigation.regionWidth": "Breedte (%)", + "investigation.regionHeight": "Hoogte (%)", + "investigation.drawRegion": "Zoekgebied tekenen", + "investigation.drawingRegion": "Zoekgebied tekenen…", + "investigation.clearRegion": "Gebied wissen", + "investigation.useFullFrame": "Volledig beeld gebruiken", + "investigation.drawRegionPrompt": "Sleep over de video om het zoekgebied te definiëren", + "investigation.applyFilters": "Filters toepassen", + "investigation.searching": "Gebeurtenissen zoeken…", + "investigation.searchResults": "Resultaten", + "investigation.searchHelp": "Laad een onderzoek om de opgeslagen metadata van gebeurtenissen te doorzoeken.", + "investigation.resultCount": "{count} overeenkomende gebeurtenissen", + "investigation.results": "resultaten", + "investigation.resultHistogram": "Gebeurtenishistogram", + "investigation.histogramHelp": "Selecteer een balk om de gedeelde cursor te verplaatsen.", + "investigation.previousResult": "Vorige gebeurtenis", + "investigation.nextResult": "Volgende gebeurtenis", + "investigation.previousResultShortcut": "Vorige gebeurtenis ([)", + "investigation.nextResultShortcut": "Volgende gebeurtenis (])", + "investigation.noResults": "Geen opgeslagen gebeurtenissen gevonden voor deze camera, tijd en filterselectie.", + "investigation.noThumbnail": "Geen miniatuurafbeelding", + "investigation.exploreThumbnails": "Miniatuurafbeeldingen verkennen", + "investigation.exploreSelectedThumbnails": "Verkennen rond gebeurtenis", + "investigation.thumbnailDrilldown": "Miniatuurafbeelding drill-down", + "investigation.thumbnailDrilldownHelp": "Kies een moment, ook een leegte, om de gedeelde cursor te verplaatsen en een smaller set monsters te genereren.", + "investigation.selectThumbnailSample": "Inspecteren rond {time}", + "investigation.loadingThumbnail": "Miniatuurafbeelding laden…", + "investigation.thumbnailUnavailable": "Miniatuurafbeelding niet beschikbaar", + "investigation.loadingSamples": "Miniatuurmonsters laden…", + "investigation.thumbnailCoverageTruncated": "Dit interval bevat meer opnames dan de sampler kon inspecteren. Beperk het tijdvenster voor volledige dekking.", + "investigation.bookmarks.save": "Bladwijzer opslaan", + "investigation.bookmarks.open": "Bladwijzers", + "investigation.bookmarks.saveTitle": "Onderzoekbladwijzer opslaan", + "investigation.bookmarks.listTitle": "Onderzoekbladwijzers", + "investigation.bookmarks.notHold": "Een bladwijzer herstelt dit overzicht, maar beschermt opnames niet tegen normale bewaartermijn of verwijdering.", + "investigation.bookmarks.title": "Naam bladwijzer", + "investigation.bookmarks.note": "Privénotitie (optioneel)", + "investigation.bookmarks.titleRequired": "Voer een bladwijzernaam in.", + "investigation.bookmarks.empty": "U heeft geen opgeslagen onderzoekbladwijzers.", + "investigation.bookmarks.cameraCount": "{count} camera('s)", + "investigation.bookmarks.restore": "Openen", + "investigation.bookmarks.confirmDelete": "Bladwijzer verwijderen?", + "investigation.actions.open": "Beschermen / downloaden", + "investigation.actions.title": "Onderzoeksopnames", + "investigation.actions.notEvidenceExport": "Bescherming voorkomt verwijdering door de normale bewaartermijn. De ZIP-download is een handige export, geen geverifieerd bewispakket.", + "investigation.actions.scope": "Opnamebereik", + "investigation.actions.selectedResult": "Geselecteerde gebeurtenis en camera", + "investigation.actions.fullWindow": "Alle camera's in het onderzoekvenster", + "investigation.actions.preview": "Opnames voorvertonen", + "investigation.actions.previewing": "Overlappende opnames zoeken…", + "investigation.actions.invalidRange": "Kies een geldig tijdsbereik met een einde na het begin.", + "investigation.actions.recordingCount": "{count} overlappende opname(s)", + "investigation.actions.protectedCount": "{count} al beschermd", + "investigation.actions.noRecordings": "Geen voltooide opnames overlappen deze camera- en tijdsselectie.", + "investigation.actions.protectDenied": "{count} onbeschermde opname(s) vallen buiten uw beschermingsbereik en zijn uitgesloten van deze actie.", + "investigation.actions.exportDenied": "Exportmachtiging ontbreekt voor {count} opname(s). Downloads zijn alles-of-niets, dus deze selectie kan niet worden geëxporteerd.", + "investigation.actions.camera": "Camera", + "investigation.actions.recording": "Opname", + "investigation.actions.size": "Grootte", + "investigation.actions.notPermitted": "Niet toegestaan", + "investigation.actions.protectButton": "{count} beschermen", + "investigation.actions.protecting": "Bezig met beschermen…", + "investigation.actions.protectUnavailable": "Er zijn geen onbeschermde opnames die u mag beschermen.", + "investigation.actions.protectResult": "Beschermen voltooid: {success} gelukt, {failed} mislukt.", + "investigation.actions.downloadButton": "{count} downloaden", + "investigation.actions.downloadUnavailable": "Voor elke opname is een exportmachtiging vereist voordat een ZIP kan worden aangemaakt.", + "investigation.actions.buildingArchive": "ZIP samenstellen…", + "investigation.actions.downloadFailed": "ZIP-aanmaak mislukt op de server.", + "investigation.actions.downloadTimedOut": "ZIP-aanmaak werd niet binnen vijf minuten voltooid. Probeer een smaller interval.", + "investigation.actions.downloadStarted": "ZIP-download gestart.", + "investigation.backOneLevel": "Eén niveau terug", + "investigation.thumbnailMinimumWindow": "Dit is het smalste beschikbare interval van één seconde. De gedeelde cursor is wel naar het geselecteerde moment bewogen.", + "investigation.localSource": "lokaal", + "investigation.mediaAvailable": "Media beschikbaar", + "investigation.durationSeconds": "Duur: {count}s", + "investigation.pageNumber": "Pagina {count}", + "investigation.incompleteCoverage": "{count} verouderde gebeurtenisrijen konden niet worden toegewezen aan een onveranderlijke camera-identiteit.", + "investigation.spatialCoverageGap": "{count} gebeurtenisrijen binnen het bereik hadden geen omkaderingsbox en zijn niet ruimtelijk doorzocht.", + "investigation.noSpatialMetadata": "Geen gebeurtenissen binnen het bereik hebben omkaderingsboxen voor deze metadata-zoekopdracht.", + "investigation.selectCameraError": "Selecteer minimaal één camera.", + "investigation.selectRecordingError": "Selecteer minimaal één opname.", + "investigation.investigateSelectedCount": "Onderzoek {count} geselecteerde opname(s)", + "investigation.missingCameraIdentity": "Kan niet onderzoeken: {count} geselecteerde opname(s) hebben geen camera-identiteit.", + "investigation.recordingTimeError": "De geselecteerde opnames hebben geen geldig tijdsbereik.", + "investigation.windowLimit": "De geselecteerde opnames overschrijden de onderzoekslimiet van 31 dagen.", + "investigation.timeRangeError": "De eindtijd moet na de starttijd liggen.", + "investigation.cameraLimit": "Een onderzoek kan maximaal {count} camera's bevatten.", + "investigation.decoderLimit": "Er kunnen maximaal {count} cameraspelers tegelijk actief zijn.", + "investigation.playbackControls": "Gesynchroniseerde afspeelknoppen", + "investigation.play": "Afspelen", + "investigation.pause": "Pauzeren", + "investigation.mode": "Afspeelmodus", + "investigation.wallClock": "Wandklok", + "investigation.skipCommonGaps": "Veelvoorkomende gaten overslaan", + "investigation.speed": "Snelheid", + "investigation.sharedCursor": "Gedeelde UTC-cursor", + "investigation.activePlayers": "actieve spelers", + "investigation.timeline": "gedeelde tijdlijn", + "investigation.segments": "segmenten", + "investigation.truncated": "afgekapt", + "investigation.gap": "Geen beeldmateriaal", + "investigation.players": "Gesynchroniseerde cameraspelers", + "investigation.activateCamera": "Activeer minimaal één tijdlijnrij om video te laden.", + "investigation.noFootage": "Geen beeldmateriaal", + "investigation.noFootageAtTime": "Geen beeldmateriaal op het gedeelde tijdstip", + "investigation.primaryAudio": "Primair geluid", + "investigation.makePrimary": "Als primair instellen", + "investigation.status.loading": "Media laden", + "investigation.status.synchronizing": "Synchroniseren", + "investigation.status.ready": "Gesynchroniseerd", + "investigation.status.late": "Achterstand — herstellen", + "investigation.status.error": "Media niet beschikbaar", + "investigation.status.paused-by-browser": "Selecteer afspelen om media toe te staan", + "streamsConfig.eptzTitle": "Fisheye ePTZ", + "streamsConfig.eptzEnable": "Fisheye ePTZ aan de browserkant inschakelen", + "streamsConfig.eptzHelp": "Ontwarp de onbewerkte fisheye-stream in Livebeeld, Tijdlijn-afspelen en Onderzoek. Dit wijzigt geen opnames of camera-uitvoer.", + "streamsConfig.eptzModelHelp": "Projectie: equidistante circulaire fisheye · Montage: plafond. Midden en straal gebruiken genormaliseerde bronbeeldcoördinaten.", + "streamsConfig.eptzCenterX": "Optisch midden X", + "streamsConfig.eptzCenterY": "Optisch midden Y", + "streamsConfig.eptzRadius": "Beeldcirkelstraal", + "streamsConfig.eptzLensFov": "Lens FOV (graden)", + "streamsConfig.eptzRotation": "Lensrotatie (graden)", + "streamsConfig.eptzDefaultYaw": "Standaard pan (graden)", + "streamsConfig.eptzDefaultTilt": "Standaard tilt (graden)", + "streamsConfig.eptzViewFov": "Standaard weergave FOV", + "streamsConfig.eptzCalibrationHelp": "Sleep om rond te kijken, gebruik het scrollwiel of knijp om te zoomen, en druk op Home om de virtuele camera te resetten. Stel midden en straal bij als de rand van de beeldcirkel niet uitlijnt.", + "settings.archive.targetType": "Opslagtype", + "settings.archive.filesystem": "Lokaal of aangekoppeld bestandssysteem (NFS/SAN)", + "settings.archive.s3": "S3-compatibele archiefbucket", + "settings.archive.endpoint": "HTTPS-eindpunt", + "settings.archive.region": "Regio", + "settings.archive.bucket": "Toegewezen bucket", + "settings.archive.credential_ref": "Verwijzing naar referenties", + "settings.archive.budget": "Archiefbudget (GiB, 0 = onbeperkt)", + "settings.archive.connectionHelp": "Gebruik een privé, niet-versiebeheerde bucket zonder lifecycle-vervalregels. De verwijzing naar referenties selecteert een geheim bestand dat op de server is aangekoppeld. Voer de beheerde locatie in als s3://bucket/instance-prefix.", + "settings.archive.policy": "Extern archiefbeleid", + "settings.archive.archive_after_seconds": "Archiveren na vastlegging (seconden, -1 = uitgeschakeld)", + "settings.archive.hot_residency_seconds": "Hete kopie bewaren (seconden, -1 = verplaatsen na archivering)", + "settings.archive.archive_protected": "Archivering van beschermde opnames prioriteren", + "settings.archive.archive_on_pressure": "Vroegtijdig archiveren wanneer hete opslag onder druk staat", + "settings.archive.policyHelp": "Archiveringstijd gebruikt de leeftijd van de vastlegging en vereist een voltooide opname. -1 schakelt leeftijdgebaseerde archivering uit of verwijdert het minimum voor hete residentie; 0 betekent onmiddellijk. Wijzigingen zijn van toepassing op nieuwe opnames. Controleer bestaande opnames om er een nieuwe herziening op toe te passen.", + "settings.archive.deletion_pending": "Verwijdering in behandeling", + "settings.archive.archived": "Gearchiveerd", + "settings.archive.hot": "Hot", + "settings.archive.hot_and_archive": "Hot + archief", + "settings.archive.archiving": "Archiveren", + "settings.archive.preparing": "Afspelen voorbereiden", + "settings.archive.unavailable": "Niet beschikbaar", + "settings.archive.operations": "Archiefbewerkingen", + "settings.archive.readOnly": "Herstelmodus: opnamemigratie en -verwijdering zijn gepauzeerd.", + "settings.archive.disabledBuild": "S3-ondersteuning is uitgeschakeld in deze build. Aangekoppelde bestandssysteemdoelen blijven beschikbaar.", + "settings.archive.stored": "Opgeslagen in buckets", + "settings.archive.backlog": "Overdrachtwachtrij", + "settings.archive.cache": "Ophaalcache", + "settings.archive.objectsRemaining": "objecten over", + "settings.archive.waitingForReaders": "In wachtrij, of wachtend op actieve lezers.", + "settings.archive.applied": "Beleidsrevisie toegepast op bestaande opnames", + "settings.archive.reviewExisting": "Bestaande opnames controleren", + "settings.archive.applySummary": "{count} opnames ({bytes}) gebruiken deze revisie. {expired} hebben de bewaarlimiet al overschreden.", + "settings.archive.applyHelp": "Beveiliging en opnameoverschrijvingen blijven van toepassing. Stream- en systeemretentie zijn ook van toepassing. Nieuwe archieftiming en -bestemming worden toegepast bij de volgende levenscyclusscan.", + "settings.archive.applyBlocked": "Voltooi of los gekoppelde overdrachten op voordat u deze revisie toepast.", + "settings.archive.apply": "Toepassen op bestaande opnames", + "common.fullscreenUnsupported": "Beeldvullende modus wordt niet ondersteund in deze browser.", + "recordings.viewInTimelineTitle": "Bekijk deze stream op dit moment in de tijdlijnweergave", + "recordings.clickToRetry": "Klik om opnieuw te proberen", + "timeline.previousDay": "Vorige dag", + "timeline.nextDay": "Volgende dag", + "timeline.previousMonth": "Vorige maand", + "timeline.nextMonth": "Volgende maand", + "settings.searchLabel": "Zoekinstellingen", + "settings.clearSearch": "Zoekopdracht wissen", + "recordings.addTagPlaceholder": "Tag toevoegen…", + "recordings.addNewTagPlaceholder": "Nieuwe tag toevoegen…" } diff --git a/web/public/locales/pl.json b/web/public/locales/pl.json index 50221863..57c47c7e 100644 --- a/web/public/locales/pl.json +++ b/web/public/locales/pl.json @@ -9,6 +9,84 @@ "nav.timeline": "Oś czasu", "nav.health": "Zdrowie", "nav.toggleMenu": "Przełącz menu", + "live.navigator.title": "Nawigator", + "live.navigator.subtitle": "Lokalizacje, układy i aktywność", + "live.navigator.cameras": "Kamery", + "live.navigator.plans": "Plan", + "live.navigator.views": "Widoki", + "live.navigator.events": "Zdarzenia", + "live.navigator.search": "Znajdź kamerę…", + "live.navigator.allCameras": "Wszystkie kamery", + "live.navigator.unassigned": "Nieprzypisane", + "live.navigator.noCameras": "Żadna kamera nie pasuje do tego zakresu.", + "live.navigator.saveCurrent": "Zapisz bieżący układ", + "live.navigator.noLayouts": "Brak zapisanych układów.", + "live.navigator.layoutNamePrompt": "Nazwij ten układ widoku na żywo", + "live.navigator.shareLayoutPrompt": "Udostępnić ten układ innym operatorom?", + "live.navigator.layoutSaved": "Zapisano: {name}", + "live.navigator.layoutLoaded": "Wczytano: {name}", + "live.navigator.deleteLayoutConfirm": "Usunąć {name}?", + "live.navigator.shared": "Udostępniony", + "live.navigator.loadingEvents": "Ładowanie ostatnich zdarzeń…", + "live.navigator.noRecentEvents": "Brak wykryć w ciągu ostatniej godziny.", + "live.navigator.expand": "Rozwiń nawigator", + "live.navigator.collapse": "Zwiń nawigator", + "live.plan.navigatorHelp": "Wybierz budynek lub piętro. Podglądy kamer otwierają się tylko na żądanie.", + "live.plan.noPlans": "Brak planów budynków. Utwórz jeden w obszarze roboczym planów.", + "live.plan.emptyTitle": "Zbuduj przestrzenny widok kamer", + "live.plan.emptyDescription": "Plan pokazuje znaczniki stanu dla całego obiektu i otwiera wideo tylko na żądanie operatora. Narysuj tutaj pomieszczenia i ściany albo prześlij zeskanowany plan, rysunek obiektu lub zrzut z oprogramowania NVR, a następnie przypisz kamery do rzeczywistych pomieszczeń.", + "live.plan.sketch.tools": "Narzędzia układu", + "live.plan.sketch.tool.select": "Zaznaczanie", + "live.plan.sketch.tool.room": "Pomieszczenie", + "live.plan.sketch.tool.wall": "Ściana", + "live.plan.sketch.tool.area": "Obszar", + "live.plan.sketch.tool.label": "Etykieta", + "live.plan.sketch.undo": "Cofnij rysowanie", + "live.plan.sketch.redo": "Ponów rysowanie", + "live.plan.sketch.snap": "Przyciągaj do siatki", + "live.plan.sketch.hint.select": "Przeciągnij kształty lub kamery, aby je przenieść. Kliknij kształt, aby go edytować; przytrzymaj Alt, aby pominąć siatkę.", + "live.plan.sketch.hint.room": "Przeciągnij po planie, aby narysować pomieszczenie lub obrys budynku.", + "live.plan.sketch.hint.wall": "Klikaj, aby dodawać punkty ściany. Podwójne kliknięcie lub Enter kończy, Escape anuluje.", + "live.plan.sketch.hint.area": "Klikaj, aby obrysować obszar. Kliknij pierwszy punkt lub naciśnij Enter, aby go zamknąć.", + "live.plan.sketch.hint.label": "Kliknij plan, aby umieścić etykietę tekstową.", + "live.plan.sketch.type.rect": "Pomieszczenie", + "live.plan.sketch.type.wall": "Ściana", + "live.plan.sketch.type.area": "Obszar", + "live.plan.sketch.type.label": "Etykieta", + "live.plan.sketch.pointCount": "Punkty: {count}", + "live.plan.sketch.defaultLabel": "Etykieta", + "live.plan.sketch.shapes": "Kształty układu", + "live.plan.sketch.noShapes": "Nic jeszcze nie narysowano. Wybierz narzędzie nad planem, aby zacząć.", + "live.plan.sketch.tone": "Kolor", + "live.plan.sketch.tone.slate": "Łupkowy", + "live.plan.sketch.tone.blue": "Niebieski", + "live.plan.sketch.tone.green": "Zielony", + "live.plan.sketch.tone.amber": "Bursztynowy", + "live.plan.sketch.tone.red": "Czerwony", + "live.plan.sketch.tone.violet": "Fioletowy", + "live.plan.sketch.labelText": "Etykieta", + "live.plan.sketch.text": "Tekst", + "live.plan.sketch.size": "Rozmiar", + "live.plan.sketch.size.sm": "Mały", + "live.plan.sketch.size.md": "Średni", + "live.plan.sketch.size.lg": "Duży", + "live.plan.sketch.filled": "Wypełnij pomieszczenie", + "live.plan.sketch.left": "Lewo %", + "live.plan.sketch.top": "Góra %", + "live.plan.sketch.width": "Szerokość %", + "live.plan.sketch.height": "Wysokość %", + "live.plan.sketch.points": "Punkty", + "live.plan.sketch.point": "Punkt {index}", + "live.plan.sketch.delete": "Usuń kształt", + "live.plan.sketch.duplicate": "Duplikuj", + "live.plan.sketch.deselect": "Gotowe", + "live.plan.sketch.emptyTitle": "Na tym planie jeszcze nic nie ma", + "live.plan.sketch.emptyBody": "Narysuj tutaj pomieszczenia, ściany i etykiety albo prześlij zeskanowany plan, rysunek obiektu lub eksport PNG/JPEG (do 768 KB).", + "live.plan.sketch.emptyBodyReadOnly": "Administrator może narysować układ lub przesłać plan rzeczywistego budynku.", + "live.plan.sketch.drawLayout": "Narysuj układ", + "live.plan.sketch.uploadImage": "Prześlij obraz", + "live.plan.sketch.limitReached": "Osiągnięto limit kształtów ({max})", + "live.plan.sketch.discardDrawing": "Rysowanie anulowane", "streamHealth.title": "Streamuj zdrowie", "streamHealth.loading": "Ładowanie danych zdrowotnych...", "streamHealth.error": "Nie udało się załadować danych o stanie zdrowia", @@ -405,6 +483,12 @@ "live.errorProcessingStreams": "Błąd podczas przetwarzania strumieni: {message}", "live.couldNotEnableFullscreen": "Nie można włączyć trybu pełnoekranowego: {message}", "live.allTags": "Wszystkie tagi", + "live.favorites": "Ulubione", + "live.favoritesOnly": "Pokazuj tylko ulubione kamery", + "live.addFavorite": "Dodaj {stream} do ulubionych", + "live.removeFavorite": "Usuń {stream} z ulubionych", + "live.noFavorites": "Brak ulubionych kamer. Użyj gwiazdki na kafelku kamery, aby ją dodać.", + "live.favoriteUpdateError": "Nie udało się zaktualizować ulubionych: {message}", "live.tags": "Tagi", "live.stream": "Strumień", "live.filterByTag": "Filtruj według tagu: {tag}", @@ -589,6 +673,7 @@ "live.forceRefreshWarning": "Spowoduje to krótkie przerwanie połączenia go2rtc, przerywając aktywne nagrywanie. Nagrywanie zostanie wznowione automatycznie.", "live.viewInTimeline": "Zobacz na osi czasu", "live.toggleFullscreen": "Przełącz tryb pełnoekranowy", + "live.resetZoom": "Resetuj powiększenie", "live.streamStarting": "Rozpoczęcie transmisji...", "live.go2rtcNotRespondingRetry": "go2rtc jest włączony, ale nie odpowiada. Sprawdź status usługi go2rtc. Kliknij opcję Spróbuj ponownie, aby spróbować ponownie.", "live.go2rtcHlsFailedRetry": "Strumień HLS go2rtc nie powiódł się. Kliknij opcję Spróbuj ponownie, aby spróbować ponownie.", @@ -603,12 +688,14 @@ "live.failedToCreateMediaBuffer": "Nie udało się utworzyć bufora multimediów", "live.webSocketConnectionError": "Błąd połączenia WebSocket", "live.webrtcAutoplayBlocked": "Kliknij, aby odtworzyć wideo (automatyczne odtwarzanie zablokowane)", + "live.audioPlaybackBlocked": "Przeglądarka zablokowała dźwięk kamery. Kliknij ponownie przycisk głośnika, aby ponowić próbę.", "live.webrtcConnectionLostRetry": "Utracono połączenie WebRTC. Kliknij Spróbuj ponownie, aby połączyć się ponownie.", "live.streamConnectedNoVideoDataRetry": "Strumień podłączony, ale brak danych wideo. Kliknij Spróbuj ponownie, aby połączyć się ponownie.", "live.failedToLoadVideo": "Nie udało się załadować wideo", "live.webrtcIceConnectionFailed": "Połączenie WebRTC ICE nie powiodło się", "live.webrtcConnectionLostPleaseRetry": "Utracono połączenie WebRTC. Spróbuj ponownie.", "live.autoRetryingIn": "Ponowna próba za {seconds} s…", + "live.fullscreenSubStreamFallback": "{stream}: za mało przepustowości dla strumienia w pełnej rozdzielczości na pełnym ekranie — przełączono na podstrumień.", "live.connectionTimeoutCheckNetwork": "Przekroczono limit czasu połączenia. Sprawdź ustawienia sieci/zapory sieciowej.", "live.failedToEstablishWebrtcConnection": "Nie udało się nawiązać połączenia WebRTC", "live.cannotConnectToSource": "Nie można połączyć się ze źródłem kamery", @@ -622,6 +709,16 @@ "live.connectionQuality.bad": "Złe", "live.muteCameraAudio": "Wycisz dźwięk kamery", "live.unmuteCameraAudio": "Wyłącz wyciszenie dźwięku kamery", + "live.tileActions": "Akcje kamery", + "live.takeSnapshot": "Zrób migawkę", + "live.openStreamRecordings": "Otwórz nagrania tego strumienia", + "live.enterReorderMode": "Zmień kolejność kamer", + "live.pullToRefresh": "Pociągnij, aby odświeżyć strumienie", + "live.releaseToRefresh": "Puść, aby odświeżyć strumienie", + "live.refreshingStreams": "Odświeżanie strumieni…", + "live.streamsRefreshed": "Odświeżono strumienie", + "live.refreshStreamsFailed": "Nie udało się odświeżyć strumieni: {message}", + "live.tipDoubleTapFullscreen": "Wskazówka: stuknij dwukrotnie kafelek, aby otworzyć go na pełnym ekranie.", "live.switchToToggleMode": "Przełącz na tryb przełączania", "live.switchToPushToTalkMode": "Przełącz na funkcję „Naciśnij i mów”.", "live.releaseToStopTalking": "Puść, aby przestać mówić", @@ -636,6 +733,40 @@ "live.pauseForPrivacyConfirm": "Wstrzymać tę transmisję, aby zachować prywatność? Nagrywanie i podgląd na żywo zostaną zatrzymane, ale strumień pozostanie widoczny na tej stronie z nakładką prywatności. Po zakończeniu kliknij Wznów.", "live.streamPausedForPrivacy": "Transmisja wstrzymana ze względu na prywatność", "live.resumeStream": "Wznów transmisję", + "live.dayNightControl": "Tryb dzień/noc", + "live.dayNightLoading": "Ładowanie…", + "live.dayNightApplying": "Stosowanie…", + "live.dayNightMode_auto": "Auto", + "live.dayNightMode_day": "Dzień", + "live.dayNightMode_night": "Noc", + "live.dayNightMode_unknown": "Nieznany", + "live.dayNightApplied": "Tryb dzień/noc ustawiony na {mode}", + "live.dayNightApplyFailed": "Nie udało się ustawić trybu dzień/noc", + "live.dayNightLoadFailed": "Nie udało się odczytać trybu dzień/noc", + "live.playbackFallbackUsed": "Zapasowo: {transport}", + "live.playbackTransportUnavailable": "{transport} jest wyłączony na serwerze dla tego strumienia.", + "live.recordingMode.constant": "Ciągłe nagrywanie", + "live.recordingMode.detection": "Nagrywanie przy wykryciu", + "live.recordingMode.schedule": "Nagrywanie według harmonogramu", + "live.recordingMode.none": "Bez nagrywania", + "live.health.healthy": "Strumień sprawny", + "live.health.degraded": "Strumień buforuje lub odzyskuje się", + "live.health.offline": "Strumień niedostępny", + "live.enterPictureInPicture": "Otwórz obraz w obrazie", + "live.exitPictureInPicture": "Zamknij obraz w obrazie", + "live.pictureInPictureError": "Obraz w obrazie nie powiódł się: {message}", + "live.alwaysFullscreenOnTapEnable": "Włącz pełny ekran przy pojedynczym stuknięciu kafelka", + "live.alwaysFullscreenOnTapDisable": "Wyłącz pełny ekran przy pojedynczym stuknięciu kafelka", + "live.displayMode": "Tryb wyświetlania", + "live.displayModeFit": "Dopasuj", + "live.displayModeFill": "Wypełnij", + "live.displayModeFitDescription": "Dopasuj: pokazuj całą klatkę z czarnymi pasami", + "live.displayModeFillDescription": "Wypełnij: wypełnij kafelek i przytnij krawędzie klatki", + "live.slideshowStartCameras": "Rozpocznij pokaz slajdów: przewijaj kamery", + "live.slideshowStartPages": "Rozpocznij pokaz slajdów: przewijaj strony siatki", + "live.slideshowStop": "Zatrzymaj pokaz slajdów", + "live.slideshowInterval": "Odstęp pokazu slajdów", + "live.slideshowSeconds": "{seconds} s", "streams.toggleDisable": "Wyłącz strumień", "streams.toggleEnable": "Włącz strumień", "streams.readOnlyInsufficientPermissions": "Tylko do odczytu (niewystarczające uprawnienia do modyfikacji)", @@ -759,9 +890,9 @@ "streamsConfig.streamNameImmutable": "Nazwy strumienia nie można zmienić po utworzeniu", "streamsConfig.streamNameAllowedChars": "Dozwolone są tylko litery, cyfry, „.”, „-” i „_” (bez spacji).", "streamsConfig.streamUrl": "Przesyłaj strumieniowo URL", - "streamsConfig.streamUrlPlaceholder": "rtsp://nazwa użytkownika:hasło@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "Podstrumień URL (opcjonalnie)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://nazwa użytkownika:hasło@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "Strumień URL o niskiej rozdzielczości dla widoku siatki deski rozdzielczej. Pozostaw puste, aby wszędzie używać głównego strumienia. Podstrumień jest używany wyłącznie do podglądu na żywo w trybie siatki; nagrywanie i tryb pełnoekranowy zawsze korzystają ze strumienia głównego.", "streamsConfig.urlCredentialsHiddenTitle": "Dane uwierzytelniające URL są ukryte w trybie demonstracyjnym/przeglądarki", "streamsConfig.urlCredentialsHidden": "Poświadczenia URL ukryte ze względów bezpieczeństwa", @@ -819,7 +950,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "Upewnij się, że na tym punkcie końcowym działa funkcja wykrywania obiektów świetlnych", "streamsConfig.customApiEndpointUrl": "Niestandardowy punkt końcowy API URL", "streamsConfig.useDefaultEndpoint": "Użyj domyślnego punktu końcowego", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "Wprowadź pełny kod URL do niestandardowego punktu końcowego wykrywania API", "streamsConfig.overrideWithCustomEndpoint": "Zastąp niestandardowym punktem końcowym", "streamsConfig.detectionThreshold": "Próg wykrywania", @@ -1056,7 +1187,7 @@ "settings.detectionModelsPath": "Ścieżka modeli detekcji", "settings.detectionModelsPathHelp": "Katalog, w którym przechowywane są modele detekcji", "settings.apiDetectionUrl": "API Wykrywanie URL", - "settings.apiDetectionUrlHelp": "URL punktu końcowego wykrywania obiektów zewnętrznych API", + "settings.apiDetectionUrlHelp": "Punkt końcowy light-object-detect, np. http://localhost:8000/api/v1/detect. Zrzut jest przesyłany jako dane formularza multipart z dołączonymi parametrami zapytania backend i confidence_threshold.", "settings.apiDetectionBackend": "Moduł wykrywania API", "settings.apiDetectionBackendOnnx": "Czas działania ONNX", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1122,7 +1253,7 @@ "settings.clientId": "Identyfikator klienta", "settings.clientIdHelp": "Unikalny identyfikator tego klienta", "settings.topicPrefix": "Prefiks tematu", - "settings.topicPrefixPublishedTo": "Zdarzenia opublikowane w: {prefix}/detections/", + "settings.topicPrefixPublishedTo": "Zdarzenia opublikowane w: {prefix}/detections/", "settings.enableTls": "Włącz TLS", "settings.enableTlsHelp": "Użyj szyfrowanego połączenia (zazwyczaj port 8883)", "settings.keepaliveSeconds": "Keepalive (sekundy)", @@ -1156,5 +1287,1361 @@ "settings.discoveryIntervalSecondsRangeHelp": "Jak często skanować w poszukiwaniu kamer (30–3600 sekund)", "settings.discoveryNetwork": "Sieć Odkryć", "settings.discoveryNetworkExamples": "Przykłady: 192.168.1.0/24, 10.0.0.0/16, auto", - "settings.saveSettings": "Zapisz ustawienia" + "settings.saveSettings": "Zapisz ustawienia", + "live.plan.previewUnavailable": "Podgląd kamery niedostępny", + "live.plan.previewAlt": "Bieżący widok z {name}", + "live.plan.degreesValue": "{value} stopni", + "live.plan.inDegrees": "{label} w stopniach", + "live.plan.imageDimensionsError": "Nie udało się odczytać wymiarów obrazu", + "live.plan.loading": "Ładowanie planów budynków…", + "live.plan.created": "Utworzono {name}", + "live.plan.renamed": "Zmieniono nazwę na {name}", + "live.plan.deleted": "Usunięto {name}", + "live.plan.backgroundType": "Tło musi być obrazem PNG lub JPEG", + "live.plan.backgroundTooLarge": "Obraz tła jest zbyt duży; maksymalnie 768 KB", + "live.plan.backgroundAspect": "Przesłano, ale proporcje obrazu nie pasują do żadnego prawidłowego rozmiaru płótna", + "live.plan.backgroundUpdatedSave": "Zaktualizowano tło dla {name}; zapisz układ, aby zastosować rozmiar płótna", + "live.plan.backgroundNotResized": "Przesłano tło, ale płótno nie zostało przeskalowane: {error}", + "live.plan.backgroundUpdated": "Zaktualizowano tło dla {name}", + "live.plan.backgroundRemoved": "Usunięto tło", + "live.plan.saved": "Zapisano {name}", + "live.plan.createTitle": "Utwórz plan budynku", + "live.plan.createDescription": "Nadaj temu budynkowi lub piętru wyraźną nazwę. Narysuj układ lub prześlij obraz planu, a następnie rozmieść kamery.", + "live.plan.nameLabel": "Nazwa planu", + "live.plan.namePlaceholder": "Główny budynek · Parter", + "live.plan.createConfirm": "Utwórz plan", + "live.plan.eyebrow": "Plan budynku", + "live.plan.placedSummary": "{placed} rozmieszczonych · {live} na żywo", + "live.plan.zoomAndPan": "Powiększanie i przesuwanie planu", + "live.plan.panLeft": "Przesuń w lewo", + "live.plan.panUp": "Przesuń w górę", + "live.plan.panDown": "Przesuń w dół", + "live.plan.panRight": "Przesuń w prawo", + "live.plan.zoomOut": "Oddal", + "live.plan.zoomIn": "Przybliż", + "live.plan.fitTitle": "Dopasuj plan", + "live.plan.fit": "Dopasuj", + "live.plan.backgroundMenu": "Tło…", + "live.plan.save": "Zapisz plan", + "live.plan.uploadBackgroundTitle": "Prześlij obraz PNG lub JPEG jako tło planu", + "live.plan.replaceBackground": "Zastąp tło", + "live.plan.uploadBackground": "Prześlij tło", + "live.plan.removeBackground": "Usuń tło", + "live.plan.rename": "Zmień nazwę", + "live.plan.newPlan": "Nowy plan", + "live.plan.editLayout": "Edytuj układ", + "live.plan.placementHint": "Kliknij plan, aby umieścić {name}", + "live.plan.clusterLabel": "Kamery: {count}; przybliż", + "live.plan.markerLabel": "{name}; {availability}; skierowana na {rotation}° z polem widzenia {fov}°", + "live.plan.cameraFallback": "Kamera", + "live.plan.legendLive": "Na żywo", + "live.plan.canvas": "Płótno planu", + "live.plan.width": "Szerokość", + "live.plan.height": "Wysokość", + "live.plan.canvasHint": "Przesłanie obrazu tła przeskalowuje płótno, aby do niego pasować.", + "live.plan.canvasInvalid": "Szerokość musi mieścić się w zakresie 400–4000, a wysokość 300–4000.", + "live.plan.openLive": "Otwórz kamerę na żywo", + "live.plan.direction": "Kierunek kamery", + "live.plan.fov": "Pole widzenia", + "live.plan.coverageNote": "Wycinki pokazują tylko kierunek i kąt; odległość na planie nie jest skalibrowana.", + "live.plan.removeCamera": "Usuń z planu", + "live.plan.selectCamera": "Wybierz kamerę", + "live.plan.selectHintEditing": "Przeciągaj rozmieszczone znaczniki, aby doprecyzować. Sprawdzaj stan i na żądanie otwieraj jeden widok na żywo.", + "live.plan.selectHint": "Sprawdzaj stan i na żądanie otwieraj jeden widok na żywo.", + "live.plan.cameras": "Kamery planu", + "live.plan.findPlaceholder": "Znajdź na tym planie…", + "live.plan.findLabel": "Znajdź kamerę na tym planie", + "live.plan.unplaced": "Nierozmieszczone kamery", + "live.plan.unplacedHint": "Wybierz kamerę, a następnie kliknij jej pozycję na planie.", + "live.plan.renameTitle": "Zmień nazwę planu", + "live.plan.renameDescription": "Plany są udostępniane wszystkim operatorom tego obiektu.", + "live.plan.deleteTitle": "Usuń plan", + "live.plan.deleteMessage": "Usunąć “{name}” wraz z przesłanym tłem? Rozmieszczenia kamer na tym planie zostaną usunięte; same kamery pozostaną nietknięte.", + "setupWizard.welcomeTitle": "Witamy w LightNVR", + "setupWizard.welcomeIntro": "Skonfigurujmy Twój NVR w kilku szybkich krokach. Do tych ustawień zawsze wrócisz później ze strony Ustawienia.", + "setupWizard.welcomeStorage": "Ścieżka magazynu i limity rozmiaru", + "setupWizard.welcomePerformance": "Limity wydajności dla Twojej liczby kamer", + "setupWizard.welcomeSecurity": "Bezpieczne logowanie administratora", + "setupWizard.storageTitle": "Magazyn i baza danych", + "setupWizard.storageIntro": "Gdzie przechowywać nagrania i bazę danych?", + "setupWizard.storagePath": "Ścieżka magazynu nagrań", + "setupWizard.storagePathHint": "Ścieżka bezwzględna, do której zapisywane są pliki wideo.", + "setupWizard.maxStorage": "Maksymalny rozmiar magazynu (GB)", + "setupWizard.maxStorageHint": "0 = bez limitu.", + "setupWizard.dbPath": "Ścieżka bazy danych", + "setupWizard.dbPathHint": "Lokalizacja pliku bazy danych SQLite.", + "setupWizard.performanceTitle": "Wydajność", + "setupWizard.performanceIntro": "Te ustawienia sterują pojemnością, nie jakością obrazu. Większość użytkowników może zostawić wartości domyślne.", + "setupWizard.threadPool": "Rozmiar puli wątków roboczych", + "setupWizard.threadPoolInfo": "dotyczy pracy w tle weba/serwera. Zalecana wartość domyślna zwykle jest najlepsza, chyba że stroisz wydajność.", + "setupWizard.maxStreams": "Maksymalna liczba strumieni jednoczesnych", + "setupWizard.maxStreamsInfo": "to limit pojemności kamer dla tego uruchomionego egzemplarza. Ustaw go przynajmniej na liczbę kamer, które planujesz dodać, plus trochę zapasu.", + "setupWizard.important": "Ważne:", + "setupWizard.restartWarning": "jeśli zmienisz którekolwiek z tych ustawień, nowa wartość zostanie zapisana teraz, ale użyta dopiero po ponownym uruchomieniu LightNVR. Np. jeśli obecny limit strumieni wynosi 1, a podniesiesz go do 32, musisz zrestartować przed dodaniem kamer ponad stary limit.", + "setupWizard.threadPoolHintCores": "Zalecane: {recommended} (2× Twój procesor {cores}-rdzeniowy). To steruje wątkami roboczymi w tle biblioteki libuv. Zakres: 2–128.", + "setupWizard.threadPoolHint": "Zalecane: {recommended} (2× rdzenie Twojego procesora). To steruje wątkami roboczymi w tle biblioteki libuv. Zakres: 2–128.", + "setupWizard.maxStreamsHint": "Ile kamer LightNVR może naraz utrzymać aktywnych. Domyślnie 32, maks. {max}. Jeśli spodziewasz się 8 kamer, wybierz co najmniej 8. Wymaga restartu, aby zadziałało.", + "setupWizard.completeTitle": "Konfiguracja zakończona!", + "setupWizard.saved": "Ustawienia zostały zapisane pomyślnie.", + "setupWizard.notSaved": "Nie zmieniono żadnych ustawień — zostaną użyte wartości domyślne.", + "setupWizard.restartRequired": "Wymagany restart", + "setupWizard.restartRequiredInfo": "zmiany rozmiaru puli wątków i/lub maksimum strumieni są zapisane, ale nie zadziałają, dopóki usługa się nie zrestartuje. Zrestartuj przed dodaniem kolejnych kamer lub oczekiwaniem na nowy limit pojemności.", + "setupWizard.saveFailed": "Nie udało się zapisać ustawień: {error}", + "setupWizard.back": "Wstecz", + "setupWizard.saving": "Zapisywanie…", + "setupWizard.saveContinue": "Zapisz i kontynuuj", + "setupWizard.next": "Dalej →", + "setupWizard.finish": "Przejdź do pulpitu", + "setupWizard.skip": "Pomiń kreatora konfiguracji", + "live.eptzCanvasLabel": "Widok elektronicznego panoramowania, nachylania i zoomu dla obiektywu typu rybie oko", + "live.eptzCanvasHint": "Przeciągaj, aby panoramować i nachylać; kółko lub uszczypnięcie zoomuje; Home przywraca", + "live.eptzReset": "Resetuj widok ePTZ", + "live.autoShort": "Auto", + "live.webrtcShort": "WebRTC", + "nav.investigation": "Dochodzenie", + "availability.label": "Dostępność kamer", + "availability.live": "Na żywo", + "availability.offline": "Offline (wcześniej połączone)", + "availability.neverConnected": "Nigdy nie połączone", + "availability.disabled": "Wyłączone", + "availability.all": "Wszystkie kamery", + "streams.inventory": "Wykaz", + "streams.configuration": "Konfiguracja", + "events.tab": "Zdarzenia", + "events.eyebrow": "Integracje oparte na zdarzeniach", + "events.title": "Zdarzenia i trasowanie", + "events.description": "Przekształcaj zdarzenia kamery i systemu w trwałe strumienie MQTT do automatyzacji, usług powiadomień i przetwarzania zewnętrznego. LightNVR udostępnia interfejs zdarzeń; dostarczanie e-maili i SMS-ów pozostaje w usługach downstream.", + "events.routes": "Trasy", + "events.destinations": "Miejsca docelowe", + "events.catalog": "Katalog zdarzeń", + "events.enable": "Włącz", + "events.loadError": "Nie udało się wczytać konfiguracji trasowania zdarzeń", + "events.accessDenied": "Odmowa dostępu – niewystarczające uprawnienia", + "events.summary.routes": "Trasy", + "events.summary.enabled": "{count} włączonych", + "events.summary.destinations": "Miejsca docelowe", + "events.summary.managedActive": "{count} zarządzanych i aktywnych", + "events.summary.types": "Zarejestrowane typy", + "events.summary.registry": "Wersjonowany katalog zdarzeń", + "events.summary.interface": "Interfejs", + "events.summary.interfaceHelp": "Trwałe wyjście zdarzeń", + "events.route.add": "Dodaj trasę", + "events.route.addTitle": "Utwórz trasę zdarzeń", + "events.route.editTitle": "Edytuj trasę zdarzeń", + "events.route.create": "Utwórz trasę", + "events.route.editorDescription": "Wybierz, które zdarzenia kwalifikują się, które kamery są w zakresie, dokąd trafiają i jak kontrolowane są hałaśliwe źródła.", + "events.route.emptyTitle": "Brak skonfigurowanych tras zdarzeń", + "events.route.emptyDescription": "Utwórz trasę, aby wybrać typy zdarzeń, zakres kamer, harmonogram, politykę tłumienia i cel MQTT.", + "events.route.enabled": "Trasa włączona", + "events.route.enabledHelp": "Pasujące zdarzenia są akceptowane do trwałej dostawy", + "events.route.destination": "Cel", + "events.route.destinationHelp": "Pasujące zdarzenie jest zapisywane raz dla każdego unikalnego celu.", + "events.route.eventTypes": "Typy zdarzeń", + "events.route.eventTypesHelp": "Wybierz jeden lub więcej wersjonowanych kontraktów zdarzeń z rejestru.", + "events.route.detectionFilters": "Filtruj detekcje obiektów", + "events.route.detectionFiltersHelp": "Opcjonalnie wymagaj etykiet, stref lub minimalnej pewności dla zdarzeń detekcji obiektów.", + "events.route.healthFilters": "Filtruj zdarzenia stanu systemu", + "events.route.healthFiltersHelp": "Opcjonalnie dopasuj zarejestrowane kody stanów lub poziomy ważności. Dostępne wartości pochodzą z tego rejestratora.", + "events.route.healthConditions": "Stany systemu (dowolny)", + "events.route.healthSeverities": "Poziomy ważności (dowolny)", + "events.route.healthRegistryUnavailable": "Rejestr stanów systemu jest niedostępny. Przeładuj przed konfiguracją filtrów stanów.", + "events.route.labels": "Etykiety (dowolna)", + "events.route.zones": "ID stref (dowolne)", + "events.route.listHelp": "Oddziel wartości przecinkami.", + "events.route.minConfidence": "Minimalna pewność", + "events.route.confidenceHelp": "Wartość od 0 do 1.", + "events.route.cameraScope": "Zakres kamer", + "events.route.cameraScopeHelp": "Użyj lokalizacji floty, tagów, kolekcji atrybutów lub wybranych kamer bez ładowania całej floty.", + "events.route.allCameras": "Wszystkie kamery", + "events.route.dynamicScope": "Dynamiczny selektor kamer", + "events.route.systemScopeHelp": "Zdarzenia systemowe nie są kamerami. Selektory kamer są niedostępne, gdy ta trasa obejmuje zdarzenia systemowe.", + "events.route.schedule": "Harmonogram", + "events.route.scheduleHelp": "Użyj czasu wystąpienia zdarzenia w strefie czasowej IANA; obsługiwane są okna nocne.", + "events.route.restrictSchedule": "Tylko w skonfigurowanych oknach", + "events.route.suppression": "Polityka szumów i dostarczania", + "events.route.suppressionHelp": "Zero wyłącza kontrolę. Tłumienie postępuje dopiero po zaakceptowaniu trwałego zdarzenia przez ten cel.", + "events.route.debounce": "Sekundy debounce", + "events.route.debounceHelp": "Powtarzające się obserwacje wydłużają ten okres wyciszenia.", + "events.route.cooldown": "Sekundy czasu chłodzenia", + "events.route.cooldownHelp": "Minimalny interwał po zaakceptowanym zdarzeniu.", + "events.route.grouping": "Sekundy okna grupowania", + "events.route.groupingHelp": "Zachowaj pierwsze zdarzenie i scalaj powtórzenia.", + "events.route.rateLimit": "Zdarzenia na minutę", + "events.route.rateLimitHelp": "Maksymalna liczba w stałym oknie na trasę i kamerę.", + "events.route.deliveryPolicy": "Polika dostarczania", + "events.route.suppressionActive": "Kontrola szumów aktywna", + "events.route.everyMatch": "Każde dopasowanie", + "events.route.preview": "Podgląd trasy", + "events.route.previewing": "Podgląd…", + "events.route.previewResult": "Podgląd trasy", + "events.route.cameraMatches": "{count} kamer pasuje", + "events.route.previewNoPublish": "Podgląd weryfikuje pełną regułę i rozwiązuje próbkę kamer; nigdy nie publikuje zdarzenia.", + "events.route.systemPreviewHelp": "Zdarzenia systemowe pomijają wybór kamer, dlatego w tym podglądzie raportują zero pasujących kamer.", + "events.route.created": "Trasa zdarzeń utworzona", + "events.route.updated": "Trasa zdarzeń zaktualizowana", + "events.route.deleted": "Trasa zdarzeń usunięta", + "events.route.disabled": "Trasa zdarzeń wyłączona", + "events.route.enabledMessage": "Trasa zdarzeń włączona", + "events.route.deleteConfirm": "Usunąć trasę zdarzeń „{name}\"?", + "events.route.validation.name": "Wprowadź nazwę trasy.", + "events.route.validation.destination": "Wybierz cel.", + "events.route.validation.event_types": "Wybierz co najmniej jeden typ zdarzenia.", + "events.route.validation.selector": "Uzupełnij lub popraw selektor kamer.", + "events.route.validation.system_scope": "Selektory kamer nie mogą być używane ze zdarzeniami o zakresie systemowym.", + "events.route.validation.detection_type": "Filtry detekcji wymagają typu zdarzenia detekcji obiektów.", + "events.route.validation.detection_filter": "Dodaj co najmniej jedną etykietę detekcji, strefę lub próg pewności.", + "events.route.validation.confidence": "Minimalna pewność musi wynosić od 0 do 1.", + "events.route.validation.predicate_mix": "Filtry detekcji i stanu nie mogą być łączone w jednej trasie.", + "events.route.validation.health_type": "Filtry stanu wymagają wyłącznie zarejestrowanych typów zdarzeń kondycji systemu.", + "events.route.validation.health_filter": "Wybierz co najmniej jeden zarejestrowany warunek stanu lub poziom ważności.", + "events.route.validation.health_condition": "Wybierz tylko kody warunków zwracane przez rejestr stanu rejestratora.", + "events.route.validation.health_severity": "Wybierz tylko poziomy ważności obsługiwane przez wybrane typy zdarzeń stanu.", + "events.route.validation.timezone": "Wprowadź zainstalowaną strefę czasową IANA, np. UTC lub America/New_York.", + "events.route.validation.schedule_window": "Każde okno harmonogramu wymaga co najmniej jednego dnia oraz różnych, prawidłowych godzin rozpoczęcia i zakończenia.", + "events.route.validation.suppression": "Wartości tłumienia muszą być liczbami całkowitymi w dozwolonych zakresach.", + "events.schedule.timezone": "Strefa czasowa", + "events.schedule.timezoneHelp": "Musi znajdować się w bazie stref czasowych rejestratora.", + "events.schedule.addWindow": "Dodaj okno czasowe", + "events.schedule.windowNumber": "Okno {number}", + "events.schedule.start": "Początek", + "events.schedule.end": "Koniec", + "events.schedule.sunday": "Nd", + "events.schedule.monday": "Pn", + "events.schedule.tuesday": "Wt", + "events.schedule.wednesday": "Śr", + "events.schedule.thursday": "Cz", + "events.schedule.friday": "Pt", + "events.schedule.saturday": "So", + "events.destination.add": "Dodaj odbiorcę", + "events.destination.addTitle": "Dodaj odbiorcę MQTT", + "events.destination.editTitle": "Edytuj odbiorcę MQTT", + "events.destination.create": "Utwórz odbiorcę", + "events.destination.editorDescription": "Skonfiguruj trwały kanał wyjściowy zdarzeń. Dane uwierzytelniające są tylko do zapisu i nigdy nie są zwracane przez API.", + "events.destination.default": "Domyślne ustawienia MQTT", + "events.destination.settingsManaged": "Ustawienia zarządzane", + "events.destination.defaultDescription": "Istniejąca konfiguracja MQTT pozostaje dostępna jako mqtt:default i jest używana przez {count} tras.", + "events.destination.openSettings": "Otwórz ustawienia MQTT", + "events.destination.emptyTitle": "Brak zarządzanych odbiorców", + "events.destination.emptyDescription": "Dodaj kolejny broker MQTT do niezależnego dostarczania zdarzeń do konektora chmurowego, systemu automatyzacji lub usługi powiadomień.", + "events.destination.identity": "Tożsamość odbiorcy", + "events.destination.enabled": "Odbiorca włączony", + "events.destination.enabledHelp": "Połącz i opróżnij jego trwałą kolejkę", + "events.destination.active": "Aktywne", + "events.destination.paused": "Wstrzymane", + "events.destination.pause": "Wstrzymaj", + "events.destination.broker": "Broker", + "events.destination.host": "Host brokera", + "events.destination.hostHelp": "Tylko nazwa hosta lub adres IP; nie uwzględniaj schematu URL.", + "events.destination.port": "Port", + "events.destination.clientId": "ID klienta", + "events.destination.clientIdHelp": "Musi być unikalne dla tego połączenia z brokerem.", + "events.destination.topic": "Temat", + "events.destination.topicTemplate": "Szablon tematu", + "events.destination.topicHelp": "Musi zawierać tokeny typu zdarzenia i ID podmiotu; symbole wieloznaczne MQTT nie są dozwolone.", + "events.destination.keepalive": "Sekundy keepalive", + "events.destination.statusTopicTemplate": "Temat statusu obecności", + "events.destination.statusTopicHelp": "Opcjonalne. Musi zawierać {installation_uuid}; {destination_uuid} również jest dostępny. Symbole wieloznaczne MQTT nie są dozwolone.", + "events.destination.statusTopicEnabled": "Obecność jest jawnie włączona dla tego celu. Temat nigdy nie jest wywnioskowany z tematu zdarzenia.", + "events.destination.statusTopicDisabled": "Obecność jest wyłączona dla tego celu. Pozostaw to pole puste, aby pozostało wyłączone.", + "events.destination.qos": "Jakość usługi", + "events.destination.qos0": "wyślij raz", + "events.destination.qos1": "co najmniej raz", + "events.destination.qos2": "dokładnie raz", + "events.destination.authentication": "Uwierzytelnianie", + "events.destination.passwordPreserved": "Pozostaw puste, aby zachować zapisane hasło tylko do zapisu.", + "events.destination.passwordOptional": "Opcjonalne, gdy broker zezwala na anonimowych klientów.", + "events.destination.clearPassword": "Wyczyść zapisane hasło", + "events.destination.transportSecurity": "Bezpieczeństwo transportu", + "events.destination.tlsMode": "Tryb TLS", + "events.destination.tlsSystem": "Systemowy magazyn zaufania", + "events.destination.tlsCustomCa": "Własny urząd certyfikacji", + "events.destination.tlsMutual": "Wzajemne TLS", + "events.destination.tlsDisabled": "Wyłączone (tekst jawny)", + "events.destination.tlsHelp.system": "Zweryfikuj certyfikat brokera względem systemowego magazynu zaufania.", + "events.destination.tlsHelp.custom_ca": "Weryfikuj broker na podstawie jawnego pliku urzędu certyfikacji w formacie PEM.", + "events.destination.tlsHelp.mutual": "Weryfikuj broker na podstawie jawnego CA i przedstaw certyfikat oraz klucz klienta.", + "events.destination.tlsHelp.disabled": "Brak szyfrowania transportu ani weryfikacji tożsamości brokera.", + "events.destination.caFile": "Plik CA", + "events.destination.certFile": "Plik certyfikatu klienta", + "events.destination.keyFile": "Plik klucza klienta", + "events.destination.absolutePathHelp": "Użyj ścieżki bezwzględnej odczytywalnej przez usługę LightNVR.", + "events.destination.plaintextWarning": "MQTT bez szyfrowania może ujawniać metadane zdarzeń i dane uwierzytelniające. Używaj tylko w zaufanej, izolowanej sieci.", + "events.destination.security": "Bezpieczeństwo", + "events.destination.tls.system": "Zaufanie systemowe", + "events.destination.tls.custom_ca": "Własne CA", + "events.destination.tls.mutual": "Mutual TLS", + "events.destination.tls.disabled": "Bez szyfrowania", + "events.destination.routes": "Trasy", + "events.destination.presence": "Temat obecności", + "events.destination.deleteInUse": "Usuń lub przekieruj trasy przed usunięciem tego celu.", + "events.destination.created": "Cel MQTT utworzony", + "events.destination.updated": "Cel MQTT zaktualizowany", + "events.destination.deleted": "Cel MQTT usunięty", + "events.destination.pausedMessage": "Cel MQTT wstrzymany; zdarzenia w kolejce pozostają trwałe do wygaśnięcia.", + "events.destination.enabledMessage": "Cel MQTT włączony", + "events.destination.deleteConfirm": "Usunąć cel MQTT \"{name}\"?", + "events.destination.validation.name": "Wprowadź nazwę celu.", + "events.destination.validation.host": "Wprowadź nazwę hosta brokera lub adres IP.", + "events.destination.validation.client_id": "Wprowadź identyfikator klienta brokera.", + "events.destination.validation.topic": "Temat musi zawierać tokeny event-type i subject-ID i nie może zawierać symboli wieloznacznych MQTT.", + "events.destination.validation.status_topic": "Opcjonalny temat obecności musi zawierać token installation UUID, używać tylko obsługiwanych tokenów i nie może zawierać symboli wieloznacznych MQTT.", + "events.destination.validation.port": "Port musi być liczbą całkowitą od 1 do 65535.", + "events.destination.validation.keepalive": "Keepalive musi być liczbą całkowitą od 5 do 3600 sekund.", + "events.destination.validation.qos": "Wybierz MQTT QoS 0, 1 lub 2.", + "events.destination.validation.username": "Skonfigurowane hasło wymaga nazwy użytkownika.", + "events.destination.validation.ca_file": "Ten tryb TLS wymaga bezwzględnej ścieżki do pliku CA.", + "events.destination.validation.mutual_files": "Wymagane są ścieżki bezwzględne CA, certyfikatu klienta i klucza klienta dla wzajemnego TLS.", + "fleet.eyebrow": "Operacje kamery", + "fleet.title": "Inwentarz kamer", + "fleet.description": "Znajdowanie, ocena i organizacja kamer w dużych wdrożeniach bez ładowania całego inwentarza do przeglądarki.", + "fleet.summary": "Podsumowanie stanu floty", + "fleet.totalCameras": "Pasujące kamery", + "fleet.needsAttention": "Zdegradowana", + "fleet.searchLabel": "Szukaj kamer", + "fleet.searchPlaceholder": "Szukaj nazwy, adresu, lokalizacji, tagu, producenta lub modelu…", + "fleet.resultCount": "{count} kamer", + "fleet.filters": "Filtry", + "fleet.clearFilters": "Wyczyść filtry", + "fleet.filter.health": "Stan", + "fleet.filter.enabled": "Stan kamery", + "fleet.filter.anyState": "Dowolny stan", + "fleet.filter.recording": "Tryb nagrywania", + "fleet.filter.location": "Poddrzewo lokalizacji", + "fleet.filter.allLocations": "Wszystkie lokalizacje", + "fleet.filter.tags": "Tagi (dowolny)", + "fleet.filter.collection": "Kolekcja kamer", + "fleet.health.unknown": "Nieznany", + "fleet.health.up": "Online", + "fleet.health.degraded": "Zdegradowana", + "fleet.health.down": "Offline", + "fleet.health.disabled": "Wyłączona", + "fleet.recording.off": "Wył.", + "fleet.recording.continuous": "Ciągły", + "fleet.recording.detection": "Detekcja", + "fleet.recordingActive": "Nagrywanie teraz", + "fleet.recordingInactive": "Brak nagrywania", + "fleet.column.camera": "Kamera", + "fleet.column.health": "Stan", + "fleet.column.location": "Lokalizacja", + "fleet.column.tags": "Tagi", + "fleet.column.recording": "Nagrywanie", + "fleet.viewLive": "Na żywo", + "fleet.lastFrame": "Ostatnia klatka", + "fleet.noAddress": "Adres niedostępny", + "fleet.unassigned": "Nieprzypisane", + "fleet.loading": "Ładowanie floty kamer…", + "fleet.refreshing": "Odświeżanie…", + "fleet.loadError": "Nie udało się załadować floty kamer", + "fleet.emptyTitle": "Brak skonfigurowanych kamer", + "fleet.emptyDescription": "Dodaj strumień, aby udostępnić go w obszarze roboczym floty.", + "fleet.emptyFilteredTitle": "Brak kamer pasujących do tego widoku", + "fleet.emptyFilteredDescription": "Spróbuj rozszerzyć wyszukiwanie lub wyczyścić co najmniej jeden filtr.", + "fleet.paginationSummary": "Wyświetlanie {first}–{last} z {total}", + "fleet.perPage": "Na stronę", + "fleet.pageOf": "Strona {page} z {pages}", + "fleet.selectPage": "Zaznacz wszystkie kamery na tej stronie", + "fleet.selectCamera": "Zaznacz {name}", + "fleet.selectedCount": "Zaznaczono {count} kamer", + "fleet.organizeSelected": "Zorganizuj zaznaczone", + "fleet.clearSelection": "Wyczyść zaznaczenie", + "fleet.organization.manage": "Zarządzaj organizacją", + "fleet.organization.title": "Organizacja kamer", + "fleet.organization.description": "Zarządzaj wielokrotnie używaną hierarchią lokalizacji i znormalizowanym słownikiem tagów dla floty kamer.", + "fleet.organization.locations": "Lokalizacje", + "fleet.organization.tags": "Tagi", + "fleet.organization.locationsDescription": "Modeluj obiekty, budynki, piętra i obszary operacyjne jako nawigowalną hierarchię.", + "fleet.organization.tagsDescription": "Używaj zarządzanego słownika tagów zamiast niespójnych, dowolnych etykiet.", + "fleet.organization.addRoot": "Dodaj lokalizację najwyższego poziomu", + "fleet.organization.addLocation": "Dodaj lokalizację", + "fleet.organization.editLocation": "Edytuj lokalizację", + "fleet.organization.addChild": "Dodaj podrzędną", + "fleet.organization.type": "Typ", + "fleet.organization.parent": "Lokalizacja nadrzędna", + "fleet.organization.topLevel": "Poziom najwyższy", + "fleet.organization.sortOrder": "Kolejność sortowania", + "fleet.organization.contents": "Zawartość", + "fleet.organization.cameras": "Kamery", + "fleet.organization.system": "System", + "fleet.organization.contentCounts": "{cameras} kamer · {children} podrzędnych", + "fleet.organization.locationNotEmpty": "Najpierw przenieś kamery i usuń lokalizacje podrzędne", + "fleet.organization.noLocations": "Nie skonfigurowano żadnych lokalizacji.", + "fleet.organization.locationCreated": "Lokalizacja utworzona", + "fleet.organization.locationUpdated": "Lokalizacja zaktualizowana", + "fleet.organization.locationDeleted": "Lokalizacja usunięta", + "fleet.organization.deleteLocationConfirm": "Usunąć lokalizację \"{name}\"?", + "fleet.organization.addTag": "Dodaj tag", + "fleet.organization.editTag": "Edytuj tag", + "fleet.organization.tagLabel": "Tag", + "fleet.organization.color": "Kolor (#RRGGBB)", + "fleet.organization.tagDescription": "Opis", + "fleet.organization.noTags": "Nie skonfigurowano żadnych znormalizowanych tagów.", + "fleet.organization.tagCreated": "Tag utworzony", + "fleet.organization.tagUpdated": "Tag zaktualizowany", + "fleet.organization.tagDeleted": "Tag usunięty", + "fleet.organization.deleteTagConfirm": "Usunąć \"{name}\"? Jest obecnie przypisany do {count} kamer.", + "fleet.organization.merge": "Scal", + "fleet.organization.mergeTagNamed": "Scal \"{name}\"", + "fleet.organization.mergeInto": "Scal z", + "fleet.organization.chooseTag": "Wybierz tag do zachowania", + "fleet.organization.mergeWarning": "Wszystkie przypisania kamer zostaną przeniesione do zachowanego tagu; tag źródłowy zostanie następnie usunięty.", + "fleet.organization.tagsMerged": "Tagi scalone", + "fleet.organization.saveError": "Nie udało się zapisać: {message}", + "fleet.organization.deleteError": "Nie udało się usunąć: {message}", + "fleet.locationType.site": "Obiekt", + "fleet.locationType.building": "Budynek", + "fleet.locationType.floor": "Piętro", + "fleet.locationType.area": "Obszar", + "fleet.locationType.zone": "Strefa", + "fleet.locationType.system": "System", + "fleet.bulk.title": "Organizuj wybrane kamery", + "fleet.bulk.description": "Zastosuj zmiany lokalizacji i tagów dla {count} kamer z ograniczoną współbieżnością.", + "fleet.bulk.location": "Przypisanie lokalizacji", + "fleet.bulk.locationHelp": "Wszystkie wybrane kamery zostaną przeniesione do wybranej lokalizacji.", + "fleet.bulk.keepLocations": "Zachowaj bieżące lokalizacje", + "fleet.bulk.tags": "Przypisanie tagów", + "fleet.bulk.tagsHelp": "Dodaj lub usuń tagi bez wpływu na inne przypisania, lub wyraźnie zastąp cały zestaw tagów.", + "fleet.bulk.tagOperation.none": "Zachowaj", + "fleet.bulk.tagOperation.add": "Dodaj", + "fleet.bulk.tagOperation.remove": "Usuń", + "fleet.bulk.tagOperation.replace": "Zastąp wszystkie", + "fleet.bulk.replaceWarning": "Zastąp wszystkie usuwa każdy bieżący tag przed zastosowaniem tego wyboru. Pusty wybór czyści wszystkie tagi.", + "fleet.bulk.apply": "Zastosuj zmiany", + "fleet.bulk.working": "Zastosowywanie zmian…", + "fleet.bulk.success": "Zaktualizowano {count} kamer", + "fleet.bulk.partial": "Zaktualizowano {succeeded} kamer; {failed} nie powiodło się", + "fleet.bulk.error": "Nie udało się zorganizować kamer: {message}", + "fleet.bulk.failures": "Kamery, których nie udało się zaktualizować", + "fleet.queues.degraded": "Zdegradowane strumienie", + "fleet.queues.offline": "Kamery offline", + "fleet.queues.oldest": "Najstarsze: {time}", + "fleet.queues.noneActive": "Brak aktywnych warunków", + "fleet.views.title": "Zapisane widoki", + "fleet.views.choose": "Wybierz zapisany widok", + "fleet.views.none": "Brak zapisanych widoków", + "fleet.views.shared": "Udostępnione", + "fleet.views.saveCurrent": "Zapisz bieżący widok", + "fleet.views.name": "Nazwa widoku", + "fleet.views.share": "Udostępnij wszystkim operatorom", + "fleet.views.saved": "Widok floty zapisany", + "fleet.views.saveError": "Nie udało się zapisać widoku: {message}", + "fleet.views.deleted": "Widok floty usunięty", + "fleet.views.deleteConfirm": "Usunąć zapisany widok \"{name}\"?", + "fleet.views.deleteError": "Nie udało się usunąć widoku: {message}", + "fleet.views.unsupported": "Ten zapisany selektor nie może być przedstawiony za pomocą obecnych kontrolek filtrowania.", + "collections.manage": "Kolekcje", + "collections.all": "Wszystkie kolekcje", + "collections.filter": "Kolekcja", + "collections.loadMembersError": "Nie udało się załadować kamer kolekcji: {message}", + "collections.title": "Kolekcje kamer", + "collections.subtitle": "Twórz grupy kamer wielokrotnego użytku do operacji, zapisanych widoków i dalszych procesów roboczych.", + "collections.listDescription": "Kolekcje statyczne utrzymują jawną przynależność; kolekcje inteligentne ciągle oceniają reguły floty.", + "collections.create": "Utwórz kolekcję", + "collections.edit": "Edytuj kolekcję", + "collections.editorDescription": "Definicje kolekcji używają stabilnych identyfikatorów UUID kamer, lokalizacji i tagów.", + "collections.backToList": "Wróć do kolekcji", + "collections.type": "Typ kolekcji", + "collections.type.static": "Statyczna", + "collections.type.smart": "Inteligentna", + "collections.description": "Opis", + "collections.shared": "Kolekcja udostępniona", + "collections.sharedHelp": "Pozwól innym autoryzowanym użytkownikom na podgląd tej kolekcji; reguły dostępu do kamer nadal obowiązują.", + "collections.typeChangeWarning": "Zmiana typu kolekcji zastępuje jej model przynależności. Statyczni członkowie lub inteligentne reguły z poprzedniego typu nie będą już obowiązywać.", + "collections.selectorError": "Selektor jest nieprawidłowy: {message}", + "collections.created": "Kolekcja utworzona", + "collections.updated": "Kolekcja zaktualizowana", + "collections.saveError": "Nie udało się zapisać kolekcji: {message}", + "collections.loadError": "Nie udało się wczytać kolekcji: {message}", + "collections.cameras": "kamery", + "collections.visibility.shared": "Udostępnione", + "collections.visibility.private": "Prywatne", + "collections.selectorRedacted": "Reguły prywatne", + "collections.emptyTitle": "Brak kolekcji", + "collections.emptyAdmin": "Utwórz grupę statyczną lub inteligentny widok oparty na regułach, aby wielokrotnie korzystać z wybranych kamer.", + "collections.emptyViewer": "Brak udostępnionych kolekcji w zakresie Twoich kamer.", + "collections.deleteConfirm": "Usunąć kolekcję \"{name}\"?", + "collections.deleted": "Kolekcja usunięta", + "collections.deleteError": "Nie udało się usunąć kolekcji: {message}", + "collections.preview.title": "Podgląd reguły", + "collections.preview.matches": "{count} pasujących kamer", + "collections.preview.action": "Podgląd", + "collections.preview.hide": "Ukryj podgląd", + "collections.preview.loading": "Ocena…", + "collections.preview.empty": "Brak pasujących kamer.", + "collections.preview.sample": "Wyświetlono próbkę {count} kamer z {total} pasujących.", + "collections.preview.error": "Nie udało się wygenerować podglądu kolekcji: {message}", + "collections.members.title": "Członkowie statyczni", + "collections.members.selected": "{count} kamer zaznaczonych na wszystkich stronach", + "collections.members.search": "Szukaj kamer…", + "collections.members.selectPage": "Zaznacz tę stronę", + "collections.members.empty": "Brak kamer pasujących do wyszukiwania.", + "collections.builder.title": "Inteligentne reguły", + "collections.builder.description": "Reguły są oceniane na podstawie bieżącej organizacji, konfiguracji, możliwości i stanu kamer.", + "collections.builder.match": "Dopasuj", + "collections.builder.allRules": "wszystkie reguły", + "collections.builder.anyRule": "dowolna reguła", + "collections.builder.addRule": "Dodaj regułę", + "collections.builder.removeRule": "Usuń regułę", + "collections.builder.matchesAll": "Brak kompletnych reguł — kolekcja obejmuje wszystkie kamery w zakresie autoryzacji użytkownika.", + "collections.builder.incompleteRule": "Ukończ lub usuń każdą regułę przed zapisaniem.", + "collections.builder.chooseLocation": "Wybierz poddrzewo lokalizacji", + "collections.builder.vendorPlaceholder": "Nazwy producentów, oddzielone przecinkami", + "collections.builder.modelPlaceholder": "Nazwy modeli, oddzielone przecinkami", + "collections.builder.advancedMode": "Zaawansowany JSON", + "collections.builder.visualMode": "Kreator wizualny", + "collections.builder.cannotVisualize": "Ten selektor zawiera zagnieżdżoną lub zaawansowaną logikę, której kreator wizualny nie może bezpiecznie przedstawić.", + "collections.rule.location_subtree": "Lokalizacja znajduje się w", + "collections.rule.camera_uuid": "Konkretne kamery", + "collections.rule.tag_any": "Ma dowolny tag", + "collections.rule.tag_all": "Ma wszystkie tagi", + "collections.rule.tag_none": "Nie ma żadnego z tagów", + "collections.rule.health": "Stan zdrowia to", + "collections.rule.enabled": "Kamera jest", + "collections.rule.recording_mode": "Tryb nagrywania to", + "collections.rule.capability_any": "Ma dowolną funkcję", + "collections.rule.capability_all": "Ma wszystkie funkcje", + "collections.rule.vendor": "Producent to", + "collections.rule.model": "Model to", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Kanał zwrotny audio", + "streamHealth.observedFps": "Obserwowane FPS", + "streamHealth.expectedFps": "Oczekiwane", + "streamHealth.fpsHelp": "Obserwowane przez LightNVR; oczekiwane pochodzi z metadanych strumienia kamery.", + "login.passwordChanged": "Hasło zostało zmienione pomyślnie. Zaloguj się nowym hasłem.", + "passwordChangeRequired.title": "Zmień domyślne hasło", + "passwordChangeRequired.description": "Ta instalacja nadal używa domyślnego hasła administratora. Zmień je przed przejściem do LightNVR. MFA, jeśli jest włączone, zostanie sprawdzone przy następnym logowaniu.", + "passwordChangeRequired.currentPassword": "Bieżące hasło", + "passwordChangeRequired.newPassword": "Nowe hasło", + "passwordChangeRequired.confirmPassword": "Potwierdź nowe hasło", + "passwordChangeRequired.passwordHelp": "Użyj co najmniej 8 znaków. Hasło nie może brzmieć „admin\".", + "passwordChangeRequired.submit": "Zmień hasło", + "passwordChangeRequired.saving": "Zmienianie hasła...", + "passwordChangeRequired.error.currentRequired": "Wprowadź bieżące hasło.", + "passwordChangeRequired.error.tooShort": "Nowe hasło musi mieć co najmniej 8 znaków.", + "passwordChangeRequired.error.defaultPassword": "Nowe hasło nie może brzmieć „admin\".", + "passwordChangeRequired.error.mismatch": "Nowe hasła nie są zgodne.", + "passwordChangeRequired.error.generic": "Nie udało się zmienić hasła. Spróbuj ponownie.", + "settings.tab.health": "Stan", + "settings.tab.workspaces": "Przestrzenie robocze", + "settings.health.title": "Stan hosta i sprzętu", + "settings.health.description": "Skonfiguruj ograniczone monitorowanie systemu operacyjnego i sprzętu bez ujawniania ścieżek urządzeń ani sekretów.", + "settings.health.enabled": "Włącz monitorowanie stanu", + "settings.health.enabledHelp": "Zbieraj obsługiwane sygnały hosta, usług, pamięci masowej, sieci i sprzętu.", + "settings.health.profile": "Profil zasad", + "settings.health.profileHelp": "Zrównoważony to domyślny profil; konserwatywny wymaga mocniejszych dowodów przed wysłaniem alertu.", + "settings.health.profile.balanced": "Zrównoważony", + "settings.health.profile.conservative": "Konserwatywny", + "settings.health.hardwareProvider": "Dostawca sprzętowy", + "settings.health.provider.auto": "Automatyczny (dostawcy jądra)", + "settings.health.provider.smartctl": "smartctl (jawny)", + "settings.health.providerHelp.auto": "Używa wyłącznie ograniczonych dostawców sysfs, NVMe i jądra; smartctl nigdy nie jest włączany automatycznie.", + "settings.health.providerHelp.smartctl": "Jawnie włącza opcjonalny ograniczony dostawcę smartctl JSON dla wykrytych urządzeń.", + "settings.health.providerHelp.disabled": "Wyłącza opcjonalnych dostawców sprzętowych, pozostawiając przenośne monitorowanie stanu dostępne.", + "settings.health.writeProbe": "Włącz sondę zapisu pamięci masowej", + "settings.health.writeProbeHelp": "Okresowo wykonuje ograniczoną sondę skonfigurowanego celu nagrywania.", + "settings.health.cadences": "Częstotliwości próbkowania", + "settings.health.cadencesHelp": "Interwały muszą być uporządkowane od szybkiego do próbkowania urządzeń i mieścić się w granicach serwera.", + "settings.health.fastInterval": "Interwał szybki", + "settings.health.normalInterval": "Interwał normalny", + "settings.health.slowInterval": "Interwał wolny", + "settings.health.deviceInterval": "Interwał urządzenia", + "settings.health.presenceInterval": "Interwał obecności", + "settings.health.retention": "Retencja incydentów", + "settings.health.conditions": "Nadpisania warunków", + "settings.health.conditionsHelp": "Nadpisuj tylko kody warunków i jednostki zwracane przez rejestr obowiązujących polityk.", + "settings.health.conditionOverride": "nadpisanie warunku", + "settings.health.overrideMode": "Tryb nadpisania", + "settings.health.overrideModeHelp": "Odziedzicz wybrany profil, wybierz inny ograniczony profil, wyłącz warunek lub ustaw zwalidowane progi.", + "settings.health.profileDefault": "Użyj wybranego profilu", + "settings.health.custom": "Progi niestandardowe", + "settings.health.warning": "Próg ostrzeżenia", + "settings.health.critical": "Próg krytyczny", + "settings.health.recovery": "Próg przywrócenia", + "settings.health.warning_for_seconds": "Sekundy utrzymania ostrzeżenia", + "settings.health.critical_for_seconds": "Sekundy utrzymania krytycznego", + "settings.health.recovery_for_seconds": "Sekundy utrzymania przywrócenia", + "settings.health.clearOverrides": "Wyczyść nadpisania", + "settings.health.registryUnavailable": "Serwer nie zwrócił rejestru warunków. Przeładuj przed edycją nadpisań.", + "settings.health.resetDefaults": "Przywróć domyślne wartości stanu", + "settings.health.reloadGuidance": "Zapis jest atomowy. Przeładuj po pomyślnym zapisie, aby potwierdzić obowiązującą politykę; uruchom ponownie tylko wtedy, gdy serwer wyraźnie tego zażąda.", + "settings.health.validation.profile": "Wybierz obsługiwany profil stanu.", + "settings.health.validation.provider": "Wybierz obsługiwanego dostawcę sprzętu.", + "settings.health.validation.healthFastIntervalSeconds": "Szybki interwał musi być liczbą całkowitą od 5 do 60 sekund.", + "settings.health.validation.healthNormalIntervalSeconds": "Normalny interwał musi być liczbą całkowitą od 15 do 600 sekund.", + "settings.health.validation.healthSlowIntervalSeconds": "Wolny interwał musi być liczbą całkowitą od 60 do 3600 sekund.", + "settings.health.validation.healthDeviceIntervalSeconds": "Interwał urządzenia musi być liczbą całkowitą od 300 do 86400 sekund.", + "settings.health.validation.healthPresenceIntervalSeconds": "Interwał obecności musi być liczbą całkowitą od 15 do 3600 sekund.", + "settings.health.validation.healthIncidentRetentionDays": "Retencja incydentów musi być liczbą całkowitą od 7 do 3650 dni.", + "settings.health.validation.ordered": "Interwały próbkowania muszą być uporządkowane: szybki, normalny, wolny, następnie urządzenia.", + "settings.health.validation.overrides": "Nadpisania warunków muszą używać unikalnych kodów i obsługiwanych profili z rejestru serwera.", + "settings.health.validation.thresholds": "Progi niestandardowe muszą być wartościami skończonymi w granicach jednostki warunku.", + "settings.health.validation.thresholdOrder": "Progi ostrzeżenia, krytyczny i przywrócenia muszą zachowywać kierunek alertu i histerezę warunku.", + "settings.health.validation.dwell": "Czasy utrzymania muszą być liczbami całkowitymi sekund w ciągu siedmiu dni; utrzymanie ostrzeżenia i przywrócenia nie może wynosić zero.", + "workspaces.title": "Przestrzenie robocze operatora", + "workspaces.description": "Wybierz, które wyspecjalizowane obszary robocze mają być widoczne w nawigacji i interfejsie.", + "workspaces.saved": "Preferencje obszaru roboczego zapisane", + "workspaces.saveError": "Nie udało się zapisać preferencji obszaru roboczego: {message}", + "workspaces.loadError": "Nie udało się wczytać preferencji obszaru roboczego.", + "workspaces.showWorkspace": "Pokaż {name}", + "workspaces.authorizationNote": "To ustawienie dotyczy tylko prezentacji. Bezpośrednie adresy URL i dostęp do API nadal podlegają Twojej polityce autoryzacji.", + "workspaces.liveNavigator": "Rozszerzony nawigator na żywo", + "workspaces.liveNavigatorDescription": "Drzewo lokalizacji, filtry dostępności, zapisane układy i ostatnie zdarzenia.", + "workspaces.investigation": "Śledztwo", + "workspaces.investigationDescription": "Wyszukuj, koreluj, zabezpieczaj i eksportuj zarejestrowane dowody.", + "settings.reduceMotion": "Ogranicz animacje", + "settings.reduceMotionHelp": "Wyłącza nieistotne animacje i przejścia. Tryb Auto stosuje preferencje systemu operacyjnego.", + "settings.reduceMotionPreference": "Preferencja ograniczenia animacji", + "settings.reduceMotionAuto": "Auto", + "settings.reduceMotionOn": "Włączone", + "settings.reduceMotionOff": "Wyłączone", + "settings.audioCompliance": "Zgodność audio", + "settings.disableAudioGlobally": "Wyłącz audio w tej instancji", + "settings.audioDisabled": "Audio jest wyłączone globalnie", + "settings.audioComplianceHelp": "Blokuje nasłuch na żywo, rozmowę dwukierunkową i audio w nowych nagraniach w tej instancji. Zapisywanie restartuje aktywne sesje multimedialne go2rtc. Istniejące nagrania nie są modyfikowane.", + "tokens.manage": "Zarządzaj dostępem do API", + "tokens.title": "Dostęp do API — {username}", + "tokens.description": "Twórz wąsko zakresowane poświadczenia dla integracji i odwołuj je niezależnie.", + "tokens.recommendedTitle": "Zalecane są tokeny zakresowane", + "tokens.recommendedDescription": "Każdy token wygasa, ma jawne uprawnienia i zakres kamer, i nigdy nie może wykraczać poza bieżącą politykę dostępu użytkownika.", + "tokens.coverageNotice": "Dostępne uprawnienia odzwierciedlają to, co wymusza ten serwer. Token może korzystać wyłącznie z uprawnień, które posiada jego użytkownik.", + "tokens.createTitle": "Utwórz token zakresowany", + "tokens.createDescription": "Używaj jednego tokenu na integrację, aby można go było zidentyfikować, obrócić i odwołać bez zakłócania pozostałych.", + "tokens.name": "Nazwa integracji", + "tokens.namePlaceholder": "np. Mostek PTZ garażu północnego", + "tokens.expiry": "Wygasa po", + "tokens.expiryDays": "{days} dni", + "tokens.actions": "Dozwolone akcje", + "tokens.actionsHelp": "Wybierz tylko to, czego potrzebuje ta integracja. Destrukcyjne akcje powinny mieć własny token.", + "tokens.destructive": "Destrukcyjne", + "tokens.noEnforcedActions": "Ta wersja serwera nie udostępnia akcji obsługujących tokeny.", + "tokens.scope.label": "Zakres kamer", + "tokens.scope.all": "Cała flota kamer", + "tokens.scope.collection": "Wspólna kolekcja", + "tokens.scope.selector": "Własny selektor", + "tokens.scope.chooseCollection": "Wspólna kolekcja kamer", + "tokens.scope.allValue": "Cała flota", + "tokens.scope.collectionValue": "Kolekcja: {name}", + "tokens.scope.selectorValue": "Własny selektor dynamiczny", + "tokens.create": "Utwórz token", + "tokens.creating": "Tworzenie tokenu…", + "tokens.createdSuccess": "Utworzono token API z zakresem", + "tokens.createError": "Nie udało się utworzyć tokenu API: {message}", + "tokens.invalidResponse": "Serwer zwrócił niekompletną odpowiedź uwierzytelniającą.", + "tokens.existingTitle": "Istniejące tokeny", + "tokens.existingDescription": "Po utworzeniu dostępne pozostają tylko prefiksy i metadane.", + "tokens.emptyTitle": "Brak aktywnych tokenów", + "tokens.emptyDescription": "Utwórz token z zakresem dla pierwszej integracji wymagającej dostępu do API.", + "tokens.showInactive": "Pokaż {count} nieaktywnych", + "tokens.status.active": "Aktywny", + "tokens.status.expired": "Wygasły", + "tokens.status.revoked": "Unieważniony", + "tokens.expires": "Wygasa", + "tokens.expiresValue": "Wygasa {date}", + "tokens.created": "Utworzono", + "tokens.lastUsed": "Ostatnio użyty", + "tokens.revoke": "Unieważnij", + "tokens.revoking": "Unieważnianie…", + "tokens.revokeConfirm": "Unieważnić \"{description}\"? Żądania korzystające z tego tokenu przestaną działać natychmiast.", + "tokens.revokedSuccess": "Token API odwołany", + "tokens.revokeError": "Nie udało się odwołać tokena API: {message}", + "tokens.validation.missing_description": "Podaj nazwę integracji, która będzie korzystać z tego tokena.", + "tokens.validation.description_too_long": "Nazwa integracji musi mieć mniej niż 128 znaków.", + "tokens.validation.invalid_expiry": "Wybierz okres ważności tokena od 1 do 365 dni.", + "tokens.validation.missing_actions": "Wybierz co najmniej jedną dozwoloną akcję.", + "tokens.validation.invalid_action": "Jedna lub więcej wybranych akcji nie obsługuje tokenów na tym serwerze.", + "tokens.validation.invalid_scope": "Wybierz prawidłowy zakres kamer.", + "tokens.validation.requires_all_scope": "Uprawnienia spoza kamer wymagają zakresu Cała flota kamer. Wybierz ten zakres lub usuń te uprawnienia.", + "tokens.validation.missing_collection": "Wybierz dostępną współdzieloną kolekcję.", + "tokens.validation.invalid_selector": "Uzupełnij lub popraw niestandardowy selektor kamer.", + "tokens.secret.oneTime": "Wyświetlany raz", + "tokens.secret.scopedTitle": "Zapisz teraz ten token zakresowy", + "tokens.secret.legacyTitle": "Zapisz teraz ten starszy klucz API", + "tokens.secret.scopedDescription": "lightNVR przechowuje tylko skrót tego tokena. Jeśli zostanie utracony, odwołaj go i utwórz nowy.", + "tokens.secret.legacyDescription": "Ten klucz kompatybilności jest wyświetlany tutaj tylko raz. Wygenerowanie kolejnego klucza unieważni ten.", + "tokens.secret.value": "Dane uwierzytelniające API", + "tokens.secret.copied": "Skopjowano", + "tokens.secret.copySuccess": "Dane uwierzytelniające API skopiowane", + "tokens.secret.copyError": "Nie udało się skopiować automatycznie; zaznacz i skopiuj dane uwierzytelniające ręcznie.", + "tokens.secret.savedConfirm": "Zapisałem/am te dane uwierzytelniające w bezpieczny sposób", + "tokens.secret.savedHelp": "Potwierdzenie zamknie to okno. Pełna wartość nie może być wyświetlona ponownie.", + "tokens.legacy.title": "Starszy klucz kompatybilności", + "tokens.legacy.description": "Starszy klucz ma pełny dostęp tego użytkownika, nie wygasa i nie może być ograniczany do kamer lub akcji.", + "tokens.legacy.warning": "Wygeneruj tylko dla istniejącej integracji, której punkty końcowe nie zostały przeniesione na wymuszanie tokenów zakresowych. Wygenerowanie go natychmiast unieważnia poprzedni starszy klucz.", + "tokens.legacy.generate": "Wygeneruj starszy klucz", + "tokens.legacy.confirm": "Wygenerować nowy starszy klucz? Spowoduje to natychmiastowe unieważnienie bieżącego starszego klucza użytkownika.", + "tokens.legacy.createdSuccess": "Starszy klucz API wygenerowany", + "tokens.legacy.createError": "Nie udało się wygenerować starszego klucza API: {message}", + "audit.manage": "Historia audytu", + "audit.title": "Audyt bezpieczeństwa i dostępu", + "audit.description": "Śledź wyniki logowania, decyzje dostępowe i zmiany polityk bez ujawniania danych uwierzytelniających.", + "audit.retention": "Retencja", + "audit.retentionDescription": "Wydarzenia są obecnie przechowywane przez {days} dni. Zmniejszenie tej wartości natychmiast usunie starszą historię.", + "audit.retentionDays": "Dni", + "audit.retentionInvalid": "Wybierz okres retencji od 1 do 3650 dni.", + "audit.retentionSaved": "Zapisano retencję audytu; usunięto {count} wygasłych wydarzeń", + "audit.retentionError": "Nie udało się zapisać retencji audytu: {message}", + "audit.filters": "Filtry", + "audit.clearFilters": "Wyczyść filtry", + "audit.applyFilters": "Zastosuj filtry", + "audit.actor": "Aktor", + "audit.unauthenticated": "Niezweryfikowany", + "audit.outcome": "Wynik", + "audit.action": "Dokładna akcja", + "audit.filterToAction": "Filtruj do tej akcji", + "audit.since": "Od", + "audit.until": "Do", + "audit.invalidDateRange": "Data początkowa musi być wcześniejsza niż data końcowa.", + "audit.source": "Adres źródłowy", + "audit.target": "Cel", + "audit.targetUuid": "UUID celu", + "audit.noTarget": "Ogólnosystemowy", + "audit.requestId": "ID żądania", + "audit.apiToken": "ID tokena zakresowego", + "audit.showDetails": "Pokaż szczegóły", + "audit.hideDetails": "Ukryj szczegóły", + "audit.pageSize": "Na stronę", + "audit.resultRange": "Wyświetlono {start}–{end} z {total}", + "audit.empty": "Brak pasujących wydarzeń audytu", + "audit.emptyDescription": "Spróbuj wyczyścić jeden lub więcej filtrów lub poczekać na nową aktywność bezpieczeństwa.", + "audit.exportPage": "Eksportuj tę stronę", + "audit.exporting": "Eksportowanie…", + "audit.exported": "Strona audytu wyeksportowana", + "audit.exportError": "Nie można wyeksportować zdarzeń audytu: {message}", + "audit.pagination": "Strony historii audytu", + "audit.page": "Strona {page}", + "audit.modesTitle": "Dozwolone decyzje", + "audit.modesDescription": "Wybierz sposób rejestrowania dozwolonego dostępu tylko do odczytu dla każdej akcji. Żądania zmieniające dane, odmowy, błędy i logowania są zawsze rejestrowane. Tryb podsumowania zapisuje jeden wpis na użytkownika, kamerę i klienta co {minutes} minut z licznikiem.", + "audit.mode.record": "Rejestruj każdy", + "audit.mode.summarize": "Podsumuj", + "audit.mode.off": "Wyłączone", + "audit.modeOffWarning": "Dozwolony dostęp dla tej akcji nie będzie już widoczny w historii audytu.", + "audit.modesSaved": "Tryby decyzji audytu zapisane", + "audit.modesError": "Nie można zapisać trybów decyzji audytu: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Typ zdarzenia", + "audit.eventTypeSummary": "Podsumowania", + "audit.eventTypeDecision": "Pojedyncze decyzje", + "access.cameraSearch": "Szukaj kamer", + "access.cameraSearchPlaceholder": "Wpisz co najmniej dwa znaki, aby wyszukać…", + "access.cameraSearchHint": "Szukaj po nazwie kamery, UUID, adresie, lokalizacji, tagu, producencie lub modelu.", + "access.cameraSelected": "Wybrane", + "access.cameraAdd": "Dodaj", + "access.cameraLimit": "Selektor może zawierać maksymalnie 64 kamery. Użyj reguły lokalizacji lub tagu dla większych zakresów.", + "access.roles.manage": "Zarządzaj rolami", + "access.roles.title": "Role autoryzacji", + "access.roles.description": "Grupuj akcje w role wielokrotnego użytku, a następnie przypisuj je do zakresów kamer.", + "access.roles.create": "Utwórz rolę", + "access.roles.newRole": "Nowa rola", + "access.roles.copyName": "Kopia {name}", + "access.roles.clone": "Klonuj", + "access.roles.builtin": "Wbudowane", + "access.roles.builtinHelp": "Role wbudowane to stałe szablony bezpieczne przy aktualizacjach. Sklonuj rolę, aby ją dostosować.", + "access.roles.actionCount": "{count} akcji", + "access.roles.destructive": "Akcja wrażliwa", + "access.roles.notEnforced": "Nie jest jeszcze egzekwowane przez żaden punkt końcowy", + "access.roles.destructiveWarning": "Ta rola może zmieniać konfigurację lub dowody. Przyznawaj ją tylko w zakresach, w których wymagane są takie uprawnienia.", + "access.roles.created": "Rola utworzona", + "access.roles.updated": "Rola zaktualizowana", + "access.roles.deleted": "Rola usunięta", + "access.roles.saveError": "Nie udało się zapisać roli: {message}", + "access.roles.deleteError": "Nie udało się usunąć roli: {message}", + "access.roles.deleteConfirm": "Usunąć rolę \"{name}\"? Ról przywoływanych przez przydziały nie można usunąć.", + "access.policy.manage": "Zarządzaj dostępem", + "access.policy.column": "Dostęp", + "access.policy.scopedShort": "Zakresowy", + "access.policy.title": "Polityka dostępu — {username}", + "access.policy.description": "Zarządzaj przydziałami ról z domyślną odmową i podglądaj ich zakresy kamer.", + "access.policy.tab.grants": "Przydziały", + "access.policy.tab.test": "Testuj dostęp", + "access.policy.scopedWarning": "Działają tylko akcje dozwolone przez pasujący przydział i zakres kamer.", + "access.policy.grants": "Przydziały ról", + "access.policy.grantsDescription": "Przydział łączy jedną rolę z całą flotą, współdzieloną kolekcją lub niestandardowym selektorem kamer.", + "access.policy.addGrant": "Dodaj przydział", + "access.policy.noGrants": "Brak skonfigurowanych przydziałów", + "access.policy.noGrantsHelp": "Dodaj co najmniej jeden przydział przed aktywacją polityki zakresowej, chyba że ten użytkownik nie powinien mieć dostępu.", + "access.policy.role": "Rola", + "access.policy.chooseRole": "Wybierz rolę", + "access.policy.scope": "Zakres kamer", + "access.policy.allCameras": "Cała flota kamer", + "access.policy.collectionScope": "Współdzielona kolekcja", + "access.policy.collection": "Kolekcja kamer", + "access.policy.chooseCollection": "Wybierz współdzieloną kolekcję", + "access.policy.collectionHelp": "Dostęp śledzi kolekcję w miarę dodawania, usuwania lub dopasowywania kamer przez jej reguły.", + "access.policy.dynamicScope": "Selektor dynamiczny", + "access.policy.activateConfirm": "Aktywować politykę zakresową z domyślną odmową dla {username}? Akcje bez pasującego przydziału zostaną odrzucone.", + "access.policy.emptyConfirm": "Aktywować politykę zakresową dla {username} bez przydziałów? To celowo usuwa cały dostęp kontrolowany przez politykę.", + "access.policy.saved": "Polityka dostępu zapisana", + "access.policy.saveError": "Nie udało się zapisać polityki dostępu: {message}", + "access.policy.version": "Wersja polityki {version}", + "access.policy.unsaved": "Niezapisane zmiany", + "access.policy.validation.invalid_mode": "Wybierz prawidłowy tryb oceny.", + "access.policy.validation.missing_role": "Każde uprawnienie musi odwoływać się do dostępnej roli.", + "access.policy.validation.invalid_scope": "Każde uprawnienie musi używać zakresu całej floty, wspólnej kolekcji lub selektora.", + "access.policy.validation.invalid_selector": "Uzupełnij lub popraw każdy selektor kamery przed zapisaniem.", + "access.policy.validation.missing_collection": "Wybierz dostępną wspólną kolekcję dla każdego uprawnienia kolekcji.", + "access.policy.validation.duplicate_grant": "Usuń zduplikowane uprawnienia ról i zakresów przed zapisaniem.", + "access.test.title": "Sprawdź skuteczny dostęp", + "access.test.description": "Oceń zapisaną akcję i kamerę jako {username} bez jej wykonywania.", + "access.test.saveFirst": "Zapisz lub odrzuć zmiany uprawnień przed testowaniem, aby wynik odzwierciedlał politykę wyświetlaną tutaj.", + "access.test.action": "Akcja", + "access.test.camera": "Kamera", + "access.test.run": "Testuj dostęp", + "access.test.running": "Testowanie…", + "access.test.allowed": "Dozwolone", + "access.test.denied": "Odmowa", + "access.test.version": "Wersja {version}", + "access.test.source": "Źródło: {source} · Rola: {role}", + "recordings.pullToRefresh": "Przeciągnij, aby odświeżyć nagrania", + "recordings.releaseToRefresh": "Puść, aby odświeżyć nagrania", + "recordings.refreshing": "Odświeżanie nagrań…", + "recordings.refreshed": "Nagrania odświeżone", + "recordings.refreshFailed": "Nie udało się odświeżyć nagrań: {message}", + "recordings.download": "Pobierz", + "recordings.tags": "Tagi", + "recordings.selectRecording": "Wybierz nagranie", + "timeline.legend.recording": "Nagranie", + "timeline.legend.detection": "Zdarzenie detekcji", + "timeline.detectionEvent": "Zdarzenie detekcji", + "streams.showCredentials": "Pokaż dane uwierzytelniające", + "streams.hideCredentials": "Ukryj dane uwierzytelniające", + "streams.streamSuccessfullyEnabled": "Strumień został pomyślnie włączony.", + "streams.errorEnablingStream": "Błąd podczas włączania strumienia: {message}", + "system.health.tab": "Stan", + "system.health.operatorView": "Stan operacyjny", + "system.health.title": "Stan systemu", + "system.health.loading": "Ładowanie stanu systemu…", + "system.health.loadError": "Nie udało się załadować stanu systemu.", + "system.health.refreshing": "Odświeżanie…", + "system.health.activeIncidentCount": "{count} aktywnych incydentów", + "system.health.coverage": "Zakres", + "system.health.monitoringDisabled": "Monitorowanie stanu jest wyłączone", + "system.health.lastRecordedValue": "Ostatnia zarejestrowana wartość", + "system.health.monitoringDisabledHelp": "Monitorowanie stanu jest wyłączone. Włącz je w Ustawienia → Stan; uruchom ponownie, jeśli zostanie to wymagane po zapisaniu. Historia incydentów pokazuje przeszłe zdarzenia, a nie bieżące wykorzystanie zasobów.", + "system.health.monitoringRestartRequired": "Monitorowanie stanu jest włączone w zapisanej konfiguracji, ale działający próbnik jest nadal wyłączony. Uruchom ponownie LightNVR, aby zastosować zmianę. Historia incydentów pokazuje przeszłe zdarzenia.", + "system.health.containerCoverage": "Ograniczony zakres hosta", + "system.health.hostHardwareUnavailable": "Ta instalacja widzi stan kontenerów i zamontowanych zasobów, ale sprzęt hosta jest niedostępny. Brakujące wartości hosta są nieznane, a nie prawidłowe.", + "system.health.coverageUnknown": "Brak jeszcze kompletnego zrzutu stanu. Wartości pozostają nieznane do zakończenia zbierania danych.", + "system.health.coverageComplete": "Wszystkie dane widoczne dla tej instalacji zostały pomyślnie zebrane.", + "system.health.coveragePartial": "Zakres jest częściowy. {count} obserwacji lub kontroli zbierania danych jest niedostępnych, nieaktualnych lub niekompletnych.", + "system.health.effectiveScope": "Efektywny zakres", + "system.health.activeIncidents": "Aktywne incydenty", + "system.health.noActiveIncidents": "Brak aktywnych incydentów w widocznym zakresie.", + "system.health.duration": "Czas trwania", + "system.health.currentValue": "Bieżąca wartość", + "system.health.thresholds": "Próg i czas utrzymania", + "system.health.thresholdSummary": "Ostrzeżenie {warning}, krytyczne {critical}, powrót {recovery} {unit}; czas utrzymania ostrzeżenia {seconds}s", + "system.health.remediation": "Zalecana reakcja", + "system.health.facts": "Dane o stanie", + "system.health.group.resources": "Zasoby", + "system.health.group.storage": "Przechowywanie", + "system.health.group.hardware": "Sprzęt", + "system.health.group.network": "Sieć", + "system.health.group.clock": "Zegar", + "system.health.group.components": "Komponenty", + "system.health.noFacts": "Brak widocznych danych w tej grupie.", + "system.health.observationState": "Możliwości i aktualność", + "system.health.valueUnavailable": "Jedna lub więcej wartości jest nieznanych", + "system.health.componentStatus": "Komponenty monitorowania", + "system.health.collectors": "Kolektory", + "system.health.collectorSummary": "{total} zarejestrowanych · {attention} wymaga uwagi", + "system.health.collectorsNeedingAttention": "Kolektory wymagające uwagi", + "system.health.collectionFailures": "{count} błędów lub przekroczeń limitu czasu", + "system.health.stale": "nieaktualne", + "system.health.eventDelivery": "Dostarczanie zdarzeń", + "system.health.degraded": "Ograniczone", + "system.health.circularDelivery": "To jedyna skonfigurowana ścieżka alertów, więc nie może niezależnie zgłaszać własnej awarii.", + "system.health.incidentPersistence": "Trwałość incydentów", + "system.health.persistenceSummary": "{pending} oczekujących · {failures} błędów · {retries} ponownych prób", + "system.health.recentSamples": "Ostatnia aktywność kolekcji", + "system.health.recentSamplesHelp": "Do {count} ograniczonych podsumowań generowania po stronie serwera; to aktywność pokrycia, nie wykres wartości.", + "system.health.sampleSequence": "Generacja {sequence}", + "system.health.sampleCoverage": "{observations} obserwacji · {dropped} odrzuconych", + "system.health.noSamples": "Brak dostępnych zakończonych generacji kolekcji.", + "system.health.incidentHistory": "Historia incydentów", + "system.health.incidentHistoryHelp": "Najnowsze incydenty na początku. Historia jest ładowana w ograniczonych stronach.", + "system.health.loadingHistory": "Ładowanie historii incydentów…", + "system.health.historyError": "Nie udało się załadować historii incydentów.", + "system.health.emptyHistory": "Nie zarejestrowano żadnych incydentów.", + "system.health.firstSeen": "Pierwsze wystąpienie", + "system.health.lastSeen": "Ostatnie wystąpienie", + "system.health.deliveryState": "Stan dostarczenia", + "system.health.historyPagination": "Strony historii incydentów", + "system.health.pageCount": "{count} zdarzeń na tej stronie", + "system.health.remediation.memory": "Zmniejsz obciążenie pamięci, sprawdź limity procesu i cgroup oraz przeanalizuj ostatnią aktywność OOM.", + "system.health.remediation.cpu": "Zidentyfikuj procesy o stałym obciążeniu CPU i zweryfikuj przepustowość usługi przed zmianą limitów.", + "system.health.remediation.io": "Sprawdź opóźnienia pamięci masowej i aktywne zapisy; zabezpiecz nagrania przed inwazyjną konserwacją.", + "system.health.remediation.filesystem": "Sprawdź nazwany system plików, wolne miejsce lub i-węzły i upewnij się, że pozostaje zapisywalny.", + "system.health.remediation.thermal": "Popraw chłodzenie i zmniejsz obciążenie; sprawdź wentylatory i otwory wentylacyjne, zanim temperatura osiągnie limit wyłączania.", + "system.health.remediation.network": "Sprawdź widoczny interfejs, łącze, przełącznik i liczniki błędów z niezależnej ścieżki sieciowej.", + "system.health.remediation.clock": "Przywróć synchronizację czasu i zweryfikuj źródło zegara hosta przed poleganiem na znacznikach czasu zdarzeń.", + "system.health.remediation.process": "Sprawdź limity zasobów LightNVR i logi, a następnie zmniejsz obciążenie lub podnieś zweryfikowane limity.", + "system.health.remediation.storage": "Utwórz kopię zapasową ważnych nagrań i sprawdź zmapowane urządzenie pamięci masowej przed wymianą lub naprawą.", + "system.health.remediation.hardware": "Sprawdź dotknięty sprzęt i logi platformy; zaplanuj konserwację, jeśli problem się utrzymuje.", + "system.health.remediation.health": "Przywróć dostęp i uprawnienia kolektora, aby umożliwić ocenę brakujących danych o stanie.", + "system.health.remediation.system": "Przeanalizuj poprzednie uruchomienie i logi hosta, aby odróżnić restart procesu od restartu hosta.", + "system.health.remediation.event": "Użyj lokalnego API lub widoku metryk, zmniejsz obciążenie trwałej kolejki i przywróć niezależne miejsce docelowe alertów.", + "system.health.remediation.default": "Przeanalizuj dotknięty komponent i ostatnie logi, a następnie zweryfikuj odzyskanie w nowym cyklu diagnostycznym.", + "system.capacityTarget": "Cel pojemności", + "system.capacityTargetValue": "Zachowaj {pct}% wolnego", + "system.fillRate": "Tempo zapełniania", + "system.fillRateValue": "{value} / dzień", + "system.projectedToTarget": "Szacowany czas do osiągnięcia celu", + "system.projectedNow": "Cel osiągnięty/przekroczony", + "system.projectedDays": "~{count} dni", + "system.projectedHours": "~{count} godz.", + "system.projectedUnknown": "—", + "common.description": "Opis", + "common.remove": "Usuń", + "streams.selectStream": "Wybierz {name}", + "streams.search": "Szukaj strumieni", + "streams.searchPlaceholder": "Szukaj kamer, lokalizacji lub tagów", + "streams.noStreamsMatchFilters": "Brak strumieni pasujących do bieżących filtrów.", + "streamHealth.sourceConnected": "Źródło połączone", + "streamHealth.videoAdvancing": "Wideo postępuje", + "streamHealth.recorderWriting": "Zapis przez rejestrator", + "streamHealth.detectorOperating": "Detektor aktywny", + "streamHealth.lastSegment": "Ostatni ukończony segment", + "streams.disablingStreamsProgress": "Wyłączanie strumieni…", + "streams.onvifInvalidAddress": "Adres IP urządzenia ONVIF jest nieobecny lub nieprawidłowy.", + "streams.warningFallingBackToHttp": "Połączenie HTTPS nie powiodło się; ponowna próba przez HTTP. Dane uwierzytelniające mogą być przesyłane zwykłym tekstem.", + "streamsConfig.playbackTransport": "Transport odtwarzania", + "streamsConfig.playbackTransportHelp": "Wybierz metodę odtwarzania w przeglądarce dla tej kamery i, jeśli wybrano, jej kolejność awaryjną.", + "streamsConfig.playbackTransportUnavailable": "Niedostępne na serwerze: {transports}. Włącz transport globalnie lub wybierz inny profil.", + "streamsConfig.audioDisabledByPolicy": "Dźwięk jest wyłączony przez politykę instancji", + "streamsConfig.audioDisabledByPolicyHelp": "Nagrywanie, odsłuch na żywo i rozmowa dwukierunkowa są niedostępne, gdy włączona jest globalna polityka zgodności audio.", + "streamsConfig.audioVoiceEnhancement": "Wzmocnienie głosu (nagrania)", + "streamsConfig.customApiModel": "Wykrywanie przez niestandardowe API", + "streamsConfig.modelNotSupportedByBuild": "nieobsługiwane w tej wersji", + "streamsConfig.tierCriticalMultiplier": "Krytyczny poziom ×", + "streamsConfig.tierImportantMultiplier": "Ważny poziom ×", + "streamsConfig.tierEphemeralMultiplier": "Przejściowy poziom ×", + "streamsConfig.tierMultipliersHelp": "Mnożniki retencji bazowej dla każdego poziomu. Materiał z wyższych poziomów jest przechowywany dłużej i usuwany jako ostatni przy braku miejsca na dysku.", + "streamsConfig.storagePriority": "Priorytet przechowywania (1-10)", + "streamsConfig.storagePriorityHelp": "Względna ważność materiału z tego strumienia przy odzyskiwaniu miejsca; wyższy priorytet jest dłużej zachowywany.", + "streamsConfig.restream": "Restreaming / Publikacja (RTMP)", + "streamsConfig.publishUrl": "URL publikacji (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "Transmituj tę kamerę do serwisu takiego jak YouTube Live przez go2rtc. Wklej pełny adres URL przyjmowania RTMP wraz z kluczem strumienia (np. rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Aby transmitować do wielu serwisów jednocześnie, oddziel adresy URL przecinkami. YouTube wymaga wideo H264 i dźwięku AAC; LightNVR teraz transkoduje automatycznie (H264 dla kamer nie-H264, AAC dla dźwięku nie-AAC), więc większość kamer działa bez zmian. Uwaga: YouTube wymaga również ścieżki audio — kamera całkowicie bez dźwięku nadal zostanie odrzucona. Pozostaw puste, aby wyłączyć.", + "streams.lastSeen": "Ostatnio widziany {time}", + "streams.claimed": "Przejęty", + "streams.duplicateSuspected": "Możliwy duplikat", + "streams.duplicateSuspectedHelp": "Trwała tożsamość lub dowody punktu końcowego są sprzeczne z innym rekordem wykrywania.", + "streams.onvifClaimWarning": "Strumień został dodany, ale jego rekord wykrywania nie mógł zostać oznaczony jako przejęty: {message}", + "common.online": "Online", + "common.offline": "Offline", + "settings.storageTargets.title": "Miejsca przechowywania nagrań", + "settings.storageTargets.description": "Zarejestruj dyski lokalne oraz systemy plików NFS lub SMB zamontowane przez administratora jako niezależnie monitorowane miejsca docelowe nagrań.", + "settings.storageTargets.foundationNotice": "Zapis wykorzystuje cele systemu plików. Kosze S3 oraz zamontowane cele NFS/SAN mogą przechowywać zweryfikowane kopie archiwalne. Gorący bufor zabezpiecza zarchiwizowane nagrania do momentu wygaśnięcia ich logicznego okresu retencji.", + "settings.storageTargets.add": "Dodaj cel przechowywania", + "settings.storageTargets.edit": "Edytuj cel przechowywania", + "settings.storageTargets.editorHelp": "Włączone cele muszą już istnieć i przejść test zapisu, fsync oraz czyszczenia. Zapisz niedostępny przyszły montaż jako wyłączony, a następnie włącz go po zamontowaniu.", + "settings.storageTargets.name": "Nazwa celu", + "settings.storageTargets.root": "Ścieżka główna montażu", + "settings.storageTargets.rootLocked": "Domyślny lub niepusty cel zachowuje niezmienialny katalog główny, aby istniejące nagrania nie zostały osierocone.", + "settings.storageTargets.class": "Klasa wydajności", + "settings.storageTargets.hot": "Gorący — aktywne nagrywanie", + "settings.storageTargets.warm": "Ciepły — zamontowane archiwum", + "settings.storageTargets.cold": "Zimny — rzadki dostęp", + "settings.storageTargets.reserveGb": "Zarezerwowany zapas (GB)", + "settings.storageTargets.lowWatermark": "Dolny próg (% wykorzystania)", + "settings.storageTargets.highWatermark": "Górny próg (% wykorzystania)", + "settings.storageTargets.migrationBandwidth": "Pasmo cyklu życia (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 oznacza brak limitu. Limit jest zapisywany w migawce w momencie tworzenia zadania przenoszenia lub kopiowania.", + "settings.storageTargets.archiveStart": "Początek okna archiwizacji", + "settings.storageTargets.archiveEnd": "Koniec okna archiwizacji", + "settings.storageTargets.archiveWindowHelp": "Czas lokalny. Równe wartości początku i końca pozwalają na zadania cyklu życia przez cały dzień; okno nocne może przekraczać północ.", + "settings.storageTargets.enabled": "Włączony (polityki rozmieszczania mogą wybrać ten cel)", + "settings.storageTargets.notRouted": "Żadna włączona polityka rozmieszczania nie kieruje kamer do tego celu. Nowe nagrania trafiają nadal do celu domyślnego, dopóki polityka nie wskaże tego celu jako głównego, członka puli lub celu archiwizacji.", + "settings.storageTargets.degradedNotice": "Powyżej górnego progu lub wewnątrz zarezerwowanego zapasu. Polityki rozmieszczania pomijają ten cel do momentu zwolnienia miejsca.", + "settings.storageTargets.probePassedIneligible": "Test zapisu zakończony sukcesem, ale cel ma status {status}: polityki rozmieszczania go nie wybiorą.", + "settings.storageTargets.mountRequired": "Wymagaj zamontowanego systemu plików", + "settings.storageTargets.mountRequiredHelp": "Przypnij ten cel do bieżącego punktu montażu innego niż katalog główny. Jeśli montaż NFS, SMB, bind lub PVC zniknie, nagrywanie zostanie wstrzymane zamiast zapisu do katalogu hosta.", + "settings.storageTargets.mountGuard": "Wymagany montaż", + "settings.storageTargets.mountPending": "Zostanie wykryty po włączeniu celu", + "settings.storageTargets.default": "Domyślny", + "settings.storageTargets.capacity": "Pojemność", + "settings.storageTargets.available": "Dostępne", + "settings.storageTargets.recordings": "Zaindeksowane nagrania", + "settings.storageTargets.replicas": "{count} zweryfikowanych kopii · {bytes}", + "settings.storageTargets.reserve": "Zarezerwowane", + "settings.storageTargets.pressure.normal": "Ciśnienie normalne", + "settings.storageTargets.pressure.high": "Wysoki próg", + "settings.storageTargets.pressure.reserve": "Rezerwa przekroczona", + "settings.storageTargets.pressure.unavailable": "Ciśnienie niedostępne", + "settings.storageTargets.cleanupActive": "Czyszczenie ograniczone do celu jest aktywne i będzie dążyć do {target} wolnego miejsca bez usuwania nagrań przypisanych do innego celu.", + "settings.storageTargets.test": "Testuj cel", + "settings.storageTargets.probing": "Testowanie…", + "settings.storageTargets.probePassed": "Test zapisu celu przechowywania zakończony sukcesem", + "settings.storageTargets.duplicateFilesystem": "Ten katalog główny współdzieli ten sam system plików z innym celem. Pojemność nie może być liczona podwójnie, gdy włączone jest rozmieszczanie.", + "settings.storageTargets.deleteLocked": "Nie można usunąć celów domyślnych i niepustych.", + "settings.storageTargets.deleteConfirm": "Usunąć pusty cel przechowywania „{name}\"? Żadne pliki nie zostaną usunięte.", + "settings.storageTargets.created": "Cel przechowywania utworzony", + "settings.storageTargets.updated": "Cel przechowywania zaktualizowany", + "settings.storageTargets.deleted": "Cel przechowywania usunięty", + "settings.storageTargets.invalidThresholds": "Sprawdź progi, rezerwę, przepustowość cyklu życia i czasy okna archiwizacji.", + "settings.storageTargets.loadError": "Nie udało się wczytać celów przechowywania", + "settings.storagePools.title": "Pule przechowywania", + "settings.storagePools.description": "Grupuj sprawne cele w celu automatycznego przepełnienia i replikacji na różne cele.", + "settings.storagePools.add": "Dodaj pulę", + "settings.storagePools.strategy": "Strategia alokacji", + "settings.storagePools.mostFree": "Najwięcej wolnego miejsca", + "settings.storagePools.roundRobin": "Cyklicznie", + "settings.storagePools.priority": "Wyraźny priorytet", + "settings.storagePools.members": "Cele (kolejność wyświetlania to priorytet alokacji)", + "settings.storagePools.enabled": "Pula włączona", + "settings.storagePools.active": "Aktywna", + "settings.storagePools.inactive": "Wyłączona", + "settings.storagePools.strategyValue.most_free": "najwięcej wolnego", + "settings.storagePools.strategyValue.round_robin": "cyklicznie", + "settings.storagePools.strategyValue.priority": "kolejność priorytetów", + "settings.storagePools.created": "Pula przechowywania utworzona", + "settings.storagePools.updated": "Pula pamięci zaktualizowana", + "settings.storagePools.deleted": "Pula pamięci usunięta", + "settings.storagePools.deleteConfirm": "Usunąć pulę pamięci \"{name}\"?", + "settings.storagePools.empty": "Brak pul pamięci.", + "settings.storageMigrations.title": "Zadania migracji nagrań", + "settings.storageMigrations.description": "Trwałe przenosiny i zachowane kopie uwzględniają okno archiwizacji i limit przepustowości każdego celu, weryfikują SHA-256 i bezpiecznie wznawiają pracę po restarcie.", + "settings.storageMigrations.empty": "Brak zadań migracji nagrań.", + "settings.storageMigrations.loadError": "Nie udało się załadować zadań migracji nagrań", + "settings.storageMigrations.recording": "Nagranie #{id}", + "settings.storageMigrations.attempt": "Próba {current}/{max}", + "settings.storageMigrations.operation.move": "Przeniesienie", + "settings.storageMigrations.operation.copy": "Zachowana kopia", + "settings.storageMigrations.cancelled": "Anulowanie migracji przyjęte", + "settings.storageMigrations.cancelling": "Anulowanie…", + "settings.storageMigrations.retried": "Migracja w kolejce do ponownej próby", + "settings.storageMigrations.state.queued": "W kolejce", + "settings.storageMigrations.state.copying": "Kopiowanie", + "settings.storageMigrations.state.verifying": "Weryfikacja", + "settings.storageMigrations.state.committing": "Zatwierdzanie", + "settings.storageMigrations.state.cleanup_pending": "Czyszczenie źródła", + "settings.storageMigrations.state.retry_wait": "Oczekiwanie na ponowną próbę", + "settings.storageMigrations.state.completed": "Zakończono", + "settings.storageMigrations.state.failed": "Niepowodzenie", + "settings.storageMigrations.state.cancelled": "Anulowano", + "settings.storagePolicies.title": "Zasady rozmieszczania kamer", + "settings.storagePolicies.description": "Kieruje pasujące kamery do podstawowego celu nagrywania według priorytetu. Kamera korzysta z pierwszej włączonej pasującej zasady.", + "settings.storagePolicies.add": "Dodaj zasadę rozmieszczania", + "settings.storagePolicies.edit": "Edytuj zasadę rozmieszczania", + "settings.storagePolicies.editorHelp": "Zasada jest ponownie oceniana dla nowych segmentów. Zmiany nie przenoszą istniejących nagrań.", + "settings.storagePolicies.priority": "Priorytet (wyższy pierwszy)", + "settings.storagePolicies.priorityValue": "Priorytet {priority}", + "settings.storagePolicies.primary": "Podstawowy cel", + "settings.storagePolicies.primaryPool": "Pula rozmieszczenia (opcjonalnie)", + "settings.storagePolicies.exactTarget": "Użyj dokładnego celu podstawowego", + "settings.storagePolicies.fallback": "Jeśli cel podstawowy jest niedostępny", + "settings.storagePolicies.fallbackDefault": "Użyj celu domyślnego", + "settings.storagePolicies.fallbackTarget": "Użyj nazwanego celu zapasowego", + "settings.storagePolicies.fallbackPause": "Wstrzymaj nagrywanie", + "settings.storagePolicies.fallbackFail": "Nie rozpoczynaj nagrywania", + "settings.storagePolicies.namedFallback": "Cel zapasowy", + "settings.storagePolicies.chooseTarget": "Wybierz cel", + "settings.storagePolicies.choosePool": "Wybierz pulę", + "settings.storagePolicies.minimumDays": "Minimalne przechowywanie (dni)", + "settings.storagePolicies.desiredDays": "Oczekiwane przechowywanie (dni)", + "settings.storagePolicies.maximumDays": "Maksymalne przechowywanie (dni)", + "settings.storagePolicies.copyCount": "Wymagane zweryfikowane kopie", + "settings.storagePolicies.replicationPool": "Pula replikacji", + "settings.storagePolicies.migrateAfter": "Przenieś po upływie (dni)", + "settings.storagePolicies.migrationTarget": "Cel archiwizacji", + "settings.storagePolicies.pressurePriority": "Priorytet usuwania pod presją (niższy pierwszy)", + "settings.storagePolicies.disabledTarget": "wyłączone", + "settings.storagePolicies.enabled": "Polityka włączona", + "settings.storagePolicies.selector": "Dopasowane kamery", + "settings.storagePolicies.preview": "Podgląd pierwszeństwa", + "settings.storagePolicies.previewing": "Ocena…", + "settings.storagePolicies.previewRequired": "Sprawdź bieżący szkic przed zapisaniem, aby zobaczyć nakładanie się kamer i obowiązującą politykę.", + "settings.storagePolicies.previewSummary": "Dopasowuje {matched} kamer; ten szkic jest skuteczny dla {effective}.", + "settings.storagePolicies.previewShadowed": "Polityka o wyższym priorytecie wygrywa dla {count} dopasowanych kamer.", + "settings.storagePolicies.previewWins": "Wygrywa z „{policy}\" (priorytet {priority}) dla {count} kamer.", + "settings.storagePolicies.previewLoses": "Przegrywa z „{policy}\" (priorytet {priority}) dla {count} kamer.", + "settings.storagePolicies.previewNoMatches": "Ten selektor nie pasuje obecnie do żadnych kamer.", + "settings.storagePolicies.invalidPriority": "Priorytet musi być liczbą całkowitą od -1 000 000 do 1 000 000.", + "settings.storagePolicies.invalidLifecycle": "Sprawdź kolejność przechowywania, liczbę kopii i pulę replikacji oraz wiek i cel migracji.", + "settings.storagePolicies.created": "Polityka rozmieszczenia utworzona", + "settings.storagePolicies.updated": "Polityka rozmieszczenia zaktualizowana", + "settings.storagePolicies.deleted": "Polityka rozmieszczenia usunięta", + "settings.storagePolicies.deleteConfirm": "Usunąć politykę rozmieszczenia „{name}\"? Istniejące nagrania nie zostaną usunięte.", + "settings.storagePolicies.active": "Aktywna", + "settings.storagePolicies.inactive": "Wyłączona", + "settings.storagePolicies.routesTo": "Cel główny: {target}", + "settings.storagePolicies.lifecycleSummary": "Retencja min./oczekiwana/maks.: {minimum}/{desired}/{maximum} dni · {copies} zweryfikowane kopie", + "settings.storagePolicies.fallsBackTo": "Cel awaryjny: {target}", + "settings.storagePolicies.mode.default": "Awaryjnie: cel domyślny", + "settings.storagePolicies.mode.pause": "Awaryjnie: wstrzymaj nagrywanie", + "settings.storagePolicies.mode.fail": "Awaryjnie: przerwij rozpoczęcie nagrywania", + "settings.storagePolicies.empty": "Brak polityk rozmieszczenia. Kamery nadal korzystają z celu domyślnego; pozostałe cele nie otrzymują danych, dopóki polityka nie skieruje do nich kamer.", + "settings.storagePolicies.archiveNoTrigger": "Cel archiwizacji jest ustawiony, ale nic nie wywołuje przeniesienia. Ustaw „Przenieś po wieku (dni)\", wiek archiwizacji lub opcję archiwizacji; w przeciwnym razie żadne nagrania nie zostaną przeniesione.", + "settings.storageCompliance.title": "Pojemność i zgodność z polityką", + "settings.storageCompliance.description": "Zaobserwowane wskaźniki z 30 dni prognozują obciążenie celu i osiągniętą retencję; aktywne naruszenia cyklu życia pozostają widoczne do ich rozwiązania.", + "settings.storageCompliance.loadError": "Nie udało się załadować zgodności przechowywania", + "settings.storageCompliance.unknown": "Nieznany", + "settings.storageCompliance.days": "{days} dni", + "settings.storageCompliance.day": "dzień", + "settings.storageCompliance.targetForecasts": "Prognozy celu", + "settings.storageCompliance.target": "Cel", + "settings.storageCompliance.dailyRate": "Zaobserwowany wskaźnik", + "settings.storageCompliance.toHigh": "Do wysokiego progu", + "settings.storageCompliance.expected": "Oczekiwana retencja", + "settings.storageCompliance.confidence": "Pewność", + "settings.storageCompliance.policyCompliance": "Zgodność z polityką", + "settings.storageCompliance.compliant": "Brak aktywnych naruszeń", + "settings.storageCompliance.violationCount": "{count} naruszeń", + "settings.storageCompliance.policyForecast": "Osiągnięto {achieved}; prognoza {expected}; oczekiwane {desired} dni.", + "settings.storageCompliance.copyDeficits": "{count} nagrań wymaga kolejnej zweryfikowanej kopii.", + "settings.storageCompliance.activeViolations": "Aktywne naruszenia", + "settings.storageCompliance.type.copy_count": "Liczba kopii", + "settings.storageCompliance.type.minimum_retention": "Minimalna pojemność retencji", + "settings.storageCompliance.type.target_unavailable": "Cel niedostępny", + "settings.storageCompliance.type.migration_failed": "Zadanie cyklu życia nie powiodło się", + "settings.recordingDirectoryFormat": "Struktura folderów nagrań", + "settings.recordingDirectoryFormatHelp": "Tworzy podfoldery dla nowych nagrań MP4 w folderze każdej kamery. Istniejące nagrania nie są przenoszone.", + "settings.recordingDirectoryFlat": "Płaska (tylko folder kamery)", + "settings.recordingDirectoryMonth": "Wg miesiąca (RRRR/MM)", + "settings.recordingDirectoryDay": "Wg dnia (RRRR/MM/DD)", + "settings.minFreePct": "Minimalna wolna przestrzeń (%)", + "settings.minFreePctHelp": "Utrzymuje co najmniej taki procent wolnej przestrzeni woluminu, automatycznie usuwając najstarsze nagrania niezależnie od dni retencji. Ogranicza to użycie do rozmiaru dysku — ustaw tę wartość, a dysk nigdy się nie zapełni. Wartość 0 wyłącza limit pojemności.", + "settings.pressureThresholds": "Progi obciążenia dysku (%)", + "settings.pressureThresholdsHelp": "Zakresy wolnej przestrzeni zwiększające intensywność automatycznego czyszczenia. Muszą spełniać warunek: awaryjny < krytyczny < ostrzegawczy.", + "settings.pressureWarningPct": "Ostrzeżenie poniżej (% wolne)", + "settings.pressureCriticalPct": "Krytyczny poniżej (% wolne)", + "settings.pressureEmergencyPct": "Awaryjny poniżej (% wolne)", + "settings.databaseBackupVerify": "Weryfikacja kopii zapasowej", + "settings.databaseBackupVerifyFull": "Pełna (integrity_check, weryfikuje każdy indeks)", + "settings.databaseBackupVerifyQuick": "Szybka (quick_check, tylko struktura stron)", + "settings.databaseBackupVerifyOff": "Wyłączona (brak skanowania po skopiowaniu)", + "settings.databaseBackupVerifyHelp": "Skanowanie stosowane do każdej skopiowanej kopii zapasowej przed jej opublikowaniem. Pełne skanowanie może trwać dłużej niż samo kopiowanie na dużej bazie danych na dysku mechanicznym i może osiągnąć limit bezpieczeństwa 30 minut, powodując odrzucenie tej kopii; szybkie skanowanie nadal wykrywa uszkodzone lub ucięte strony przy znacznie mniejszej liczbie operacji dyskowych.", + "settings.viewMethodAuto": "Auto — preferencja per kamera z przełączeniem awaryjnym", + "settings.resetWizardPending": "Uruchamianie kreatora…", + "settings.apiDetectionFormat": "Format żądania API", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (wieloczęściowe przesyłanie obrazu)", + "settings.apiDetectionFormatDoods2": "DOODS2 (ciało JSON z obrazem base64)", + "settings.apiDetectionFormatHelp": "Format przesyłania używany przez LightNVR przy wysyłaniu migawek do API detekcji. Wybierz light-object-detect dla light-object-detect lub dowolnego serwera implementującego jego kontrakt; wybierz DOODS2 dla serwera DOODS2.", + "settings.apiDetectionUrlHelpDoods2": "Punkt końcowy DOODS2 /detect, np. http://localhost:8080/detect. Żądanie jest wysyłane jako JSON bez dodatkowych parametrów zapytania.", + "settings.apiDetectionDetectorName": "Nazwa detektora DOODS2", + "settings.apiDetectionDetectorNameHelp": "Wysyłana jako detector_name w każdym żądaniu. Musi odpowiadać detektorowi zwracanemu przez GET /detectors serwera; wartość „default\" używa domyślnego detektora serwera.", + "settings.defaultPlaybackTransport": "Domyślny transport odtwarzania", + "settings.defaultPlaybackTransportHelp": "Profil odtwarzania stosowany do nowo tworzonych strumieni. Istniejące strumienie zachowują własny wybór.", + "playbackTransport.auto": "Auto (zalecane)", + "playbackTransport.webrtcOnly": "Tylko WebRTC", + "playbackTransport.mseOnly": "Tylko MSE", + "playbackTransport.hlsOnly": "Tylko HLS", + "playbackTransport.webrtcThenMse": "WebRTC, następnie MSE", + "playbackTransport.mseThenHls": "MSE, następnie HLS", + "investigation.experimental": "Eksperymentalna przestrzeń robocza", + "investigation.title": "Dochodzenie", + "investigation.description": "Przeglądaj wiele kamer względem jednego wspólnego kursora UTC bez ukrywania przerw w nagraniach.", + "investigation.query": "Okno dochodzenia", + "investigation.queryHelp": "Wybierz do 16 kamer. Aktywne są maksymalnie cztery odtwarzacze wideo jednocześnie.", + "investigation.cameras": "kamery", + "investigation.cameraSelection": "Wybór kamery", + "investigation.start": "Początek", + "investigation.end": "Koniec", + "investigation.load": "Wczytaj dochodzenie", + "investigation.applyWindow": "Zastosuj okno czasowe", + "investigation.loading": "Wczytywanie dochodzenia…", + "investigation.eventType": "Typ zdarzenia", + "investigation.anyEventType": "Dowolny typ zdarzenia", + "investigation.eventType.detection": "Wykrycie", + "investigation.eventType.motion": "Ruch", + "investigation.location": "Lokalizacja", + "investigation.anyLocation": "Dowolna lokalizacja", + "investigation.objectLabel": "Etykieta obiektu", + "investigation.anyLabel": "Dowolna etykieta", + "investigation.zone": "Strefa", + "investigation.anyZone": "Dowolna strefa", + "investigation.source": "Źródło wykrycia", + "investigation.anySource": "Dowolne źródło", + "investigation.captureMethod": "Metoda przechwytywania", + "investigation.anyCaptureMethod": "Dowolna metoda przechwytywania", + "investigation.recordingTag": "Tag nagrania", + "investigation.anyRecordingTag": "Dowolny tag nagrania", + "investigation.protection": "Ochrona", + "investigation.anyProtection": "Dowolna ochrona", + "investigation.protected": "Chroniony", + "investigation.unprotected": "Niechroniony", + "investigation.minimumConfidence": "Minimalna pewność", + "investigation.confidenceError": "Minimalna pewność musi być między 0 a 1.", + "investigation.metadataRegionSearch": "Wyszukiwanie w regionie metadanych", + "investigation.regionSearchHelp": "Wybierz kamerę główną z materiałem wideo, a następnie narysuj obszar na jej podglądzie.", + "investigation.regionActive": "Wyszukiwanie zapisanych obiektów z {camera}. Brak wyniku nie oznacza, że nic nie przekroczyło obszaru.", + "investigation.regionMatch": "Dopasowanie obiektów", + "investigation.regionMatch.center": "Środek wewnątrz", + "investigation.regionMatch.intersects": "Dowolne przecięcie", + "investigation.regionMatch.minimumIntersection": "Minimalne nakładanie się", + "investigation.regionMinimumOverlap": "Minimalne nakładanie się (%)", + "investigation.regionLeft": "Lewo (%)", + "investigation.regionTop": "Góra (%)", + "investigation.regionWidth": "Szerokość (%)", + "investigation.regionHeight": "Wysokość (%)", + "investigation.drawRegion": "Narysuj obszar wyszukiwania", + "investigation.drawingRegion": "Rysowanie obszaru wyszukiwania…", + "investigation.clearRegion": "Wyczyść obszar", + "investigation.useFullFrame": "Użyj pełnego kadru", + "investigation.drawRegionPrompt": "Przeciągnij po wideo, aby zdefiniować obszar wyszukiwania", + "investigation.applyFilters": "Zastosuj filtry", + "investigation.searching": "Wyszukiwanie zdarzeń…", + "investigation.searchResults": "Wyniki zdarzeń", + "investigation.searchHelp": "Wczytaj śledztwo, aby wyszukać jego zapisane metadane zdarzeń.", + "investigation.resultCount": "{count} pasujących zdarzeń", + "investigation.results": "wyniki", + "investigation.resultHistogram": "Histogram zdarzeń", + "investigation.histogramHelp": "Wybierz słupek, aby przesunąć wspólny kursor.", + "investigation.previousResult": "Poprzednie zdarzenie", + "investigation.nextResult": "Następne zdarzenie", + "investigation.previousResultShortcut": "Poprzednie zdarzenie ([)", + "investigation.nextResultShortcut": "Następne zdarzenie (])", + "investigation.noResults": "Brak zapisanych zdarzeń pasujących do wybranej kamery, czasu i filtrów.", + "investigation.noThumbnail": "Brak miniatury", + "investigation.exploreThumbnails": "Przeglądaj miniatury", + "investigation.exploreSelectedThumbnails": "Przeglądaj w okolicy zdarzenia", + "investigation.thumbnailDrilldown": "Zagłębianie w miniaturach", + "investigation.thumbnailDrilldownHelp": "Wybierz dowolny moment, w tym lukę, aby przesunąć wspólny kursor i wygenerować węższy zbiór próbek.", + "investigation.selectThumbnailSample": "Sprawdź w okolicy {time}", + "investigation.loadingThumbnail": "Ładowanie miniatury…", + "investigation.thumbnailUnavailable": "Miniatura niedostępna", + "investigation.loadingSamples": "Ładowanie próbek miniatur…", + "investigation.thumbnailCoverageTruncated": "Ten przedział zawiera więcej nagrań niż próbnik mógł przeanalizować. Zawęź okno czasowe, aby uzyskać pełne pokrycie.", + "investigation.bookmarks.save": "Zapisz zakładkę", + "investigation.bookmarks.open": "Zakładki", + "investigation.bookmarks.saveTitle": "Zapisz zakładkę śledztwa", + "investigation.bookmarks.listTitle": "Zakładki śledztwa", + "investigation.bookmarks.notHold": "Zakładka przywraca ten widok, ale nie chroni nagrań przed normalnym usunięciem przez retencję.", + "investigation.bookmarks.title": "Nazwa zakładki", + "investigation.bookmarks.note": "Prywatna notatka (opcjonalnie)", + "investigation.bookmarks.titleRequired": "Wpisz nazwę zakładki.", + "investigation.bookmarks.empty": "Nie masz zapisanych zakładek śledztwa.", + "investigation.bookmarks.cameraCount": "{count} kamer(y)", + "investigation.bookmarks.restore": "Otwórz", + "investigation.bookmarks.confirmDelete": "Usunąć zakładkę?", + "investigation.actions.open": "Chroń / pobierz", + "investigation.actions.title": "Nagrania śledztwa", + "investigation.actions.notEvidenceExport": "Ochrona zapobiega normalnemu usunięciu przez retencję. Pobranie ZIP to wygodny eksport, nie zweryfikowany pakiet dowodowy.", + "investigation.actions.scope": "Zakres nagrania", + "investigation.actions.selectedResult": "Wybrane zdarzenie i kamera", + "investigation.actions.fullWindow": "Wszystkie kamery w oknie śledztwa", + "investigation.actions.preview": "Podgląd nagrań", + "investigation.actions.previewing": "Wyszukiwanie nakładających się nagrań…", + "investigation.actions.invalidRange": "Wybierz prawidłowy zakres czasu, w którym koniec jest późniejszy niż początek.", + "investigation.actions.recordingCount": "{count} nakładających się nagrań", + "investigation.actions.protectedCount": "{count} już chronionych", + "investigation.actions.noRecordings": "Żadne zakończone nagrania nie nakładają się na wybraną kamerę i zakres czasu.", + "investigation.actions.protectDenied": "{count} niechronionych nagrań znajduje się poza Twoim zakresem ochrony i zostało wykluczonych z tej akcji.", + "investigation.actions.exportDenied": "Brak uprawnień do eksportu dla {count} nagrań. Pobieranie jest traktowane jako całość, więc tego wyboru nie można wyeksportować.", + "investigation.actions.camera": "Kamera", + "investigation.actions.recording": "Nagranie", + "investigation.actions.size": "Rozmiar", + "investigation.actions.notPermitted": "Brak uprawnień", + "investigation.actions.protectButton": "Chroń {count}", + "investigation.actions.protecting": "Ochrona…", + "investigation.actions.protectUnavailable": "Brak niechronionych nagrań, które możesz chronić.", + "investigation.actions.protectResult": "Ochrona zakończona: {success} zakończonych sukcesem, {failed} nieudanych.", + "investigation.actions.downloadButton": "Pobierz {count}", + "investigation.actions.downloadUnavailable": "Każde nagranie wymaga uprawnień do eksportu przed utworzeniem pliku ZIP.", + "investigation.actions.buildingArchive": "Tworzenie pliku ZIP…", + "investigation.actions.downloadFailed": "Tworzenie pliku ZIP nie powiodło się po stronie serwera.", + "investigation.actions.downloadTimedOut": "Tworzenie pliku ZIP nie zakończyło się w ciągu pięciu minut. Spróbuj węższego przedziału czasu.", + "investigation.actions.downloadStarted": "Pobieranie pliku ZIP rozpoczęte.", + "investigation.backOneLevel": "Wróć o jeden poziom", + "investigation.thumbnailMinimumWindow": "To najwęższy dostępny jednosekundowy przedział. Współdzielony kursor nadal przesunął się do wybranego momentu.", + "investigation.localSource": "lokalny", + "investigation.mediaAvailable": "Dostępne multimedia", + "investigation.durationSeconds": "Czas trwania: {count} s", + "investigation.pageNumber": "Strona {count}", + "investigation.incompleteCoverage": "{count} starszych wierszy zdarzeń nie można przypisać do niezmiennej tożsamości kamery.", + "investigation.spatialCoverageGap": "{count} wierszy zdarzeń w zakresie nie miało ramki ograniczającej i nie zostało przeszukane przestrzennie.", + "investigation.noSpatialMetadata": "Żadne zdarzenia w zakresie nie mają ramek ograniczających dla tego wyszukiwania metadanych.", + "investigation.selectCameraError": "Wybierz co najmniej jedną kamerę.", + "investigation.selectRecordingError": "Wybierz co najmniej jedno nagranie.", + "investigation.investigateSelectedCount": "Zbadaj {count} wybranych nagrań", + "investigation.missingCameraIdentity": "Nie można zbadać: {count} wybranych nagrań nie ma identyfikacji kamery.", + "investigation.recordingTimeError": "Wybrane nagrania nie mają prawidłowego zakresu czasu.", + "investigation.windowLimit": "Wybrane nagrania przekraczają limit badania wynoszący 31 dni.", + "investigation.timeRangeError": "Czas zakończenia musi być późniejszy niż czas rozpoczęcia.", + "investigation.cameraLimit": "Badanie może obejmować maksymalnie {count} kamer.", + "investigation.decoderLimit": "Jednocześnie aktywne mogą być tylko {count} odtwarzaczy kamer.", + "investigation.playbackControls": "Synchronizowane sterowanie odtwarzaniem", + "investigation.play": "Odtwórz", + "investigation.pause": "Pauza", + "investigation.mode": "Tryb odtwarzania", + "investigation.wallClock": "Czas rzeczywisty", + "investigation.skipCommonGaps": "Pomiń wspólne przerwy", + "investigation.speed": "Prędkość", + "investigation.sharedCursor": "Wspólny kursor UTC", + "investigation.activePlayers": "aktywne odtwarzacze", + "investigation.timeline": "wspólna oś czasu", + "investigation.segments": "segmenty", + "investigation.truncated": "przycięte", + "investigation.gap": "Brak nagrań", + "investigation.players": "Synchronizowane odtwarzacze kamer", + "investigation.activateCamera": "Aktywuj co najmniej jeden wiersz osi czasu, aby załadować wideo.", + "investigation.noFootage": "Brak nagrań", + "investigation.noFootageAtTime": "Brak nagrań we wspólnym czasie", + "investigation.primaryAudio": "Dźwięk główny", + "investigation.makePrimary": "Ustaw jako główny", + "investigation.status.loading": "Ładowanie multimediów", + "investigation.status.synchronizing": "Synchronizowanie", + "investigation.status.ready": "Zsynchronizowano", + "investigation.status.late": "Opóźnienie — przywracanie", + "investigation.status.error": "Multimedia niedostępne", + "investigation.status.paused-by-browser": "Wybierz odtwarzanie, aby zezwolić na multimedia", + "streamsConfig.eptzTitle": "Fisheye ePTZ", + "streamsConfig.eptzEnable": "Włącz fisheye ePTZ po stronie przeglądarki", + "streamsConfig.eptzHelp": "Odkształcaj oryginalny strumień fisheye w Podglądzie na żywo, odtwarzaniu osi czasu i Śledztwie. Nie wpływa to na nagrania ani wyjście kamery.", + "streamsConfig.eptzModelHelp": "Projekcja: równoodległościowa fisheye kołowa · Montaż: sufitowy. Środek i promień używają znormalizowanych współrzędnych obrazu źródłowego.", + "streamsConfig.eptzCenterX": "Ośrodek optyczny X", + "streamsConfig.eptzCenterY": "Ośrodek optyczny Y", + "streamsConfig.eptzRadius": "Promień koła obrazu", + "streamsConfig.eptzLensFov": "FOV obiektywu (stopnie)", + "streamsConfig.eptzRotation": "Rotacja obiektywu (stopnie)", + "streamsConfig.eptzDefaultYaw": "Domyślne przechylenie poziome (stopnie)", + "streamsConfig.eptzDefaultTilt": "Domyślne przechylenie pionowe (stopnie)", + "streamsConfig.eptzViewFov": "Domyślne FOV widoku", + "streamsConfig.eptzCalibrationHelp": "Przeciągnij, aby rozejrzeć się, użyj kółka lub gestu szczypania, aby przybliżyć, i naciśnij Home, aby zresetować kamerę wirtualną. Dostosuj środek i promień, jeśli krawędź koła obrazu nie jest wyrównana.", + "settings.archive.targetType": "Typ przechowywania", + "settings.archive.filesystem": "Lokalny lub zamontowany system plików (NFS/SAN)", + "settings.archive.s3": "Kosz archiwum zgodny z S3", + "settings.archive.endpoint": "Punkt końcowy HTTPS", + "settings.archive.region": "Region", + "settings.archive.bucket": "Dedykowany kosz", + "settings.archive.credential_ref": "Odwołanie do poświadczeń", + "settings.archive.budget": "Budżet archiwum (GiB, 0 = bez limitu)", + "settings.archive.connectionHelp": "Użyj prywatnego kosza bez wersjonowania i reguł wygasania cyklu życia. Odwołanie do poświadczeń wskazuje plik z sekretem zamontowany na serwerze. Wprowadź lokalizację zarządzaną w formacie s3://bucket/instance-prefix.", + "settings.archive.policy": "Zasada archiwizacji zewnętrznej", + "settings.archive.archive_after_seconds": "Archiwizuj po przechwyceniu (sekundy, -1 = wyłączone)", + "settings.archive.hot_residency_seconds": "Zachowaj kopię gorącą (sekundy, -1 = przenieś po zarchiwizowaniu)", + "settings.archive.archive_protected": "Priorytetyzuj archiwizację chronionych nagrań", + "settings.archive.archive_on_pressure": "Archiwizuj wcześniej, gdy pamięć gorąca jest przeciążona", + "settings.archive.policyHelp": "Czas archiwizacji opiera się na wieku przechwycenia i wymaga zakończonego nagrania. -1 wyłącza archiwizację opartą na wieku lub usuwa minimalny czas pobytu w pamięci gorącej; 0 oznacza natychmiast. Zmiany dotyczą nowych nagrań. Sprawdź istniejące nagrania, aby zastosować do nich nową rewizję.", + "settings.archive.deletion_pending": "Oczekiwanie na usunięcie", + "settings.archive.archived": "Zarchiwizowane", + "settings.archive.hot": "Gorące", + "settings.archive.hot_and_archive": "Gorące + archiwum", + "settings.archive.archiving": "Archiwizacja", + "settings.archive.preparing": "Przygotowywanie odtwarzania", + "settings.archive.unavailable": "Niedostępne", + "settings.archive.operations": "Operacje archiwizacji", + "settings.archive.readOnly": "Tryb odzyskiwania: migracja i usuwanie nagrań są wstrzymane.", + "settings.archive.disabledBuild": "Obsługa S3 jest wyłączona w tej wersji. Zamontowane systemy plików pozostają dostępne.", + "settings.archive.stored": "Przechowywane w bucketach", + "settings.archive.backlog": "Kolejka transferów", + "settings.archive.cache": "Pamięć podręczna pobierania", + "settings.archive.objectsRemaining": "obiektów pozostało", + "settings.archive.waitingForReaders": "W kolejce lub oczekuje na aktywnych odbiorców.", + "settings.archive.applied": "Rewizja zasad zastosowana do istniejących nagrań", + "settings.archive.reviewExisting": "Przejrzyj istniejące nagrania", + "settings.archive.applySummary": "{count} nagrań ({bytes}) będzie korzystać z tej rewizji. {expired} już przekroczyło limit retencji.", + "settings.archive.applyHelp": "Ochrona i nadpisania nagrań nadal obowiązują. Retencja strumienia i systemu również obowiązują. Nowe ustawienia czasu i miejsca archiwizacji wejdą w życie przy następnym skanie cyklu życia.", + "settings.archive.applyBlocked": "Zakończ lub rozwiąż powiązane transfery przed zastosowaniem tej rewizji.", + "settings.archive.apply": "Zastosuj do istniejących nagrań", + "common.fullscreenUnsupported": "Tryb pełnoekranowy nie jest obsługiwany w tej przeglądarce.", + "recordings.viewInTimelineTitle": "Wyświetl ten strumień w tym momencie w widoku osi czasu", + "recordings.clickToRetry": "Kliknij, aby ponowić", + "timeline.previousDay": "Poprzedni dzień", + "timeline.nextDay": "Następny dzień", + "timeline.previousMonth": "Poprzedni miesiąc", + "timeline.nextMonth": "Następny miesiąc", + "settings.searchLabel": "Szukaj ustawień", + "settings.clearSearch": "Wyczyść wyszukiwanie", + "recordings.addTagPlaceholder": "Dodaj tag...", + "recordings.addNewTagPlaceholder": "Dodaj nowy tag..." } diff --git a/web/public/locales/pt-BR.json b/web/public/locales/pt-BR.json index f34f08ad..ace905ea 100644 --- a/web/public/locales/pt-BR.json +++ b/web/public/locales/pt-BR.json @@ -43,7 +43,7 @@ "live.plan.sketch.snap": "Alinhar à grade", "live.plan.sketch.hint.select": "Arraste formas ou câmeras para movê-las. Clique em uma forma para editá-la; segure Alt para ignorar a grade.", "live.plan.sketch.hint.room": "Arraste sobre a planta para desenhar um ambiente ou o contorno de um prédio.", - "live.plan.sketch.hint.wall": "Clique para adicionar pontos da parede. Clique duas vezes ou pressione Enter para concluir, Esc para cancelar.", + "live.plan.sketch.hint.wall": "Clique para adicionar pontos da parede. Clique duas vezes ou pressione Enter para concluir, Escape para cancelar.", "live.plan.sketch.hint.area": "Clique para contornar uma área. Clique no primeiro ponto ou pressione Enter para fechá-la.", "live.plan.sketch.hint.label": "Clique na planta para posicionar um rótulo de texto.", "live.plan.sketch.type.rect": "Ambiente", @@ -678,7 +678,6 @@ "system.activeStreams": "Streams ativos", "system.recordingsSize": "Tamanho das gravações", "common.download": "Baixar", - "common.name": "Nome", "common.status": "Status", "common.url": "URL", "common.enabled": "Ativo", @@ -912,9 +911,9 @@ "streamsConfig.streamNameImmutable": "O nome do stream não pode ser alterado após a criação", "streamsConfig.streamNameAllowedChars": "Somente letras, dígitos, '.', '-' e '_' são permitidos (sem espaços).", "streamsConfig.streamUrl": "URL do stream", - "streamsConfig.streamUrlPlaceholder": "rtsp://usuario:senha@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "URL do Sub-stream (opcional)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://usuario:senha@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "URL do stream de baixa resolução para a visualização em grade do painel. Deixe vazio para usar o stream principal em todos os lugares. O sub-stream é usado apenas para pré-visualização ao vivo no modo grade; gravação e tela cheia sempre usam o stream principal.", "streamsConfig.urlCredentialsHiddenTitle": "As credenciais da URL estão ocultas no modo demo/visualizador", "streamsConfig.urlCredentialsHidden": "Credenciais da URL ocultas por segurança", @@ -972,7 +971,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "Certifique-se de que o light-object-detect esteja em execução neste endpoint", "streamsConfig.customApiEndpointUrl": "URL personalizada do endpoint da API", "streamsConfig.useDefaultEndpoint": "Usar endpoint padrão", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "Insira a URL completa do seu endpoint personalizado da API de detecção", "streamsConfig.overrideWithCustomEndpoint": "Substituir por endpoint personalizado", "streamsConfig.detectionThreshold": "Limiar de detecção", @@ -1209,7 +1208,7 @@ "settings.detectionModelsPath": "Caminho dos modelos de detecção", "settings.detectionModelsPathHelp": "Diretório onde os modelos de detecção são armazenados", "settings.apiDetectionUrl": "URL da API de detecção", - "settings.apiDetectionUrlHelp": "URL do endpoint externo da API de detecção de objetos", + "settings.apiDetectionUrlHelp": "Endpoint do light-object-detect, ex.: http://localhost:8000/api/v1/detect. O snapshot é enviado como multipart form data com os parâmetros de consulta backend e confidence_threshold anexados.", "settings.apiDetectionBackend": "Backend da API de detecção", "settings.apiDetectionBackendOnnx": "ONNX Runtime", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1359,5 +1358,1290 @@ "settings.discoveryIntervalSecondsRangeHelp": "Com que frequência procurar câmeras (30–3600 segundos)", "settings.discoveryNetwork": "Rede de descoberta", "settings.discoveryNetworkExamples": "Exemplos: 192.168.1.0/24, 10.0.0.0/16, auto", - "settings.saveSettings": "Salvar configurações" + "settings.saveSettings": "Salvar configurações", + "live.navigator.layoutNamePrompt": "Nomeie este layout ao vivo", + "live.navigator.shareLayoutPrompt": "Compartilhar este layout com outros operadores?", + "live.navigator.layoutSaved": "Salvo: {name}", + "live.navigator.layoutLoaded": "Carregado: {name}", + "live.navigator.deleteLayoutConfirm": "Excluir {name}?", + "live.navigator.shared": "Compartilhado", + "live.navigator.loadingEvents": "Carregando eventos recentes…", + "live.navigator.noRecentEvents": "Nenhuma detecção na última hora.", + "live.navigator.expand": "Expandir navegador", + "live.navigator.collapse": "Recolher navegador", + "live.favorites": "Favoritos", + "live.favoritesOnly": "Mostrar apenas câmeras favoritas", + "live.addFavorite": "Adicionar {stream} aos favoritos", + "live.removeFavorite": "Remover {stream} dos favoritos", + "live.noFavorites": "Nenhuma câmera favorita ainda. Use a estrela em um bloco de câmera para adicionar uma.", + "live.favoriteUpdateError": "Não foi possível atualizar os favoritos: {message}", + "live.resetZoom": "Redefinir zoom", + "live.audioPlaybackBlocked": "O navegador bloqueou o áudio da câmera. Clique no botão de alto-falante novamente para tentar.", + "live.fullscreenSubStreamFallback": "{stream}: largura de banda insuficiente para o stream em resolução máxima em tela cheia — alternado para o sub-stream.", + "live.tileActions": "Ações da câmera", + "live.takeSnapshot": "Capturar instantâneo", + "live.openStreamRecordings": "Abrir gravações deste stream", + "live.enterReorderMode": "Reordenar câmeras", + "live.pullToRefresh": "Puxe para atualizar os streams", + "live.releaseToRefresh": "Solte para atualizar os streams", + "live.refreshingStreams": "Atualizando streams…", + "live.streamsRefreshed": "Streams atualizados", + "live.refreshStreamsFailed": "Não foi possível atualizar os streams: {message}", + "live.tipDoubleTapFullscreen": "Dica: toque duas vezes em um bloco para abrir em tela cheia.", + "live.dayNightControl": "Modo dia/noite", + "live.dayNightLoading": "Carregando…", + "live.dayNightApplying": "Aplicando…", + "live.dayNightMode_auto": "Automático", + "live.dayNightMode_day": "Dia", + "live.dayNightMode_night": "Noite", + "live.dayNightMode_unknown": "Desconhecido", + "live.dayNightApplied": "Modo dia/noite definido como {mode}", + "live.dayNightApplyFailed": "Falha ao definir o modo dia/noite", + "live.dayNightLoadFailed": "Falha ao ler o modo dia/noite", + "live.playbackFallbackUsed": "Alternativa: {transport}", + "live.playbackTransportUnavailable": "{transport} está desabilitado no servidor para este stream.", + "live.recordingMode.constant": "Gravação contínua", + "live.recordingMode.detection": "Gravação por detecção", + "live.recordingMode.schedule": "Gravação programada", + "live.recordingMode.none": "Sem gravação", + "live.health.healthy": "Stream saudável", + "live.health.degraded": "Stream em buffer ou se recuperando", + "live.health.offline": "Stream indisponível", + "live.enterPictureInPicture": "Abrir imagem na imagem", + "live.exitPictureInPicture": "Fechar imagem na imagem", + "live.pictureInPictureError": "Falha na imagem na imagem: {message}", + "live.alwaysFullscreenOnTapEnable": "Ativar tela cheia ao tocar em um único tile", + "live.alwaysFullscreenOnTapDisable": "Desativar tela cheia ao tocar em um único tile", + "live.displayMode": "Modo de exibição", + "live.displayModeFit": "Ajustar", + "live.displayModeFill": "Preencher", + "live.displayModeFitDescription": "Ajustar: exibir o quadro inteiro com bordas", + "live.displayModeFillDescription": "Preencher: preencher o tile e cortar as bordas do quadro", + "live.slideshowStartCameras": "Iniciar apresentação de slides: alternar entre câmeras", + "live.slideshowStartPages": "Iniciar apresentação de slides: alternar entre páginas da grade", + "live.slideshowStop": "Parar apresentação de slides", + "live.slideshowInterval": "Intervalo da apresentação de slides", + "live.slideshowSeconds": "{seconds}s", + "live.plan.previewUnavailable": "Pré-visualização da câmera indisponível", + "live.plan.previewAlt": "Visualização atual de {name}", + "live.plan.degreesValue": "{value} graus", + "live.plan.inDegrees": "{label} em graus", + "live.plan.imageDimensionsError": "Não foi possível ler as dimensões da imagem", + "live.plan.loading": "Carregando plantas do prédio…", + "live.plan.created": "{name} criado", + "live.plan.renamed": "Renomeado para {name}", + "live.plan.deleted": "{name} excluído", + "live.plan.backgroundType": "O plano de fundo deve ser uma imagem PNG ou JPEG", + "live.plan.backgroundTooLarge": "Imagem de fundo muito grande; o máximo é 768 KB", + "live.plan.backgroundAspect": "Enviada, mas a proporção da imagem não corresponde a nenhum tamanho de tela válido", + "live.plan.backgroundUpdatedSave": "Plano de fundo atualizado para {name}; salve o layout para aplicar o tamanho da tela", + "live.plan.backgroundNotResized": "Plano de fundo enviado, mas a tela não foi redimensionada: {error}", + "live.plan.backgroundUpdated": "Plano de fundo atualizado para {name}", + "live.plan.backgroundRemoved": "Plano de fundo removido", + "live.plan.saved": "{name} salvo", + "live.plan.createTitle": "Criar planta do edifício", + "live.plan.createDescription": "Dê um nome claro a este edifício ou andar. Desenhe o layout ou envie uma imagem da planta, depois posicione as câmeras.", + "live.plan.nameLabel": "Nome da planta", + "live.plan.namePlaceholder": "Edifício principal · Primeiro andar", + "live.plan.createConfirm": "Criar planta", + "live.plan.eyebrow": "Planta do edifício", + "live.plan.placedSummary": "{placed} posicionadas · {live} ao vivo agora", + "live.plan.zoomAndPan": "Zoom e deslocamento da planta", + "live.plan.panLeft": "Deslocar para a esquerda", + "live.plan.panUp": "Deslocar para cima", + "live.plan.panDown": "Deslocar para baixo", + "live.plan.panRight": "Deslocar para a direita", + "live.plan.zoomOut": "Reduzir zoom", + "live.plan.zoomIn": "Aumentar zoom", + "live.plan.fitTitle": "Ajustar planta", + "live.plan.fit": "Ajustar", + "live.plan.backgroundMenu": "Plano de fundo…", + "live.plan.save": "Salvar plano", + "live.plan.uploadBackgroundTitle": "Envie uma imagem PNG ou JPEG como plano de fundo", + "live.plan.replaceBackground": "Substituir plano de fundo", + "live.plan.uploadBackground": "Enviar plano de fundo", + "live.plan.removeBackground": "Remover plano de fundo", + "live.plan.rename": "Renomear", + "live.plan.newPlan": "Novo plano", + "live.plan.editLayout": "Editar layout", + "live.plan.placementHint": "Clique no plano para posicionar {name}", + "live.plan.clusterLabel": "{count} câmeras; amplie", + "live.plan.markerLabel": "{name}; {availability}; voltada para {rotation}° com visão de {fov}°", + "live.plan.cameraFallback": "Câmera", + "live.plan.legendLive": "Ao vivo", + "live.plan.canvas": "Tela do plano", + "live.plan.width": "Largura", + "live.plan.height": "Altura", + "live.plan.canvasHint": "Enviar uma imagem de plano de fundo redimensiona a tela para corresponder a ela.", + "live.plan.canvasInvalid": "A largura deve ser de 400 a 4000 e a altura de 300 a 3000.", + "live.plan.openLive": "Abrir câmera ao vivo", + "live.plan.direction": "Direção da câmera", + "live.plan.fov": "Campo de visão", + "live.plan.coverageNote": "Os setores mostram apenas direção e ângulo; a distância no plano não está calibrada.", + "live.plan.removeCamera": "Remover do plano", + "setupWizard.dbPathHint": "Localização do arquivo de banco de dados SQLite.", + "setupWizard.performanceTitle": "Desempenho", + "setupWizard.performanceIntro": "Essas configurações controlam a capacidade, não a qualidade de vídeo. A maioria dos usuários pode manter os padrões.", + "setupWizard.threadPool": "Tamanho do pool de threads de trabalho", + "setupWizard.threadPoolInfo": "afeta o processamento em segundo plano do servidor web. O padrão recomendado geralmente é o melhor, a menos que você esteja ajustando o desempenho.", + "setupWizard.maxStreams": "Máximo de streams simultâneos", + "setupWizard.maxStreamsInfo": "é o limite de capacidade de câmeras para esta instância em execução. Defina pelo menos o número de câmeras que você planeja adicionar, com uma pequena margem.", + "setupWizard.important": "Importante:", + "setupWizard.restartWarning": "se você alterar qualquer uma dessas configurações, o novo valor será salvo agora, mas só será utilizado após reiniciar o LightNVR. Por exemplo, se o limite atual de streams for 1 e você aumentá-lo para 32, será necessário reiniciar antes de adicionar câmeras além do limite antigo.", + "setupWizard.threadPoolHintCores": "Recomendado: {recommended} (2× seu processador de {cores} núcleos). Controla as threads de trabalho em segundo plano do libuv. Intervalo: 2–128.", + "setupWizard.threadPoolHint": "Recomendado: {recommended} (2× os núcleos do seu processador). Controla as threads de trabalho em segundo plano do libuv. Intervalo: 2–128.", + "setupWizard.maxStreamsHint": "Quantas câmeras o LightNVR pode manter ativas simultaneamente. Padrão: 32, máximo: {max}. Se você espera ter 8 câmeras, escolha pelo menos 8. Requer reinicialização para ter efeito.", + "setupWizard.completeTitle": "Configuração concluída!", + "setupWizard.saved": "Suas configurações foram salvas com sucesso.", + "setupWizard.notSaved": "Nenhuma configuração foi alterada — os padrões serão utilizados.", + "setupWizard.restartRequired": "Reinicialização necessária", + "setupWizard.restartRequiredInfo": "as alterações no tamanho do pool de threads e/ou no máximo de streams foram salvas, mas só terão efeito após reiniciar o serviço. Reinicie antes de adicionar mais câmeras ou esperar que o novo limite de capacidade seja aplicado.", + "setupWizard.saveFailed": "Falha ao salvar configurações: {error}", + "setupWizard.back": "Voltar", + "setupWizard.saving": "Salvando…", + "setupWizard.saveContinue": "Salvar e continuar", + "setupWizard.next": "Próximo →", + "setupWizard.finish": "Ir para o painel", + "setupWizard.skip": "Pular assistente de configuração", + "live.eptzCanvasLabel": "Visão de pan, tilt e zoom eletrônico fisheye", + "live.eptzCanvasHint": "Arraste para pan e tilt; role ou pinça para zoom; Home redefine", + "live.eptzReset": "Redefinir visão ePTZ", + "live.autoShort": "Auto", + "live.webrtcShort": "WebRTC", + "live.plan.selectCamera": "Selecionar uma câmera", + "live.plan.selectHintEditing": "Arraste os marcadores posicionados para ajustes finos. Inspecione o status e abra uma visualização ao vivo sob demanda.", + "live.plan.selectHint": "Verifique o status e abra uma visualização ao vivo sob demanda.", + "live.plan.cameras": "Câmeras do plano", + "live.plan.findPlaceholder": "Buscar neste plano…", + "live.plan.findLabel": "Encontrar uma câmera neste plano", + "live.plan.unplaced": "Câmeras não posicionadas", + "live.plan.unplacedHint": "Selecione uma câmera e clique na sua posição na planta.", + "live.plan.renameTitle": "Renomear plano", + "live.plan.renameDescription": "Os planos são compartilhados com todos os operadores neste site.", + "live.plan.deleteTitle": "Excluir plano", + "live.plan.deleteMessage": "Excluir “{name}” e o plano de fundo enviado? As posições das câmeras neste plano serão removidas; as câmeras em si não serão afetadas.", + "setupWizard.welcomeTitle": "Bem-vindo ao LightNVR", + "setupWizard.welcomeIntro": "Vamos configurar seu NVR em poucos passos rápidos. Você sempre pode revisar essas configurações depois na página de Configurações.", + "setupWizard.welcomeStorage": "Caminho de armazenamento e limites de tamanho", + "setupWizard.welcomePerformance": "Limites de desempenho para o número de câmeras", + "setupWizard.welcomeSecurity": "Login seguro do administrador", + "setupWizard.storageTitle": "Armazenamento e Banco de dados", + "setupWizard.storageIntro": "Onde as gravações e o banco de dados devem ser armazenados?", + "setupWizard.storagePath": "Caminho de armazenamento das gravações", + "setupWizard.storagePathHint": "Caminho absoluto onde os arquivos de vídeo são gravados.", + "setupWizard.maxStorage": "Tamanho máximo de armazenamento (GB)", + "setupWizard.maxStorageHint": "0 = ilimitado.", + "setupWizard.dbPath": "Caminho do banco de dados", + "events.enable": "Ativar", + "events.summary.managedActive": "{count} gerenciadas e ativas", + "events.route.addTitle": "Criar rota de eventos", + "events.route.editTitle": "Editar rota de eventos", + "events.route.create": "Criar rota", + "events.route.editorDescription": "Escolha quais eventos se qualificam, quais câmeras estão no escopo, para onde vão e como fontes ruidosas são controladas.", + "events.route.emptyTitle": "Nenhuma rota de eventos configurada", + "events.route.emptyDescription": "Crie uma rota para selecionar tipos de eventos, escopo de câmeras, agenda, política de supressão e destino MQTT.", + "events.route.enabled": "Rota ativada", + "events.route.enabledHelp": "Eventos correspondentes são aceitos para entrega durável", + "events.route.destination": "Destino", + "events.route.destinationHelp": "Um evento correspondente é persistido uma vez para cada destino único.", + "events.route.eventTypes": "Tipos de eventos", + "events.route.eventTypesHelp": "Selecione um ou mais contratos de eventos versionados do registro.", + "events.route.detectionFilters": "Filtrar detecções de objetos", + "events.route.detectionFiltersHelp": "Opcionalmente, exija rótulos, zonas ou uma confiança mínima para eventos de detecção de objetos.", + "events.route.healthFilters": "Filtrar eventos de saúde do sistema", + "events.route.healthFiltersHelp": "Opcionalmente, corresponda a códigos de condições de saúde registrados ou severidades. Os valores disponíveis vêm deste gravador.", + "events.route.healthConditions": "Condições de saúde (qualquer)", + "events.route.healthSeverities": "Severidades (qualquer)", + "events.route.healthRegistryUnavailable": "O registro de condições de saúde está indisponível. Recarregue antes de configurar filtros de condição.", + "events.route.labels": "Rótulos (qualquer)", + "events.route.zones": "IDs de zona (qualquer)", + "events.route.listHelp": "Separe os valores com vírgulas.", + "events.route.minConfidence": "Confiança mínima", + "events.route.confidenceHelp": "Um valor de 0 a 1.", + "events.route.cameraScope": "Escopo de câmeras", + "events.route.cameraScopeHelp": "Reutilize localizações da frota, tags, coleções de atributos ou câmeras específicas sem carregar toda a frota.", + "events.route.allCameras": "Todas as câmeras", + "events.route.dynamicScope": "Seletor dinâmico de câmeras", + "events.route.systemScopeHelp": "Eventos de sistema não são câmeras. Seletores de câmeras estão indisponíveis quando esta rota inclui eventos de escopo do sistema.", + "events.route.schedule": "Agenda", + "events.route.scheduleHelp": "Use o horário de ocorrência do evento em um fuso horário IANA; janelas noturnas são suportadas.", + "events.route.restrictSchedule": "Somente durante janelas configuradas", + "events.route.suppression": "Política de ruído e entrega", + "events.route.suppressionHelp": "Zero desativa um controle. A supressão avança somente após o destino aceitar o evento durável.", + "events.route.debounce": "Segundos de debounce", + "events.route.debounceHelp": "Observações repetidas estendem este intervalo silencioso.", + "events.route.cooldown": "Segundos de cooldown", + "events.route.cooldownHelp": "Intervalo mínimo após um evento aceito.", + "events.route.grouping": "Segundos da janela de agrupamento", + "events.route.groupingHelp": "Preserva o primeiro evento e agrupa as repetições.", + "events.route.rateLimit": "Eventos por minuto", + "events.route.rateLimitHelp": "Máximo por janela fixa por rota e câmera.", + "events.route.deliveryPolicy": "Política de entrega", + "events.route.suppressionActive": "Controles de ruído ativos", + "events.route.everyMatch": "Cada correspondência", + "events.route.preview": "Pré-visualizar rota", + "events.route.previewing": "Pré-visualizando…", + "events.route.previewResult": "Pré-visualização da rota", + "events.route.cameraMatches": "{count} câmeras correspondem", + "events.route.previewNoPublish": "A pré-visualização valida a regra completa e resolve uma amostra de câmeras; nunca publica um evento.", + "events.route.systemPreviewHelp": "Eventos de sistema ignoram a seleção de câmeras e, portanto, reportam zero câmeras correspondentes nesta pré-visualização.", + "events.route.created": "Rota de evento criada", + "events.route.updated": "Rota de evento atualizada", + "events.route.deleted": "Rota de evento excluída", + "events.route.disabled": "Rota de evento desativada", + "events.route.enabledMessage": "Rota de evento ativada", + "events.route.deleteConfirm": "Excluir a rota de evento \"{name}\"?", + "events.route.validation.name": "Informe um nome para a rota.", + "events.route.validation.destination": "Escolha um destino.", + "events.route.validation.event_types": "Selecione pelo menos um tipo de evento.", + "events.route.validation.selector": "Complete ou corrija o seletor de câmeras.", + "events.route.validation.system_scope": "Seletores de câmeras não podem ser usados com eventos de escopo de sistema.", + "events.route.validation.detection_type": "Filtros de detecção exigem o tipo de evento de detecção de objetos.", + "events.route.validation.detection_filter": "Adicione pelo menos um rótulo de detecção, zona ou limite de confiança.", + "events.route.validation.confidence": "A confiança mínima deve ser de 0 a 1.", + "events.route.validation.predicate_mix": "Filtros de detecção e de saúde não podem ser combinados em uma rota.", + "events.route.validation.health_type": "Filtros de saúde exigem apenas tipos de evento de saúde do sistema registrados.", + "events.route.validation.health_filter": "Selecione pelo menos uma condição de saúde ou severidade registrada.", + "events.route.validation.health_condition": "Selecione apenas códigos de condição retornados pelo registro de saúde do gravador.", + "events.route.validation.health_severity": "Selecione apenas severidades suportadas pelos tipos de evento de saúde selecionados.", + "events.route.validation.timezone": "Insira um fuso horário IANA instalado, como UTC ou America/New_York.", + "events.route.validation.schedule_window": "Cada janela de programação precisa de pelo menos um dia e horários de início e fim válidos e distintos.", + "events.route.validation.suppression": "Os valores de supressão devem ser números inteiros dentro dos intervalos permitidos.", + "events.schedule.timezone": "Fuso horário", + "events.schedule.timezoneHelp": "Deve estar presente no banco de dados de fusos horários do gravador.", + "events.schedule.addWindow": "Adicionar janela de tempo", + "events.schedule.windowNumber": "Janela {number}", + "events.schedule.start": "Início", + "events.schedule.end": "Fim", + "events.schedule.sunday": "Dom", + "events.schedule.monday": "Seg", + "events.schedule.tuesday": "Ter", + "events.schedule.wednesday": "Qua", + "events.schedule.thursday": "Qui", + "events.schedule.friday": "Sex", + "events.schedule.saturday": "Sáb", + "events.destination.add": "Adicionar destino", + "events.destination.addTitle": "Adicionar destino MQTT", + "events.destination.editTitle": "Editar destino MQTT", + "events.destination.create": "Criar destino", + "events.destination.editorDescription": "Configure uma saída de eventos durável. As credenciais permanecem somente para escrita e nunca são retornadas pela API.", + "events.destination.default": "Configurações padrão do MQTT", + "events.destination.settingsManaged": "Configurações gerenciadas", + "events.destination.defaultDescription": "A configuração MQTT existente permanece disponível como mqtt:default e é usada por {count} rotas.", + "events.destination.openSettings": "Abrir configurações de MQTT", + "events.destination.emptyTitle": "Nenhum destino gerenciado", + "events.destination.emptyDescription": "Adicione outro broker MQTT para entrega independente de eventos a um conector de nuvem, sistema de automação ou serviço de notificação.", + "events.destination.identity": "Identidade do destino", + "events.destination.enabled": "Destino habilitado", + "events.destination.enabledHelp": "Conectar e esvaziar sua fila durável", + "events.destination.active": "Ativo", + "events.destination.paused": "Pausado", + "events.destination.pause": "Pausar", + "events.destination.broker": "Broker", + "events.destination.host": "Host do broker", + "events.destination.hostHelp": "Apenas nome de host ou endereço IP; não inclua um esquema de URL.", + "events.destination.port": "Porta", + "events.destination.clientId": "ID do cliente", + "events.destination.clientIdHelp": "Deve ser exclusivo para esta conexão com o broker.", + "events.destination.topic": "Tópico", + "events.destination.topicTemplate": "Modelo de tópico", + "events.destination.topicHelp": "Deve incluir os tokens de tipo de evento e ID do assunto; curingas MQTT não são permitidos.", + "events.destination.keepalive": "Segundos de keepalive", + "events.destination.statusTopicTemplate": "Tópico de status de presença", + "events.destination.statusTopicHelp": "Opcional. Deve incluir {installation_uuid}; {destination_uuid} também está disponível. Curingas MQTT não são permitidos.", + "events.destination.statusTopicEnabled": "A presença está explicitamente habilitada para este destino. O tópico nunca é inferido a partir do tópico de evento.", + "events.destination.statusTopicDisabled": "A presença está desabilitada para este destino. Deixe este campo vazio para mantê-la desabilitada.", + "events.destination.qos": "Qualidade de serviço", + "events.destination.qos0": "enviar uma vez", + "events.destination.qos1": "pelo menos uma vez", + "events.destination.qos2": "exatamente uma vez", + "events.destination.authentication": "Autenticação", + "events.destination.passwordPreserved": "Deixe em branco para preservar a senha somente escrita armazenada.", + "events.destination.passwordOptional": "Opcional quando o broker permite clientes anônimos.", + "events.destination.clearPassword": "Limpar a senha armazenada", + "events.destination.transportSecurity": "Segurança de transporte", + "events.destination.tlsMode": "Modo TLS", + "events.destination.tlsSystem": "Loja de confiança do sistema", + "events.destination.tlsCustomCa": "Autoridade de certificação personalizada", + "events.destination.tlsMutual": "TLS mútuo", + "events.destination.tlsDisabled": "Desativado (texto plano)", + "events.destination.tlsHelp.system": "Verifique o certificado do broker contra a loja de confiança do sistema operacional.", + "events.destination.tlsHelp.custom_ca": "Verifique o broker contra um arquivo de autoridade de certificação PEM explícito.", + "events.destination.tlsHelp.mutual": "Verifique o broker com uma CA explícita e apresente um certificado e chave de cliente.", + "events.destination.tlsHelp.disabled": "Sem criptografia de transporte ou verificação de identidade do broker.", + "events.destination.caFile": "Arquivo CA", + "events.destination.certFile": "Arquivo de certificado de cliente", + "events.destination.keyFile": "Arquivo de chave de cliente", + "events.destination.absolutePathHelp": "Use um caminho absoluto legível pelo serviço LightNVR.", + "events.destination.plaintextWarning": "MQTT em texto plano pode expor metadados de eventos e credenciais. Use apenas em uma rede confiável e isolada.", + "events.destination.security": "Segurança", + "events.destination.tls.system": "Confiança do sistema", + "events.destination.tls.custom_ca": "CA personalizada", + "events.destination.tls.mutual": "TLS mútuo", + "events.destination.tls.disabled": "Texto plano", + "events.destination.routes": "Rotas", + "events.destination.presence": "Tópico de presença", + "events.destination.deleteInUse": "Remova ou redirecione as rotas antes de excluir este destino.", + "events.destination.created": "Destino MQTT criado", + "events.destination.updated": "Destino MQTT atualizado", + "events.destination.deleted": "Destino MQTT excluído", + "events.destination.pausedMessage": "Destino MQTT pausado; eventos na fila permanecem duráveis até a expiração.", + "events.destination.enabledMessage": "Destino MQTT ativado", + "events.destination.deleteConfirm": "Excluir o destino MQTT \"{name}\"?", + "events.destination.validation.name": "Insira um nome de destino.", + "events.destination.validation.host": "Insira um hostname ou endereço IP do broker.", + "events.destination.validation.client_id": "Insira um ID de cliente do broker.", + "events.destination.validation.topic": "O tópico deve incluir os tokens de tipo de evento e ID de assunto e não pode conter curingas MQTT.", + "events.destination.validation.status_topic": "O tópico de presença opcional deve incluir o token UUID da instalação, usar apenas tokens suportados e não pode conter curingas MQTT.", + "events.destination.validation.port": "A porta deve ser um número inteiro de 1 a 65535.", + "events.destination.validation.keepalive": "O Keepalive deve ser um número inteiro de 5 a 3600 segundos.", + "events.destination.validation.qos": "Escolha MQTT QoS 0, 1 ou 2.", + "events.destination.validation.username": "Uma senha configurada requer um nome de usuário.", + "events.destination.validation.ca_file": "Este modo TLS requer um caminho absoluto para o arquivo CA.", + "events.destination.validation.mutual_files": "O TLS mútuo requer caminhos absolutos para CA, certificado do cliente e chave do cliente.", + "fleet.summary": "Resumo de saúde da frota", + "fleet.clearFilters": "Limpar filtros", + "fleet.filter.location": "Subárvore de localizações", + "fleet.filter.allLocations": "Todas as localizações", + "fleet.filter.tags": "Tags (corresponder a qualquer)", + "fleet.filter.collection": "Coleção de câmeras", + "fleet.recordingActive": "Gravando agora", + "fleet.column.tags": "Tags", + "fleet.lastFrame": "Último quadro", + "fleet.noAddress": "Endereço indisponível", + "fleet.loading": "Carregando frota de câmeras…", + "fleet.refreshing": "Atualizando…", + "fleet.loadError": "Não foi possível carregar a frota de câmeras", + "fleet.emptyTitle": "Nenhuma câmera configurada", + "fleet.emptyDescription": "Adicione um stream para torná-lo disponível na área de trabalho da frota.", + "fleet.emptyFilteredTitle": "Nenhuma câmera corresponde a esta visualização", + "fleet.emptyFilteredDescription": "Tente ampliar a busca ou limpar um ou mais filtros.", + "fleet.selectPage": "Selecionar todas as câmeras nesta página", + "fleet.selectCamera": "Selecionar {name}", + "fleet.selectedCount": "{count} câmeras selecionadas", + "fleet.organizeSelected": "Organizar selecionadas", + "fleet.clearSelection": "Limpar seleção", + "fleet.organization.manage": "Gerenciar organização", + "fleet.organization.title": "Organização de câmeras", + "fleet.organization.description": "Mantenha uma hierarquia de localizações reutilizável e um dicionário de tags normalizado para a frota de câmeras.", + "fleet.organization.locations": "Locais", + "fleet.organization.tags": "Tags", + "fleet.organization.locationsDescription": "Modele sites, prédios, andares e áreas operacionais como uma hierarquia navegável.", + "fleet.organization.tagsDescription": "Use um dicionário de tags padronizado em vez de rótulos livres inconsistentes.", + "fleet.organization.addRoot": "Adicionar local de nível superior", + "fleet.organization.addLocation": "Adicionar local", + "fleet.organization.editLocation": "Editar local", + "fleet.organization.addChild": "Adicionar filho", + "fleet.organization.type": "Tipo", + "fleet.organization.parent": "Local pai", + "fleet.organization.topLevel": "Nível superior", + "fleet.organization.sortOrder": "Ordem de ordenação", + "fleet.organization.contents": "Conteúdo", + "fleet.organization.cameras": "Câmeras", + "fleet.organization.system": "Sistema", + "fleet.organization.contentCounts": "{cameras} câmeras · {children} filhos", + "fleet.organization.locationNotEmpty": "Mova as câmeras e exclua os locais filhos primeiro", + "fleet.organization.noLocations": "Nenhum local configurado.", + "fleet.organization.locationCreated": "Local criado", + "fleet.organization.locationUpdated": "Local atualizado", + "fleet.organization.locationDeleted": "Local excluído", + "fleet.organization.deleteLocationConfirm": "Excluir o local \"{name}\"?", + "fleet.organization.addTag": "Adicionar tag", + "fleet.organization.editTag": "Editar tag", + "fleet.organization.tagLabel": "Tag", + "fleet.organization.color": "Cor (#RRGGBB)", + "fleet.organization.tagDescription": "Descrição", + "fleet.organization.noTags": "Nenhuma tag padronizada configurada.", + "fleet.organization.tagCreated": "Tag criada", + "fleet.organization.tagUpdated": "Tag atualizada", + "fleet.organization.tagDeleted": "Tag excluída", + "fleet.organization.deleteTagConfirm": "Excluir \"{name}\"? Ela está atualmente atribuída a {count} câmeras.", + "fleet.organization.merge": "Mesclar", + "fleet.organization.mergeTagNamed": "Mesclar \"{name}\"", + "fleet.organization.mergeInto": "Mesclar em", + "fleet.organization.chooseTag": "Escolha a tag a ser mantida", + "fleet.organization.mergeWarning": "Todas as atribuições de câmera são movidas para a tag mantida; a tag de origem é removida em seguida.", + "fleet.organization.tagsMerged": "Tags mescladas", + "fleet.organization.saveError": "Não foi possível salvar: {message}", + "fleet.organization.deleteError": "Não foi possível excluir: {message}", + "fleet.locationType.site": "Site", + "fleet.locationType.building": "Prédio", + "fleet.locationType.floor": "Andar", + "fleet.locationType.area": "Área", + "fleet.locationType.zone": "Zona", + "fleet.locationType.system": "Sistema", + "fleet.bulk.title": "Organizar câmeras selecionadas", + "fleet.bulk.description": "Aplicar alterações de localização e tag a {count} câmeras com concorrência limitada.", + "fleet.bulk.location": "Atribuição de localização", + "fleet.bulk.locationHelp": "Todas as câmeras selecionadas serão movidas para a localização escolhida.", + "fleet.bulk.keepLocations": "Manter localizações atuais", + "fleet.bulk.tags": "Atribuição de tag", + "fleet.bulk.tagsHelp": "Adicionar ou remover tags sem afetar outras atribuições, ou substituir explicitamente o conjunto completo de tags.", + "fleet.bulk.tagOperation.none": "Manter", + "fleet.bulk.tagOperation.add": "Adicionar", + "fleet.bulk.tagOperation.remove": "Remover", + "fleet.bulk.tagOperation.replace": "Substituir tudo", + "fleet.bulk.replaceWarning": "Substituir tudo remove todas as tags atuais antes de aplicar esta seleção. Uma seleção vazia limpa todas as tags.", + "fleet.bulk.apply": "Aplicar alterações", + "fleet.bulk.working": "Aplicando alterações…", + "fleet.bulk.success": "{count} câmeras atualizadas", + "fleet.bulk.partial": "{succeeded} câmeras atualizadas; {failed} falharam", + "fleet.bulk.error": "Não foi possível organizar as câmeras: {message}", + "fleet.bulk.failures": "Câmeras que não puderam ser atualizadas", + "fleet.views.choose": "Escolher uma visualização salva", + "fleet.views.shared": "Compartilhado", + "fleet.views.name": "Nome da visualização", + "fleet.views.share": "Compartilhar com todos os operadores", + "fleet.views.saved": "Visualização da frota salva", + "fleet.views.saveError": "Não foi possível salvar a visualização: {message}", + "fleet.views.deleted": "Visualização da frota excluída", + "fleet.views.deleteConfirm": "Excluir a visualização salva \"{name}\"?", + "fleet.views.deleteError": "Não foi possível excluir a visualização: {message}", + "fleet.views.unsupported": "Este seletor salvo não pode ser representado pelos controles de filtro atuais.", + "collections.all": "Todas as coleções", + "collections.filter": "Coleção", + "collections.loadMembersError": "Não foi possível carregar as câmeras da coleção: {message}", + "collections.subtitle": "Crie grupos de câmeras reutilizáveis para operações, visualizações salvas e fluxos de trabalho subsequentes.", + "collections.listDescription": "Coleções estáticas mantêm associação explícita; coleções inteligentes avaliam continuamente as regras da frota.", + "collections.create": "Criar coleção", + "collections.edit": "Editar coleção", + "collections.editorDescription": "As definições de coleção usam UUIDs estáveis de câmeras, localizações e tags.", + "collections.backToList": "Voltar para coleções", + "collections.type": "Tipo de coleção", + "collections.type.static": "Estática", + "collections.type.smart": "Inteligente", + "collections.description": "Descrição", + "collections.shared": "Coleção compartilhada", + "collections.sharedHelp": "Permitir que outros usuários autorizados visualizem esta coleção; as regras de acesso às câmeras ainda se aplicam.", + "collections.typeChangeWarning": "Alterar o tipo de coleção substitui seu modelo de associação. Membros estáticos ou regras inteligentes do tipo anterior não serão mais aplicados.", + "collections.selectorError": "Seletor inválido: {message}", + "collections.created": "Coleção criada", + "collections.updated": "Coleção atualizada", + "collections.saveError": "Não foi possível salvar a coleção: {message}", + "collections.loadError": "Não foi possível carregar a coleção: {message}", + "collections.cameras": "câmeras", + "collections.visibility.shared": "Compartilhado", + "collections.visibility.private": "Privado", + "collections.selectorRedacted": "Regras privadas", + "collections.emptyTitle": "Nenhuma coleção ainda", + "collections.emptyAdmin": "Crie um grupo estático ou uma visualização inteligente baseada em regras para reutilizar seleções de câmeras.", + "collections.emptyViewer": "Nenhuma coleção compartilhada está disponível para o seu escopo de câmeras.", + "collections.deleteConfirm": "Excluir a coleção \"{name}\"?", + "collections.deleted": "Coleção excluída", + "collections.deleteError": "Não foi possível excluir a coleção: {message}", + "collections.preview.title": "Pré-visualização de regra", + "collections.preview.matches": "{count} câmeras correspondentes", + "collections.preview.action": "Pré-visualizar", + "collections.preview.hide": "Ocultar pré-visualização", + "collections.preview.loading": "Avaliando…", + "collections.preview.empty": "Nenhuma câmera corresponde no momento.", + "collections.preview.sample": "Exibindo uma amostra de {count} câmeras de {total} correspondências.", + "collections.preview.error": "Não foi possível pré-visualizar a coleção: {message}", + "collections.members.title": "Membros estáticos", + "collections.members.selected": "{count} câmeras selecionadas em todas as páginas", + "collections.members.search": "Buscar câmeras…", + "collections.members.selectPage": "Selecionar esta página", + "collections.members.empty": "Nenhuma câmera corresponde a esta busca.", + "collections.builder.title": "Regras inteligentes", + "collections.builder.description": "As regras são avaliadas com base na organização, configuração, capacidades e saúde atuais das câmeras.", + "collections.builder.match": "Corresponder a", + "collections.builder.allRules": "todas as regras", + "collections.builder.anyRule": "qualquer regra", + "collections.builder.addRule": "Adicionar regra", + "collections.builder.removeRule": "Remover regra", + "collections.builder.matchesAll": "Sem regras completas, esta coleção corresponde a todas as câmeras no escopo autorizado do usuário.", + "collections.builder.incompleteRule": "Complete ou remova todas as regras antes de salvar.", + "collections.builder.chooseLocation": "Escolha uma subárvore de localização", + "collections.builder.vendorPlaceholder": "Nomes de fabricantes, separados por vírgula", + "collections.builder.modelPlaceholder": "Nomes de modelos, separados por vírgula", + "collections.builder.advancedMode": "JSON avançado", + "collections.builder.visualMode": "Construtor visual", + "collections.builder.cannotVisualize": "Este seletor contém lógica aninhada ou avançada que o construtor visual não pode representar com segurança.", + "collections.rule.location_subtree": "Localização está dentro de", + "collections.rule.camera_uuid": "Câmeras específicas", + "collections.rule.tag_any": "Possui qualquer tag", + "collections.rule.tag_all": "Possui todas as tags", + "collections.rule.tag_none": "Não possui nenhuma das tags", + "collections.rule.health": "Saúde é", + "collections.rule.enabled": "Câmera está", + "collections.rule.recording_mode": "Modo de gravação é", + "collections.rule.capability_any": "Possui qualquer capacidade", + "collections.rule.capability_all": "Possui todas as capacidades", + "collections.rule.vendor": "Fabricante é", + "collections.rule.model": "Modelo é", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Canal de retorno de áudio", + "streamHealth.observedFps": "FPS observado", + "streamHealth.expectedFps": "Esperado", + "streamHealth.fpsHelp": "Observado pelo LightNVR; o esperado vem dos metadados do stream da câmera.", + "login.passwordChanged": "Senha alterada com sucesso. Faça login com sua nova senha.", + "passwordChangeRequired.title": "Alterar a senha padrão", + "passwordChangeRequired.description": "Esta instalação ainda está usando a senha padrão do administrador. Substitua-a antes de continuar para o LightNVR. A MFA, quando habilitada, será verificada no próximo login.", + "passwordChangeRequired.currentPassword": "Senha atual", + "passwordChangeRequired.newPassword": "Nova senha", + "passwordChangeRequired.confirmPassword": "Confirmar nova senha", + "passwordChangeRequired.passwordHelp": "Use pelo menos 8 caracteres. A senha não pode ser admin.", + "passwordChangeRequired.submit": "Alterar senha", + "passwordChangeRequired.saving": "Alterando senha...", + "passwordChangeRequired.error.currentRequired": "Digite sua senha atual.", + "passwordChangeRequired.error.tooShort": "A nova senha deve ter pelo menos 8 caracteres.", + "passwordChangeRequired.error.defaultPassword": "A nova senha não pode ser admin.", + "passwordChangeRequired.error.mismatch": "As novas senhas não coincidem.", + "passwordChangeRequired.error.generic": "A senha não pôde ser alterada. Tente novamente.", + "settings.tab.health": "Saúde", + "settings.tab.workspaces": "Espaços de trabalho", + "settings.health.title": "Saúde do host e do hardware", + "settings.health.description": "Configure o monitoramento limitado do sistema operacional e do hardware sem expor caminhos de dispositivos ou segredos.", + "settings.health.enabled": "Ativar monitoramento de saúde", + "settings.health.enabledHelp": "Coletar sinais suportados de host, serviço, armazenamento, rede e hardware.", + "settings.health.profile": "Perfil de política", + "settings.health.profileHelp": "Equilibrado é o padrão normal; conservador exige evidências mais fortes antes de alertar.", + "settings.health.profile.balanced": "Equilibrado", + "settings.health.profile.conservative": "Conservador", + "settings.health.hardwareProvider": "Provedor de hardware", + "settings.health.provider.auto": "Automático (provedores do kernel)", + "settings.health.provider.smartctl": "smartctl (explícito)", + "settings.health.providerHelp.auto": "Usa apenas provedores limitados de sysfs, NVMe e kernel; smartctl nunca é inferido.", + "settings.health.providerHelp.smartctl": "Ativa explicitamente o provedor JSON smartctl opcional e limitado para dispositivos descobertos.", + "settings.health.providerHelp.disabled": "Desativa provedores de hardware opcionais, mantendo o monitoramento de saúde portátil disponível.", + "settings.health.writeProbe": "Ativar teste de escrita no armazenamento", + "settings.health.writeProbeHelp": "Executa periodicamente o teste limitado do destino de gravação configurado.", + "settings.health.cadences": "Cadências de amostragem", + "settings.health.cadencesHelp": "Os intervalos devem permanecer ordenados do mais rápido até a amostragem de dispositivos e dentro dos limites do servidor.", + "settings.health.fastInterval": "Intervalo rápido", + "settings.health.normalInterval": "Intervalo normal", + "settings.health.slowInterval": "Intervalo lento", + "settings.health.deviceInterval": "Intervalo de dispositivo", + "settings.health.presenceInterval": "Intervalo de presença", + "settings.health.retention": "Retenção de incidentes", + "settings.health.conditions": "Substituições de condição", + "settings.health.conditionsHelp": "Substituir apenas os códigos de condição e unidades retornados pelo registro de política efetiva.", + "settings.health.conditionOverride": "substituição de condição", + "settings.health.overrideMode": "Modo de substituição", + "settings.health.overrideModeHelp": "Herdar o perfil selecionado, selecionar outro perfil limitado, desativar a condição ou definir limiares validados.", + "settings.health.profileDefault": "Usar perfil selecionado", + "settings.health.custom": "Limiares personalizados", + "settings.health.warning": "Limiar de aviso", + "settings.health.critical": "Limiar crítico", + "settings.health.recovery": "Limiar de recuperação", + "settings.health.warning_for_seconds": "Segundos de permanência para aviso", + "settings.health.critical_for_seconds": "Segundos de permanência para crítico", + "settings.health.recovery_for_seconds": "Segundos de permanência para recuperação", + "settings.health.clearOverrides": "Limpar substituições", + "settings.health.registryUnavailable": "O servidor não retornou um registro de condições. Recarregue antes de editar substituições.", + "settings.health.resetDefaults": "Restaurar padrões de saúde", + "settings.health.reloadGuidance": "A gravação é atômica. Recarregue após uma gravação bem-sucedida para confirmar a política efetiva; reinicie apenas quando o servidor solicitar explicitamente.", + "settings.health.validation.profile": "Escolha um perfil de saúde suportado.", + "settings.health.validation.provider": "Escolha um provedor de hardware suportado.", + "settings.health.validation.healthFastIntervalSeconds": "O intervalo rápido deve ser um número inteiro de 5 a 60 segundos.", + "settings.health.validation.healthNormalIntervalSeconds": "O intervalo normal deve ser um número inteiro de 15 a 600 segundos.", + "settings.health.validation.healthSlowIntervalSeconds": "O intervalo lento deve ser um número inteiro de 60 a 3600 segundos.", + "settings.health.validation.healthDeviceIntervalSeconds": "O intervalo de dispositivo deve ser um número inteiro de 300 a 86400 segundos.", + "settings.health.validation.healthPresenceIntervalSeconds": "O intervalo de presença deve ser um número inteiro de 15 a 3600 segundos.", + "settings.health.validation.healthIncidentRetentionDays": "A retenção de incidentes deve ser um número inteiro de 7 a 3650 dias.", + "settings.health.validation.ordered": "Os intervalos de amostragem devem estar ordenados: rápido, normal, lento e dispositivo.", + "settings.health.validation.overrides": "As substituições de condição devem usar códigos únicos e perfis suportados do registro do servidor.", + "settings.health.validation.thresholds": "Os limiares personalizados devem ser valores finitos dentro dos limites da unidade da condição.", + "settings.health.validation.thresholdOrder": "Os limiares de aviso, crítico e recuperação devem preservar a direção do alerta e a histerese da condição.", + "settings.health.validation.dwell": "Os tempos de permanência devem ser segundos inteiros dentro de sete dias; a permanência de aviso e recuperação não pode ser zero.", + "settings.audioCompliance": "Conformidade de áudio", + "settings.disableAudioGlobally": "Desativar áudio nesta instância", + "settings.audioDisabled": "O áudio está desativado globalmente", + "settings.audioComplianceHelp": "Impede escuta ao vivo, comunicação bidirecional e áudio em novas gravações nesta instância. Salvar reinicia as sessões de mídia go2rtc ativas. Gravações existentes não são modificadas.", + "tokens.manage": "Gerenciar acesso à API", + "tokens.title": "Acesso à API — {username}", + "tokens.description": "Crie credenciais com escopo restrito para integrações e revogue cada uma independentemente.", + "tokens.recommendedTitle": "Tokens com escopo são recomendados", + "tokens.recommendedDescription": "Todo token expira, possui ações explícitas e um escopo de câmera, e nunca pode exceder a política de acesso atual do usuário.", + "tokens.coverageNotice": "As permissões disponíveis refletem o que este servidor aplica. Um token só pode usar permissões que seu usuário já possui.", + "tokens.createTitle": "Criar token com escopo", + "tokens.createDescription": "Use um token por integração para que ele possa ser identificado, rotacionado e revogado sem afetar nada mais.", + "tokens.name": "Nome da integração", + "tokens.namePlaceholder": "ex.: Ponte PTZ da garagem norte", + "tokens.expiry": "Expira após", + "tokens.expiryDays": "{days} dias", + "tokens.actions": "Ações permitidas", + "tokens.actionsHelp": "Escolha apenas o que esta integração precisa. Ações destrutivas merecem um token próprio.", + "tokens.destructive": "Destrutiva", + "tokens.noEnforcedActions": "Nenhuma ação habilitada para tokens está disponível nesta versão do servidor.", + "tokens.scope.label": "Escopo de câmera", + "tokens.scope.all": "Toda a frota de câmeras", + "tokens.scope.collection": "Coleção compartilhada", + "tokens.scope.selector": "Seletor personalizado", + "tokens.scope.chooseCollection": "Coleção compartilhada de câmeras", + "tokens.scope.allValue": "Toda a frota", + "tokens.scope.collectionValue": "Coleção: {name}", + "tokens.scope.selectorValue": "Seletor dinâmico personalizado", + "tokens.create": "Criar token", + "tokens.creating": "Criando token…", + "tokens.createdSuccess": "Token de API com escopo criado", + "tokens.createError": "Não foi possível criar o token de API: {message}", + "tokens.invalidResponse": "O servidor retornou uma resposta de credencial incompleta.", + "tokens.existingTitle": "Tokens existentes", + "tokens.existingDescription": "Apenas prefixos e metadados permanecem disponíveis após a criação.", + "tokens.emptyTitle": "Nenhum token ativo", + "tokens.emptyDescription": "Crie um token com escopo para a primeira integração que precisa de acesso à API.", + "tokens.showInactive": "Mostrar {count} inativos", + "tokens.status.active": "Ativo", + "tokens.status.expired": "Expirado", + "tokens.status.revoked": "Revogado", + "tokens.expires": "Expira", + "tokens.expiresValue": "Expira em {date}", + "tokens.created": "Criado", + "tokens.lastUsed": "Último uso", + "tokens.revoke": "Revogar", + "tokens.revoking": "Revogando…", + "tokens.revokeConfirm": "Revogar \"{description}\"? As requisições que o utilizam pararão de funcionar imediatamente.", + "tokens.revokedSuccess": "Token de API revogado", + "tokens.revokeError": "Não foi possível revogar o token de API: {message}", + "tokens.validation.missing_description": "Nomeie a integração que utilizará este token.", + "tokens.validation.description_too_long": "Mantenha o nome da integração com menos de 128 caracteres.", + "tokens.validation.invalid_expiry": "Escolha um tempo de vida do token entre 1 e 365 dias.", + "tokens.validation.missing_actions": "Escolha pelo menos uma ação permitida.", + "tokens.validation.invalid_action": "Uma ou mais ações selecionadas não estão habilitadas para token neste servidor.", + "tokens.validation.invalid_scope": "Escolha um escopo de câmera válido.", + "tokens.validation.requires_all_scope": "Permissões que não são de câmera exigem o escopo de frota inteira de câmeras. Escolha esse escopo ou remova essas permissões.", + "tokens.validation.missing_collection": "Escolha uma coleção compartilhada disponível.", + "tokens.validation.invalid_selector": "Complete ou corrija o seletor de câmera personalizado.", + "tokens.secret.oneTime": "Exibido uma vez", + "tokens.secret.scopedTitle": "Salve este token com escopo agora", + "tokens.secret.legacyTitle": "Salve esta chave de API legada agora", + "tokens.secret.scopedDescription": "O lightNVR armazena apenas um hash deste token. Se ele for perdido, revogue-o e crie outro.", + "tokens.secret.legacyDescription": "Esta chave de compatibilidade é exibida aqui apenas uma vez. Gerar outra chave a invalidará.", + "tokens.secret.value": "Credencial de API", + "tokens.secret.copied": "Copiado", + "tokens.secret.copySuccess": "Credencial de API copiada", + "tokens.secret.copyError": "Não foi possível copiar automaticamente; selecione e copie a credencial manualmente.", + "tokens.secret.savedConfirm": "Salvei esta credencial com segurança", + "tokens.secret.savedHelp": "Confirmar fecha este diálogo. O valor completo não pode ser exibido novamente.", + "tokens.legacy.title": "Chave de compatibilidade legada", + "tokens.legacy.description": "A chave legada possui acesso total efetivo deste usuário, não expira e não pode ser limitada por câmera ou ação.", + "tokens.legacy.warning": "Gere uma apenas para uma integração existente cujos endpoints não migraram para a aplicação de tokens com escopo. Gerá-la invalida imediatamente a chave legada anterior.", + "tokens.legacy.generate": "Gerar chave legada", + "tokens.legacy.confirm": "Gerar uma nova chave legada? Isso invalida imediatamente a chave legada atual do usuário.", + "tokens.legacy.createdSuccess": "Chave de API legada gerada", + "tokens.legacy.createError": "Não foi possível gerar a chave de API legada: {message}", + "audit.manage": "Histórico de auditoria", + "audit.title": "Auditoria de segurança e acesso", + "audit.description": "Rastreie resultados de login, decisões de acesso e alterações sensíveis de política sem expor credenciais.", + "audit.retention": "Retenção", + "audit.retentionDescription": "Os eventos são atualmente retidos por {days} dias. Reduzir este valor remove imediatamente o histórico mais antigo.", + "audit.retentionDays": "Dias", + "audit.retentionInvalid": "Escolha um período de retenção entre 1 e 3650 dias.", + "audit.retentionSaved": "Retenção de auditoria salva; {count} eventos expirados removidos", + "audit.retentionError": "Não foi possível salvar a retenção de auditoria: {message}", + "audit.filters": "Filtros", + "audit.clearFilters": "Limpar filtros", + "audit.applyFilters": "Aplicar filtros", + "audit.actor": "Ator", + "audit.unauthenticated": "Não autenticado", + "audit.outcome": "Resultado", + "audit.action": "Ação exata", + "audit.filterToAction": "Filtrar por esta ação", + "audit.since": "De", + "audit.until": "Até", + "audit.invalidDateRange": "A data \"De\" deve ser anterior à data \"Até\".", + "audit.source": "Endereço de origem", + "audit.target": "Destino", + "audit.targetUuid": "UUID do destino", + "audit.noTarget": "Em todo o sistema", + "audit.requestId": "ID da solicitação", + "audit.apiToken": "ID do token com escopo", + "audit.showDetails": "Mostrar detalhes", + "audit.hideDetails": "Ocultar detalhes", + "audit.pageSize": "Por página", + "audit.resultRange": "Exibindo {start}–{end} de {total}", + "audit.empty": "Nenhum evento de auditoria correspondente", + "audit.emptyDescription": "Tente limpar um ou mais filtros, ou aguarde nova atividade de segurança.", + "audit.exportPage": "Exportar esta página", + "audit.exporting": "Exportando…", + "audit.exported": "Página de auditoria exportada", + "audit.exportError": "Não foi possível exportar eventos de auditoria: {message}", + "audit.pagination": "Páginas do histórico de auditoria", + "audit.page": "Página {page}", + "audit.modesTitle": "Decisões permitidas", + "audit.modesDescription": "Escolha como o acesso somente leitura permitido é registrado para cada ação. Solicitações que alteram algo, negações, erros e inícios de sessão são sempre registrados. Resumir mantém uma entrada por usuário, câmera e cliente a cada {minutes} minutos com uma contagem.", + "audit.mode.record": "Registrar cada", + "audit.mode.summarize": "Resumir", + "audit.mode.off": "Desativado", + "audit.modeOffWarning": "O acesso permitido para esta ação não aparecerá mais no histórico de auditoria.", + "audit.modesSaved": "Modos de decisão de auditoria salvos", + "audit.modesError": "Não foi possível salvar os modos de decisão de auditoria: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Tipo de evento", + "audit.eventTypeSummary": "Resumos", + "audit.eventTypeDecision": "Decisões individuais", + "access.cameraSearch": "Buscar câmeras", + "access.cameraSearchPlaceholder": "Digite pelo menos dois caracteres para buscar…", + "access.cameraSearchHint": "Busque por nome da câmera, UUID, endereço, localização, tag, fabricante ou modelo.", + "access.cameraSelected": "Selecionado", + "access.cameraAdd": "Adicionar", + "access.cameraLimit": "Um seletor pode conter no máximo 64 câmeras explícitas. Use uma regra de localização ou tag para escopos maiores.", + "access.roles.manage": "Gerenciar Papéis", + "access.roles.title": "Papéis de Autorização", + "access.roles.description": "Agrupe ações em papéis reutilizáveis e conceda esses papéis sobre escopos de câmeras.", + "access.roles.create": "Criar Papel", + "access.roles.newRole": "Novo papel", + "access.roles.copyName": "Cópia de {name}", + "access.roles.clone": "Clonar", + "access.roles.builtin": "Integrado", + "access.roles.builtinHelp": "Papéis integrados são modelos fixos e seguros para atualizações. Clone um para personalizá-lo.", + "access.roles.actionCount": "{count} ações", + "access.roles.destructive": "Ação sensível", + "access.roles.notEnforced": "Ainda não aplicado por nenhum endpoint", + "access.roles.destructiveWarning": "Este papel pode alterar configurações ou evidências. Conceda-o apenas sobre os escopos onde essa autoridade é necessária.", + "access.roles.created": "Papel criado", + "access.roles.updated": "Papel atualizado", + "access.roles.deleted": "Papel excluído", + "access.roles.saveError": "Não foi possível salvar o papel: {message}", + "access.roles.deleteError": "Não foi possível excluir o papel: {message}", + "access.roles.deleteConfirm": "Excluir o papel \"{name}\"? Papéis referenciados por concessões não podem ser excluídos.", + "access.policy.manage": "Gerenciar Acesso", + "access.policy.column": "Acesso", + "access.policy.scopedShort": "Com escopo", + "access.policy.title": "Política de Acesso — {username}", + "access.policy.description": "Gerencie concessões de papéis com negar por padrão e visualize seus escopos de câmeras.", + "access.policy.tab.grants": "Concessões", + "access.policy.tab.test": "Testar Acesso", + "access.policy.scopedWarning": "Somente ações permitidas por uma concessão e escopo de câmera correspondentes funcionarão.", + "access.policy.grants": "Concessões de papéis", + "access.policy.grantsDescription": "Uma concessão combina um papel com toda a frota, uma coleção compartilhada ou um seletor de câmeras personalizado.", + "access.policy.addGrant": "Adicionar Concessão", + "access.policy.noGrants": "Nenhuma permissão configurada", + "access.policy.noGrantsHelp": "Adicione pelo menos uma permissão antes de ativar a política de escopo, a menos que este usuário não deva ter acesso.", + "access.policy.role": "Função", + "access.policy.chooseRole": "Escolha uma função", + "access.policy.scope": "Escopo de câmera", + "access.policy.allCameras": "Toda a frota de câmeras", + "access.policy.collectionScope": "Coleção compartilhada", + "access.policy.collection": "Coleção de câmeras", + "access.policy.chooseCollection": "Escolha uma coleção compartilhada", + "access.policy.collectionHelp": "O acesso acompanha a coleção conforme câmeras são adicionadas, removidas ou correspondidas pelas suas regras.", + "access.policy.dynamicScope": "Seletor dinâmico", + "access.policy.activateConfirm": "Ativar política de escopo com negação padrão para {username}? Ações sem uma permissão correspondente serão negadas.", + "access.policy.emptyConfirm": "Ativar política de escopo para {username} sem permissões? Isso remove intencionalmente todo o acesso controlado por política.", + "access.policy.saved": "Política de acesso salva", + "access.policy.saveError": "Não foi possível salvar a política de acesso: {message}", + "access.policy.version": "Versão da política {version}", + "access.policy.unsaved": "Alterações não salvas", + "access.policy.validation.invalid_mode": "Escolha um modo de avaliação válido.", + "access.policy.validation.missing_role": "Cada permissão deve referenciar uma função disponível.", + "access.policy.validation.invalid_scope": "Cada permissão deve usar um escopo de frota inteira, coleção compartilhada ou seletor.", + "access.policy.validation.invalid_selector": "Complete ou corrija cada seletor de câmera antes de salvar.", + "access.policy.validation.missing_collection": "Escolha uma coleção compartilhada disponível para cada permissão de coleção.", + "access.policy.validation.duplicate_grant": "Remova permissões duplicadas de função e escopo antes de salvar.", + "access.test.title": "Testar acesso efetivo", + "access.test.description": "Avalie uma ação salva e uma câmera como {username} sem executá-la.", + "access.test.saveFirst": "Salve ou descarte as alterações de permissão antes de testar para que o resultado reflita a política exibida aqui.", + "access.test.action": "Ação", + "access.test.camera": "Câmera", + "access.test.run": "Testar acesso", + "access.test.running": "Testando…", + "access.test.allowed": "Permitido", + "access.test.denied": "Negado", + "access.test.version": "Versão {version}", + "access.test.source": "Fonte: {source} · Função: {role}", + "recordings.pullToRefresh": "Puxe para atualizar gravações", + "recordings.releaseToRefresh": "Solte para atualizar gravações", + "recordings.refreshing": "Atualizando gravações…", + "recordings.refreshed": "Gravações atualizadas", + "recordings.refreshFailed": "Não foi possível atualizar as gravações: {message}", + "recordings.download": "Baixar", + "recordings.tags": "Tags", + "recordings.selectRecording": "Selecionar gravação", + "timeline.legend.recording": "Gravação", + "timeline.legend.detection": "Evento de detecção", + "timeline.detectionEvent": "Evento de detecção", + "streams.showCredentials": "Mostrar credenciais", + "streams.hideCredentials": "Ocultar credenciais", + "streams.streamSuccessfullyEnabled": "Stream habilitado com sucesso.", + "streams.errorEnablingStream": "Erro ao habilitar stream: {message}", + "system.health.tab": "Saúde", + "system.health.operatorView": "Saúde operacional", + "system.health.title": "Saúde do sistema", + "system.health.loading": "Carregando saúde do sistema…", + "system.health.loadError": "Não foi possível carregar a saúde do sistema.", + "system.health.refreshing": "Atualizando…", + "system.health.activeIncidentCount": "{count} incidentes ativos", + "system.health.coverage": "Cobertura", + "system.health.monitoringDisabled": "Monitoramento de saúde desativado", + "system.health.lastRecordedValue": "Último valor registrado", + "system.health.monitoringDisabledHelp": "Os dados atuais de saúde não estão sendo coletados. Ative o monitoramento de saúde em Configurações → Saúde; reinicie se solicitado após salvar. O histórico de incidentes mostra eventos passados, não o uso atual de recursos.", + "system.health.monitoringRestartRequired": "O monitoramento de saúde está ativado na configuração salva, mas o coletor em execução ainda está desativado. Reinicie o LightNVR para aplicar a alteração. O histórico de incidentes mostra eventos passados.", + "system.health.containerCoverage": "Cobertura limitada do host", + "system.health.hostHardwareUnavailable": "Esta instalação pode ver a saúde de contêineres e recursos montados, mas o hardware do host está indisponível. Valores ausentes do host são desconhecidos, não saudáveis.", + "system.health.coverageUnknown": "Nenhum instantâneo de saúde concluído está disponível ainda. Os valores permanecem desconhecidos até que a coleta seja concluída.", + "system.health.coverageComplete": "Todos os fatos visíveis para esta instalação foram coletados com sucesso.", + "system.health.coveragePartial": "A cobertura é parcial. {count} observações ou verificações de coleta estão indisponíveis, desatualizadas ou incompletas.", + "system.health.effectiveScope": "Escopo efetivo", + "system.health.activeIncidents": "Incidentes ativos", + "system.health.noActiveIncidents": "Nenhum incidente ativo foi reportado para a cobertura visível.", + "system.health.duration": "Duração", + "system.health.currentValue": "Valor atual", + "system.health.thresholds": "Limiar e tempo de permanência", + "system.health.thresholdSummary": "Aviso {warning}, crítico {critical}, recuperação {recovery} {unit}; tempo de permanência do aviso {seconds}s", + "system.health.remediation": "Resposta sugerida", + "system.health.facts": "Fatos de saúde", + "system.health.group.resources": "Recursos", + "system.health.group.storage": "Armazenamento", + "system.health.group.hardware": "Hardware", + "system.health.group.network": "Rede", + "system.health.group.clock": "Relógio", + "system.health.group.components": "Componentes", + "system.health.noFacts": "Nenhum fato visível neste grupo.", + "system.health.observationState": "Capacidade e atualização", + "system.health.valueUnavailable": "Um ou mais valores são desconhecidos", + "system.health.componentStatus": "Componentes de monitoramento", + "system.health.collectors": "Coletores", + "system.health.collectorSummary": "{total} registrados · {attention} precisam de atenção", + "system.health.collectorsNeedingAttention": "Coletores que precisam de atenção", + "system.health.collectionFailures": "{count} falhas ou tempos limite excedidos", + "system.health.stale": "desatualizado", + "system.health.eventDelivery": "Entrega de eventos", + "system.health.degraded": "Degradado", + "system.health.circularDelivery": "Este é o único caminho de alerta configurado, portanto não pode reportar independentemente sua própria falha.", + "system.health.incidentPersistence": "Persistência de incidentes", + "system.health.persistenceSummary": "{pending} pendentes · {failures} falhas · {retries} tentativas", + "system.health.recentSamples": "Atividade recente de coleta", + "system.health.recentSamplesHelp": "Até {count} resumos de geração do lado do servidor; isto é atividade de cobertura, não um gráfico de valores.", + "system.health.sampleSequence": "Geração {sequence}", + "system.health.sampleCoverage": "{observations} observações · {dropped} descartadas", + "system.health.noSamples": "Nenhuma geração de coleta concluída está disponível.", + "system.health.incidentHistory": "Histórico de incidentes", + "system.health.incidentHistoryHelp": "Incidentes mais recentes primeiro. O histórico é carregado em páginas limitadas.", + "system.health.loadingHistory": "Carregando histórico de incidentes…", + "system.health.historyError": "Não foi possível carregar o histórico de incidentes.", + "system.health.emptyHistory": "Nenhum incidente foi registrado.", + "system.health.firstSeen": "Primeira ocorrência", + "system.health.lastSeen": "Última ocorrência", + "system.health.deliveryState": "Estado de entrega", + "system.health.historyPagination": "Páginas do histórico de incidentes", + "system.health.pageCount": "{count} incidentes nesta página", + "system.health.remediation.memory": "Reduza a pressão de memória, verifique os limites de processo e cgroup, e revise a atividade recente de OOM.", + "system.health.remediation.cpu": "Identifique consumidores sustentados de CPU e verifique a vazão do serviço antes de alterar limites.", + "system.health.remediation.io": "Verifique a latência de armazenamento e escritores ativos; preserve gravações antes de manutenção disruptiva.", + "system.health.remediation.filesystem": "Verifique o sistema de arquivos lógico nomeado, espaço livre ou inodes, e confirme que permanece gravável.", + "system.health.remediation.thermal": "Melhore o resfriamento e reduza a carga; inspecione ventiladores e saídas de ar antes que as temperaturas atinjam limites de desligamento.", + "system.health.remediation.network": "Verifique a interface visível, link, switch e contadores de erros por um caminho de rede independente.", + "system.health.remediation.clock": "Restaure a sincronização de tempo e verifique a fonte do relógio do host antes de confiar nos timestamps de eventos.", + "system.health.remediation.process": "Inspecione os limites de recursos e logs do LightNVR, depois reduza a carga ou aumente limites validados.", + "system.health.remediation.storage": "Faça backup de gravações importantes e inspecione o dispositivo de armazenamento mapeado antes de substituição ou reparo.", + "system.health.remediation.hardware": "Inspecione o hardware afetado e os logs da plataforma; agende manutenção se a condição persistir.", + "system.health.remediation.health": "Restaure o acesso e as permissões do coletor para que as evidências de saúde ausentes possam ser avaliadas.", + "system.health.remediation.system": "Revise a execução anterior e os logs do host para distinguir uma reinicialização de processo de um reinício do host.", + "system.health.remediation.event": "Use a API local ou a visualização de métricas, alivie a pressão da fila durável e restaure um destino de alerta independente.", + "system.health.remediation.default": "Revise o componente afetado e os logs recentes, depois verifique a recuperação em uma nova geração de saúde.", + "system.capacityTarget": "Meta de capacidade", + "system.capacityTargetValue": "Manter {pct}% livre", + "system.fillRate": "Taxa de preenchimento", + "system.fillRateValue": "{value} / dia", + "system.projectedToTarget": "Tempo projetado até o alvo", + "system.projectedNow": "No alvo ou acima agora", + "system.projectedDays": "~{count}d", + "system.projectedHours": "~{count}h", + "system.projectedUnknown": "—", + "common.description": "Descrição", + "common.remove": "Remover", + "streams.selectStream": "Selecionar {name}", + "streams.search": "Buscar streams", + "streams.noStreamsMatchFilters": "Nenhum stream corresponde aos filtros atuais.", + "streamHealth.sourceConnected": "Fonte conectada", + "streamHealth.videoAdvancing": "Vídeo avançando", + "streamHealth.recorderWriting": "Gravador escrevendo", + "streamHealth.detectorOperating": "Detector operando", + "streamHealth.lastSegment": "Último segmento concluído", + "streams.disablingStreamsProgress": "Desativando streams…", + "streams.onvifInvalidAddress": "O endereço IP do dispositivo ONVIF está ausente ou inválido.", + "streams.warningFallingBackToHttp": "A conexão HTTPS falhou; tentando novamente via HTTP. As credenciais podem ser enviadas em texto simples.", + "streamsConfig.playbackTransport": "Transporte de reprodução", + "streamsConfig.playbackTransportHelp": "Escolha o método de reprodução no navegador para esta câmera e, quando selecionado, sua ordem de fallback.", + "streamsConfig.playbackTransportUnavailable": "Indisponível no servidor: {transports}. Ative o transporte globalmente ou escolha outro perfil.", + "streamsConfig.audioDisabledByPolicy": "O áudio está desativado pela política da instância", + "streamsConfig.audioDisabledByPolicyHelp": "Gravação, escuta ao vivo e comunicação bidirecional estão indisponíveis enquanto a política global de conformidade de áudio estiver ativada.", + "streamsConfig.audioVoiceEnhancement": "Aprimoramento de voz (gravações)", + "streamsConfig.customApiModel": "Detecção de API personalizada", + "streamsConfig.modelNotSupportedByBuild": "não suportado por esta versão", + "streamsConfig.tierCriticalMultiplier": "Nível crítico ×", + "streamsConfig.tierImportantMultiplier": "Nível importante ×", + "streamsConfig.tierEphemeralMultiplier": "Nível efêmero ×", + "streamsConfig.tierMultipliersHelp": "Multiplicadores por nível sobre a retenção base. Gravações de nível superior são mantidas por mais tempo e removidas por último sob pressão de disco.", + "streamsConfig.storagePriority": "Prioridade de armazenamento (1-10)", + "streamsConfig.storagePriorityHelp": "Importância relativa das gravações deste stream ao recuperar espaço; prioridade mais alta é preservada por mais tempo.", + "streamsConfig.restream": "Transmitir / Publicar (RTMP)", + "streamsConfig.publishUrl": "URL de publicação (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "Transmita esta câmera para um serviço como YouTube Live via go2rtc. Cole a URL completa de ingestão RTMP incluindo a chave de stream (ex.: rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Para transmitir para vários serviços ao mesmo tempo, separe as URLs com vírgulas. O YouTube requer vídeo H264 e áudio AAC; o LightNVR agora transcodifica automaticamente (H264 para câmeras não-H264, AAC para áudio não-AAC), então a maioria das câmeras funciona como está. Nota: o YouTube também requer uma faixa de áudio — uma câmera sem áudio será rejeitada. Deixe em branco para desabilitar.", + "streams.lastSeen": "Visto por último {time}", + "streams.claimed": "Reivindicado", + "streams.duplicateSuspected": "Possível duplicata", + "streams.duplicateSuspectedHelp": "Evidência de identidade estável ou endpoint conflita com outro registro de descoberta.", + "streams.onvifClaimWarning": "O stream foi adicionado, mas seu registro de descoberta não pôde ser marcado como reivindicado: {message}", + "common.online": "Online", + "common.offline": "Offline", + "settings.storageTargets.title": "Destinos de armazenamento de gravações", + "settings.storageTargets.description": "Registre discos locais e sistemas de arquivos NFS ou SMB montados pelo administrador como destinos de gravação monitorados independentemente.", + "settings.storageTargets.foundationNotice": "A captura usa destinos de sistema de arquivos. Buckets S3 e destinos NFS/SAN montados podem armazenar cópias de arquivo verificadas. A pressão hot preserva gravações arquivadas até que sua retenção lógica expire.", + "settings.storageTargets.add": "Adicionar destino de armazenamento", + "settings.storageTargets.edit": "Editar destino de armazenamento", + "settings.storageTargets.editorHelp": "Destinos habilitados devem já existir e passar em um teste de escrita, fsync e limpeza. Salve uma montagem futura indisponível como desabilitada e habilite-a após a montagem.", + "settings.storageTargets.name": "Nome do destino", + "settings.storageTargets.root": "Caminho raiz montado", + "settings.storageTargets.rootLocked": "Um destino padrão ou não vazio mantém uma raiz imutável para que gravações existentes não fiquem órfãs.", + "settings.storageTargets.class": "Classe de desempenho", + "settings.storageTargets.hot": "Hot — gravação ativa", + "settings.storageTargets.warm": "Warm — arquivo montado", + "settings.storageTargets.cold": "Cold — acesso infrequente", + "settings.storageTargets.reserveGb": "Espaço reservado (GB)", + "settings.storageTargets.lowWatermark": "Marca baixa (% usado)", + "settings.storageTargets.highWatermark": "Marca alta (% usado)", + "settings.storageTargets.migrationBandwidth": "Largura de banda do ciclo de vida (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 é ilimitado. O limite é registrado quando um trabalho de movimentação ou cópia é criado.", + "settings.storageTargets.archiveStart": "Início da janela de arquivamento", + "settings.storageTargets.archiveEnd": "Fim da janela de arquivamento", + "settings.storageTargets.archiveWindowHelp": "Horário local. Início e fim iguais permitem trabalhos de ciclo de vida o dia todo; uma janela noturna pode cruzar a meia-noite.", + "settings.storageTargets.enabled": "Habilitado (políticas de alocação podem selecionar este destino)", + "settings.storageTargets.notRouted": "Nenhuma política de alocação habilitada direciona câmeras para aqui. Novas gravações continuam indo para o destino padrão até que uma política defina este destino como primário, membro de pool ou destino de arquivamento.", + "settings.storageTargets.degradedNotice": "Acima do limite superior ou dentro da reserva. As políticas de alocação ignoram este destino até que espaço seja liberado.", + "settings.storageTargets.probePassedIneligible": "Teste de escrita aprovado, mas o destino está {status}: as políticas de alocação não o selecionarão.", + "settings.storageTargets.mountRequired": "Exigir um sistema de arquivos montado", + "settings.storageTargets.mountRequiredHelp": "Fixar este destino ao ponto de montagem não raiz atual. Se a montagem NFS, SMB, bind ou PVC desaparecer, a gravação pausa em vez de escrever no diretório subjacente do host.", + "settings.storageTargets.mountGuard": "Montagem obrigatória", + "settings.storageTargets.mountPending": "Será detectado quando o destino for habilitado", + "settings.storageTargets.default": "Padrão", + "settings.storageTargets.capacity": "Capacidade", + "settings.storageTargets.available": "Disponível", + "settings.storageTargets.recordings": "Gravações indexadas", + "settings.storageTargets.replicas": "{count} cópias verificadas · {bytes}", + "settings.storageTargets.reserve": "Reservado", + "settings.storageTargets.pressure.normal": "Pressão normal", + "settings.storageTargets.pressure.high": "Limite superior", + "settings.storageTargets.pressure.reserve": "Reserva excedida", + "settings.storageTargets.pressure.unavailable": "Pressão indisponível", + "settings.storageTargets.cleanupActive": "A limpeza por destino está ativa e trabalhará para manter {target} disponível sem excluir gravações atribuídas a outro destino.", + "settings.storageTargets.test": "Testar destino", + "settings.storageTargets.probing": "Testando…", + "settings.storageTargets.probePassed": "Teste de escrita no destino de armazenamento aprovado", + "settings.storageTargets.duplicateFilesystem": "Esta raiz compartilha o mesmo sistema de arquivos subjacente de outro destino. A capacidade não deve ser contada duas vezes quando a alocação está habilitada.", + "settings.storageTargets.deleteLocked": "Destinos padrão e não vazios não podem ser excluídos.", + "settings.storageTargets.deleteConfirm": "Excluir o destino de armazenamento vazio \"{name}\"? Nenhum arquivo será removido.", + "settings.storageTargets.created": "Destino de armazenamento criado", + "settings.storageTargets.updated": "Destino de armazenamento atualizado", + "settings.storageTargets.deleted": "Destino de armazenamento excluído", + "settings.storageTargets.invalidThresholds": "Verifique os limites, a reserva, a largura de banda do ciclo de vida e os horários da janela de arquivamento.", + "settings.storageTargets.loadError": "Não foi possível carregar os destinos de armazenamento", + "settings.storagePools.title": "Pools de armazenamento", + "settings.storagePools.description": "Agrupe destinos saudáveis para transbordamento automático e replicação em destinos distintos.", + "settings.storagePools.add": "Adicionar pool", + "settings.storagePools.strategy": "Estratégia de alocação", + "settings.storagePools.mostFree": "Mais espaço livre", + "settings.storagePools.roundRobin": "Rodízio", + "settings.storagePools.priority": "Prioridade explícita", + "settings.storagePools.members": "Destinos (a ordem de exibição é a prioridade de alocação)", + "settings.storagePools.enabled": "Pool habilitado", + "settings.storagePools.active": "Ativo", + "settings.storagePools.inactive": "Desabilitado", + "settings.storagePools.strategyValue.most_free": "mais livre", + "settings.storagePools.strategyValue.round_robin": "rodízio", + "settings.storagePools.strategyValue.priority": "ordem de prioridade", + "settings.storagePools.created": "Pool de armazenamento criado", + "settings.storagePools.updated": "Pool de armazenamento atualizado", + "settings.storagePools.deleted": "Pool de armazenamento excluído", + "settings.storagePools.deleteConfirm": "Excluir pool de armazenamento \"{name}\"?", + "settings.storagePools.empty": "Nenhum pool de armazenamento ainda.", + "settings.storageMigrations.title": "Tarefas de migração de gravações", + "settings.storageMigrations.description": "Movimentos duráveis e cópias retidas respeitam a janela de arquivamento e o limite de largura de banda de cada destino, verificam SHA-256 e se recuperam com segurança após reinicialização.", + "settings.storageMigrations.empty": "Nenhuma tarefa de migração de gravações ainda.", + "settings.storageMigrations.loadError": "Não foi possível carregar as tarefas de migração de gravações", + "settings.storageMigrations.recording": "Gravação #{id}", + "settings.storageMigrations.attempt": "Tentativa {current}/{max}", + "settings.storageMigrations.operation.move": "Mover", + "settings.storageMigrations.operation.copy": "Cópia retida", + "settings.storageMigrations.cancelled": "Cancelamento de migração aceito", + "settings.storageMigrations.cancelling": "Cancelando…", + "settings.storageMigrations.retried": "Migração na fila para nova tentativa", + "settings.storageMigrations.state.queued": "Na fila", + "settings.storageMigrations.state.copying": "Copiando", + "settings.storageMigrations.state.verifying": "Verificando", + "settings.storageMigrations.state.committing": "Confirmando", + "settings.storageMigrations.state.cleanup_pending": "Limpando origem", + "settings.storageMigrations.state.retry_wait": "Aguardando nova tentativa", + "settings.storageMigrations.state.completed": "Concluído", + "settings.storageMigrations.state.failed": "Falhou", + "settings.storageMigrations.state.cancelled": "Cancelado", + "settings.storagePolicies.title": "Políticas de posicionamento de câmera", + "settings.storagePolicies.description": "Encaminha câmeras correspondentes para um alvo de gravação primário em ordem de prioridade. Uma câmera usa a primeira política habilitada que corresponde.", + "settings.storagePolicies.add": "Adicionar política de posicionamento", + "settings.storagePolicies.edit": "Editar política de posicionamento", + "settings.storagePolicies.editorHelp": "A política é reavaliada para novos segmentos. Alterações não movem gravações que já existem.", + "settings.storagePolicies.priority": "Prioridade (maior primeiro)", + "settings.storagePolicies.priorityValue": "Prioridade {priority}", + "settings.storagePolicies.primary": "Alvo primário", + "settings.storagePolicies.primaryPool": "Pool de posicionamento (opcional)", + "settings.storagePolicies.exactTarget": "Usar alvo primário exato", + "settings.storagePolicies.fallback": "Se o primário estiver indisponível", + "settings.storagePolicies.fallbackDefault": "Usar o alvo padrão", + "settings.storagePolicies.fallbackTarget": "Usar um alvo de fallback nomeado", + "settings.storagePolicies.fallbackPause": "Pausar gravação", + "settings.storagePolicies.fallbackFail": "Falhar ao iniciar gravação", + "settings.storagePolicies.namedFallback": "Alvo de fallback", + "settings.storagePolicies.chooseTarget": "Escolher um alvo", + "settings.storagePolicies.choosePool": "Escolher um pool", + "settings.storagePolicies.minimumDays": "Retenção mínima (dias)", + "settings.storagePolicies.desiredDays": "Retenção desejada (dias)", + "settings.storagePolicies.maximumDays": "Retenção máxima (dias)", + "settings.storagePolicies.copyCount": "Cópias verificadas obrigatórias", + "settings.storagePolicies.replicationPool": "Pool de replicação", + "settings.storagePolicies.migrateAfter": "Mover após (dias)", + "settings.storagePolicies.migrationTarget": "Alvo de arquivamento", + "settings.storagePolicies.pressurePriority": "Prioridade de exclusão por pressão (menor primeiro)", + "settings.storagePolicies.disabledTarget": "desabilitado", + "settings.storagePolicies.enabled": "Política habilitada", + "settings.storagePolicies.selector": "Câmeras correspondentes", + "settings.storagePolicies.preview": "Precedência da pré-visualização", + "settings.storagePolicies.previewing": "Avaliando…", + "settings.storagePolicies.previewRequired": "Pré-visualize o rascunho atual antes de salvar para ver a sobreposição de câmeras e a política vencedora efetiva.", + "settings.storagePolicies.previewSummary": "Corresponde a {matched} câmeras; este rascunho é efetivo para {effective}.", + "settings.storagePolicies.previewShadowed": "Uma política de maior precedência vence para {count} câmeras correspondentes.", + "settings.storagePolicies.previewWins": "Vence \"{policy}\" (prioridade {priority}) para {count} câmeras.", + "settings.storagePolicies.previewLoses": "Perde para \"{policy}\" (prioridade {priority}) para {count} câmeras.", + "settings.storagePolicies.previewNoMatches": "Este seletor atualmente não corresponde a nenhuma câmera.", + "settings.storagePolicies.invalidPriority": "A prioridade deve ser um número inteiro entre -1.000.000 e 1.000.000.", + "settings.storagePolicies.invalidLifecycle": "Verifique a ordem de retenção, contagem de cópias e pool de replicação, e idade e destino de migração.", + "settings.storagePolicies.created": "Política de posicionamento criada", + "settings.storagePolicies.updated": "Política de posicionamento atualizada", + "settings.storagePolicies.deleted": "Política de posicionamento excluída", + "settings.storagePolicies.deleteConfirm": "Excluir a política de posicionamento \"{name}\"? As gravações existentes não são afetadas.", + "settings.storagePolicies.active": "Ativa", + "settings.storagePolicies.inactive": "Desativada", + "settings.storagePolicies.routesTo": "Destino principal: {target}", + "settings.storagePolicies.lifecycleSummary": "Retenção mín./desejada/máx.: {minimum}/{desired}/{maximum} dias · {copies} cópia(s) verificada(s)", + "settings.storagePolicies.fallsBackTo": "Destino alternativo: {target}", + "settings.storagePolicies.mode.default": "Alternativa: destino padrão", + "settings.storagePolicies.mode.pause": "Alternativa: pausar gravação", + "settings.storagePolicies.mode.fail": "Alternativa: falhar ao iniciar gravação", + "settings.storagePolicies.empty": "Nenhuma política de posicionamento. As câmeras continuam usando o destino padrão; outros destinos não recebem nada até que uma política direcione câmeras para eles.", + "settings.storagePolicies.archiveNoTrigger": "Um destino de arquivamento está definido, mas nada aciona uma movimentação. Defina 'Mover após idade (dias)', uma idade de arquivamento ou uma opção de arquivamento; caso contrário, nenhuma gravação será movida.", + "settings.storageCompliance.title": "Conformidade de capacidade e política", + "settings.storageCompliance.description": "Taxas observadas em 30 dias preveem a pressão do destino e a retenção alcançada; violações ativas do ciclo de vida permanecem visíveis até serem resolvidas.", + "settings.storageCompliance.loadError": "Não foi possível carregar a conformidade de armazenamento", + "settings.storageCompliance.unknown": "Desconhecido", + "settings.storageCompliance.days": "{days} dias", + "settings.storageCompliance.day": "dia", + "settings.storageCompliance.targetForecasts": "Previsões do destino", + "settings.storageCompliance.target": "Alvo", + "settings.storageCompliance.dailyRate": "Taxa observada", + "settings.storageCompliance.toHigh": "Até o limite superior", + "settings.storageCompliance.expected": "Retenção esperada", + "settings.storageCompliance.confidence": "Confiança", + "settings.storageCompliance.policyCompliance": "Conformidade com a política", + "settings.storageCompliance.compliant": "Nenhuma violação ativa", + "settings.storageCompliance.violationCount": "{count} violação(ões)", + "settings.storageCompliance.policyForecast": "Atingido {achieved}; previsto {expected}; desejado {desired} dias.", + "settings.storageCompliance.copyDeficits": "{count} gravação(ões) precisa(m) de outra cópia verificada.", + "settings.storageCompliance.activeViolations": "Violações ativas", + "settings.storageCompliance.type.copy_count": "Contagem de cópias", + "settings.storageCompliance.type.minimum_retention": "Capacidade mínima de retenção", + "settings.storageCompliance.type.target_unavailable": "Alvo indisponível", + "settings.storageCompliance.type.migration_failed": "Falha na tarefa de ciclo de vida", + "settings.recordingDirectoryFormat": "Layout de pastas de gravação", + "settings.recordingDirectoryFormatHelp": "Organiza novas gravações MP4 em subpastas dentro da pasta de cada câmera. Gravações existentes não são movidas.", + "settings.recordingDirectoryFlat": "Plano (apenas pasta da câmera)", + "settings.recordingDirectoryMonth": "Por mês (AAAA/MM)", + "settings.recordingDirectoryDay": "Por dia (AAAA/MM/DD)", + "settings.minFreePct": "Espaço livre mínimo (%)", + "settings.minFreePctHelp": "Mantenha pelo menos essa porcentagem do volume livre removendo automaticamente as gravações mais antigas, independentemente dos dias de retenção. Isso limita o uso ao tamanho do disco — defina-o e o disco nunca enche. 0 desativa o limite de capacidade.", + "settings.pressureThresholds": "Limiares de pressão do disco (%)", + "settings.pressureThresholdsHelp": "Faixas de espaço livre que escalam a limpeza automática. Devem satisfazer emergência < crítico < aviso.", + "settings.pressureWarningPct": "Aviso abaixo de (% livre)", + "settings.pressureCriticalPct": "Crítico abaixo de (% livre)", + "settings.pressureEmergencyPct": "Emergência abaixo de (% livre)", + "settings.databaseBackupVerify": "Verificação de backup", + "settings.databaseBackupVerifyFull": "Completa (integrity_check, verifica todos os índices)", + "settings.databaseBackupVerifyQuick": "Rápida (quick_check, apenas estrutura de páginas)", + "settings.databaseBackupVerifyOff": "Desativado (sem verificação pós-cópia)", + "settings.databaseBackupVerifyHelp": "Verificação aplicada a cada backup copiado antes de ser publicado. A verificação completa pode levar mais tempo que a cópia em um banco de dados grande em disco mecânico e pode atingir a válvula de segurança de 30 minutos, descartando aquele backup; a verificação rápida ainda detecta páginas corrompidas ou truncadas com muito menos buscas.", + "settings.viewMethodAuto": "Auto — preferência por câmera com alternativa", + "settings.resetWizardPending": "Iniciando assistente…", + "settings.apiDetectionFormat": "Formato de requisição da API", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (upload de imagem multipart)", + "settings.apiDetectionFormatDoods2": "DOODS2 (corpo JSON com imagem base64)", + "settings.apiDetectionFormatHelp": "Formato de transmissão que o LightNVR usa ao enviar snapshots para a API de detecção. Mantenha light-object-detect para light-object-detect ou qualquer servidor que implemente seu contrato; escolha DOODS2 para um servidor DOODS2.", + "settings.apiDetectionUrlHelpDoods2": "Endpoint /detect do DOODS2, ex.: http://localhost:8080/detect. A requisição é enviada como JSON e nenhum parâmetro de consulta é adicionado.", + "settings.apiDetectionDetectorName": "Nome do detector DOODS2", + "settings.apiDetectionDetectorNameHelp": "Enviado como detector_name em cada requisição. Deve corresponder a um detector listado pelo servidor em GET /detectors; \"default\" usa o detector padrão do servidor.", + "settings.defaultPlaybackTransport": "Transporte de reprodução padrão", + "settings.defaultPlaybackTransportHelp": "Perfil de reprodução aplicado a streams recém-criados. Streams existentes mantêm sua própria seleção.", + "playbackTransport.auto": "Auto (recomendado)", + "playbackTransport.webrtcOnly": "Somente WebRTC", + "playbackTransport.mseOnly": "Somente MSE", + "playbackTransport.hlsOnly": "Somente HLS", + "playbackTransport.webrtcThenMse": "WebRTC, depois MSE", + "playbackTransport.mseThenHls": "MSE, depois HLS", + "investigation.load": "Carregar investigação", + "investigation.loading": "Carregando investigação…", + "investigation.confidenceError": "A confiança mínima deve estar entre 0 e 1.", + "investigation.regionActive": "Buscando caixas armazenadas de {camera}. Um resultado ausente não é prova de que nada cruzou a área.", + "investigation.regionMatch": "Correspondência de caixa", + "investigation.regionMatch.center": "Centro dentro", + "investigation.regionMatch.intersects": "Qualquer interseção", + "investigation.regionMatch.minimumIntersection": "Sobreposição mínima", + "investigation.regionMinimumOverlap": "Sobreposição mínima (%)", + "investigation.regionLeft": "Esquerda (%)", + "investigation.regionTop": "Topo (%)", + "investigation.regionWidth": "Largura (%)", + "investigation.regionHeight": "Altura (%)", + "investigation.drawingRegion": "Desenhando área de busca…", + "investigation.clearRegion": "Limpar área", + "investigation.drawRegionPrompt": "Arraste sobre o vídeo para definir a área de busca", + "investigation.searching": "Buscando eventos…", + "investigation.searchHelp": "Carregue uma investigação para buscar seus metadados de eventos persistidos.", + "investigation.results": "resultados", + "investigation.previousResultShortcut": "Evento anterior ([)", + "investigation.nextResultShortcut": "Próximo evento (])", + "investigation.noThumbnail": "Sem miniatura", + "investigation.exploreSelectedThumbnails": "Explorar ao redor do evento", + "investigation.thumbnailDrilldown": "Detalhamento por miniatura", + "investigation.thumbnailDrilldownHelp": "Escolha qualquer momento, incluindo lacunas, para mover o cursor compartilhado e gerar um conjunto mais restrito de amostras.", + "investigation.selectThumbnailSample": "Inspecionar ao redor de {time}", + "investigation.loadingThumbnail": "Carregando miniatura…", + "investigation.thumbnailUnavailable": "Miniatura indisponível", + "investigation.loadingSamples": "Carregando amostras de miniaturas…", + "investigation.thumbnailCoverageTruncated": "Este intervalo contém mais gravações do que o amostrador pôde inspecionar. Reduza a janela de tempo para cobertura completa.", + "investigation.bookmarks.saveTitle": "Salvar marcador de investigação", + "investigation.bookmarks.listTitle": "Marcadores de investigação", + "investigation.bookmarks.notHold": "Um marcador restaura esta visualização, mas não protege as gravações da retenção ou exclusão normal.", + "investigation.bookmarks.title": "Nome do marcador", + "investigation.bookmarks.note": "Nota privada (opcional)", + "investigation.bookmarks.titleRequired": "Digite um nome para o marcador.", + "investigation.bookmarks.empty": "Você não possui marcadores de investigação salvos.", + "investigation.bookmarks.cameraCount": "{count} câmera(s)", + "investigation.bookmarks.restore": "Abrir", + "investigation.bookmarks.confirmDelete": "Excluir marcador?", + "investigation.actions.title": "Gravações da investigação", + "investigation.actions.notEvidenceExport": "A proteção impede a exclusão por retenção normal. O download ZIP é uma exportação de conveniência, não um pacote de evidências verificado.", + "investigation.actions.scope": "Escopo da gravação", + "investigation.actions.selectedResult": "Evento e câmera selecionados", + "investigation.actions.fullWindow": "Todas as câmeras na janela da investigação", + "investigation.actions.preview": "Pré-visualizar gravações", + "investigation.actions.previewing": "Buscando gravações sobrepostas…", + "investigation.actions.invalidRange": "Escolha um intervalo de tempo válido com o fim após o início.", + "investigation.actions.recordingCount": "{count} gravação(ões) sobreposta(s)", + "investigation.actions.protectedCount": "{count} já protegida(s)", + "investigation.actions.noRecordings": "Nenhuma gravação concluída se sobrepõe a esta câmera e seleção de tempo.", + "investigation.actions.protectDenied": "{count} gravação(ões) não protegida(s) estão fora do seu escopo de proteção e foram excluídas desta ação.", + "investigation.actions.exportDenied": "Permissão de exportação ausente para {count} gravação(ões). Downloads são tudo ou nada, então esta seleção não pode ser exportada.", + "investigation.actions.camera": "Câmera", + "investigation.actions.recording": "Gravação", + "investigation.actions.size": "Tamanho", + "investigation.actions.notPermitted": "Não permitido", + "investigation.actions.protectButton": "Proteger {count}", + "investigation.actions.protecting": "Protegendo…", + "investigation.actions.protectUnavailable": "Não há gravações não protegidas que você tem permissão para proteger.", + "investigation.actions.protectResult": "Proteção concluída: {success} com sucesso, {failed} com falha.", + "investigation.actions.downloadButton": "Baixar {count}", + "investigation.actions.downloadUnavailable": "Cada gravação requer permissão de exportação antes que um ZIP possa ser criado.", + "investigation.actions.buildingArchive": "Gerando ZIP…", + "investigation.actions.downloadFailed": "Falha na criação do ZIP no servidor.", + "investigation.actions.downloadTimedOut": "A criação do ZIP não foi concluída em cinco minutos. Tente um intervalo mais curto.", + "investigation.actions.downloadStarted": "Download do ZIP iniciado.", + "investigation.backOneLevel": "Voltar um nível", + "investigation.thumbnailMinimumWindow": "Este é o intervalo de um segundo mais estreito disponível. O cursor compartilhado ainda se moveu para o momento selecionado.", + "investigation.localSource": "local", + "investigation.mediaAvailable": "Mídia disponível", + "investigation.durationSeconds": "Duração de {count}s", + "investigation.pageNumber": "Página {count}", + "investigation.incompleteCoverage": "{count} linhas de eventos legados não puderam ser atribuídas a uma identidade de câmera imutável.", + "investigation.spatialCoverageGap": "{count} linhas de eventos no escopo não tinham caixa delimitadora e não foram pesquisadas espacialmente.", + "investigation.noSpatialMetadata": "Nenhum evento no escopo possui caixa delimitadora para esta busca de metadados.", + "investigation.selectCameraError": "Selecione pelo menos uma câmera.", + "investigation.selectRecordingError": "Selecione pelo menos uma gravação.", + "investigation.investigateSelectedCount": "Investigar {count} gravação(ões) selecionada(s)", + "investigation.missingCameraIdentity": "Não é possível investigar: {count} gravação(ões) selecionada(s) não possuem identidade de câmera.", + "investigation.recordingTimeError": "As gravações selecionadas não possuem um intervalo de tempo válido.", + "investigation.windowLimit": "As gravações selecionadas ultrapassam o limite de investigação de 31 dias.", + "investigation.timeRangeError": "A hora de término deve ser posterior à hora de início.", + "investigation.cameraLimit": "Uma investigação pode incluir no máximo {count} câmeras.", + "investigation.decoderLimit": "Apenas {count} players de câmera podem estar ativos ao mesmo tempo.", + "investigation.playbackControls": "Controles de reprodução sincronizada", + "investigation.play": "Reproduzir", + "investigation.pause": "Pausar", + "investigation.mode": "Modo de reprodução", + "investigation.wallClock": "Relógio de parede", + "investigation.skipCommonGaps": "Pular lacunas comuns", + "investigation.speed": "Velocidade", + "investigation.sharedCursor": "Cursor UTC compartilhado", + "investigation.activePlayers": "players ativos", + "investigation.timeline": "linha do tempo compartilhada", + "investigation.truncated": "truncado", + "investigation.players": "Players de câmera sincronizados", + "investigation.activateCamera": "Ative pelo menos uma linha da linha do tempo para carregar o vídeo.", + "investigation.noFootageAtTime": "Nenhuma gravação no horário compartilhado", + "investigation.primaryAudio": "Áudio principal", + "investigation.makePrimary": "Definir como principal", + "investigation.status.loading": "Carregando mídia", + "investigation.status.synchronizing": "Sincronizando", + "investigation.status.ready": "Sincronizado", + "investigation.status.late": "Atrasado — recuperando", + "investigation.status.error": "Mídia indisponível", + "investigation.status.paused-by-browser": "Selecione reproduzir para permitir a mídia", + "streamsConfig.eptzTitle": "Fisheye ePTZ", + "streamsConfig.eptzEnable": "Ativar fisheye ePTZ no navegador", + "streamsConfig.eptzHelp": "Desdistorça o stream fisheye original na Visualização ao vivo, Reprodução na linha do tempo e Investigação. Isso não altera gravações nem a saída da câmera.", + "streamsConfig.eptzModelHelp": "Projeção: fisheye circular equidistante · Montagem: teto. Centro e raio usam coordenadas normalizadas da imagem de origem.", + "streamsConfig.eptzCenterX": "Centro óptico X", + "streamsConfig.eptzCenterY": "Centro óptico Y", + "streamsConfig.eptzRadius": "Raio do círculo de imagem", + "streamsConfig.eptzLensFov": "FOV da lente (graus)", + "streamsConfig.eptzRotation": "Rotação da lente (graus)", + "streamsConfig.eptzDefaultYaw": "Pan padrão (graus)", + "streamsConfig.eptzDefaultTilt": "Tilt padrão (graus)", + "streamsConfig.eptzViewFov": "FOV de visão padrão", + "streamsConfig.eptzCalibrationHelp": "Arraste para olhar ao redor, use a roda do mouse ou pinça para zoom e pressione Home para redefinir a câmera virtual. Ajuste o centro e o raio se a borda do círculo de imagem não estiver alinhada.", + "settings.archive.targetType": "Tipo de armazenamento", + "settings.archive.filesystem": "Sistema de arquivos local ou montado (NFS/SAN)", + "settings.archive.s3": "Bucket de arquivamento compatível com S3", + "settings.archive.endpoint": "Endpoint HTTPS", + "settings.archive.region": "Região", + "settings.archive.bucket": "Bucket dedicado", + "settings.archive.credential_ref": "Referência de credencial", + "settings.archive.budget": "Orçamento de arquivamento (GiB, 0 = ilimitado)", + "settings.archive.connectionHelp": "Use um bucket privado, sem versionamento e sem regras de expiração de ciclo de vida. A referência de credencial seleciona um arquivo de segredo montado no servidor. Insira o local gerenciado como s3://bucket/instance-prefix.", + "settings.archive.policy": "Política de arquivamento externo", + "settings.archive.archive_after_seconds": "Arquivar após captura (segundos, -1 = desativado)", + "settings.archive.hot_residency_seconds": "Manter cópia quente (segundos, -1 = mover após arquivamento)", + "settings.archive.archive_protected": "Priorizar arquivamento de gravações protegidas", + "settings.archive.archive_on_pressure": "Arquivar antecipadamente quando o armazenamento quente estiver sob pressão", + "settings.archive.policyHelp": "O tempo de arquivamento usa a idade da captura e requer uma gravação concluída. -1 desativa o arquivamento por idade ou remove o mínimo de permanência quente; 0 significa imediatamente. As edições se aplicam a novas gravações. Revise as gravações existentes para aplicar uma nova revisão a elas.", + "settings.archive.deletion_pending": "Exclusão pendente", + "settings.archive.archived": "Arquivado", + "settings.archive.hot": "Quente", + "settings.archive.hot_and_archive": "Quente + arquivamento", + "settings.archive.archiving": "Arquivando", + "settings.archive.preparing": "Preparando reprodução", + "settings.archive.unavailable": "Indisponível", + "settings.archive.operations": "Operações de arquivamento", + "settings.archive.readOnly": "Modo de recuperação: migração e exclusão de gravações estão pausadas.", + "settings.archive.disabledBuild": "Suporte a S3 está desabilitado nesta versão. Destinos de sistema de arquivos montados permanecem disponíveis.", + "settings.archive.stored": "Armazenado em buckets", + "settings.archive.backlog": "Fila de transferência", + "settings.archive.cache": "Cache de recuperação", + "settings.archive.objectsRemaining": "objetos restantes", + "settings.archive.waitingForReaders": "Na fila, ou aguardando leitores ativos.", + "settings.archive.applied": "Revisão de política aplicada a gravações existentes", + "settings.archive.reviewExisting": "Revisar gravações existentes", + "settings.archive.applySummary": "{count} gravações ({bytes}) usarão esta revisão. {expired} já ultrapassaram o limite de retenção.", + "settings.archive.applyHelp": "Proteções e substituições de gravação ainda se aplicam. Retenção de stream e do sistema também se aplicam. Novo agendamento e destino de arquivamento entram em vigor na próxima verificação de ciclo de vida.", + "settings.archive.applyBlocked": "Conclua ou resolva as transferências associadas antes de aplicar esta revisão.", + "settings.archive.apply": "Aplicar a gravações existentes", + "common.fullscreenUnsupported": "Modo de tela cheia não é suportado neste navegador.", + "recordings.viewInTimelineTitle": "Ver este stream neste ponto no tempo na visualização de Linha do tempo", + "recordings.clickToRetry": "Clique para tentar novamente", + "timeline.previousDay": "Dia anterior", + "timeline.nextDay": "Próximo dia", + "timeline.previousMonth": "Mês anterior", + "timeline.nextMonth": "Próximo mês", + "settings.searchLabel": "Configurações de busca", + "settings.clearSearch": "Limpar busca", + "recordings.addTagPlaceholder": "Adicionar uma tag...", + "recordings.addNewTagPlaceholder": "Adicionar nova tag..." } diff --git a/web/public/locales/pt-PT.json b/web/public/locales/pt-PT.json index aebc59c4..c3a86488 100644 --- a/web/public/locales/pt-PT.json +++ b/web/public/locales/pt-PT.json @@ -9,6 +9,84 @@ "nav.timeline": "Linha temporal", "nav.health": "Estado", "nav.toggleMenu": "Mostrar/ocultar menu", + "live.navigator.title": "Navegador", + "live.navigator.subtitle": "Localizações, layouts e atividade", + "live.navigator.cameras": "Câmaras", + "live.navigator.plans": "Planta", + "live.navigator.views": "Vistas", + "live.navigator.events": "Eventos", + "live.navigator.search": "Procurar uma câmara…", + "live.navigator.allCameras": "Todas as câmaras", + "live.navigator.unassigned": "Não atribuídas", + "live.navigator.noCameras": "Nenhuma câmara corresponde a este âmbito.", + "live.navigator.saveCurrent": "Guardar o layout atual", + "live.navigator.noLayouts": "Ainda não há layouts guardados.", + "live.navigator.layoutNamePrompt": "Dar nome a este layout de vista em direto", + "live.navigator.shareLayoutPrompt": "Partilhar este layout com outros operadores?", + "live.navigator.layoutSaved": "{name} guardado", + "live.navigator.layoutLoaded": "{name} carregado", + "live.navigator.deleteLayoutConfirm": "Eliminar {name}?", + "live.navigator.shared": "Partilhado", + "live.navigator.loadingEvents": "A carregar eventos recentes…", + "live.navigator.noRecentEvents": "Sem deteções na última hora.", + "live.navigator.expand": "Expandir o navegador", + "live.navigator.collapse": "Colapsar o navegador", + "live.plan.navigatorHelp": "Escolha um edifício ou um piso. As pré-visualizações das câmaras só abrem quando solicitadas.", + "live.plan.noPlans": "Ainda não há plantas de edifícios. Crie uma na área de trabalho de plantas.", + "live.plan.emptyTitle": "Construa uma vista espacial de câmaras", + "live.plan.emptyDescription": "Uma planta mostra marcadores de estado para todo o local e abre o vídeo apenas quando um operador o solicita. Desenhe aqui as salas e as paredes, ou carregue uma planta digitalizada, um desenho do local ou uma captura do seu software NVR, e depois mapeie as câmaras nas salas reais.", + "live.plan.sketch.tools": "Ferramentas de layout", + "live.plan.sketch.tool.select": "Selecionar", + "live.plan.sketch.tool.room": "Sala", + "live.plan.sketch.tool.wall": "Parede", + "live.plan.sketch.tool.area": "Área", + "live.plan.sketch.tool.label": "Etiqueta", + "live.plan.sketch.undo": "Desfazer o desenho", + "live.plan.sketch.redo": "Refazer o desenho", + "live.plan.sketch.snap": "Ajustar à grelha", + "live.plan.sketch.hint.select": "Arraste formas ou câmaras para as mover. Clique numa forma para a editar; mantenha o Alt premido para ignorar a grelha.", + "live.plan.sketch.hint.room": "Arraste na planta para desenhar uma sala ou o contorno de um edifício.", + "live.plan.sketch.hint.wall": "Clique para adicionar pontos de parede. Faça duplo clique ou prima Enter para terminar, Escape para cancelar.", + "live.plan.sketch.hint.area": "Clique para delinear uma área. Clique no primeiro ponto ou prima Enter para a fechar.", + "live.plan.sketch.hint.label": "Clique na planta para colocar uma etiqueta de texto.", + "live.plan.sketch.type.rect": "Sala", + "live.plan.sketch.type.wall": "Parede", + "live.plan.sketch.type.area": "Área", + "live.plan.sketch.type.label": "Etiqueta", + "live.plan.sketch.pointCount": "{count} pontos", + "live.plan.sketch.defaultLabel": "Etiqueta", + "live.plan.sketch.shapes": "Formas do layout", + "live.plan.sketch.noShapes": "Ainda nada desenhado. Escolha uma ferramenta acima da planta para começar.", + "live.plan.sketch.tone": "Cor", + "live.plan.sketch.tone.slate": "Cinzento", + "live.plan.sketch.tone.blue": "Azul", + "live.plan.sketch.tone.green": "Verde", + "live.plan.sketch.tone.amber": "Âmbar", + "live.plan.sketch.tone.red": "Vermelho", + "live.plan.sketch.tone.violet": "Violeta", + "live.plan.sketch.labelText": "Etiqueta", + "live.plan.sketch.text": "Texto", + "live.plan.sketch.size": "Tamanho", + "live.plan.sketch.size.sm": "Pequeno", + "live.plan.sketch.size.md": "Médio", + "live.plan.sketch.size.lg": "Grande", + "live.plan.sketch.filled": "Preencher a sala", + "live.plan.sketch.left": "Esquerda %", + "live.plan.sketch.top": "Topo %", + "live.plan.sketch.width": "Largura %", + "live.plan.sketch.height": "Altura %", + "live.plan.sketch.points": "Pontos", + "live.plan.sketch.point": "Ponto {index}", + "live.plan.sketch.delete": "Eliminar a forma", + "live.plan.sketch.duplicate": "Duplicar", + "live.plan.sketch.deselect": "Concluído", + "live.plan.sketch.emptyTitle": "Ainda nada nesta planta", + "live.plan.sketch.emptyBody": "Desenhe aqui salas, paredes e etiquetas, ou carregue uma planta digitalizada, um desenho do local ou uma exportação PNG/JPEG (até 768 KB).", + "live.plan.sketch.emptyBodyReadOnly": "Um administrador pode desenhar o layout ou carregar uma planta do edifício real.", + "live.plan.sketch.drawLayout": "Desenhar o layout", + "live.plan.sketch.uploadImage": "Carregar imagem", + "live.plan.sketch.limitReached": "Limite de formas atingido ({max})", + "live.plan.sketch.discardDrawing": "Desenho cancelado", "streamHealth.title": "Estado dos streams", "streamHealth.loading": "A carregar dados de estado...", "streamHealth.error": "Falha ao carregar os dados de estado", @@ -405,6 +483,12 @@ "live.errorProcessingStreams": "Erro ao processar streams: {message}", "live.couldNotEnableFullscreen": "Não foi possível ativar o modo tela cheia: {message}", "live.allTags": "Todas as tags", + "live.favorites": "Favoritos", + "live.favoritesOnly": "Mostrar apenas câmaras favoritas", + "live.addFavorite": "Adicionar {stream} aos favoritos", + "live.removeFavorite": "Remover {stream} dos favoritos", + "live.noFavorites": "Ainda não há câmaras favoritas. Use a estrela num mosaico de câmara para adicionar uma.", + "live.favoriteUpdateError": "Não foi possível atualizar os favoritos: {message}", "live.tags": "Tags", "live.stream": "Stream", "live.filterByTag": "Filtrar por tag: {tag}", @@ -589,6 +673,7 @@ "live.forceRefreshWarning": "Isto irá interromper brevemente a ligação go2rtc, quebrando a gravação ativa. A gravação será retomada automaticamente.", "live.viewInTimeline": "Ver na linha temporal", "live.toggleFullscreen": "Alternar tela cheia", + "live.resetZoom": "Reiniciar o zoom", "live.streamStarting": "A iniciar stream...", "live.go2rtcNotRespondingRetry": "O go2rtc está ativado mas não responde. Verifique o estado do serviço go2rtc. Clique em Tentar novamente para tentar de novo.", "live.go2rtcHlsFailedRetry": "Falha no stream HLS do go2rtc. Clique em Tentar novamente para tentar outra vez.", @@ -603,12 +688,14 @@ "live.failedToCreateMediaBuffer": "Falha ao criar o buffer de mídia", "live.webSocketConnectionError": "Erro de ligação WebSocket", "live.webrtcAutoplayBlocked": "Clique para reproduzir o vídeo (reprodução automática bloqueada)", + "live.audioPlaybackBlocked": "O navegador bloqueou o áudio da câmara. Clique novamente no botão do altifalante para tentar de novo.", "live.webrtcConnectionLostRetry": "Ligação WebRTC perdida. Clique em Tentar novamente para restabelecer.", "live.streamConnectedNoVideoDataRetry": "Stream conectado, mas sem dados de vídeo. Clique em Tentar novamente para reconectar.", "live.failedToLoadVideo": "Falha ao carregar o vídeo", "live.webrtcIceConnectionFailed": "Falha na conexão ICE do WebRTC", "live.webrtcConnectionLostPleaseRetry": "Conexão WebRTC perdida. Tente novamente.", "live.autoRetryingIn": "A tentar novamente em {seconds} s…", + "live.fullscreenSubStreamFallback": "{stream}: largura de banda insuficiente para o stream de resolução completa em tela cheia; mudou para o substream.", "live.connectionTimeoutCheckNetwork": "Tempo limite de ligação excedido. Verifique as definições de rede/firewall.", "live.failedToEstablishWebrtcConnection": "Falha ao estabelecer a conexão WebRTC", "live.cannotConnectToSource": "Não é possível conectar à fonte da câmara", @@ -622,6 +709,16 @@ "live.connectionQuality.bad": "Má", "live.muteCameraAudio": "Silenciar áudio da câmara", "live.unmuteCameraAudio": "Ativar áudio da câmara", + "live.tileActions": "Ações da câmara", + "live.takeSnapshot": "Capturar imagem", + "live.openStreamRecordings": "Abrir as gravações deste stream", + "live.enterReorderMode": "Reordenar câmaras", + "live.pullToRefresh": "Puxe para atualizar os streams", + "live.releaseToRefresh": "Largue para atualizar os streams", + "live.refreshingStreams": "A atualizar streams…", + "live.streamsRefreshed": "Streams atualizados", + "live.refreshStreamsFailed": "Não foi possível atualizar os streams: {message}", + "live.tipDoubleTapFullscreen": "Dica: toque duas vezes num mosaico para o abrir em tela cheia.", "live.switchToToggleMode": "Mudar para modo alternar", "live.switchToPushToTalkMode": "Mudar para premir para falar", "live.releaseToStopTalking": "Largue para parar de falar", @@ -636,6 +733,40 @@ "live.pauseForPrivacyConfirm": "Pausar este stream por privacidade? A gravação e a visualização em direto param, mas o stream continua visível nesta página com uma sobreposição de privacidade. Clique em Retomar quando terminar.", "live.streamPausedForPrivacy": "Transmissão pausada por questões de privacidade", "live.resumeStream": "Retomar stream", + "live.dayNightControl": "Modo dia/noite", + "live.dayNightLoading": "A carregar…", + "live.dayNightApplying": "A aplicar…", + "live.dayNightMode_auto": "Automático", + "live.dayNightMode_day": "Dia", + "live.dayNightMode_night": "Noite", + "live.dayNightMode_unknown": "Desconhecido", + "live.dayNightApplied": "Modo dia/noite definido como {mode}", + "live.dayNightApplyFailed": "Falha ao definir o modo dia/noite", + "live.dayNightLoadFailed": "Falha ao ler o modo dia/noite", + "live.playbackFallbackUsed": "Recurso: {transport}", + "live.playbackTransportUnavailable": "{transport} está desativado no servidor para este stream.", + "live.recordingMode.constant": "Gravação contínua", + "live.recordingMode.detection": "Gravação por deteção", + "live.recordingMode.schedule": "Gravação agendada", + "live.recordingMode.none": "Sem gravação", + "live.health.healthy": "Stream saudável", + "live.health.degraded": "Stream em buffer ou a recuperar", + "live.health.offline": "Stream indisponível", + "live.enterPictureInPicture": "Abrir imagem na imagem", + "live.exitPictureInPicture": "Fechar imagem na imagem", + "live.pictureInPictureError": "Imagem na imagem falhou: {message}", + "live.alwaysFullscreenOnTapEnable": "Ativar tela cheia num único toque no mosaico", + "live.alwaysFullscreenOnTapDisable": "Desativar tela cheia num único toque no mosaico", + "live.displayMode": "Modo de visualização", + "live.displayModeFit": "Ajustar", + "live.displayModeFill": "Preencher", + "live.displayModeFitDescription": "Ajustar: mostrar toda a imagem com barras negras", + "live.displayModeFillDescription": "Preencher: preencher o mosaico e cortar as margens da imagem", + "live.slideshowStartCameras": "Iniciar apresentação: percorrer as câmaras", + "live.slideshowStartPages": "Iniciar apresentação: percorrer as páginas da grelha", + "live.slideshowStop": "Parar a apresentação", + "live.slideshowInterval": "Intervalo da apresentação", + "live.slideshowSeconds": "{seconds} s", "streams.toggleDisable": "Desativar stream", "streams.toggleEnable": "Ativar stream", "streams.readOnlyInsufficientPermissions": "Só leitura (permissões insuficientes para alterar)", @@ -759,9 +890,9 @@ "streamsConfig.streamNameImmutable": "O nome do stream não pode ser alterado depois de criado", "streamsConfig.streamNameAllowedChars": "Somente letras, dígitos, '.', '-' e '_' são permitidos (sem espaços).", "streamsConfig.streamUrl": "URL do stream", - "streamsConfig.streamUrlPlaceholder": "rtsp://usuario:senha@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "URL do sub-stream (opcional)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://usuario:senha@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "URL do stream de baixa resolução para a vista em grelha do painel. Deixe vazio para usar o stream principal em todo o lado. O sub-stream é usado apenas na pré-visualização em direto em modo grelha; a gravação e o ecrã inteiro usam sempre o stream principal.", "streamsConfig.urlCredentialsHiddenTitle": "As credenciais do URL estão ocultas no modo de demonstração/visualizador", "streamsConfig.urlCredentialsHidden": "Credenciais do URL ocultas por segurança", @@ -819,7 +950,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "Confirme que o light-object-detect está em execução neste endpoint", "streamsConfig.customApiEndpointUrl": "URL de endpoint API personalizado", "streamsConfig.useDefaultEndpoint": "Usar endpoint predefinido", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "Introduza o URL completo do seu endpoint API de deteção personalizado", "streamsConfig.overrideWithCustomEndpoint": "Substituir por endpoint personalizado", "streamsConfig.detectionThreshold": "Limiar de deteção", @@ -1056,7 +1187,7 @@ "settings.detectionModelsPath": "Caminho dos modelos de deteção", "settings.detectionModelsPathHelp": "Diretório onde os modelos de deteção são armazenados", "settings.apiDetectionUrl": "URL da API de deteção", - "settings.apiDetectionUrlHelp": "URL do endpoint da API externa de deteção de objetos", + "settings.apiDetectionUrlHelp": "Endpoint do light-object-detect, p. ex. http://localhost:8000/api/v1/detect. A captura é enviada como multipart form data com os parâmetros de consulta backend e confidence_threshold anexados.", "settings.apiDetectionBackend": "Backend da API de deteção", "settings.apiDetectionBackendOnnx": "ONNX Runtime", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1156,5 +1287,1361 @@ "settings.discoveryIntervalSecondsRangeHelp": "Com que frequência analisar câmaras (30–3600 segundos)", "settings.discoveryNetwork": "Rede de descoberta", "settings.discoveryNetworkExamples": "Exemplos: 192.168.1.0/24, 10.0.0.0/16, auto", - "settings.saveSettings": "Guardar definições" + "settings.saveSettings": "Guardar definições", + "live.plan.previewUnavailable": "Pré-visualização da câmara indisponível", + "live.plan.previewAlt": "Vista atual de {name}", + "live.plan.degreesValue": "{value} graus", + "live.plan.inDegrees": "{label} em graus", + "live.plan.imageDimensionsError": "Não foi possível ler as dimensões da imagem", + "live.plan.loading": "A carregar plantas de edifícios…", + "live.plan.created": "{name} criada", + "live.plan.renamed": "Renomeada para {name}", + "live.plan.deleted": "{name} eliminada", + "live.plan.backgroundType": "O fundo tem de ser uma imagem PNG ou JPEG", + "live.plan.backgroundTooLarge": "Imagem de fundo demasiado grande; o máximo é 768 KB", + "live.plan.backgroundAspect": "Carregada, mas as proporções da imagem não correspondem a nenhum tamanho de tela válido", + "live.plan.backgroundUpdatedSave": "Fundo atualizado para {name}; guarde o layout para aplicar o tamanho da tela", + "live.plan.backgroundNotResized": "Fundo carregado, mas a tela não foi redimensionada: {error}", + "live.plan.backgroundUpdated": "Fundo atualizado para {name}", + "live.plan.backgroundRemoved": "Fundo removido", + "live.plan.saved": "{name} guardada", + "live.plan.createTitle": "Criar planta de edifício", + "live.plan.createDescription": "Dê um nome claro a este edifício ou piso. Desenhe o layout ou carregue uma imagem de planta e depois coloque as câmaras.", + "live.plan.nameLabel": "Nome da planta", + "live.plan.namePlaceholder": "Edifício principal · 1.º piso", + "live.plan.createConfirm": "Criar planta", + "live.plan.eyebrow": "Planta de edifício", + "live.plan.placedSummary": "{placed} colocadas · {live} em direto agora", + "live.plan.zoomAndPan": "Zoom e deslocamento da planta", + "live.plan.panLeft": "Deslocar para a esquerda", + "live.plan.panUp": "Deslocar para cima", + "live.plan.panDown": "Deslocar para baixo", + "live.plan.panRight": "Deslocar para a direita", + "live.plan.zoomOut": "Reduzir o zoom", + "live.plan.zoomIn": "Ampliar o zoom", + "live.plan.fitTitle": "Ajustar a planta", + "live.plan.fit": "Ajustar", + "live.plan.backgroundMenu": "Fundo…", + "live.plan.save": "Guardar a planta", + "live.plan.uploadBackgroundTitle": "Carregar uma imagem PNG ou JPEG como fundo da planta", + "live.plan.replaceBackground": "Substituir o fundo", + "live.plan.uploadBackground": "Carregar o fundo", + "live.plan.removeBackground": "Remover o fundo", + "live.plan.rename": "Renomear", + "live.plan.newPlan": "Nova planta", + "live.plan.editLayout": "Editar o layout", + "live.plan.placementHint": "Clique na planta para posicionar {name}", + "live.plan.clusterLabel": "{count} câmaras; amplie", + "live.plan.markerLabel": "{name}; {availability}; virada para {rotation}° com um campo de visão de {fov}°", + "live.plan.cameraFallback": "Câmara", + "live.plan.legendLive": "Em direto", + "live.plan.canvas": "Tela da planta", + "live.plan.width": "Largura", + "live.plan.height": "Altura", + "live.plan.canvasHint": "Ao carregar uma imagem de fundo, a tela é redimensionada para lhe corresponder.", + "live.plan.canvasInvalid": "A largura tem de ser 400–4000 e a altura 300–4000.", + "live.plan.openLive": "Abrir câmara em direto", + "live.plan.direction": "Direção da câmara", + "live.plan.fov": "Campo de visão", + "live.plan.coverageNote": "Os setores mostram apenas direção e ângulo; a distância na planta não está calibrada.", + "live.plan.removeCamera": "Remover da planta", + "live.plan.selectCamera": "Selecione uma câmara", + "live.plan.selectHintEditing": "Arraste os marcadores colocados para afinação. Inspecione o estado e abra uma vista em direto a pedido.", + "live.plan.selectHint": "Inspecione o estado e abra uma vista em direto a pedido.", + "live.plan.cameras": "Câmaras da planta", + "live.plan.findPlaceholder": "Procurar nesta planta…", + "live.plan.findLabel": "Procurar uma câmara nesta planta", + "live.plan.unplaced": "Câmaras não colocadas", + "live.plan.unplacedHint": "Selecione uma câmara e clique na posição dela na planta.", + "live.plan.renameTitle": "Renomear planta", + "live.plan.renameDescription": "As plantas são partilhadas com todos os operadores deste local.", + "live.plan.deleteTitle": "Eliminar planta", + "live.plan.deleteMessage": "Eliminar “{name}” e o respetivo fundo carregado? As posições das câmaras nesta planta são removidas; as câmaras em si ficam intactas.", + "setupWizard.welcomeTitle": "Bem-vindo ao LightNVR", + "setupWizard.welcomeIntro": "Vamos configurar o seu NVR em alguns passos rápidos. Poderá sempre rever estas definições mais tarde na página Definições.", + "setupWizard.welcomeStorage": "Caminho de armazenamento e limites de tamanho", + "setupWizard.welcomePerformance": "Limites de desempenho para o seu número de câmaras", + "setupWizard.welcomeSecurity": "Início de sessão seguro do administrador", + "setupWizard.storageTitle": "Armazenamento e base de dados", + "setupWizard.storageIntro": "Onde devem ser armazenadas as gravações e a base de dados?", + "setupWizard.storagePath": "Caminho de armazenamento das gravações", + "setupWizard.storagePathHint": "Caminho absoluto onde os ficheiros de vídeo são escritos.", + "setupWizard.maxStorage": "Tamanho máximo de armazenamento (GB)", + "setupWizard.maxStorageHint": "0 = ilimitado.", + "setupWizard.dbPath": "Caminho da base de dados", + "setupWizard.dbPathHint": "Localização do ficheiro da base de dados SQLite.", + "setupWizard.performanceTitle": "Desempenho", + "setupWizard.performanceIntro": "Estas definições controlam a capacidade, não a qualidade de vídeo. A maioria dos utilizadores pode manter as predefinições.", + "setupWizard.threadPool": "Tamanho do conjunto de threads de trabalho", + "setupWizard.threadPoolInfo": "afeta o trabalho em segundo plano da web/servidor. O valor predefinido recomendado costuma ser o melhor, salvo se estiver a otimizar o desempenho.", + "setupWizard.maxStreams": "Máximo de streams simultâneos", + "setupWizard.maxStreamsInfo": "é o limite de capacidade de câmaras desta instância em execução. Defina-o pelo menos para o número de câmaras que planeia adicionar, mais alguma margem.", + "setupWizard.important": "Importante:", + "setupWizard.restartWarning": "se alterar qualquer uma das definições, o novo valor é guardado agora, mas não será usado até o LightNVR reiniciar. Por exemplo, se o limite atual de streams é 1 e o aumenta para 32, tem de reiniciar antes de adicionar câmaras para além do limite antigo.", + "setupWizard.threadPoolHintCores": "Recomendado: {recommended} (2× o seu CPU de {cores} núcleos). Isto controla as threads de trabalho em segundo plano do libuv. Intervalo: 2–128.", + "setupWizard.threadPoolHint": "Recomendado: {recommended} (2× os núcleos do seu CPU). Isto controla as threads de trabalho em segundo plano do libuv. Intervalo: 2–128.", + "setupWizard.maxStreamsHint": "Quantas câmaras o LightNVR consegue manter ativas ao mesmo tempo. Predefinição 32, máximo {max}. Se espera 8 câmaras, escolha pelo menos 8. Requer reinício para surtir efeito.", + "setupWizard.completeTitle": "Configuração concluída!", + "setupWizard.saved": "As suas definições foram guardadas com sucesso.", + "setupWizard.notSaved": "Nenhuma definição foi alterada — serão usadas as predefinições.", + "setupWizard.restartRequired": "Reinício necessário", + "setupWizard.restartRequiredInfo": "as alterações do tamanho do conjunto de threads e/ou do máximo de streams estão guardadas, mas não surtirão efeito até o serviço reiniciar. Reinicie antes de adicionar mais câmaras ou de esperar que o novo limite de capacidade se aplique.", + "setupWizard.saveFailed": "Falha ao guardar as definições: {error}", + "setupWizard.back": "Anterior", + "setupWizard.saving": "A guardar…", + "setupWizard.saveContinue": "Guardar e continuar", + "setupWizard.next": "Seguinte →", + "setupWizard.finish": "Ir para o painel", + "setupWizard.skip": "Ignorar o assistente de configuração", + "live.eptzCanvasLabel": "Vista eletrónica de pan, tilt e zoom para olho de peixe", + "live.eptzCanvasHint": "Arraste para pan e tilt; roda ou pinça para zoom; Home restaura", + "live.eptzReset": "Repor a vista ePTZ", + "live.autoShort": "Auto", + "live.webrtcShort": "WebRTC", + "nav.investigation": "Investigação", + "availability.label": "Disponibilidade das câmaras", + "availability.live": "Em direto agora", + "availability.offline": "Desligada (anteriormente ligada)", + "availability.neverConnected": "Nunca ligada", + "availability.disabled": "Desativada", + "availability.all": "Todas as câmaras", + "streams.inventory": "Inventário", + "streams.configuration": "Configuração", + "events.tab": "Eventos", + "events.eyebrow": "Integrações orientadas por eventos", + "events.title": "Eventos e encaminhamento", + "events.description": "Transforme eventos de câmara e de sistema em fluxos MQTT duráveis para automação, serviços de notificação e processamento externo. O LightNVR fornece a interface de eventos; a entrega por email e SMS permanece nos serviços a jusante.", + "events.routes": "Rotas", + "events.destinations": "Destinos", + "events.catalog": "Catálogo de eventos", + "events.enable": "Ativar", + "events.loadError": "Não foi possível carregar a configuração de encaminhamento de eventos", + "events.accessDenied": "Acesso negado - privilégios insuficientes", + "events.summary.routes": "Rotas", + "events.summary.enabled": "{count} ativas", + "events.summary.destinations": "Destinos", + "events.summary.managedActive": "{count} geridas e ativas", + "events.summary.types": "Tipos registados", + "events.summary.registry": "Catálogo de eventos versionado", + "events.summary.interface": "Interface", + "events.summary.interfaceHelp": "Saída de eventos durável", + "events.route.add": "Adicionar rota", + "events.route.addTitle": "Criar rota de eventos", + "events.route.editTitle": "Editar rota de eventos", + "events.route.create": "Criar rota", + "events.route.editorDescription": "Escolha quais os eventos que se qualificam, quais as câmaras em âmbito, para onde são enviados e como são controladas as fontes ruidosas.", + "events.route.emptyTitle": "Nenhuma rota de eventos configurada", + "events.route.emptyDescription": "Crie uma rota para selecionar tipos de eventos, âmbito de câmaras, agendamento, política de supressão e destino MQTT.", + "events.route.enabled": "Rota ativa", + "events.route.enabledHelp": "Os eventos correspondentes são aceites para entrega durável", + "events.route.destination": "Destino", + "events.route.destinationHelp": "Um evento correspondente é persistido uma vez para cada destino único.", + "events.route.eventTypes": "Tipos de eventos", + "events.route.eventTypesHelp": "Selecione um ou mais contratos de eventos versionados do registo.", + "events.route.detectionFilters": "Filtrar deteções de objetos", + "events.route.detectionFiltersHelp": "Opcionalmente, exija rótulos, zonas ou uma confiança mínima para eventos de deteção de objetos.", + "events.route.healthFilters": "Filtrar eventos de estado do sistema", + "events.route.healthFiltersHelp": "Opcionalmente, associe códigos de condições de estado ou gravidades registados. Os valores disponíveis provêm deste gravador.", + "events.route.healthConditions": "Condições de estado (qualquer)", + "events.route.healthSeverities": "Gravidades (qualquer)", + "events.route.healthRegistryUnavailable": "O registo de condições de estado está indisponível. Recarregue antes de configurar filtros de condições.", + "events.route.labels": "Rótulos (qualquer)", + "events.route.zones": "IDs de zona (qualquer)", + "events.route.listHelp": "Separe os valores com vírgulas.", + "events.route.minConfidence": "Confiança mínima", + "events.route.confidenceHelp": "Um valor de 0 a 1.", + "events.route.cameraScope": "Âmbito de câmaras", + "events.route.cameraScopeHelp": "Reutilize localizações da frota, etiquetas, coleções de atributos ou câmaras explícitas sem carregar toda a frota.", + "events.route.allCameras": "Todas as câmaras", + "events.route.dynamicScope": "Seletor dinâmico de câmaras", + "events.route.systemScopeHelp": "Os eventos de sistema não são câmaras. Os seletores de câmaras estão indisponíveis quando esta rota inclui eventos de âmbito de sistema.", + "events.route.schedule": "Agendamento", + "events.route.scheduleHelp": "Utilize a hora de ocorrência do evento num fuso horário IANA; janelas noturnas são suportadas.", + "events.route.restrictSchedule": "Apenas durante janelas configuradas", + "events.route.suppression": "Política de ruído e entrega", + "events.route.suppressionHelp": "Zero desativa um controlo. A supressão avança apenas após esse destino aceitar o evento durável.", + "events.route.debounce": "Segundos de debounce", + "events.route.debounceHelp": "Observações repetidas prolongam este intervalo de silêncio.", + "events.route.cooldown": "Segundos de arrefecimento", + "events.route.cooldownHelp": "Intervalo mínimo após um evento aceite.", + "events.route.grouping": "Segundos da janela de agrupamento", + "events.route.groupingHelp": "Preserva o primeiro evento e consolida repetições.", + "events.route.rateLimit": "Eventos por minuto", + "events.route.rateLimitHelp": "Máximo de janela fixa por rota e câmara.", + "events.route.deliveryPolicy": "Política de entrega", + "events.route.suppressionActive": "Controlos de ruído ativos", + "events.route.everyMatch": "Cada correspondência", + "events.route.preview": "Pré-visualizar rota", + "events.route.previewing": "A pré-visualizar…", + "events.route.previewResult": "Pré-visualização da rota", + "events.route.cameraMatches": "{count} câmaras correspondem", + "events.route.previewNoPublish": "A pré-visualização valida a regra completa e resolve uma amostra de câmaras; nunca publica um evento.", + "events.route.systemPreviewHelp": "Os eventos de sistema ignoram a seleção de câmaras e, por isso, reportam zero câmaras correspondentes nesta pré-visualização.", + "events.route.created": "Rota de eventos criada", + "events.route.updated": "Rota de eventos atualizada", + "events.route.deleted": "Rota de eventos eliminada", + "events.route.disabled": "Rota de eventos desativada", + "events.route.enabledMessage": "Rota de eventos ativada", + "events.route.deleteConfirm": "Eliminar a rota de eventos \"{name}\"?", + "events.route.validation.name": "Introduza um nome de rota.", + "events.route.validation.destination": "Escolha um destino.", + "events.route.validation.event_types": "Selecione pelo menos um tipo de evento.", + "events.route.validation.selector": "Complete ou corrija o seletor de câmaras.", + "events.route.validation.system_scope": "Os seletores de câmaras não podem ser utilizados com eventos de âmbito do sistema.", + "events.route.validation.detection_type": "Os filtros de deteção requerem o tipo de evento de deteção de objetos.", + "events.route.validation.detection_filter": "Adicione pelo menos uma etiqueta de deteção, zona ou limiar de confiança.", + "events.route.validation.confidence": "A confiança mínima deve ser entre 0 e 1.", + "events.route.validation.predicate_mix": "Os filtros de deteção e de estado não podem ser combinados numa rota.", + "events.route.validation.health_type": "Os filtros de estado requerem apenas tipos de evento de estado do sistema registados.", + "events.route.validation.health_filter": "Selecione pelo menos uma condição de estado ou gravidade registada.", + "events.route.validation.health_condition": "Selecione apenas os códigos de condição devolvidos pelo registo de saúde do gravador.", + "events.route.validation.health_severity": "Selecione apenas as severidades suportadas pelos tipos de eventos de saúde selecionados.", + "events.route.validation.timezone": "Introduza um fuso horário IANA instalado, como UTC ou America/New_York.", + "events.route.validation.schedule_window": "Cada janela de agendamento necessita de pelo menos um dia e horas de início e fim válidas e distintas.", + "events.route.validation.suppression": "Os valores de supressão devem ser números inteiros dentro dos intervalos permitidos.", + "events.schedule.timezone": "Fuso horário", + "events.schedule.timezoneHelp": "Deve estar presente na base de dados de fusos horários do gravador.", + "events.schedule.addWindow": "Adicionar janela de tempo", + "events.schedule.windowNumber": "Janela {number}", + "events.schedule.start": "Início", + "events.schedule.end": "Fim", + "events.schedule.sunday": "Dom", + "events.schedule.monday": "Seg", + "events.schedule.tuesday": "Ter", + "events.schedule.wednesday": "Qua", + "events.schedule.thursday": "Qui", + "events.schedule.friday": "Sex", + "events.schedule.saturday": "Sáb", + "events.destination.add": "Adicionar destino", + "events.destination.addTitle": "Adicionar destino MQTT", + "events.destination.editTitle": "Editar destino MQTT", + "events.destination.create": "Criar destino", + "events.destination.editorDescription": "Configure uma saída de eventos durável. As credenciais são apenas de escrita e nunca são devolvidas pela API.", + "events.destination.default": "Definições MQTT predefinidas", + "events.destination.settingsManaged": "Definições geridas", + "events.destination.defaultDescription": "A configuração MQTT existente permanece disponível como mqtt:default e é utilizada por {count} rotas.", + "events.destination.openSettings": "Abrir definições MQTT", + "events.destination.emptyTitle": "Sem destinos geridos", + "events.destination.emptyDescription": "Adicione outro broker MQTT para entrega independente de eventos a um conector de nuvem, sistema de automação ou serviço de notificações.", + "events.destination.identity": "Identidade do destino", + "events.destination.enabled": "Destino ativado", + "events.destination.enabledHelp": "Ligar e esvaziar a sua fila durável", + "events.destination.active": "Ativo", + "events.destination.paused": "Em pausa", + "events.destination.pause": "Pausar", + "events.destination.broker": "Broker", + "events.destination.host": "Host do broker", + "events.destination.hostHelp": "Apenas nome de host ou endereço IP; não inclua um esquema de URL.", + "events.destination.port": "Porta", + "events.destination.clientId": "ID do cliente", + "events.destination.clientIdHelp": "Deve ser único para esta ligação ao broker.", + "events.destination.topic": "Tópico", + "events.destination.topicTemplate": "Modelo de tópico", + "events.destination.topicHelp": "Deve incluir os tokens de tipo de evento e ID do assunto; não são permitidos caracteres wildcard MQTT.", + "events.destination.keepalive": "Segundos de keepalive", + "events.destination.statusTopicTemplate": "Tópico de estado de presença", + "events.destination.statusTopicHelp": "Opcional. Deve incluir {installation_uuid}; {destination_uuid} também está disponível. Não são permitidos caracteres wildcard MQTT.", + "events.destination.statusTopicEnabled": "A presença está explicitamente ativada para este destino. O tópico nunca é inferido a partir do tópico de evento.", + "events.destination.statusTopicDisabled": "A presença está desativada para este destino. Deixe este campo vazio para a manter desativada.", + "events.destination.qos": "Qualidade de serviço", + "events.destination.qos0": "enviar uma vez", + "events.destination.qos1": "pelo menos uma vez", + "events.destination.qos2": "exatamente uma vez", + "events.destination.authentication": "Autenticação", + "events.destination.passwordPreserved": "Deixe em branco para manter a palavra-passe somente de escrita guardada.", + "events.destination.passwordOptional": "Opcional quando o broker permite clientes anónimos.", + "events.destination.clearPassword": "Limpar a palavra-passe guardada", + "events.destination.transportSecurity": "Segurança de transporte", + "events.destination.tlsMode": "Modo TLS", + "events.destination.tlsSystem": "Armazenamento de confiança do sistema", + "events.destination.tlsCustomCa": "Autoridade de certificação personalizada", + "events.destination.tlsMutual": "TLS mútuo", + "events.destination.tlsDisabled": "Desativado (texto em claro)", + "events.destination.tlsHelp.system": "Verificar o certificado do broker contra o armazenamento de confiança do sistema operativo.", + "events.destination.tlsHelp.custom_ca": "Verificar o broker contra um ficheiro de autoridade de certificação PEM explícito.", + "events.destination.tlsHelp.mutual": "Verificar o broker com uma CA explícita e apresentar um certificado e chave de cliente.", + "events.destination.tlsHelp.disabled": "Sem encriptação de transporte nem verificação de identidade do broker.", + "events.destination.caFile": "Ficheiro CA", + "events.destination.certFile": "Ficheiro de certificado de cliente", + "events.destination.keyFile": "Ficheiro de chave de cliente", + "events.destination.absolutePathHelp": "Utilize um caminho absoluto legível pelo serviço LightNVR.", + "events.destination.plaintextWarning": "O MQTT em texto simples pode expor metadados de eventos e credenciais. Utilize-o apenas numa rede de confiança e isolada.", + "events.destination.security": "Segurança", + "events.destination.tls.system": "Confiança do sistema", + "events.destination.tls.custom_ca": "CA personalizada", + "events.destination.tls.mutual": "TLS mútuo", + "events.destination.tls.disabled": "Texto simples", + "events.destination.routes": "Rotas", + "events.destination.presence": "Tópico de presença", + "events.destination.deleteInUse": "Remova ou redirecione as rotas antes de eliminar este destino.", + "events.destination.created": "Destino MQTT criado", + "events.destination.updated": "Destino MQTT atualizado", + "events.destination.deleted": "Destino MQTT eliminado", + "events.destination.pausedMessage": "Destino MQTT em pausa; os eventos em fila permanecem duráveis até à expiração.", + "events.destination.enabledMessage": "Destino MQTT ativado", + "events.destination.deleteConfirm": "Eliminar o destino MQTT \"{name}\"?", + "events.destination.validation.name": "Introduza um nome de destino.", + "events.destination.validation.host": "Introduza um nome de host ou endereço IP do broker.", + "events.destination.validation.client_id": "Introduza um ID de cliente do broker.", + "events.destination.validation.topic": "O tópico deve incluir os tokens de tipo de evento e ID de assunto e não pode conter caracteres universais MQTT.", + "events.destination.validation.status_topic": "O tópico de presença opcional deve incluir o token de UUID de instalação, utilizar apenas tokens suportados e não pode conter caracteres universais MQTT.", + "events.destination.validation.port": "A porta deve ser um número inteiro de 1 a 65535.", + "events.destination.validation.keepalive": "O keepalive deve ser um número inteiro de 5 a 3600 segundos.", + "events.destination.validation.qos": "Escolha MQTT QoS 0, 1 ou 2.", + "events.destination.validation.username": "Uma palavra-passe configurada requer um nome de utilizador.", + "events.destination.validation.ca_file": "Este modo TLS requer um caminho absoluto para o ficheiro CA.", + "events.destination.validation.mutual_files": "O Mutual TLS requer caminhos absolutos para a CA, o certificado do cliente e a chave do cliente.", + "fleet.eyebrow": "Operações da câmara", + "fleet.title": "Inventário de câmaras", + "fleet.description": "Encontrar, avaliar e organizar câmaras em grandes implantações sem carregar o inventário completo no navegador.", + "fleet.summary": "Resumo do estado da frota", + "fleet.totalCameras": "Câmaras correspondentes", + "fleet.needsAttention": "Degradado", + "fleet.searchLabel": "Procurar câmaras", + "fleet.searchPlaceholder": "Procurar por nome, endereço, localização, etiqueta, fabricante ou modelo…", + "fleet.resultCount": "{count} câmaras", + "fleet.filters": "Filtros", + "fleet.clearFilters": "Limpar filtros", + "fleet.filter.health": "Estado", + "fleet.filter.enabled": "Estado da câmara", + "fleet.filter.anyState": "Qualquer estado", + "fleet.filter.recording": "Modo de gravação", + "fleet.filter.location": "Subárvore de localização", + "fleet.filter.allLocations": "Todas as localizações", + "fleet.filter.tags": "Etiquetas (corresponder a qualquer uma)", + "fleet.filter.collection": "Coleção de câmaras", + "fleet.health.unknown": "Desconhecido", + "fleet.health.up": "Online", + "fleet.health.degraded": "Degradado", + "fleet.health.down": "Offline", + "fleet.health.disabled": "Desativado", + "fleet.recording.off": "Desligado", + "fleet.recording.continuous": "Contínuo", + "fleet.recording.detection": "Deteção", + "fleet.recordingActive": "A gravar agora", + "fleet.recordingInactive": "Sem gravação", + "fleet.column.camera": "Câmara", + "fleet.column.health": "Estado", + "fleet.column.location": "Localização", + "fleet.column.tags": "Etiquetas", + "fleet.column.recording": "Gravação", + "fleet.viewLive": "Em direto", + "fleet.lastFrame": "Último quadro", + "fleet.noAddress": "Endereço indisponível", + "fleet.unassigned": "Não atribuído", + "fleet.loading": "A carregar frota de câmaras…", + "fleet.refreshing": "A atualizar…", + "fleet.loadError": "Não foi possível carregar a frota de câmaras", + "fleet.emptyTitle": "Nenhuma câmara configurada", + "fleet.emptyDescription": "Adicione um fluxo para o tornar disponível no espaço de trabalho da frota.", + "fleet.emptyFilteredTitle": "Nenhuma câmara corresponde a esta vista", + "fleet.emptyFilteredDescription": "Tente alargar a pesquisa ou limpar um ou mais filtros.", + "fleet.paginationSummary": "A mostrar {first}–{last} de {total}", + "fleet.perPage": "Por página", + "fleet.pageOf": "Página {page} de {pages}", + "fleet.selectPage": "Selecionar todas as câmaras nesta página", + "fleet.selectCamera": "Selecionar {name}", + "fleet.selectedCount": "{count} câmaras selecionadas", + "fleet.organizeSelected": "Organizar selecionadas", + "fleet.clearSelection": "Limpar seleção", + "fleet.organization.manage": "Gerir organização", + "fleet.organization.title": "Organização de câmaras", + "fleet.organization.description": "Mantenha uma hierarquia de localizações reutilizável e um dicionário de etiquetas normalizado para a frota de câmaras.", + "fleet.organization.locations": "Localizações", + "fleet.organization.tags": "Etiquetas", + "fleet.organization.locationsDescription": "Modele locais, edifícios, pisos e áreas operacionais como uma hierarquia navegável.", + "fleet.organization.tagsDescription": "Utilize um dicionário de etiquetas governado em vez de etiquetas de texto livre inconsistentes.", + "fleet.organization.addRoot": "Adicionar localização de nível superior", + "fleet.organization.addLocation": "Adicionar localização", + "fleet.organization.editLocation": "Editar localização", + "fleet.organization.addChild": "Adicionar sublocalização", + "fleet.organization.type": "Tipo", + "fleet.organization.parent": "Localização principal", + "fleet.organization.topLevel": "Nível superior", + "fleet.organization.sortOrder": "Ordem de ordenação", + "fleet.organization.contents": "Conteúdo", + "fleet.organization.cameras": "Câmaras", + "fleet.organization.system": "Sistema", + "fleet.organization.contentCounts": "{cameras} câmaras · {children} sublocalizações", + "fleet.organization.locationNotEmpty": "Mova as câmaras e elimine as sublocalizações primeiro", + "fleet.organization.noLocations": "Nenhuma localização configurada.", + "fleet.organization.locationCreated": "Localização criada", + "fleet.organization.locationUpdated": "Localização atualizada", + "fleet.organization.locationDeleted": "Localização eliminada", + "fleet.organization.deleteLocationConfirm": "Eliminar a localização \"{name}\"?", + "fleet.organization.addTag": "Adicionar etiqueta", + "fleet.organization.editTag": "Editar etiqueta", + "fleet.organization.tagLabel": "Etiqueta", + "fleet.organization.color": "Cor (#RRGGBB)", + "fleet.organization.tagDescription": "Descrição", + "fleet.organization.noTags": "Nenhuma etiqueta normalizada configurada.", + "fleet.organization.tagCreated": "Etiqueta criada", + "fleet.organization.tagUpdated": "Etiqueta atualizada", + "fleet.organization.tagDeleted": "Etiqueta eliminada", + "fleet.organization.deleteTagConfirm": "Eliminar \"{name}\"? Está atualmente atribuída a {count} câmaras.", + "fleet.organization.merge": "Unir", + "fleet.organization.mergeTagNamed": "Unir \"{name}\"", + "fleet.organization.mergeInto": "Unir a", + "fleet.organization.chooseTag": "Escolha a etiqueta a manter", + "fleet.organization.mergeWarning": "Todas as atribuições de câmaras passam para a etiqueta mantida; a etiqueta de origem é depois removida.", + "fleet.organization.tagsMerged": "Etiquetas unidas", + "fleet.organization.saveError": "Não foi possível guardar: {message}", + "fleet.organization.deleteError": "Não foi possível eliminar: {message}", + "fleet.locationType.site": "Local", + "fleet.locationType.building": "Edifício", + "fleet.locationType.floor": "Piso", + "fleet.locationType.area": "Área", + "fleet.locationType.zone": "Zona", + "fleet.locationType.system": "Sistema", + "fleet.bulk.title": "Organizar câmaras selecionadas", + "fleet.bulk.description": "Aplicar alterações de localização e etiquetas a {count} câmaras com concorrência limitada.", + "fleet.bulk.location": "Atribuição de localização", + "fleet.bulk.locationHelp": "Todas as câmaras selecionadas serão movidas para a localização escolhida.", + "fleet.bulk.keepLocations": "Manter localizações atuais", + "fleet.bulk.tags": "Atribuição de etiquetas", + "fleet.bulk.tagsHelp": "Adicionar ou remover etiquetas sem afetar outras atribuições, ou substituir explicitamente o conjunto completo de etiquetas.", + "fleet.bulk.tagOperation.none": "Manter", + "fleet.bulk.tagOperation.add": "Adicionar", + "fleet.bulk.tagOperation.remove": "Remover", + "fleet.bulk.tagOperation.replace": "Substituir tudo", + "fleet.bulk.replaceWarning": "Substituir tudo remove todas as etiquetas atuais antes de aplicar esta seleção. Uma seleção vazia limpa todas as etiquetas.", + "fleet.bulk.apply": "Aplicar alterações", + "fleet.bulk.working": "A aplicar alterações…", + "fleet.bulk.success": "{count} câmaras atualizadas", + "fleet.bulk.partial": "{succeeded} câmaras atualizadas; {failed} falharam", + "fleet.bulk.error": "Não foi possível organizar as câmaras: {message}", + "fleet.bulk.failures": "Câmaras que não puderam ser atualizadas", + "fleet.queues.degraded": "Fluxos degradados", + "fleet.queues.offline": "Câmaras offline", + "fleet.queues.oldest": "Mais antigo: {time}", + "fleet.queues.noneActive": "Sem condições ativas", + "fleet.views.title": "Vistas guardadas", + "fleet.views.choose": "Escolher uma vista guardada", + "fleet.views.none": "Ainda sem vistas guardadas", + "fleet.views.shared": "Partilhado", + "fleet.views.saveCurrent": "Guardar vista atual", + "fleet.views.name": "Nome da vista", + "fleet.views.share": "Partilhar com todos os operadores", + "fleet.views.saved": "Vista de frota guardada", + "fleet.views.saveError": "Não foi possível guardar a vista: {message}", + "fleet.views.deleted": "Vista de frota eliminada", + "fleet.views.deleteConfirm": "Eliminar a vista guardada \"{name}\"?", + "fleet.views.deleteError": "Não foi possível eliminar a vista: {message}", + "fleet.views.unsupported": "Este seletor guardado não pode ser representado pelos controlos de filtro atuais.", + "collections.manage": "Coleções", + "collections.all": "Todas as coleções", + "collections.filter": "Coleção", + "collections.loadMembersError": "Não foi possível carregar as câmaras da coleção: {message}", + "collections.title": "Coleções de câmaras", + "collections.subtitle": "Crie grupos de câmaras reutilizáveis para operações, vistas guardadas e fluxos de trabalho a jusante.", + "collections.listDescription": "As coleções estáticas mantêm membros explícitos; as coleções inteligentes avaliam continuamente as regras da frota.", + "collections.create": "Criar coleção", + "collections.edit": "Editar coleção", + "collections.editorDescription": "As definições de coleção utilizam UUIDs estáveis de câmaras, localizações e etiquetas.", + "collections.backToList": "Voltar às coleções", + "collections.type": "Tipo de coleção", + "collections.type.static": "Estática", + "collections.type.smart": "Inteligente", + "collections.description": "Descrição", + "collections.shared": "Coleção partilhada", + "collections.sharedHelp": "Permitir que outros utilizadores autorizados vejam esta coleção; as regras de acesso às câmaras continuam a aplicar-se.", + "collections.typeChangeWarning": "Alterar o tipo de coleção substitui o modelo de membros. Os membros estáticos ou regras inteligentes do tipo anterior deixarão de se aplicar.", + "collections.selectorError": "O seletor não é válido: {message}", + "collections.created": "Coleção criada", + "collections.updated": "Coleção atualizada", + "collections.saveError": "Não foi possível guardar a coleção: {message}", + "collections.loadError": "Não foi possível carregar a coleção: {message}", + "collections.cameras": "câmaras", + "collections.visibility.shared": "Partilhada", + "collections.visibility.private": "Privada", + "collections.selectorRedacted": "Regras privadas", + "collections.emptyTitle": "Ainda não existem coleções", + "collections.emptyAdmin": "Crie um grupo estático ou uma vista baseada em regras inteligentes para reutilizar seleções de câmaras.", + "collections.emptyViewer": "Não existem coleções partilhadas disponíveis para o seu âmbito de câmaras.", + "collections.deleteConfirm": "Eliminar a coleção \"{name}\"?", + "collections.deleted": "Coleção eliminada", + "collections.deleteError": "Não foi possível eliminar a coleção: {message}", + "collections.preview.title": "Pré-visualização de regras", + "collections.preview.matches": "{count} câmaras correspondentes", + "collections.preview.action": "Pré-visualizar", + "collections.preview.hide": "Ocultar pré-visualização", + "collections.preview.loading": "A avaliar…", + "collections.preview.empty": "Nenhuma câmara corresponde atualmente.", + "collections.preview.sample": "A mostrar uma amostra de {count} câmaras de {total} correspondências.", + "collections.preview.error": "Não foi possível pré-visualizar a coleção: {message}", + "collections.members.title": "Membros estáticos", + "collections.members.selected": "{count} câmaras selecionadas em todas as páginas", + "collections.members.search": "Procurar câmaras…", + "collections.members.selectPage": "Selecionar esta página", + "collections.members.empty": "Nenhuma câmara corresponde a esta pesquisa.", + "collections.builder.title": "Regras inteligentes", + "collections.builder.description": "As regras são avaliadas com base na organização, configuração, capacidades e estado atual das câmaras.", + "collections.builder.match": "Corresponder a", + "collections.builder.allRules": "todas as regras", + "collections.builder.anyRule": "qualquer regra", + "collections.builder.addRule": "Adicionar regra", + "collections.builder.removeRule": "Remover regra", + "collections.builder.matchesAll": "Sem regras completas, esta coleção corresponde a todas as câmaras no âmbito autorizado do utilizador.", + "collections.builder.incompleteRule": "Conclua ou remova todas as regras antes de guardar.", + "collections.builder.chooseLocation": "Escolher uma subárvore de localização", + "collections.builder.vendorPlaceholder": "Nomes de fabricantes, separados por vírgulas", + "collections.builder.modelPlaceholder": "Nomes de modelos, separados por vírgulas", + "collections.builder.advancedMode": "JSON avançado", + "collections.builder.visualMode": "Editor visual", + "collections.builder.cannotVisualize": "Este seletor contém lógica aninhada ou avançada que o editor visual não consegue representar com segurança.", + "collections.rule.location_subtree": "Localização está dentro de", + "collections.rule.camera_uuid": "Câmaras específicas", + "collections.rule.tag_any": "Tem alguma etiqueta", + "collections.rule.tag_all": "Tem todas as etiquetas", + "collections.rule.tag_none": "Não tem nenhuma das etiquetas", + "collections.rule.health": "Estado de saúde é", + "collections.rule.enabled": "Câmara está", + "collections.rule.recording_mode": "Modo de gravação é", + "collections.rule.capability_any": "Tem alguma funcionalidade", + "collections.rule.capability_all": "Tem todas as funcionalidades", + "collections.rule.vendor": "Fabricante é", + "collections.rule.model": "Modelo é", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Canal de áudio de retorno", + "streamHealth.observedFps": "FPS observado", + "streamHealth.expectedFps": "Esperado", + "streamHealth.fpsHelp": "Observado pelo LightNVR; o valor esperado provém dos metadados do fluxo da câmara.", + "login.passwordChanged": "Palavra-passe alterada com sucesso. Inicie sessão com a sua nova palavra-passe.", + "passwordChangeRequired.title": "Alterar a palavra-passe predefinida", + "passwordChangeRequired.description": "Esta instalação ainda utiliza a palavra-passe predefinida do administrador. Substitua-a antes de continuar para o LightNVR. A MFA, quando ativada, é verificada no próximo início de sessão.", + "passwordChangeRequired.currentPassword": "Palavra-passe atual", + "passwordChangeRequired.newPassword": "Nova palavra-passe", + "passwordChangeRequired.confirmPassword": "Confirmar nova palavra-passe", + "passwordChangeRequired.passwordHelp": "Utilize pelo menos 8 caracteres. A palavra-passe não pode ser admin.", + "passwordChangeRequired.submit": "Alterar palavra-passe", + "passwordChangeRequired.saving": "A alterar a palavra-passe...", + "passwordChangeRequired.error.currentRequired": "Introduza a sua palavra-passe atual.", + "passwordChangeRequired.error.tooShort": "A nova palavra-passe deve ter pelo menos 8 caracteres.", + "passwordChangeRequired.error.defaultPassword": "A nova palavra-passe não pode ser admin.", + "passwordChangeRequired.error.mismatch": "As novas palavras-passe não coincidem.", + "passwordChangeRequired.error.generic": "A palavra-passe não pôde ser alterada. Tente novamente.", + "settings.tab.health": "Estado", + "settings.tab.workspaces": "Áreas de trabalho", + "settings.health.title": "Estado do host e do hardware", + "settings.health.description": "Configure a monitorização limitada do sistema operativo e do hardware sem expor caminhos de dispositivos ou segredos.", + "settings.health.enabled": "Ativar monitorização do estado", + "settings.health.enabledHelp": "Recolha sinais suportados de host, serviço, armazenamento, rede e hardware.", + "settings.health.profile": "Perfil de política", + "settings.health.profileHelp": "Equilibrado é a predefinição normal; conservador exige evidências mais fortes antes de emitir alertas.", + "settings.health.profile.balanced": "Equilibrado", + "settings.health.profile.conservative": "Conservador", + "settings.health.hardwareProvider": "Fornecedor de hardware", + "settings.health.provider.auto": "Automático (fornecedores do kernel)", + "settings.health.provider.smartctl": "smartctl (explícito)", + "settings.health.providerHelp.auto": "Utiliza apenas fornecedores sysfs, NVMe e kernel limitados; smartctl nunca é inferido.", + "settings.health.providerHelp.smartctl": "Ativa explicitamente o fornecedor JSON smartctl opcional e limitado para dispositivos detetados.", + "settings.health.providerHelp.disabled": "Desativa fornecedores de hardware opcionais, mantendo a monitorização de estado portátil disponível.", + "settings.health.writeProbe": "Ativar teste de escrita no armazenamento", + "settings.health.writeProbeHelp": "Executa periodicamente o teste limitado ao destino de gravação configurado.", + "settings.health.cadences": "Cadências de amostragem", + "settings.health.cadencesHelp": "Os intervalos devem manter-se ordenados do mais rápido até à amostragem de dispositivos e dentro dos limites do servidor.", + "settings.health.fastInterval": "Intervalo rápido", + "settings.health.normalInterval": "Intervalo normal", + "settings.health.slowInterval": "Intervalo lento", + "settings.health.deviceInterval": "Intervalo de dispositivo", + "settings.health.presenceInterval": "Intervalo de presença", + "settings.health.retention": "Retenção de incidentes", + "settings.health.conditions": "Substituições de condições", + "settings.health.conditionsHelp": "Substitua apenas códigos de condições e unidades devolvidos pelo registo de políticas efetivas.", + "settings.health.conditionOverride": "substituição de condição", + "settings.health.overrideMode": "Modo de substituição", + "settings.health.overrideModeHelp": "Herdar o perfil selecionado, selecionar outro perfil limitado, desativar a condição ou definir limiares validados.", + "settings.health.profileDefault": "Utilizar perfil selecionado", + "settings.health.custom": "Limiares personalizados", + "settings.health.warning": "Limiar de aviso", + "settings.health.critical": "Limiar crítico", + "settings.health.recovery": "Limiar de recuperação", + "settings.health.warning_for_seconds": "Segundos de permanência de aviso", + "settings.health.critical_for_seconds": "Segundos de permanência crítica", + "settings.health.recovery_for_seconds": "Segundos de permanência de recuperação", + "settings.health.clearOverrides": "Limpar substituições", + "settings.health.registryUnavailable": "O servidor não devolveu um registo de condições. Recarregue antes de editar substituições.", + "settings.health.resetDefaults": "Repor predefinições de saúde", + "settings.health.reloadGuidance": "A gravação é atómica. Recarregue após uma gravação bem-sucedida para confirmar a política efetiva; reinicie apenas quando o servidor o solicitar explicitamente.", + "settings.health.validation.profile": "Escolha um perfil de saúde suportado.", + "settings.health.validation.provider": "Escolha um fornecedor de hardware suportado.", + "settings.health.validation.healthFastIntervalSeconds": "O intervalo rápido deve ser um número inteiro entre 5 e 60 segundos.", + "settings.health.validation.healthNormalIntervalSeconds": "O intervalo normal deve ser um número inteiro entre 15 e 600 segundos.", + "settings.health.validation.healthSlowIntervalSeconds": "O intervalo lento deve ser um número inteiro entre 60 e 3600 segundos.", + "settings.health.validation.healthDeviceIntervalSeconds": "O intervalo do dispositivo deve ser um número inteiro entre 300 e 86400 segundos.", + "settings.health.validation.healthPresenceIntervalSeconds": "O intervalo de presença deve ser um número inteiro entre 15 e 3600 segundos.", + "settings.health.validation.healthIncidentRetentionDays": "A retenção de incidentes deve ser um número inteiro entre 7 e 3650 dias.", + "settings.health.validation.ordered": "Os intervalos de amostragem devem estar ordenados: rápido, normal, lento e dispositivo.", + "settings.health.validation.overrides": "As substituições de condições devem utilizar códigos únicos e perfis suportados do registo do servidor.", + "settings.health.validation.thresholds": "Os limiares personalizados devem ser valores finitos dentro dos limites da unidade da condição.", + "settings.health.validation.thresholdOrder": "Os limiares de aviso, crítico e de recuperação devem preservar a direção do alerta e a histerese da condição.", + "settings.health.validation.dwell": "Os tempos de permanência devem ser segundos inteiros dentro de sete dias; a permanência de aviso e de recuperação não pode ser zero.", + "workspaces.title": "Áreas de trabalho do operador", + "workspaces.description": "Escolha quais áreas de trabalho especializadas aparecem na sua navegação e interface da página.", + "workspaces.saved": "Preferências da área de trabalho guardadas", + "workspaces.saveError": "Não foi possível guardar as preferências da área de trabalho: {message}", + "workspaces.loadError": "Não foi possível carregar as preferências da área de trabalho.", + "workspaces.showWorkspace": "Mostrar {name}", + "workspaces.authorizationNote": "Controla apenas a apresentação. URLs diretos e acesso à API continuam a seguir a sua política de autorização.", + "workspaces.liveNavigator": "Navegador em direto avançado", + "workspaces.liveNavigatorDescription": "Árvore de localizações, filtros de disponibilidade, layouts guardados e eventos recentes.", + "workspaces.investigation": "Investigação", + "workspaces.investigationDescription": "Pesquisar, correlacionar, proteger e exportar provas gravadas.", + "settings.reduceMotion": "Reduzir movimento", + "settings.reduceMotionHelp": "Desativa animações e transições não essenciais. A opção Automática segue a preferência do seu sistema operativo.", + "settings.reduceMotionPreference": "Preferência de redução de movimento", + "settings.reduceMotionAuto": "Automática", + "settings.reduceMotionOn": "Ativado", + "settings.reduceMotionOff": "Desativado", + "settings.audioCompliance": "Conformidade de áudio", + "settings.disableAudioGlobally": "Desativar áudio em toda a instância", + "settings.audioDisabled": "O áudio está desativado globalmente", + "settings.audioComplianceHelp": "Impede a escuta em direto, a comunicação bidirecional e o áudio em novas gravações nesta instância. Guardar reinicia as sessões de multimédia go2rtc ativas. As gravações existentes não são modificadas.", + "tokens.manage": "Gerir acesso à API", + "tokens.title": "Acesso à API — {username}", + "tokens.description": "Crie credenciais com âmbito restrito para integrações e revogue cada uma independentemente.", + "tokens.recommendedTitle": "Tokens com âmbito são recomendados", + "tokens.recommendedDescription": "Cada token expira, tem ações explícitas e um âmbito de câmara, e nunca pode exceder a política de acesso atual do utilizador.", + "tokens.coverageNotice": "As permissões disponíveis refletem o que este servidor aplica. Um token só pode utilizar permissões que o seu utilizador já possui.", + "tokens.createTitle": "Criar token com âmbito", + "tokens.createDescription": "Utilize um token por integração para que possa ser identificado, renovado e revogado sem afetar o resto.", + "tokens.name": "Nome da integração", + "tokens.namePlaceholder": "ex.: Ponte PTZ da garagem norte", + "tokens.expiry": "Expira após", + "tokens.expiryDays": "{days} dias", + "tokens.actions": "Ações permitidas", + "tokens.actionsHelp": "Escolha apenas o que esta integração necessita. As ações destrutivas merecem o seu próprio token.", + "tokens.destructive": "Destrutivas", + "tokens.noEnforcedActions": "Não existem ações com token disponíveis nesta versão do servidor.", + "tokens.scope.label": "Âmbito da câmara", + "tokens.scope.all": "Toda a frota de câmaras", + "tokens.scope.collection": "Coleção partilhada", + "tokens.scope.selector": "Seletor personalizado", + "tokens.scope.chooseCollection": "Coleção de câmaras partilhada", + "tokens.scope.allValue": "Toda a frota", + "tokens.scope.collectionValue": "Coleção: {name}", + "tokens.scope.selectorValue": "Seletor dinâmico personalizado", + "tokens.create": "Criar token", + "tokens.creating": "A criar token…", + "tokens.createdSuccess": "Token de API com âmbito criado", + "tokens.createError": "Não foi possível criar o token de API: {message}", + "tokens.invalidResponse": "O servidor devolveu uma resposta de credenciais incompleta.", + "tokens.existingTitle": "Tokens existentes", + "tokens.existingDescription": "Apenas os prefixos e metadados permanecem disponíveis após a criação.", + "tokens.emptyTitle": "Sem tokens ativos", + "tokens.emptyDescription": "Crie um token com âmbito para a primeira integração que necessite de acesso à API.", + "tokens.showInactive": "Mostrar {count} inativos", + "tokens.status.active": "Ativo", + "tokens.status.expired": "Expirado", + "tokens.status.revoked": "Revogado", + "tokens.expires": "Expira", + "tokens.expiresValue": "Expira {date}", + "tokens.created": "Criado", + "tokens.lastUsed": "Última utilização", + "tokens.revoke": "Revogar", + "tokens.revoking": "A revogar…", + "tokens.revokeConfirm": "Revogar \"{description}\"? Os pedidos que o utilizam deixarão de funcionar imediatamente.", + "tokens.revokedSuccess": "Token da API revogado", + "tokens.revokeError": "Não foi possível revogar o token de API: {message}", + "tokens.validation.missing_description": "Dê um nome à integração que utilizará este token.", + "tokens.validation.description_too_long": "Mantenha o nome da integração com menos de 128 caracteres.", + "tokens.validation.invalid_expiry": "Escolha a validade do token entre 1 e 365 dias.", + "tokens.validation.missing_actions": "Escolha pelo menos uma ação permitida.", + "tokens.validation.invalid_action": "Uma ou mais ações selecionadas não estão habilitadas para token neste servidor.", + "tokens.validation.invalid_scope": "Escolha um âmbito de câmara válido.", + "tokens.validation.requires_all_scope": "As permissões que não são de câmara requerem o âmbito de frota completa de câmaras. Escolha esse âmbito ou remova essas permissões.", + "tokens.validation.missing_collection": "Escolha uma coleção partilhada disponível.", + "tokens.validation.invalid_selector": "Complete ou corrija o seletor de câmaras personalizado.", + "tokens.secret.oneTime": "Mostrado uma vez", + "tokens.secret.scopedTitle": "Guarde este token com âmbito agora", + "tokens.secret.legacyTitle": "Guarde esta chave de API legada agora", + "tokens.secret.scopedDescription": "O lightNVR armazena apenas um hash deste token. Se for perdido, revogue-o e crie outro.", + "tokens.secret.legacyDescription": "Esta chave de compatibilidade é apresentada aqui apenas uma vez. Gerar outra chave irá invalidá-la.", + "tokens.secret.value": "Credencial de API", + "tokens.secret.copied": "Copiado", + "tokens.secret.copySuccess": "Credencial de API copiada", + "tokens.secret.copyError": "Não foi possível copiar automaticamente; selecione e copie a credencial manualmente.", + "tokens.secret.savedConfirm": "Guardei esta credencial com segurança", + "tokens.secret.savedHelp": "Ao confirmar, este diálogo fecha-se. O valor completo não pode ser apresentado novamente.", + "tokens.legacy.title": "Chave de compatibilidade legada", + "tokens.legacy.description": "A chave legada tem o acesso efetivo completo deste utilizador, não expira e não pode ser limitada por câmara ou ação.", + "tokens.legacy.warning": "Gere uma apenas para uma integração existente cujos endpoints ainda não migraram para a aplicação de tokens com âmbito. Gerá-la invalida imediatamente a chave legada anterior.", + "tokens.legacy.generate": "Gerar chave legada", + "tokens.legacy.confirm": "Gerar uma nova chave legada? Isto invalida imediatamente a chave legada atual do utilizador.", + "tokens.legacy.createdSuccess": "Chave de API legada gerada", + "tokens.legacy.createError": "Não foi possível gerar a chave de API legada: {message}", + "audit.manage": "Histórico de auditoria", + "audit.title": "Auditoria de segurança e acesso", + "audit.description": "Rastreie resultados de início de sessão, decisões de acesso e alterações de políticas sensíveis sem expor credenciais.", + "audit.retention": "Retenção", + "audit.retentionDescription": "Os eventos são atualmente retidos durante {days} dias. Reduzir este valor elimina imediatamente o histórico mais antigo.", + "audit.retentionDays": "Dias", + "audit.retentionInvalid": "Escolha um período de retenção entre 1 e 3650 dias.", + "audit.retentionSaved": "Retenção de auditoria guardada; {count} eventos expirados eliminados", + "audit.retentionError": "Não foi possível guardar a retenção de auditoria: {message}", + "audit.filters": "Filtros", + "audit.clearFilters": "Limpar filtros", + "audit.applyFilters": "Aplicar filtros", + "audit.actor": "Ator", + "audit.unauthenticated": "Não autenticado", + "audit.outcome": "Resultado", + "audit.action": "Ação exata", + "audit.filterToAction": "Filtrar por esta ação", + "audit.since": "De", + "audit.until": "Até", + "audit.invalidDateRange": "A data de início deve ser anterior à data de fim.", + "audit.source": "Endereço de origem", + "audit.target": "Destino", + "audit.targetUuid": "UUID do destino", + "audit.noTarget": "Em todo o sistema", + "audit.requestId": "ID do pedido", + "audit.apiToken": "ID do token com âmbito", + "audit.showDetails": "Mostrar detalhes", + "audit.hideDetails": "Ocultar detalhes", + "audit.pageSize": "Por página", + "audit.resultRange": "A mostrar {start}–{end} de {total}", + "audit.empty": "Nenhum evento de auditoria correspondente", + "audit.emptyDescription": "Tente limpar um ou mais filtros, ou aguarde nova atividade de segurança.", + "audit.exportPage": "Exportar esta página", + "audit.exporting": "A exportar…", + "audit.exported": "Página de auditoria exportada", + "audit.exportError": "Não foi possível exportar eventos de auditoria: {message}", + "audit.pagination": "Páginas do histórico de auditoria", + "audit.page": "Página {page}", + "audit.modesTitle": "Decisões permitidas", + "audit.modesDescription": "Escolha como o acesso de leitura permitido é registado para cada ação. Pedidos que alteram algo, negações, erros e inícios de sessão são sempre registados. Resumir mantém uma entrada por utilizador, câmara e cliente a cada {minutes} minutos com uma contagem.", + "audit.mode.record": "Registar cada", + "audit.mode.summarize": "Resumir", + "audit.mode.off": "Desativado", + "audit.modeOffWarning": "O acesso permitido para esta ação deixará de aparecer no histórico de auditoria.", + "audit.modesSaved": "Modos de decisão de auditoria guardados", + "audit.modesError": "Não foi possível guardar os modos de decisão de auditoria: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Tipo de evento", + "audit.eventTypeSummary": "Resumos", + "audit.eventTypeDecision": "Decisões individuais", + "access.cameraSearch": "Procurar câmaras", + "access.cameraSearchPlaceholder": "Escreva pelo menos dois caracteres para procurar…", + "access.cameraSearchHint": "Procurar por nome da câmara, UUID, endereço, localização, etiqueta, fornecedor ou modelo.", + "access.cameraSelected": "Selecionadas", + "access.cameraAdd": "Adicionar", + "access.cameraLimit": "Um seletor pode conter no máximo 64 câmaras explícitas. Utilize uma regra de localização ou etiqueta para âmbitos maiores.", + "access.roles.manage": "Gerir funções", + "access.roles.title": "Funções de autorização", + "access.roles.description": "Agrupe ações em funções reutilizáveis e atribua essas funções a âmbitos de câmaras.", + "access.roles.create": "Criar função", + "access.roles.newRole": "Nova função", + "access.roles.copyName": "Cópia de {name}", + "access.roles.clone": "Clonar", + "access.roles.builtin": "Integrada", + "access.roles.builtinHelp": "As funções integradas são modelos fixos e seguros para atualizações. Clone uma para a personalizar.", + "access.roles.actionCount": "{count} ações", + "access.roles.destructive": "Ação sensível", + "access.roles.notEnforced": "Ainda não aplicado por nenhum endpoint", + "access.roles.destructiveWarning": "Esta função pode alterar a configuração ou evidências. Conceda-a apenas nos âmbitos onde essa autoridade é necessária.", + "access.roles.created": "Função criada", + "access.roles.updated": "Função atualizada", + "access.roles.deleted": "Função eliminada", + "access.roles.saveError": "Não foi possível guardar a função: {message}", + "access.roles.deleteError": "Não foi possível eliminar a função: {message}", + "access.roles.deleteConfirm": "Eliminar a função \"{name}\"? As funções referenciadas por concessões não podem ser eliminadas.", + "access.policy.manage": "Gerir acesso", + "access.policy.column": "Acesso", + "access.policy.scopedShort": "Com âmbito", + "access.policy.title": "Política de acesso — {username}", + "access.policy.description": "Gerir concessões de função com negação por omissão e pré-visualizar os respetivos âmbitos de câmara.", + "access.policy.tab.grants": "Concessões", + "access.policy.tab.test": "Testar acesso", + "access.policy.scopedWarning": "Apenas as ações permitidas por uma concessão correspondente e âmbito de câmara funcionarão.", + "access.policy.grants": "Concessões de função", + "access.policy.grantsDescription": "Uma concessão combina uma função com toda a frota, uma coleção partilhada ou um seletor de câmaras personalizado.", + "access.policy.addGrant": "Adicionar concessão", + "access.policy.noGrants": "Nenhuma concessão configurada", + "access.policy.noGrantsHelp": "Adicione pelo menos uma concessão antes de ativar a política com âmbito, a menos que este utilizador não deva ter acesso.", + "access.policy.role": "Função", + "access.policy.chooseRole": "Escolher uma função", + "access.policy.scope": "Âmbito de câmara", + "access.policy.allCameras": "Toda a frota de câmaras", + "access.policy.collectionScope": "Coleção partilhada", + "access.policy.collection": "Coleção de câmaras", + "access.policy.chooseCollection": "Escolher uma coleção partilhada", + "access.policy.collectionHelp": "O acesso acompanha a coleção à medida que câmaras são adicionadas, removidas ou correspondidas pelas suas regras.", + "access.policy.dynamicScope": "Seletor dinâmico", + "access.policy.activateConfirm": "Ativar a política com âmbito de negação por omissão para {username}? As ações sem uma concessão correspondente serão negadas.", + "access.policy.emptyConfirm": "Ativar a política com âmbito para {username} sem concessões? Isto remove intencionalmente todo o acesso controlado por política.", + "access.policy.saved": "Política de acesso guardada", + "access.policy.saveError": "Não foi possível guardar a política de acesso: {message}", + "access.policy.version": "Versão da política {version}", + "access.policy.unsaved": "Alterações não guardadas", + "access.policy.validation.invalid_mode": "Escolha um modo de avaliação válido.", + "access.policy.validation.missing_role": "Cada concessão deve referir uma função disponível.", + "access.policy.validation.invalid_scope": "Cada concessão deve usar um âmbito de frota completa, coleção partilhada ou seletor.", + "access.policy.validation.invalid_selector": "Complete ou corrija cada seletor de câmara antes de guardar.", + "access.policy.validation.missing_collection": "Escolha uma coleção partilhada disponível para cada concessão de coleção.", + "access.policy.validation.duplicate_grant": "Remova concessões duplicadas de função e âmbito antes de guardar.", + "access.test.title": "Testar acesso efetivo", + "access.test.description": "Avalie uma ação e câmara guardadas como {username} sem a executar.", + "access.test.saveFirst": "Guarde ou descarte as alterações de concessão antes de testar para que o resultado reflita a política apresentada aqui.", + "access.test.action": "Ação", + "access.test.camera": "Câmara", + "access.test.run": "Testar acesso", + "access.test.running": "A testar…", + "access.test.allowed": "Permitido", + "access.test.denied": "Negado", + "access.test.version": "Versão {version}", + "access.test.source": "Origem: {source} · Função: {role}", + "recordings.pullToRefresh": "Puxe para atualizar gravações", + "recordings.releaseToRefresh": "Solte para atualizar gravações", + "recordings.refreshing": "A atualizar gravações…", + "recordings.refreshed": "Gravações atualizadas", + "recordings.refreshFailed": "Não foi possível atualizar as gravações: {message}", + "recordings.download": "Transferir", + "recordings.tags": "Etiquetas", + "recordings.selectRecording": "Selecionar gravação", + "timeline.legend.recording": "Gravação", + "timeline.legend.detection": "Evento de deteção", + "timeline.detectionEvent": "Evento de deteção", + "streams.showCredentials": "Mostrar credenciais", + "streams.hideCredentials": "Ocultar credenciais", + "streams.streamSuccessfullyEnabled": "Transmissão ativada com sucesso.", + "streams.errorEnablingStream": "Erro ao ativar a transmissão: {message}", + "system.health.tab": "Estado", + "system.health.operatorView": "Estado operacional", + "system.health.title": "Estado do sistema", + "system.health.loading": "A carregar o estado do sistema…", + "system.health.loadError": "Não foi possível carregar o estado do sistema.", + "system.health.refreshing": "A atualizar…", + "system.health.activeIncidentCount": "{count} incidentes ativos", + "system.health.coverage": "Cobertura", + "system.health.monitoringDisabled": "A monitorização do estado está desativada", + "system.health.lastRecordedValue": "Último valor registado", + "system.health.monitoringDisabledHelp": "A monitorização do estado está desativada. Ative a monitorização do estado em Definições → Estado; reinicie se for solicitado após guardar. O histórico de incidentes mostra eventos passados, não a utilização atual de recursos.", + "system.health.monitoringRestartRequired": "A monitorização do estado está ativada na configuração guardada, mas o amostrador em execução continua desativado. Reinicie o LightNVR para aplicar a alteração. O histórico de incidentes mostra eventos passados.", + "system.health.containerCoverage": "Cobertura limitada do host", + "system.health.hostHardwareUnavailable": "Esta instalação pode ver o estado de contentores e recursos montados, mas o hardware do host não está disponível. Os valores em falta do host são desconhecidos, não saudáveis.", + "system.health.coverageUnknown": "Ainda não existe um instantâneo do estado concluído. Os valores permanecem desconhecidos até a recolha estar concluída.", + "system.health.coverageComplete": "Todos os factos visíveis para esta instalação foram recolhidos com sucesso.", + "system.health.coveragePartial": "A cobertura é parcial. {count} observações ou verificações de recolha estão indisponíveis, desatualizadas ou incompletas.", + "system.health.effectiveScope": "Âmbito efetivo", + "system.health.activeIncidents": "Incidentes ativos", + "system.health.noActiveIncidents": "Não são reportados incidentes ativos para a cobertura visível.", + "system.health.duration": "Duração", + "system.health.currentValue": "Valor atual", + "system.health.thresholds": "Limiar e permanência", + "system.health.thresholdSummary": "Aviso {warning}, crítico {critical}, recuperação {recovery} {unit}; permanência de aviso {seconds}s", + "system.health.remediation": "Resposta sugerida", + "system.health.facts": "Factos do estado", + "system.health.group.resources": "Recursos", + "system.health.group.storage": "Armazenamento", + "system.health.group.hardware": "Hardware", + "system.health.group.network": "Rede", + "system.health.group.clock": "Relógio", + "system.health.group.components": "Componentes", + "system.health.noFacts": "Não existem factos visíveis neste grupo.", + "system.health.observationState": "Capacidade e atualidade", + "system.health.valueUnavailable": "Um ou mais valores são desconhecidos", + "system.health.componentStatus": "Componentes de monitorização", + "system.health.collectors": "Coletores", + "system.health.collectorSummary": "{total} registados · {attention} necessitam de atenção", + "system.health.collectorsNeedingAttention": "Coletores que necessitam de atenção", + "system.health.collectionFailures": "{count} falhas ou tempos limite excedidos", + "system.health.stale": "desatualizado", + "system.health.eventDelivery": "Entrega de eventos", + "system.health.degraded": "Degradado", + "system.health.circularDelivery": "Este é o único canal de alerta configurado, pelo que não pode reportar autonomamente a sua própria falha.", + "system.health.incidentPersistence": "Persistência de incidentes", + "system.health.persistenceSummary": "{pending} pendentes · {failures} falhas · {retries} tentativas", + "system.health.recentSamples": "Atividade de recolha recente", + "system.health.recentSamplesHelp": "Até {count} resumos de geração limitados no servidor; isto é atividade de cobertura, não um gráfico de valores.", + "system.health.sampleSequence": "Geração {sequence}", + "system.health.sampleCoverage": "{observations} observações · {dropped} descartadas", + "system.health.noSamples": "Não existem gerações de recolha concluídas disponíveis.", + "system.health.incidentHistory": "Histórico de incidentes", + "system.health.incidentHistoryHelp": "Incidentes mais recentes primeiro. O histórico é carregado em páginas limitadas.", + "system.health.loadingHistory": "A carregar histórico de incidentes…", + "system.health.historyError": "Não foi possível carregar o histórico de incidentes.", + "system.health.emptyHistory": "Não foram registados incidentes.", + "system.health.firstSeen": "Primeira deteção", + "system.health.lastSeen": "Última deteção", + "system.health.deliveryState": "Estado de entrega", + "system.health.historyPagination": "Páginas do histórico de incidentes", + "system.health.pageCount": "{count} incidentes nesta página", + "system.health.remediation.memory": "Reduza a pressão de memória, verifique os limites de processos e cgroup, e reveja a atividade OOM recente.", + "system.health.remediation.cpu": "Identifique consumidores sustentados de CPU e verifique o throughput do serviço antes de alterar limites.", + "system.health.remediation.io": "Verifique a latência de armazenamento e os escritores ativos; preserve as gravações antes de manutenção disruptiva.", + "system.health.remediation.filesystem": "Verifique o sistema de ficheiros lógico designado, o espaço livre ou inodes, e confirme que permanece gravável.", + "system.health.remediation.thermal": "Melhore o arrefecimento e reduza a carga; inspecione ventoinhas e saídas de ar antes de as temperaturas atingirem os limites de desligamento.", + "system.health.remediation.network": "Verifique a interface visível, o link, o switch e os contadores de erros a partir de um caminho de rede independente.", + "system.health.remediation.clock": "Restaure a sincronização de tempo e verifique a fonte do relógio do host antes de depender das marcas temporais de eventos.", + "system.health.remediation.process": "Inspecione os limites de recursos e registos do LightNVR, depois reduza a carga ou aumente os limites validados.", + "system.health.remediation.storage": "Faça cópia de segurança das imagens importantes e inspecione o dispositivo de armazenamento mapeado antes de substituição ou reparação.", + "system.health.remediation.hardware": "Inspecione o hardware afetado e os registos da plataforma; agende manutenção se a condição persistir.", + "system.health.remediation.health": "Restaure o acesso e as permissões do coletor para que a evidência de saúde em falta possa ser avaliada.", + "system.health.remediation.system": "Reveja a execução anterior e os registos do host para distinguir um reinício de processo de um reinício do host.", + "system.health.remediation.event": "Utilize a API local ou a vista de métricas, alivie a pressão da fila durável e restaure um destino de alerta independente.", + "system.health.remediation.default": "Reveja o componente afetado e os registos recentes, depois verifique a recuperação numa nova geração de saúde.", + "system.capacityTarget": "Objetivo de capacidade", + "system.capacityTargetValue": "Manter {pct}% livre", + "system.fillRate": "Taxa de preenchimento", + "system.fillRateValue": "{value} / dia", + "system.projectedToTarget": "Tempo projetado até ao objetivo", + "system.projectedNow": "No/acima do objetivo agora", + "system.projectedDays": "~{count}d", + "system.projectedHours": "~{count}h", + "system.projectedUnknown": "—", + "common.description": "Descrição", + "common.remove": "Remover", + "streams.selectStream": "Selecionar {name}", + "streams.search": "Pesquisar streams", + "streams.searchPlaceholder": "Pesquisar câmaras, localizações ou etiquetas", + "streams.noStreamsMatchFilters": "Nenhum stream corresponde aos filtros atuais.", + "streamHealth.sourceConnected": "Fonte ligada", + "streamHealth.videoAdvancing": "Vídeo a avançar", + "streamHealth.recorderWriting": "Escrita do gravador", + "streamHealth.detectorOperating": "Detector em funcionamento", + "streamHealth.lastSegment": "Último segmento concluído", + "streams.disablingStreamsProgress": "A desativar transmissões…", + "streams.onvifInvalidAddress": "O endereço IP do dispositivo ONVIF está em falta ou é inválido.", + "streams.warningFallingBackToHttp": "A ligação HTTPS falhou; a tentar novamente via HTTP. As credenciais podem ser enviadas em texto simples.", + "streamsConfig.playbackTransport": "Transporte de reprodução", + "streamsConfig.playbackTransportHelp": "Escolha o método de reprodução no navegador para esta câmara e, quando selecionado, a sua ordem de recurso.", + "streamsConfig.playbackTransportUnavailable": "Indisponível no servidor: {transports}. Ative o transporte globalmente ou escolha outro perfil.", + "streamsConfig.audioDisabledByPolicy": "O áudio está desativado pela política da instância", + "streamsConfig.audioDisabledByPolicyHelp": "A gravação, a escuta em direto e a comunicação bidirecional estão indisponíveis enquanto a política global de conformidade de áudio estiver ativa.", + "streamsConfig.audioVoiceEnhancement": "Melhoria de voz (gravações)", + "streamsConfig.customApiModel": "Deteção de API personalizada", + "streamsConfig.modelNotSupportedByBuild": "não suportado por esta versão", + "streamsConfig.tierCriticalMultiplier": "Nível crítico ×", + "streamsConfig.tierImportantMultiplier": "Nível importante ×", + "streamsConfig.tierEphemeralMultiplier": "Nível efémero ×", + "streamsConfig.tierMultipliersHelp": "Multiplicadores por nível sobre a retenção base. As imagens de nível superior são mantidas mais tempo e removidas por último sob pressão de disco.", + "streamsConfig.storagePriority": "Prioridade de armazenamento (1-10)", + "streamsConfig.storagePriorityHelp": "Importância relativa das imagens desta transmissão ao libertar espaço; prioridade mais alta é preservada por mais tempo.", + "streamsConfig.restream": "Transmissão / Publicação (RTMP)", + "streamsConfig.publishUrl": "URL de publicação (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "Transmita esta câmara para um serviço como o YouTube Live via go2rtc. Cole o URL completo de ingestão RTMP incluindo a chave de stream (p. ex. rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Para transmitir para vários serviços em simultâneo, separe os URLs com vírgulas. O YouTube requer vídeo H264 e áudio AAC; o LightNVR agora transcodifica automaticamente (H264 para câmaras não-H264, AAC para áudio não-AAC), pelo que a maioria das câmaras funciona sem alterações. Nota: o YouTube também requer uma faixa de áudio — uma câmara sem áudio será rejeitada. Deixe em branco para desativar.", + "streams.lastSeen": "Visto pela última vez {time}", + "streams.claimed": "Reivindicado", + "streams.duplicateSuspected": "Possível duplicado", + "streams.duplicateSuspectedHelp": "A evidência de identidade estável ou de endpoint conflita com outro registo de descoberta.", + "streams.onvifClaimWarning": "A transmissão foi adicionada, mas o seu registo de descoberta não pôde ser marcado como reivindicado: {message}", + "common.online": "Online", + "common.offline": "Offline", + "settings.storageTargets.title": "Destinos de armazenamento de gravações", + "settings.storageTargets.description": "Registe discos locais e sistemas de ficheiros NFS ou SMB montados pelo administrador como destinos de gravação monitorizados de forma independente.", + "settings.storageTargets.foundationNotice": "A captura utiliza destinos de sistema de ficheiros. S3 buckets e destinos NFS/SAN montados podem conter cópias de arquivo verificadas. A pressão quente preserva as gravações arquivadas até que a sua retenção lógica expire.", + "settings.storageTargets.add": "Adicionar destino de armazenamento", + "settings.storageTargets.edit": "Editar destino de armazenamento", + "settings.storageTargets.editorHelp": "Os destinos ativados devem já existir e passar um teste de escrita, fsync e limpeza. Guarde uma montagem futura indisponível como desativada e ative-a após a montagem.", + "settings.storageTargets.name": "Nome do destino", + "settings.storageTargets.root": "Caminho raiz montado", + "settings.storageTargets.rootLocked": "Um destino predefinido ou não vazio mantém uma raiz imutável para que as gravações existentes não fiquem órfãs.", + "settings.storageTargets.class": "Classe de desempenho", + "settings.storageTargets.hot": "Quente — gravação ativa", + "settings.storageTargets.warm": "Morno — arquivo montado", + "settings.storageTargets.cold": "Frio — acesso pouco frequente", + "settings.storageTargets.reserveGb": "Espaço reservado (GB)", + "settings.storageTargets.lowWatermark": "Limiar inferior (% utilizado)", + "settings.storageTargets.highWatermark": "Limiar superior (% utilizado)", + "settings.storageTargets.migrationBandwidth": "Largura de banda do ciclo de vida (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 significa ilimitado. O limite é registado quando um trabalho de movimentação ou cópia é criado.", + "settings.storageTargets.archiveStart": "Início da janela de arquivo", + "settings.storageTargets.archiveEnd": "Fim da janela de arquivo", + "settings.storageTargets.archiveWindowHelp": "Hora local. Início e fim iguais permitem trabalhos de ciclo de vida durante todo o dia; uma janela noturna pode atravessar a meia-noite.", + "settings.storageTargets.enabled": "Ativado (as políticas de colocação podem selecionar este destino)", + "settings.storageTargets.notRouted": "Nenhuma política de colocação ativada encaminha câmaras para aqui. As novas gravações continuam a ir para o destino predefinido até que uma política defina este destino como principal, membro do grupo ou destino de arquivo.", + "settings.storageTargets.degradedNotice": "Acima do limiar superior ou dentro da reserva. As políticas de colocação ignoram este destino até que espaço seja libertado.", + "settings.storageTargets.probePassedIneligible": "O teste de escrita passou, mas o destino está {status}: as políticas de colocação não o selecionarão.", + "settings.storageTargets.mountRequired": "Exigir um sistema de ficheiros montado", + "settings.storageTargets.mountRequiredHelp": "Fixar este destino ao seu ponto de montagem atual não raiz. Se essa montagem NFS, SMB, bind ou PVC desaparecer, a gravação pausa em vez de escrever no diretório anfitrião subjacente.", + "settings.storageTargets.mountGuard": "Montagem obrigatória", + "settings.storageTargets.mountPending": "Será detetada quando o destino for ativado", + "settings.storageTargets.default": "Predefinido", + "settings.storageTargets.capacity": "Capacidade", + "settings.storageTargets.available": "Disponível", + "settings.storageTargets.recordings": "Gravações indexadas", + "settings.storageTargets.replicas": "{count} cópias verificadas · {bytes}", + "settings.storageTargets.reserve": "Reservado", + "settings.storageTargets.pressure.normal": "Pressão normal", + "settings.storageTargets.pressure.high": "Limiar elevado", + "settings.storageTargets.pressure.reserve": "Reserva excedida", + "settings.storageTargets.pressure.unavailable": "Pressão indisponível", + "settings.storageTargets.cleanupActive": "A limpeza por destino está ativa e trabalhará para {target} disponível sem eliminar gravações atribuídas a outro destino.", + "settings.storageTargets.test": "Testar destino", + "settings.storageTargets.probing": "A testar…", + "settings.storageTargets.probePassed": "Teste de escrita ao destino de armazenamento concluído", + "settings.storageTargets.duplicateFilesystem": "Esta raiz partilha o mesmo sistema de ficheiros subjacente que outro destino. A capacidade não deve ser contabilizada duas vezes quando o posicionamento está ativo.", + "settings.storageTargets.deleteLocked": "Os destinos predefinidos e não vazios não podem ser eliminados.", + "settings.storageTargets.deleteConfirm": "Eliminar o destino de armazenamento vazio \"{name}\"? Nenhum ficheiro será removido.", + "settings.storageTargets.created": "Destino de armazenamento criado", + "settings.storageTargets.updated": "Destino de armazenamento atualizado", + "settings.storageTargets.deleted": "Destino de armazenamento eliminado", + "settings.storageTargets.invalidThresholds": "Verifique os limiares, a reserva, a largura de banda do ciclo de vida e os períodos da janela de arquivo.", + "settings.storageTargets.loadError": "Não foi possível carregar os destinos de armazenamento", + "settings.storagePools.title": "Pools de armazenamento", + "settings.storagePools.description": "Agrupar destinos saudáveis para transbordo automático e replicação em destinos distintos.", + "settings.storagePools.add": "Adicionar pool", + "settings.storagePools.strategy": "Estratégia de alocação", + "settings.storagePools.mostFree": "Mais espaço livre", + "settings.storagePools.roundRobin": "Round robin", + "settings.storagePools.priority": "Prioridade explícita", + "settings.storagePools.members": "Destinos (a ordem de apresentação é a prioridade de alocação)", + "settings.storagePools.enabled": "Pool ativo", + "settings.storagePools.active": "Ativo", + "settings.storagePools.inactive": "Desativado", + "settings.storagePools.strategyValue.most_free": "mais livre", + "settings.storagePools.strategyValue.round_robin": "round robin", + "settings.storagePools.strategyValue.priority": "ordem de prioridade", + "settings.storagePools.created": "Pool de armazenamento criado", + "settings.storagePools.updated": "Pool de armazenamento atualizado", + "settings.storagePools.deleted": "Pool de armazenamento eliminado", + "settings.storagePools.deleteConfirm": "Eliminar pool de armazenamento \"{name}\"?", + "settings.storagePools.empty": "Ainda não existem pools de armazenamento.", + "settings.storageMigrations.title": "Trabalhos de migração de gravações", + "settings.storageMigrations.description": "Movimentos duráveis e cópias retidas respeitam a janela de arquivo e o limite de largura de banda de cada destino, verificam SHA-256 e recuperam com segurança após reinício.", + "settings.storageMigrations.empty": "Ainda não existem trabalhos de migração de gravações.", + "settings.storageMigrations.loadError": "Não foi possível carregar os trabalhos de migração de gravações", + "settings.storageMigrations.recording": "Gravação #{id}", + "settings.storageMigrations.attempt": "Tentativa {current}/{max}", + "settings.storageMigrations.operation.move": "Mover", + "settings.storageMigrations.operation.copy": "Cópia retida", + "settings.storageMigrations.cancelled": "Cancelamento da migração aceite", + "settings.storageMigrations.cancelling": "A cancelar…", + "settings.storageMigrations.retried": "Migração colocada na fila para nova tentativa", + "settings.storageMigrations.state.queued": "Na fila", + "settings.storageMigrations.state.copying": "A copiar", + "settings.storageMigrations.state.verifying": "A verificar", + "settings.storageMigrations.state.committing": "A confirmar", + "settings.storageMigrations.state.cleanup_pending": "A limpar origem", + "settings.storageMigrations.state.retry_wait": "A aguardar nova tentativa", + "settings.storageMigrations.state.completed": "Concluído", + "settings.storageMigrations.state.failed": "Falhado", + "settings.storageMigrations.state.cancelled": "Cancelado", + "settings.storagePolicies.title": "Políticas de colocação de câmaras", + "settings.storagePolicies.description": "Encaminha câmaras correspondentes para um destino de gravação primário por ordem de prioridade. Uma câmara utiliza a primeira política ativa que corresponda.", + "settings.storagePolicies.add": "Adicionar política de colocação", + "settings.storagePolicies.edit": "Editar política de colocação", + "settings.storagePolicies.editorHelp": "A política é reavaliada para novos segmentos. As alterações não movem gravações já existentes.", + "settings.storagePolicies.priority": "Prioridade (mais alta primeiro)", + "settings.storagePolicies.priorityValue": "Prioridade {priority}", + "settings.storagePolicies.primary": "Destino primário", + "settings.storagePolicies.primaryPool": "Pool de colocação (opcional)", + "settings.storagePolicies.exactTarget": "Utilizar o destino primário exato", + "settings.storagePolicies.fallback": "Se o primário estiver indisponível", + "settings.storagePolicies.fallbackDefault": "Utilizar o destino predefinido", + "settings.storagePolicies.fallbackTarget": "Utilizar um destino de recurso com nome", + "settings.storagePolicies.fallbackPause": "Pausar gravação", + "settings.storagePolicies.fallbackFail": "Falhar o início da gravação", + "settings.storagePolicies.namedFallback": "Destino de recurso", + "settings.storagePolicies.chooseTarget": "Escolher um destino", + "settings.storagePolicies.choosePool": "Escolher um pool", + "settings.storagePolicies.minimumDays": "Retenção mínima (dias)", + "settings.storagePolicies.desiredDays": "Retenção pretendida (dias)", + "settings.storagePolicies.maximumDays": "Retenção máxima (dias)", + "settings.storagePolicies.copyCount": "Cópias verificadas obrigatórias", + "settings.storagePolicies.replicationPool": "Pool de replicação", + "settings.storagePolicies.migrateAfter": "Mover após (dias)", + "settings.storagePolicies.migrationTarget": "Destino de arquivo", + "settings.storagePolicies.pressurePriority": "Prioridade de eliminação por pressão (menor primeiro)", + "settings.storagePolicies.disabledTarget": "desativado", + "settings.storagePolicies.enabled": "Política ativada", + "settings.storagePolicies.selector": "Câmaras correspondentes", + "settings.storagePolicies.preview": "Precedência de pré-visualização", + "settings.storagePolicies.previewing": "A avaliar…", + "settings.storagePolicies.previewRequired": "Pré-visualize o rascunho atual antes de guardar para ver a sobreposição de câmaras e a política vencedora efetiva.", + "settings.storagePolicies.previewSummary": "Corresponde a {matched} câmaras; este rascunho é efetivo para {effective}.", + "settings.storagePolicies.previewShadowed": "Uma política de precedência superior vence para {count} câmaras correspondentes.", + "settings.storagePolicies.previewWins": "Vence sobre \"{policy}\" (prioridade {priority}) para {count} câmaras.", + "settings.storagePolicies.previewLoses": "Perde para \"{policy}\" (prioridade {priority}) para {count} câmaras.", + "settings.storagePolicies.previewNoMatches": "Este seletor não corresponde atualmente a nenhuma câmara.", + "settings.storagePolicies.invalidPriority": "A prioridade deve ser um número inteiro entre -1 000 000 e 1 000 000.", + "settings.storagePolicies.invalidLifecycle": "Verifique a ordem de retenção, o número de cópias e o pool de replicação, e a idade e o destino de migração.", + "settings.storagePolicies.created": "Política de colocação criada", + "settings.storagePolicies.updated": "Política de colocação atualizada", + "settings.storagePolicies.deleted": "Política de colocação eliminada", + "settings.storagePolicies.deleteConfirm": "Eliminar a política de colocação \"{name}\"? As gravações existentes não são afetadas.", + "settings.storagePolicies.active": "Ativa", + "settings.storagePolicies.inactive": "Desativada", + "settings.storagePolicies.routesTo": "Destino principal: {target}", + "settings.storagePolicies.lifecycleSummary": "Retenção mín./desejada/máx.: {minimum}/{desired}/{maximum} dias · {copies} cópia/ cópias verificadas", + "settings.storagePolicies.fallsBackTo": "Destino alternativo: {target}", + "settings.storagePolicies.mode.default": "Alternativa: destino predefinido", + "settings.storagePolicies.mode.pause": "Alternativa: pausar gravação", + "settings.storagePolicies.mode.fail": "Alternativa: falhar o início da gravação", + "settings.storagePolicies.empty": "Sem políticas de colocação. As câmaras continuam a utilizar o destino predefinido; os outros destinos não recebem nada até uma política encaminhar câmaras para eles.", + "settings.storagePolicies.archiveNoTrigger": "Um destino de arquivo está definido, mas nada aciona uma movimentação. Defina 'Mover após idade (dias)', uma idade de arquivamento ou uma opção de arquivo; caso contrário, nenhuma gravação será movida.", + "settings.storageCompliance.title": "Capacidade e conformidade com políticas", + "settings.storageCompliance.description": "As taxas observadas a 30 dias preveem a pressão nos destinos e a retenção alcançada; as violações ativas do ciclo de vida permanecem visíveis até serem resolvidas.", + "settings.storageCompliance.loadError": "Não foi possível carregar a conformidade de armazenamento", + "settings.storageCompliance.unknown": "Desconhecido", + "settings.storageCompliance.days": "{days} dias", + "settings.storageCompliance.day": "dia", + "settings.storageCompliance.targetForecasts": "Previsões dos destinos", + "settings.storageCompliance.target": "Destino", + "settings.storageCompliance.dailyRate": "Taxa observada", + "settings.storageCompliance.toHigh": "Até ao limite superior", + "settings.storageCompliance.expected": "Retenção esperada", + "settings.storageCompliance.confidence": "Confiança", + "settings.storageCompliance.policyCompliance": "Conformidade com políticas", + "settings.storageCompliance.compliant": "Sem violações ativas", + "settings.storageCompliance.violationCount": "{count} violação(ões)", + "settings.storageCompliance.policyForecast": "Alcançado {achieved}; previsto {expected}; desejado {desired} dias.", + "settings.storageCompliance.copyDeficits": "{count} gravação(ões) precisa(m) de outra cópia verificada.", + "settings.storageCompliance.activeViolations": "Violações ativas", + "settings.storageCompliance.type.copy_count": "Número de cópias", + "settings.storageCompliance.type.minimum_retention": "Capacidade mínima de retenção", + "settings.storageCompliance.type.target_unavailable": "Destino indisponível", + "settings.storageCompliance.type.migration_failed": "Falha na tarefa de ciclo de vida", + "settings.recordingDirectoryFormat": "Estrutura de pastas de gravação", + "settings.recordingDirectoryFormatHelp": "Organiza novas gravações MP4 em subpastas dentro da pasta de cada câmara. As gravações existentes não são movidas.", + "settings.recordingDirectoryFlat": "Plano (apenas pasta da câmara)", + "settings.recordingDirectoryMonth": "Por mês (AAAA/MM)", + "settings.recordingDirectoryDay": "Por dia (AAAA/MM/DD)", + "settings.minFreePct": "Espaço livre mínimo (%)", + "settings.minFreePctHelp": "Mantém pelo menos esta percentagem do volume livre, eliminando automaticamente as gravações mais antigas, independentemente dos dias de retenção. Isto limita a utilização ao tamanho do disco — defina-o e o disco nunca se enche. 0 desativa o limite de capacidade.", + "settings.pressureThresholds": "Limiares de pressão do disco (%)", + "settings.pressureThresholdsHelp": "Intervalos de espaço livre que escalam a limpeza automática. Devem satisfazer emergência < crítico < aviso.", + "settings.pressureWarningPct": "Aviso abaixo de (% livre)", + "settings.pressureCriticalPct": "Crítico abaixo de (% livre)", + "settings.pressureEmergencyPct": "Emergência abaixo de (% livre)", + "settings.databaseBackupVerify": "Verificação de cópias de segurança", + "settings.databaseBackupVerifyFull": "Completa (integrity_check, verifica todos os índices)", + "settings.databaseBackupVerifyQuick": "Rápida (quick_check, apenas estrutura de páginas)", + "settings.databaseBackupVerifyOff": "Desativada (sem verificação pós-cópia)", + "settings.databaseBackupVerifyHelp": "Verificação aplicada a cada cópia de segurança antes de ser publicada. A verificação completa pode demorar mais do que a cópia numa base de dados grande num disco mecânico e pode atingir o limite de segurança de 30 minutos, descartando essa cópia; a verificação rápida ainda deteta páginas danificadas ou truncadas com muito menos acessos ao disco.", + "settings.viewMethodAuto": "Automático — preferência por câmara com alternativa", + "settings.resetWizardPending": "A iniciar o assistente…", + "settings.apiDetectionFormat": "Formato de pedido à API", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (carregamento de imagem multipart)", + "settings.apiDetectionFormatDoods2": "DOODS2 (corpo JSON com imagem base64)", + "settings.apiDetectionFormatHelp": "Formato de comunicação que o LightNVR utiliza ao enviar instantâneos para a API de deteção. Mantenha light-object-detect para light-object-detect ou qualquer servidor que implemente o seu contrato; escolha DOODS2 para um servidor DOODS2.", + "settings.apiDetectionUrlHelpDoods2": "Endpoint /detect do DOODS2, p. ex. http://localhost:8080/detect. O pedido é enviado como JSON e não são adicionados parâmetros de consulta.", + "settings.apiDetectionDetectorName": "Nome do detetor DOODS2", + "settings.apiDetectionDetectorNameHelp": "Enviado como detector_name em cada pedido. Deve corresponder a um detetor listado pelo GET /detectors do servidor; \"default\" utiliza o detetor predefinido do servidor.", + "settings.defaultPlaybackTransport": "Transporte de reprodução predefinido", + "settings.defaultPlaybackTransportHelp": "Perfil de reprodução aplicado a novos fluxos criados. Os fluxos existentes mantêm a sua própria seleção.", + "playbackTransport.auto": "Automático (recomendado)", + "playbackTransport.webrtcOnly": "Apenas WebRTC", + "playbackTransport.mseOnly": "Apenas MSE", + "playbackTransport.hlsOnly": "Apenas HLS", + "playbackTransport.webrtcThenMse": "WebRTC, depois MSE", + "playbackTransport.mseThenHls": "MSE, depois HLS", + "investigation.experimental": "Espaço de trabalho experimental", + "investigation.title": "Investigação", + "investigation.description": "Reveja várias câmaras com um cursor UTC partilhado sem ocultar lacunas nas imagens.", + "investigation.query": "Janela de investigação", + "investigation.queryHelp": "Escolha até 16 câmaras. No máximo, quatro leitores de vídeo estão ativos em simultâneo.", + "investigation.cameras": "câmaras", + "investigation.cameraSelection": "Seleção de câmaras", + "investigation.start": "Início", + "investigation.end": "Fim", + "investigation.load": "Carregar investigação", + "investigation.applyWindow": "Aplicar intervalo de tempo", + "investigation.loading": "A carregar investigação…", + "investigation.eventType": "Tipo de evento", + "investigation.anyEventType": "Qualquer tipo de evento", + "investigation.eventType.detection": "Deteção", + "investigation.eventType.motion": "Movimento", + "investigation.location": "Localização", + "investigation.anyLocation": "Qualquer localização", + "investigation.objectLabel": "Etiqueta do objeto", + "investigation.anyLabel": "Qualquer etiqueta", + "investigation.zone": "Zona", + "investigation.anyZone": "Qualquer zona", + "investigation.source": "Fonte de deteção", + "investigation.anySource": "Qualquer fonte", + "investigation.captureMethod": "Método de captura", + "investigation.anyCaptureMethod": "Qualquer método de captura", + "investigation.recordingTag": "Etiqueta de gravação", + "investigation.anyRecordingTag": "Qualquer etiqueta de gravação", + "investigation.protection": "Proteção", + "investigation.anyProtection": "Qualquer proteção", + "investigation.protected": "Protegido", + "investigation.unprotected": "Não protegido", + "investigation.minimumConfidence": "Confiança mínima", + "investigation.confidenceError": "A confiança mínima deve estar entre 0 e 1.", + "investigation.metadataRegionSearch": "Pesquisa por região de metadados", + "investigation.regionSearchHelp": "Escolha uma câmara principal com imagens e desenhe uma área sobre o vídeo.", + "investigation.regionActive": "A procurar caixas guardadas de {camera}. A ausência de resultados não prova que nada atravessou a área.", + "investigation.regionMatch": "Correspondência de caixas", + "investigation.regionMatch.center": "Centro dentro", + "investigation.regionMatch.intersects": "Qualquer interseção", + "investigation.regionMatch.minimumIntersection": "Sobreposição mínima", + "investigation.regionMinimumOverlap": "Sobreposição mínima (%)", + "investigation.regionLeft": "Esquerda (%)", + "investigation.regionTop": "Topo (%)", + "investigation.regionWidth": "Largura (%)", + "investigation.regionHeight": "Altura (%)", + "investigation.drawRegion": "Desenhar área de pesquisa", + "investigation.drawingRegion": "A desenhar área de pesquisa…", + "investigation.clearRegion": "Limpar área", + "investigation.useFullFrame": "Usar quadro completo", + "investigation.drawRegionPrompt": "Arraste sobre o vídeo para definir a área de pesquisa", + "investigation.applyFilters": "Aplicar filtros", + "investigation.searching": "A procurar eventos…", + "investigation.searchResults": "Resultados de eventos", + "investigation.searchHelp": "Carregue uma investigação para pesquisar os metadados de eventos persistidos.", + "investigation.resultCount": "{count} eventos correspondentes", + "investigation.results": "resultados", + "investigation.resultHistogram": "Histograma de eventos", + "investigation.histogramHelp": "Selecione uma barra para mover o cursor partilhado.", + "investigation.previousResult": "Evento anterior", + "investigation.nextResult": "Evento seguinte", + "investigation.previousResultShortcut": "Evento anterior ([)", + "investigation.nextResultShortcut": "Evento seguinte (])", + "investigation.noResults": "Nenhum evento persistido corresponde a esta câmara, período e seleção de filtros.", + "investigation.noThumbnail": "Sem miniatura", + "investigation.exploreThumbnails": "Explorar miniaturas", + "investigation.exploreSelectedThumbnails": "Explorar em redor do evento", + "investigation.thumbnailDrilldown": "Análise detalhada de miniaturas", + "investigation.thumbnailDrilldownHelp": "Escolha qualquer momento, incluindo uma lacuna, para mover o cursor partilhado e regenerar um conjunto mais restrito de amostras.", + "investigation.selectThumbnailSample": "Inspecionar em redor de {time}", + "investigation.loadingThumbnail": "A carregar miniatura…", + "investigation.thumbnailUnavailable": "Miniatura indisponível", + "investigation.loadingSamples": "A carregar amostras de miniaturas…", + "investigation.thumbnailCoverageTruncated": "Este intervalo contém mais gravações do que o amostrador conseguiu inspecionar. Reduza a janela temporal para uma cobertura completa.", + "investigation.bookmarks.save": "Guardar marcador", + "investigation.bookmarks.open": "Marcadores", + "investigation.bookmarks.saveTitle": "Guardar marcador de investigação", + "investigation.bookmarks.listTitle": "Marcadores de investigação", + "investigation.bookmarks.notHold": "Um marcador restaura esta vista, mas não protege as gravações da retenção ou eliminação normais.", + "investigation.bookmarks.title": "Nome do marcador", + "investigation.bookmarks.note": "Nota privada (opcional)", + "investigation.bookmarks.titleRequired": "Introduza um nome de marcador.", + "investigation.bookmarks.empty": "Não tem marcadores de investigação guardados.", + "investigation.bookmarks.cameraCount": "{count} câmara(s)", + "investigation.bookmarks.restore": "Abrir", + "investigation.bookmarks.confirmDelete": "Eliminar marcador?", + "investigation.actions.open": "Proteger / transferir", + "investigation.actions.title": "Gravações de investigação", + "investigation.actions.notEvidenceExport": "A proteção impede a eliminação por retenção normal. A transferência ZIP é uma exportação de conveniência, não um pacote de provas verificado.", + "investigation.actions.scope": "Âmbito da gravação", + "investigation.actions.selectedResult": "Evento e câmara selecionados", + "investigation.actions.fullWindow": "Todas as câmaras na janela de investigação", + "investigation.actions.preview": "Pré-visualizar gravações", + "investigation.actions.previewing": "A procurar gravações sobrepostas…", + "investigation.actions.invalidRange": "Escolha um intervalo de tempo válido com o fim depois do início.", + "investigation.actions.recordingCount": "{count} gravação(ões) sobreposta(s)", + "investigation.actions.protectedCount": "{count} já protegida(s)", + "investigation.actions.noRecordings": "Nenhuma gravação concluída se sobrepõe a esta seleção de câmara e tempo.", + "investigation.actions.protectDenied": "{count} gravação(ões) não protegida(s) estão fora do seu âmbito de proteção e foram excluídas desta ação.", + "investigation.actions.exportDenied": "Falta a permissão de exportação para {count} gravação(ões). As descargas são tudo ou nada, por isso esta seleção não pode ser exportada.", + "investigation.actions.camera": "Câmara", + "investigation.actions.recording": "Gravação", + "investigation.actions.size": "Tamanho", + "investigation.actions.notPermitted": "Não permitido", + "investigation.actions.protectButton": "Proteger {count}", + "investigation.actions.protecting": "A proteger…", + "investigation.actions.protectUnavailable": "Não existem gravações não protegidas que possa proteger.", + "investigation.actions.protectResult": "Proteção concluída: {success} com sucesso, {failed} com falha.", + "investigation.actions.downloadButton": "Descarregar {count}", + "investigation.actions.downloadUnavailable": "Todas as gravações requerem permissão de exportação antes de criar um ZIP.", + "investigation.actions.buildingArchive": "A criar ZIP…", + "investigation.actions.downloadFailed": "A criação do ZIP falhou no servidor.", + "investigation.actions.downloadTimedOut": "A criação do ZIP não terminou em cinco minutos. Tente um intervalo mais reduzido.", + "investigation.actions.downloadStarted": "Descarga do ZIP iniciada.", + "investigation.backOneLevel": "Voltar um nível", + "investigation.thumbnailMinimumWindow": "Este é o intervalo de um segundo mais reduzido disponível. O cursor partilhado foi movido para o momento selecionado.", + "investigation.localSource": "local", + "investigation.mediaAvailable": "Multimédia disponível", + "investigation.durationSeconds": "Duração de {count}s", + "investigation.pageNumber": "Página {count}", + "investigation.incompleteCoverage": "{count} linhas de eventos legados não puderam ser atribuídas a uma identidade de câmara imutável.", + "investigation.spatialCoverageGap": "{count} linhas de eventos no âmbito não tinham caixa delimitadora e não foram pesquisadas espacialmente.", + "investigation.noSpatialMetadata": "Nenhum evento no âmbito tem caixas delimitadoras para esta pesquisa de metadados.", + "investigation.selectCameraError": "Selecione pelo menos uma câmara.", + "investigation.selectRecordingError": "Selecione pelo menos uma gravação.", + "investigation.investigateSelectedCount": "Investigar {count} gravação(ões) selecionada(s)", + "investigation.missingCameraIdentity": "Não é possível investigar: {count} gravação(ões) selecionada(s) não têm identidade de câmara.", + "investigation.recordingTimeError": "As gravações selecionadas não têm um intervalo de tempo válido.", + "investigation.windowLimit": "As gravações selecionadas ultrapassam o limite de investigação de 31 dias.", + "investigation.timeRangeError": "A hora de fim deve ser posterior à hora de início.", + "investigation.cameraLimit": "Uma investigação pode incluir no máximo {count} câmaras.", + "investigation.decoderLimit": "Apenas {count} leitores de câmara podem estar ativos em simultâneo.", + "investigation.playbackControls": "Controlos de reprodução sincronizados", + "investigation.play": "Reproduzir", + "investigation.pause": "Pausar", + "investigation.mode": "Modo de reprodução", + "investigation.wallClock": "Tempo real", + "investigation.skipCommonGaps": "Ignorar lacunas comuns", + "investigation.speed": "Velocidade", + "investigation.sharedCursor": "Cursor UTC partilhado", + "investigation.activePlayers": "leitores ativos", + "investigation.timeline": "linha temporal partilhada", + "investigation.segments": "segmentos", + "investigation.truncated": "truncado", + "investigation.gap": "Sem imagens", + "investigation.players": "Leitores de câmara sincronizados", + "investigation.activateCamera": "Ative pelo menos uma linha da linha temporal para carregar vídeo.", + "investigation.noFootage": "Sem imagens", + "investigation.noFootageAtTime": "Sem imagens no tempo partilhado", + "investigation.primaryAudio": "Áudio principal", + "investigation.makePrimary": "Definir como principal", + "investigation.status.loading": "A carregar multimédia", + "investigation.status.synchronizing": "A sincronizar", + "investigation.status.ready": "Sincronizado", + "investigation.status.late": "Atrasado — a recuperar", + "investigation.status.error": "Multimédia indisponível", + "investigation.status.paused-by-browser": "Selecione Reproduzir para permitir multimédia", + "streamsConfig.eptzTitle": "ePTZ fisheye", + "streamsConfig.eptzEnable": "Ativar ePTZ fisheye no navegador", + "streamsConfig.eptzHelp": "Desdistorcer o fluxo fisheye original na Visualização em direto, Reprodução na linha temporal e Investigação. Isto não altera gravações nem a saída da câmara.", + "streamsConfig.eptzModelHelp": "Projeção: fisheye circular equidistante · Montagem: teto. O centro e o raio utilizam coordenadas normalizadas da imagem de origem.", + "streamsConfig.eptzCenterX": "Centro ótico X", + "streamsConfig.eptzCenterY": "Centro ótico Y", + "streamsConfig.eptzRadius": "Raio do círculo de imagem", + "streamsConfig.eptzLensFov": "FOV da lente (graus)", + "streamsConfig.eptzRotation": "Rotação da lente (graus)", + "streamsConfig.eptzDefaultYaw": "Panorâmica predefinida (graus)", + "streamsConfig.eptzDefaultTilt": "Inclinação predefinida (graus)", + "streamsConfig.eptzViewFov": "FOV de visualização predefinido", + "streamsConfig.eptzCalibrationHelp": "Arraste para deslocar a vista, utilize a roda do rato ou o gesto de pinça para ampliar, e prima Home para repor a câmara virtual. Ajuste o centro e o raio se a borda do círculo de imagem não estiver alinhada.", + "settings.archive.targetType": "Tipo de armazenamento", + "settings.archive.filesystem": "Sistema de ficheiros local ou montado (NFS/SAN)", + "settings.archive.s3": "Bucket de arquivo compatível com S3", + "settings.archive.endpoint": "Endpoint HTTPS", + "settings.archive.region": "Região", + "settings.archive.bucket": "Bucket dedicado", + "settings.archive.credential_ref": "Referência de credenciais", + "settings.archive.budget": "Orçamento de arquivo (GiB, 0 = ilimitado)", + "settings.archive.connectionHelp": "Utilize um bucket privado, sem versionamento e sem regras de expiração de ciclo de vida. A referência de credenciais seleciona um ficheiro de segredo montado no servidor. Introduza a localização gerida como s3://bucket/instance-prefix.", + "settings.archive.policy": "Política de arquivo externo", + "settings.archive.archive_after_seconds": "Arquivar após captura (segundos, -1 = desativado)", + "settings.archive.hot_residency_seconds": "Manter cópia ativa (segundos, -1 = mover após arquivamento)", + "settings.archive.archive_protected": "Priorizar o arquivamento de gravações protegidas", + "settings.archive.archive_on_pressure": "Arquivar antecipadamente quando o armazenamento ativo estiver sob pressão", + "settings.archive.policyHelp": "O temporizador de arquivamento utiliza a idade da captura e requer uma gravação concluída. -1 desativa o arquivamento por idade ou remove o mínimo de permanência ativa; 0 significa imediatamente. As edições aplicam-se a novas gravações. Revise as gravações existentes para lhes aplicar uma nova revisão.", + "settings.archive.deletion_pending": "Eliminação pendente", + "settings.archive.archived": "Arquivado", + "settings.archive.hot": "Ativo", + "settings.archive.hot_and_archive": "Ativo + arquivo", + "settings.archive.archiving": "Arquivamento", + "settings.archive.preparing": "A preparar a reprodução", + "settings.archive.unavailable": "Indisponível", + "settings.archive.operations": "Operações de arquivo", + "settings.archive.readOnly": "Modo de recuperação: a migração e eliminação de gravações estão pausadas.", + "settings.archive.disabledBuild": "O suporte S3 está desativado nesta versão. Os destinos de sistema de ficheiros montados permanecem disponíveis.", + "settings.archive.stored": "Armazenado em buckets", + "settings.archive.backlog": "Fila de transferência", + "settings.archive.cache": "Cache de recuperação", + "settings.archive.objectsRemaining": "objetos restantes", + "settings.archive.waitingForReaders": "Em fila, ou à espera de leitores ativos.", + "settings.archive.applied": "Revisão de política aplicada a gravações existentes", + "settings.archive.reviewExisting": "Rever gravações existentes", + "settings.archive.applySummary": "{count} gravações ({bytes}) utilizarão esta revisão. {expired} já ultrapassaram o seu limite de retenção.", + "settings.archive.applyHelp": "As substituições de proteção e gravação continuam a aplicar-se. A retenção de stream e do sistema também se aplica. O novo tempo e destino de arquivo entram em vigor na próxima análise do ciclo de vida.", + "settings.archive.applyBlocked": "Conclua ou resolva as transferências associadas antes de aplicar esta revisão.", + "settings.archive.apply": "Aplicar a gravações existentes", + "common.fullscreenUnsupported": "O modo de ecrã inteiro não é suportado neste navegador.", + "recordings.viewInTimelineTitle": "Ver este stream neste ponto temporal na vista de Cronologia", + "recordings.clickToRetry": "Clique para tentar novamente", + "timeline.previousDay": "Dia anterior", + "timeline.nextDay": "Dia seguinte", + "timeline.previousMonth": "Mês anterior", + "timeline.nextMonth": "Mês seguinte", + "settings.searchLabel": "Pesquisar definições", + "settings.clearSearch": "Limpar pesquisa", + "recordings.addTagPlaceholder": "Adicionar uma etiqueta...", + "recordings.addNewTagPlaceholder": "Adicionar nova etiqueta..." } diff --git a/web/public/locales/ru.json b/web/public/locales/ru.json index c0a00c22..80cb21e1 100644 --- a/web/public/locales/ru.json +++ b/web/public/locales/ru.json @@ -759,9 +759,9 @@ "streamsConfig.streamNameImmutable": "Имя потока нельзя изменить после создания.", "streamsConfig.streamNameAllowedChars": "Разрешены только буквы, цифры, «.», «-» и «_» (без пробелов).", "streamsConfig.streamUrl": "URL потока", - "streamsConfig.streamUrlPlaceholder": "rtsp://имя пользователя:пароль@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "URL дополнительного потока (необязательно)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://имя пользователя:пароль@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "Поток низкого разрешения URL для представления сетки информационной панели. Оставьте пустым, чтобы использовать основной поток везде. Дополнительный поток используется только для предварительного просмотра в реальном времени в режиме сетки; запись и полноэкранный режим всегда используют основной поток.", "streamsConfig.urlCredentialsHiddenTitle": "Учетные данные URL скрыты в демонстрационном режиме/режиме просмотра.", "streamsConfig.urlCredentialsHidden": "Учетные данные URL скрыты в целях безопасности.", @@ -819,7 +819,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "Убедитесь, что light-object-detect работает на этой конечной точке.", "streamsConfig.customApiEndpointUrl": "Пользовательская конечная точка API URL", "streamsConfig.useDefaultEndpoint": "Использовать конечную точку по умолчанию", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/обнаружить", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "Введите полный URL в конечную точку API пользовательского обнаружения.", "streamsConfig.overrideWithCustomEndpoint": "Переопределить с помощью пользовательской конечной точки", "streamsConfig.detectionThreshold": "Порог обнаружения", @@ -1056,7 +1056,7 @@ "settings.detectionModelsPath": "Путь моделей обнаружения", "settings.detectionModelsPathHelp": "Каталог, в котором хранятся модели обнаружения", "settings.apiDetectionUrl": "API Обнаружение URL", - "settings.apiDetectionUrlHelp": "URL конечной точки обнаружения внешнего объекта API", + "settings.apiDetectionUrlHelp": "Конечная точка light-object-detect, например http://localhost:8000/api/v1/detect. Снимок загружается как multipart form data с добавленными параметрами запроса backend и confidence_threshold.", "settings.apiDetectionBackend": "Серверная часть обнаружения API", "settings.apiDetectionBackendOnnx": "Среда выполнения ONNX", "settings.apiDetectionBackendTflite": "ТензорФлоу Лайт", @@ -1156,5 +1156,1492 @@ "settings.discoveryIntervalSecondsRangeHelp": "Как часто сканировать камеры (30–3600 секунд)", "settings.discoveryNetwork": "Сеть Дискавери", "settings.discoveryNetworkExamples": "Примеры: 192.168.1.0/24, 10.0.0.0/16, авто.", - "settings.saveSettings": "Сохранить настройки" + "settings.saveSettings": "Сохранить настройки", + "live.navigator.title": "Навигатор", + "live.navigator.subtitle": "Расположения, раскладки и активность", + "live.navigator.cameras": "Камеры", + "live.navigator.plans": "План", + "live.navigator.views": "Просмотры", + "live.navigator.events": "События", + "live.navigator.search": "Найти камеру…", + "live.navigator.allCameras": "Все камеры", + "live.navigator.unassigned": "Не назначены", + "live.navigator.noCameras": "Нет камер в этой области.", + "live.navigator.saveCurrent": "Сохранить текущую раскладку", + "live.navigator.noLayouts": "Нет сохранённых раскладок.", + "live.navigator.layoutNamePrompt": "Название раскладки просмотра", + "live.navigator.shareLayoutPrompt": "Поделиться раскладкой с другими операторами?", + "live.navigator.layoutSaved": "Сохранена {name}", + "live.navigator.layoutLoaded": "Загружена {name}", + "live.navigator.deleteLayoutConfirm": "Удалить {name}?", + "live.navigator.shared": "Общая", + "live.navigator.loadingEvents": "Загрузка последних событий…", + "live.navigator.noRecentEvents": "Нет обнаружений за последний час.", + "live.navigator.expand": "Развернуть навигатор", + "live.navigator.collapse": "Свернуть навигатор", + "live.plan.navigatorHelp": "Выберите здание или этаж. Предпросмотр камер открывается только по запросу.", + "live.plan.noPlans": "Нет планов зданий. Создайте план в редакторе планов.", + "live.plan.emptyTitle": "Создайте пространственный обзор камер", + "live.plan.emptyDescription": "План отображает маркеры состояния для всего объекта и открывает видео только по запросу оператора. Нарисуйте комнаты и стены прямо здесь или загрузите скан планировки, чертёж объекта или снимок из вашего ПО NVR, затем привяжите камеры к реальным помещениям.", + "live.plan.sketch.tools": "Инструменты планировки", + "live.plan.sketch.tool.select": "Выделение", + "live.plan.sketch.tool.room": "Комната", + "live.plan.sketch.tool.wall": "Стена", + "live.plan.sketch.tool.area": "Зона", + "live.plan.sketch.tool.label": "Метка", + "live.plan.sketch.undo": "Отменить рисование", + "live.plan.sketch.redo": "Повторить рисование", + "live.plan.sketch.snap": "Привязка к сетке", + "live.plan.sketch.hint.select": "Перетаскивайте фигуры или камеры для перемещения. Нажмите на фигуру для редактирования; удерживайте Alt для отключения привязки к сетке.", + "live.plan.sketch.hint.room": "Перетащите на плане, чтобы нарисовать комнату или контур здания.", + "live.plan.sketch.hint.wall": "Нажимайте для добавления точек стены. Двойной клик или Enter для завершения, Escape для отмены.", + "live.plan.sketch.hint.area": "Нажимайте для обводки зоны. Нажмите на первую точку или Enter для замыкания.", + "live.plan.sketch.hint.label": "Нажмите на план, чтобы разместить текстовую метку.", + "live.plan.sketch.type.rect": "Комната", + "live.plan.sketch.type.wall": "Стена", + "live.plan.sketch.type.area": "Зона", + "live.plan.sketch.type.label": "Метка", + "live.plan.sketch.pointCount": "{count} точек", + "live.plan.sketch.defaultLabel": "Метка", + "live.plan.sketch.shapes": "Фигуры планировки", + "live.plan.sketch.noShapes": "Ничего не нарисовано. Выберите инструмент над планом, чтобы начать.", + "live.plan.sketch.tone": "Цвет", + "live.plan.sketch.tone.slate": "Сланец", + "live.plan.sketch.tone.blue": "Синий", + "live.plan.sketch.tone.green": "Зелёный", + "live.plan.sketch.tone.amber": "Янтарный", + "live.plan.sketch.tone.red": "Красный", + "live.plan.sketch.tone.violet": "Фиолетовый", + "live.plan.sketch.labelText": "Подпись", + "live.plan.sketch.text": "Текст", + "live.plan.sketch.size": "Размер", + "live.plan.sketch.size.sm": "Малый", + "live.plan.sketch.size.md": "Средний", + "live.plan.sketch.size.lg": "Большой", + "live.plan.sketch.filled": "Заполнить комнату", + "live.plan.sketch.left": "Слева %", + "live.plan.sketch.top": "Сверху %", + "live.plan.sketch.width": "Ширина %", + "live.plan.sketch.height": "Высота %", + "live.plan.sketch.points": "Точки", + "live.plan.sketch.point": "Точка {index}", + "live.plan.sketch.delete": "Удалить фигуру", + "live.plan.sketch.duplicate": "Дублировать", + "live.plan.sketch.deselect": "Готово", + "live.plan.sketch.emptyTitle": "На этом плане пока ничего нет", + "live.plan.sketch.emptyBody": "Рисуйте комнаты, стены и подписи прямо здесь, или загрузите скан плана, чертёж объекта или экспорт PNG/JPEG (до 768 КБ).", + "live.plan.sketch.emptyBodyReadOnly": "Администратор может нарисовать планировку или загрузить план реального здания.", + "live.plan.sketch.drawLayout": "Нарисовать планировку", + "live.plan.sketch.uploadImage": "Загрузить изображение", + "live.plan.sketch.limitReached": "Достигнут предел фигур ({max})", + "live.plan.sketch.discardDrawing": "Рисование отменено", + "live.favorites": "Избранное", + "live.favoritesOnly": "Показать только избранные камеры", + "live.addFavorite": "Добавить {stream} в избранное", + "live.removeFavorite": "Убрать {stream} из избранного", + "live.noFavorites": "Пока нет избранных камер. Используйте звезду на плитке камеры, чтобы добавить.", + "live.favoriteUpdateError": "Не удалось обновить избранное: {message}", + "live.resetZoom": "Сбросить масштаб", + "live.audioPlaybackBlocked": "Браузер заблокировал аудио камеры. Нажмите кнопку динамика ещё раз для повторной попытки.", + "live.fullscreenSubStreamFallback": "{stream}: недостаточно пропускной способности для полноэкранного потока в полном разрешении — переключено на субпоток.", + "live.tileActions": "Действия с камерой", + "live.takeSnapshot": "Сделать снимок", + "live.openStreamRecordings": "Открыть записи для этого потока", + "live.enterReorderMode": "Изменить порядок камер", + "live.pullToRefresh": "Потяните для обновления потоков", + "live.releaseToRefresh": "Отпустите для обновления потоков", + "live.refreshingStreams": "Обновление потоков…", + "live.streamsRefreshed": "Потоки обновлены", + "live.refreshStreamsFailed": "Не удалось обновить потоки: {message}", + "live.tipDoubleTapFullscreen": "Совет: дважды нажмите на плитку, чтобы открыть её на весь экран.", + "live.dayNightControl": "Режим день/ночь", + "live.dayNightLoading": "Загрузка…", + "live.dayNightApplying": "Применение…", + "live.dayNightMode_auto": "Авто", + "live.dayNightMode_day": "День", + "live.dayNightMode_night": "Ночь", + "live.dayNightMode_unknown": "Неизвестно", + "live.dayNightApplied": "Режим день/ночь установлен: {mode}", + "live.dayNightApplyFailed": "Не удалось установить режим день/ночь", + "live.dayNightLoadFailed": "Не удалось получить режим день/ночь", + "live.playbackFallbackUsed": "Резервный: {transport}", + "live.playbackTransportUnavailable": "{transport} отключён на сервере для данного потока.", + "live.recordingMode.constant": "Непрерывная запись", + "live.recordingMode.detection": "Запись по детекции", + "live.recordingMode.schedule": "Запись по расписанию", + "live.recordingMode.none": "Запись не ведётся", + "live.health.healthy": "Поток в норме", + "live.health.degraded": "Буферизация или восстановление потока", + "live.health.offline": "Поток недоступен", + "live.enterPictureInPicture": "Открыть «картинка в картинке»", + "live.exitPictureInPicture": "Закрыть «картинка в картинке»", + "live.pictureInPictureError": "Ошибка «картинка в картинке»: {message}", + "live.alwaysFullscreenOnTapEnable": "Включить полноэкранный режим при одном нажатии на плитку", + "live.alwaysFullscreenOnTapDisable": "Отключить полноэкранный режим при нажатии на плитку", + "live.displayMode": "Режим отображения", + "live.displayModeFit": "Вписать", + "live.displayModeFill": "Заполнить", + "live.displayModeFitDescription": "Вписать: показать весь кадр с чёрными полосами", + "live.displayModeFillDescription": "Заполнить: заполнить плитку, обрезая края кадра", + "live.slideshowStartCameras": "Начать слайд-шоу: переключение камер", + "live.slideshowStartPages": "Начать слайд-шоу: переключение страниц сетки", + "live.slideshowStop": "Остановить слайд-шоу", + "live.slideshowInterval": "Интервал слайд-шоу", + "live.slideshowSeconds": "{seconds} с", + "live.plan.previewUnavailable": "Предпросмотр камеры недоступен", + "live.plan.previewAlt": "Текущий вид с {name}", + "live.plan.degreesValue": "{value}°", + "live.plan.inDegrees": "{label} в градусах", + "live.plan.imageDimensionsError": "Не удалось прочитать размеры изображения", + "live.plan.loading": "Загрузка планов здания…", + "live.plan.created": "Создан {name}", + "live.plan.renamed": "Переименован в {name}", + "live.plan.deleted": "Удалён {name}", + "live.plan.backgroundType": "Фон должен быть изображением PNG или JPEG", + "live.plan.backgroundTooLarge": "Изображение фона слишком большое; максимум 768 КБ", + "live.plan.backgroundAspect": "Загружено, но соотношение сторон изображения не подходит ни для одного допустимого размера холста", + "live.plan.backgroundUpdatedSave": "Фон обновлён для {name}; сохраните макет, чтобы применить размер холста", + "live.plan.backgroundNotResized": "Фон загружен, но холст не был изменён: {error}", + "live.plan.backgroundUpdated": "Фон обновлён для {name}", + "live.plan.backgroundRemoved": "Фон удалён", + "live.plan.saved": "Сохранён {name}", + "live.plan.createTitle": "Создать план здания", + "live.plan.createDescription": "Укажите понятное название здания или этажа. Нарисуйте планировку или загрузите изображение плана, затем разместите камеры.", + "live.plan.nameLabel": "Название плана", + "live.plan.namePlaceholder": "Главное здание · 1-й этаж", + "live.plan.createConfirm": "Создать план", + "live.plan.eyebrow": "План здания", + "live.plan.placedSummary": "{placed} размещено · {live} в эфире", + "live.plan.zoomAndPan": "Масштабирование и перемещение плана", + "live.plan.panLeft": "Сдвиг влево", + "live.plan.panUp": "Сдвиг вверх", + "live.plan.panDown": "Сдвиг вниз", + "live.plan.panRight": "Сдвиг вправо", + "live.plan.zoomOut": "Уменьшить масштаб", + "live.plan.zoomIn": "Увеличить масштаб", + "live.plan.fitTitle": "Вписать план", + "live.plan.fit": "Вписать", + "live.plan.backgroundMenu": "Фон…", + "live.plan.save": "Сохранить план", + "live.plan.uploadBackgroundTitle": "Загрузите изображение PNG или JPEG в качестве фона плана", + "live.plan.replaceBackground": "Заменить фон", + "live.plan.uploadBackground": "Загрузить фон", + "live.plan.removeBackground": "Удалить фон", + "live.plan.rename": "Переименовать", + "live.plan.newPlan": "Новый план", + "live.plan.editLayout": "Изменить компоновку", + "live.plan.placementHint": "Нажмите на план, чтобы разместить {name}", + "live.plan.clusterLabel": "{count} камер; увеличьте масштаб", + "live.plan.markerLabel": "{name}; {availability}; направление {rotation}°, угол обзора {fov}°", + "live.plan.cameraFallback": "Камера", + "live.plan.legendLive": "В реальном времени", + "live.plan.canvas": "Холст плана", + "live.plan.width": "Ширина", + "live.plan.height": "Высота", + "live.plan.canvasHint": "Загрузка фонового изображения изменит размер холста в соответствии с ним.", + "live.plan.canvasInvalid": "Ширина должна быть от 400 до 4000, высота — от 300 до 4000.", + "live.plan.openLive": "Открыть камеру в реальном времени", + "live.plan.direction": "Направление камеры", + "live.plan.fov": "Угол обзора", + "live.plan.coverageNote": "Сектора показывают только направление и угол; расстояние на плане не откалибровано.", + "live.plan.removeCamera": "Удалить с плана", + "live.plan.selectCamera": "Выберите камеру", + "live.plan.selectHintEditing": "Перетаскивайте маркеры для точной настройки. Просматривайте статус и открывайте трансляцию по запросу.", + "live.plan.selectHint": "Просматривайте статус и открывайте трансляцию по запросу.", + "live.plan.cameras": "Камеры плана", + "live.plan.findPlaceholder": "Найти на этом плане…", + "live.plan.findLabel": "Найти камеру на этом плане", + "live.plan.unplaced": "Не размещённые камеры", + "live.plan.unplacedHint": "Выберите камеру, затем укажите её положение на плане.", + "live.plan.renameTitle": "Переименовать план", + "live.plan.renameDescription": "Планы доступны всем операторам на этом объекте.", + "live.plan.deleteTitle": "Удалить план", + "live.plan.deleteMessage": "Удалить «{name}» и загруженный фон? Размещение камер на этом плане будет удалено; сами камеры останутся без изменений.", + "setupWizard.welcomeTitle": "Добро пожаловать в LightNVR", + "setupWizard.welcomeIntro": "Настроим ваш NVR за несколько простых шагов. Эти параметры всегда можно изменить позже на странице настроек.", + "setupWizard.welcomeStorage": "Путь хранения и лимиты размера", + "setupWizard.welcomePerformance": "Лимиты производительности для вашего количества камер", + "setupWizard.welcomeSecurity": "Безопасный вход администратора", + "setupWizard.storageTitle": "Хранилище и база данных", + "setupWizard.storageIntro": "Где хранить записи и базу данных?", + "setupWizard.storagePath": "Путь хранения записей", + "setupWizard.storagePathHint": "Абсолютный путь для записи видеофайлов.", + "setupWizard.maxStorage": "Максимальный размер хранилища (ГБ)", + "setupWizard.maxStorageHint": "0 = без ограничений.", + "setupWizard.dbPath": "Путь к базе данных", + "setupWizard.dbPathHint": "Расположение файла базы данных SQLite.", + "setupWizard.performanceTitle": "Производительность", + "setupWizard.performanceIntro": "Эти параметры влияют на пропускную способность, а не на качество видео. Большинство пользователей могут оставить значения по умолчанию.", + "setupWizard.threadPool": "Размер пула рабочих потоков", + "setupWizard.threadPoolInfo": "влияет на фоновую работу веб-сервера. Рекомендуемое значение по умолчанию обычно оптимально, если только вы не настраиваете производительность.", + "setupWizard.maxStreams": "Максимум одновременных потоков", + "setupWizard.maxStreamsInfo": "— это ограничение по количеству камер для данного экземпляра. Установите значение не меньше количества камер, которые вы планируете добавить, с небольшим запасом.", + "setupWizard.important": "Важно:", + "setupWizard.restartWarning": "при изменении любого из этих параметров новое значение сохраняется сразу, но применяется только после перезапуска LightNVR. Например, если текущий лимит потоков равен 1 и вы увеличите его до 32, необходимо выполнить перезапуск перед добавлением камер сверх старого лимита.", + "setupWizard.threadPoolHintCores": "Рекомендуется: {recommended} (2× для {cores}-ядерного процессора). Управляет фоновыми потоками libuv. Диапазон: 2–128.", + "setupWizard.threadPoolHint": "Рекомендуется: {recommended} (2× количество ядер процессора). Управляет фоновыми потоками libuv. Диапазон: 2–128.", + "setupWizard.maxStreamsHint": "Сколько камер LightNVR может одновременно поддерживать активными. По умолчанию 32, максимум {max}. Если ожидается 8 камер, выберите не менее 8. Требуется перезапуск для применения.", + "setupWizard.completeTitle": "Настройка завершена!", + "setupWizard.saved": "Настройки успешно сохранены.", + "setupWizard.notSaved": "Настройки не изменены — будут использованы значения по умолчанию.", + "setupWizard.restartRequired": "Требуется перезапуск", + "setupWizard.restartRequiredInfo": "изменения размера пула потоков и/или максимума потоков сохранены, но не будут применены до перезапуска сервиса. Выполните перезапуск перед добавлением камер или ожиданием новой ёмкости.", + "setupWizard.saveFailed": "Не удалось сохранить настройки: {error}", + "setupWizard.back": "Назад", + "setupWizard.saving": "Сохранение…", + "setupWizard.saveContinue": "Сохранить и продолжить", + "setupWizard.next": "Далее →", + "setupWizard.finish": "Перейти на панель", + "setupWizard.skip": "Пропустить мастер настройки", + "live.eptzCanvasLabel": "Электронное панорамирование, наклон и масштабирование для объектива «рыбий глаз»", + "live.eptzCanvasHint": "Перетаскивайте для панорамирования и наклона; колесо или щипок для масштабирования; Home сбрасывает", + "live.eptzReset": "Сбросить вид ePTZ", + "live.autoShort": "Авто", + "live.webrtcShort": "WebRTC", + "nav.investigation": "Расследование", + "availability.label": "Доступность камер", + "availability.live": "В эфире", + "availability.offline": "Не в сети (ранее подключалась)", + "availability.neverConnected": "Никогда не подключалась", + "availability.disabled": "Отключена", + "availability.all": "Все камеры", + "streams.inventory": "Инвентарь", + "streams.configuration": "Конфигурация", + "events.tab": "События", + "events.eyebrow": "Интеграции на основе событий", + "events.title": "События и маршрутизация", + "events.description": "Преобразуйте события камер и системы в надёжные потоки MQTT для автоматизации, сервисов уведомлений и внешней обработки. LightNVR предоставляет интерфейс событий; доставка по email и SMS остаётся на стороне внешних сервисов.", + "events.routes": "Маршруты", + "events.destinations": "Назначения", + "events.catalog": "Каталог событий", + "events.enable": "Включить", + "events.loadError": "Не удалось загрузить конфигурацию маршрутизации событий", + "events.accessDenied": "Доступ запрещён — недостаточно прав", + "events.summary.routes": "Маршруты", + "events.summary.enabled": "{count} включено", + "events.summary.destinations": "Назначения", + "events.summary.managedActive": "{count} управляемых и активных", + "events.summary.types": "Зарегистрированные типы", + "events.summary.registry": "Версионированный каталог событий", + "events.summary.interface": "Интерфейс", + "events.summary.interfaceHelp": "Надёжный вывод событий", + "events.route.add": "Добавить маршрут", + "events.route.addTitle": "Создать маршрут событий", + "events.route.editTitle": "Изменить маршрут событий", + "events.route.create": "Создать маршрут", + "events.route.editorDescription": "Выберите, какие события подходят, какие камеры входят в область действия, куда они направляются и как контролируются шумные источники.", + "events.route.emptyTitle": "Маршруты событий не настроены", + "events.route.emptyDescription": "Создайте маршрут для выбора типов событий, охвата камер, расписания, политики подавления и назначения MQTT.", + "events.route.enabled": "Маршрут включён", + "events.route.enabledHelp": "Совпадающие события принимаются для надёжной доставки", + "events.route.destination": "Назначение", + "events.route.destinationHelp": "Совпадающее событие сохраняется один раз для каждого уникального назначения.", + "events.route.eventTypes": "Типы событий", + "events.route.eventTypesHelp": "Выберите один или несколько версионированных контрактов событий из реестра.", + "events.route.detectionFilters": "Фильтр обнаружений объектов", + "events.route.detectionFiltersHelp": "При необходимости укажите метки, зоны или минимальную уверенность для событий обнаружения объектов.", + "events.route.healthFilters": "Фильтр событий состояния системы", + "events.route.healthFiltersHelp": "При необходимости укажите коды или уровни серьёзности зарегистрированных состояний. Доступные значения берутся из этого регистратора.", + "events.route.healthConditions": "Состояния (любое)", + "events.route.healthSeverities": "Уровни серьёзности (любой)", + "events.route.healthRegistryUnavailable": "Реестр состояний недоступен. Обновите страницу перед настройкой фильтров состояний.", + "events.route.labels": "Метки (любая)", + "events.route.zones": "ID зон (любой)", + "events.route.listHelp": "Разделяйте значения запятыми.", + "events.route.minConfidence": "Минимальная уверенность", + "events.route.confidenceHelp": "Значение от 0 до 1.", + "events.route.cameraScope": "Охват камер", + "events.route.cameraScopeHelp": "Используйте локации флота, теги, наборы атрибутов или конкретные камеры без загрузки всего флота.", + "events.route.allCameras": "Все камеры", + "events.route.dynamicScope": "Динамический выбор камер", + "events.route.systemScopeHelp": "Системные события не являются камерами. Выбор камер недоступен, когда маршрут включает системные события.", + "events.route.schedule": "Расписание", + "events.route.scheduleHelp": "Используйте время наступления события в часовом поясе IANA; ночные интервалы поддерживаются.", + "events.route.restrictSchedule": "Только в настроенных интервалах", + "events.route.suppression": "Политика подавления и доставки", + "events.route.suppressionHelp": "Ноль отключает параметр. Подавление применяется только после того, как назначение примет надёжное событие.", + "events.route.debounce": "Секунды дебаунса", + "events.route.debounceHelp": "Повторные наблюдения продлевают этот интервал ожидания.", + "events.route.cooldown": "Пауза (секунды)", + "events.route.cooldownHelp": "Минимальный интервал после принятого события.", + "events.route.grouping": "Окно группировки (секунды)", + "events.route.groupingHelp": "Сохранить первое событие и объединить повторения.", + "events.route.rateLimit": "Событий в минуту", + "events.route.rateLimitHelp": "Максимум за фиксированное окно на маршрут и камеру.", + "events.route.deliveryPolicy": "Политика доставки", + "events.route.suppressionActive": "Контроль шума активен", + "events.route.everyMatch": "Каждое совпадение", + "events.route.preview": "Предпросмотр маршрута", + "events.route.previewing": "Предпросмотр…", + "events.route.previewResult": "Предпросмотр маршрута", + "events.route.cameraMatches": "{count} камер совпадает", + "events.route.previewNoPublish": "Предпросмотр проверяет полное правило и определяет выборку камер; он никогда не публикует событие.", + "events.route.systemPreviewHelp": "Системные события пропускают выбор камер и поэтому показывают ноль совпадающих камер в этом предпросмотре.", + "events.route.created": "Маршрут событий создан", + "events.route.updated": "Маршрут событий обновлён", + "events.route.deleted": "Маршрут событий удалён", + "events.route.disabled": "Маршрут событий отключён", + "events.route.enabledMessage": "Маршрут событий включён", + "events.route.deleteConfirm": "Удалить маршрут событий «{name}»?", + "events.route.validation.name": "Введите название маршрута.", + "events.route.validation.destination": "Выберите назначение.", + "events.route.validation.event_types": "Выберите хотя бы один тип события.", + "events.route.validation.selector": "Завершите или исправьте выбор камер.", + "events.route.validation.system_scope": "Выбор камер нельзя использовать с системными событиями.", + "events.route.validation.detection_type": "Фильтры обнаружения требуют тип события «обнаружение объектов».", + "events.route.validation.detection_filter": "Добавьте хотя бы одну метку обнаружения, зону или порог уверенности.", + "events.route.validation.confidence": "Минимальная уверенность должна быть от 0 до 1.", + "events.route.validation.predicate_mix": "Фильтры обнаружения и состояния нельзя комбинировать в одном маршруте.", + "events.route.validation.health_type": "Фильтры состояния требуют только зарегистрированные типы событий системного состояния.", + "events.route.validation.health_filter": "Выберите хотя бы одно зарегистрированное состояние или уровень серьёзности.", + "events.route.validation.health_condition": "Выберите только коды условий, возвращаемые реестром состояния регистратора.", + "events.route.validation.health_severity": "Выберите только уровни серьёзности, поддерживаемые выбранными типами событий состояния.", + "events.route.validation.timezone": "Введите установленный часовой пояс IANA, например UTC или America/New_York.", + "events.route.validation.schedule_window": "Для каждого окна расписания необходим хотя бы один день и различные корректные время начала и окончания.", + "events.route.validation.suppression": "Значения подавления должны быть целыми числами в допустимых диапазонах.", + "events.schedule.timezone": "Часовой пояс", + "events.schedule.timezoneHelp": "Должен присутствовать в базе часовых поясов регистратора.", + "events.schedule.addWindow": "Добавить временное окно", + "events.schedule.windowNumber": "Окно {number}", + "events.schedule.start": "Начало", + "events.schedule.end": "Конец", + "events.schedule.sunday": "Вс", + "events.schedule.monday": "Пн", + "events.schedule.tuesday": "Вт", + "events.schedule.wednesday": "Ср", + "events.schedule.thursday": "Чт", + "events.schedule.friday": "Пт", + "events.schedule.saturday": "Сб", + "events.destination.add": "Добавить назначение", + "events.destination.addTitle": "Добавить назначение MQTT", + "events.destination.editTitle": "Изменить назначение MQTT", + "events.destination.create": "Создать назначение", + "events.destination.editorDescription": "Настройте надёжный вывод событий. Учётные данные доступны только для записи и никогда не возвращаются API.", + "events.destination.default": "Настройки MQTT по умолчанию", + "events.destination.settingsManaged": "Настройки управляются", + "events.destination.defaultDescription": "Существующая конфигурация MQTT остаётся доступной как mqtt:default и используется {count} маршрутами.", + "events.destination.openSettings": "Открыть настройки MQTT", + "events.destination.emptyTitle": "Нет управляемых назначений", + "events.destination.emptyDescription": "Добавьте ещё один брокер MQTT для независимой доставки событий в облачный коннектор, систему автоматизации или сервис уведомлений.", + "events.destination.identity": "Идентификатор назначения", + "events.destination.enabled": "Назначение включено", + "events.destination.enabledHelp": "Подключиться и обработать его надёжную очередь", + "events.destination.active": "Активно", + "events.destination.paused": "Приостановлено", + "events.destination.pause": "Пауза", + "events.destination.broker": "Брокер", + "events.destination.host": "Хост брокера", + "events.destination.hostHelp": "Только имя хоста или IP-адрес; не включайте схему URL.", + "events.destination.port": "Порт", + "events.destination.clientId": "Идентификатор клиента", + "events.destination.clientIdHelp": "Должен быть уникальным для данного подключения к брокеру.", + "events.destination.topic": "Топик", + "events.destination.topicTemplate": "Шаблон топика", + "events.destination.topicHelp": "Должен включать токены типа события и идентификатора субъекта; подстановочные символы MQTT не допускаются.", + "events.destination.keepalive": "Интервал keepalive, сек", + "events.destination.statusTopicTemplate": "Топик статуса присутствия", + "events.destination.statusTopicHelp": "Необязательно. Должен включать {installation_uuid}; также доступен {destination_uuid}. Подстановочные символы MQTT не допускаются.", + "events.destination.statusTopicEnabled": "Присутствие явно включено для данного назначения. Топик никогда не определяется из топика события.", + "events.destination.statusTopicDisabled": "Присутствие отключено для данного назначения. Оставьте поле пустым, чтобы оставить его отключённым.", + "events.destination.qos": "Качество обслуживания", + "events.destination.qos0": "отправить один раз", + "events.destination.qos1": "не менее одного раза", + "events.destination.qos2": "ровно один раз", + "events.destination.authentication": "Аутентификация", + "events.destination.passwordPreserved": "Оставьте пустым, чтобы сохранить сохранённый пароль (только для записи).", + "events.destination.passwordOptional": "Необязательно, если брокер разрешает анонимных клиентов.", + "events.destination.clearPassword": "Очистить сохранённый пароль", + "events.destination.transportSecurity": "Безопасность транспорта", + "events.destination.tlsMode": "Режим TLS", + "events.destination.tlsSystem": "Системное хранилище доверенных сертификатов", + "events.destination.tlsCustomCa": "Пользовательский центр сертификации", + "events.destination.tlsMutual": "Взаимный TLS", + "events.destination.tlsDisabled": "Отключено (открытый текст)", + "events.destination.tlsHelp.system": "Проверять сертификат брокера по системному хранилищу доверенных сертификатов.", + "events.destination.tlsHelp.custom_ca": "Проверять брокера по явно указанному файлу центра сертификации в формате PEM.", + "events.destination.tlsHelp.mutual": "Проверять брокера по явно указанному CA и предъявлять клиентский сертификат и ключ.", + "events.destination.tlsHelp.disabled": "Без шифрования транспорта и проверки идентичности брокера.", + "events.destination.caFile": "Файл CA", + "events.destination.certFile": "Файл клиентского сертификата", + "events.destination.keyFile": "Файл клиентского ключа", + "events.destination.absolutePathHelp": "Используйте абсолютный путь, доступный для чтения службой LightNVR.", + "events.destination.plaintextWarning": "MQTT без шифрования может раскрыть метаданные событий и учётные данные. Используйте только в доверенной изолированной сети.", + "events.destination.security": "Безопасность", + "events.destination.tls.system": "Системное доверие", + "events.destination.tls.custom_ca": "Пользовательский CA", + "events.destination.tls.mutual": "Взаимный TLS", + "events.destination.tls.disabled": "Без шифрования", + "events.destination.routes": "Маршруты", + "events.destination.presence": "Топик присутствия", + "events.destination.deleteInUse": "Удалите или перенаправьте маршруты перед удалением этого назначения.", + "events.destination.created": "Назначение MQTT создано", + "events.destination.updated": "Назначение MQTT обновлено", + "events.destination.deleted": "Назначение MQTT удалено", + "events.destination.pausedMessage": "Назначение MQTT приостановлено; события в очереди сохраняются до истечения срока.", + "events.destination.enabledMessage": "Назначение MQTT включено", + "events.destination.deleteConfirm": "Удалить назначение MQTT «{name}»?", + "events.destination.validation.name": "Введите название назначения.", + "events.destination.validation.host": "Введите имя хоста или IP-адрес брокера.", + "events.destination.validation.client_id": "Введите клиентский ID брокера.", + "events.destination.validation.topic": "Топик должен содержать токены типа события и идентификатора субъекта и не может содержать подстановочные символы MQTT.", + "events.destination.validation.status_topic": "Необязательный топик присутствия должен содержать токен UUID установки, использовать только поддерживаемые токены и не может содержать подстановочные символы MQTT.", + "events.destination.validation.port": "Порт должен быть целым числом от 1 до 65535.", + "events.destination.validation.keepalive": "Keepalive должен быть целым числом от 5 до 3600 секунд.", + "events.destination.validation.qos": "Выберите MQTT QoS 0, 1 или 2.", + "events.destination.validation.username": "Для заданного пароля требуется имя пользователя.", + "events.destination.validation.ca_file": "Для данного режима TLS требуется абсолютный путь к файлу CA.", + "events.destination.validation.mutual_files": "Для взаимного TLS требуются абсолютные пути к CA, клиентскому сертификату и ключу.", + "fleet.eyebrow": "Операции с камерами", + "fleet.title": "Инвентарь камер", + "fleet.description": "Поиск, оценка и организация камер в крупных развертываниях без загрузки всего инвентаря в браузер.", + "fleet.summary": "Сводка состояния парка", + "fleet.totalCameras": "Подходящие камеры", + "fleet.needsAttention": "Деградировано", + "fleet.searchLabel": "Поиск камер", + "fleet.searchPlaceholder": "Поиск по имени, адресу, местоположению, тегу, производителю или модели…", + "fleet.resultCount": "{count} камер", + "fleet.filters": "Фильтры", + "fleet.clearFilters": "Сбросить фильтры", + "fleet.filter.health": "Состояние", + "fleet.filter.enabled": "Состояние камеры", + "fleet.filter.anyState": "Любое состояние", + "fleet.filter.recording": "Режим записи", + "fleet.filter.location": "Поддерево местоположений", + "fleet.filter.allLocations": "Все местоположения", + "fleet.filter.tags": "Теги (любой из)", + "fleet.filter.collection": "Коллекция камер", + "fleet.health.unknown": "Неизвестно", + "fleet.health.up": "В сети", + "fleet.health.degraded": "Деградировано", + "fleet.health.down": "Не в сети", + "fleet.health.disabled": "Отключено", + "fleet.recording.off": "Выключено", + "fleet.recording.continuous": "Непрерывная", + "fleet.recording.detection": "По детекции", + "fleet.recordingActive": "Идёт запись", + "fleet.recordingInactive": "Не записывается", + "fleet.column.camera": "Камера", + "fleet.column.health": "Состояние", + "fleet.column.location": "Расположение", + "fleet.column.tags": "Теги", + "fleet.column.recording": "Запись", + "fleet.viewLive": "Прямой эфир", + "fleet.lastFrame": "Последний кадр", + "fleet.noAddress": "Адрес недоступен", + "fleet.unassigned": "Не назначено", + "fleet.loading": "Загрузка парка камер…", + "fleet.refreshing": "Обновление…", + "fleet.loadError": "Не удалось загрузить парк камер", + "fleet.emptyTitle": "Камеры не настроены", + "fleet.emptyDescription": "Добавьте поток, чтобы он стал доступен в рабочем пространстве парка камер.", + "fleet.emptyFilteredTitle": "Нет камер, соответствующих этому представлению", + "fleet.emptyFilteredDescription": "Попробуйте расширить поиск или сбросить один или несколько фильтров.", + "fleet.paginationSummary": "Показаны {first}–{last} из {total}", + "fleet.perPage": "На странице", + "fleet.pageOf": "Страница {page} из {pages}", + "fleet.selectPage": "Выбрать все камеры на этой странице", + "fleet.selectCamera": "Выбрать {name}", + "fleet.selectedCount": "Выбрано камер: {count}", + "fleet.organizeSelected": "Организовать выбранные", + "fleet.clearSelection": "Снять выделение", + "fleet.organization.manage": "Управление структурой", + "fleet.organization.title": "Структура камер", + "fleet.organization.description": "Поддерживайте переиспользуемую иерархию расположений и нормализованный словарь тегов для парка камер.", + "fleet.organization.locations": "Расположения", + "fleet.organization.tags": "Теги", + "fleet.organization.locationsDescription": "Описывайте объекты, здания, этажи и операционные зоны в виде навигируемой иерархии.", + "fleet.organization.tagsDescription": "Используйте управляемый словарь тегов вместо несогласованных произвольных меток.", + "fleet.organization.addRoot": "Добавить расположение верхнего уровня", + "fleet.organization.addLocation": "Добавить расположение", + "fleet.organization.editLocation": "Редактировать расположение", + "fleet.organization.addChild": "Добавить дочерний", + "fleet.organization.type": "Тип", + "fleet.organization.parent": "Родительское расположение", + "fleet.organization.topLevel": "Верхний уровень", + "fleet.organization.sortOrder": "Порядок сортировки", + "fleet.organization.contents": "Содержимое", + "fleet.organization.cameras": "Камеры", + "fleet.organization.system": "Система", + "fleet.organization.contentCounts": "{cameras} камер · {children} дочерних", + "fleet.organization.locationNotEmpty": "Сначала переместите камеры и удалите дочерние расположения", + "fleet.organization.noLocations": "Расположения не настроены.", + "fleet.organization.locationCreated": "Расположение создано", + "fleet.organization.locationUpdated": "Расположение обновлено", + "fleet.organization.locationDeleted": "Расположение удалено", + "fleet.organization.deleteLocationConfirm": "Удалить расположение «{name}»?", + "fleet.organization.addTag": "Добавить тег", + "fleet.organization.editTag": "Редактировать тег", + "fleet.organization.tagLabel": "Тег", + "fleet.organization.color": "Цвет (#RRGGBB)", + "fleet.organization.tagDescription": "Описание", + "fleet.organization.noTags": "Нормализованные теги не настроены.", + "fleet.organization.tagCreated": "Тег создан", + "fleet.organization.tagUpdated": "Тег обновлён", + "fleet.organization.tagDeleted": "Тег удалён", + "fleet.organization.deleteTagConfirm": "Удалить «{name}»? Он назначен {count} камерам.", + "fleet.organization.merge": "Объединить", + "fleet.organization.mergeTagNamed": "Объединить «{name}»", + "fleet.organization.mergeInto": "Объединить с", + "fleet.organization.chooseTag": "Выберите тег для сохранения", + "fleet.organization.mergeWarning": "Все назначения камер переместятся в сохраняемый тег; исходный тег будет удалён.", + "fleet.organization.tagsMerged": "Теги объединены", + "fleet.organization.saveError": "Не удалось сохранить: {message}", + "fleet.organization.deleteError": "Не удалось удалить: {message}", + "fleet.locationType.site": "Объект", + "fleet.locationType.building": "Здание", + "fleet.locationType.floor": "Этаж", + "fleet.locationType.area": "Область", + "fleet.locationType.zone": "Зона", + "fleet.locationType.system": "Система", + "fleet.bulk.title": "Организовать выбранные камеры", + "fleet.bulk.description": "Применить изменения местоположения и тегов к {count} камерам с ограниченной параллельностью.", + "fleet.bulk.location": "Назначение местоположения", + "fleet.bulk.locationHelp": "Все выбранные камеры будут перемещены в выбранное местоположение.", + "fleet.bulk.keepLocations": "Сохранить текущие местоположения", + "fleet.bulk.tags": "Назначение тегов", + "fleet.bulk.tagsHelp": "Добавить или удалить теги, не затрагивая другие назначения, или явно заменить полный набор тегов.", + "fleet.bulk.tagOperation.none": "Сохранить", + "fleet.bulk.tagOperation.add": "Добавить", + "fleet.bulk.tagOperation.remove": "Удалить", + "fleet.bulk.tagOperation.replace": "Заменить все", + "fleet.bulk.replaceWarning": "«Заменить все» удаляет все текущие теги перед применением выбранного. Пустой выбор очищает все теги.", + "fleet.bulk.apply": "Применить изменения", + "fleet.bulk.working": "Применение изменений…", + "fleet.bulk.success": "Обновлено {count} камер", + "fleet.bulk.partial": "Обновлено {succeeded} камер; {failed} не удалось", + "fleet.bulk.error": "Не удалось организовать камеры: {message}", + "fleet.bulk.failures": "Камеры, которые не удалось обновить", + "fleet.queues.degraded": "Деградированные потоки", + "fleet.queues.offline": "Камеры не в сети", + "fleet.queues.oldest": "Самое старое: {time}", + "fleet.queues.noneActive": "Нет активных условий", + "fleet.views.title": "Сохранённые представления", + "fleet.views.choose": "Выберите сохранённое представление", + "fleet.views.none": "Нет сохранённых представлений", + "fleet.views.shared": "Общий", + "fleet.views.saveCurrent": "Сохранить текущий вид", + "fleet.views.name": "Название вида", + "fleet.views.share": "Поделиться со всеми операторами", + "fleet.views.saved": "Вид флота сохранён", + "fleet.views.saveError": "Не удалось сохранить вид: {message}", + "fleet.views.deleted": "Вид флота удалён", + "fleet.views.deleteConfirm": "Удалить сохранённый вид «{name}»?", + "fleet.views.deleteError": "Не удалось удалить вид: {message}", + "fleet.views.unsupported": "Сохранённый селектор не может быть отображён текущими элементами фильтра.", + "collections.manage": "Коллекции", + "collections.all": "Все коллекции", + "collections.filter": "Коллекция", + "collections.loadMembersError": "Не удалось загрузить камеры коллекции: {message}", + "collections.title": "Коллекции камер", + "collections.subtitle": "Создавайте переиспользуемые группы камер для операций, сохранённых видов и последующих рабочих процессов.", + "collections.listDescription": "Статические коллекции хранят явный состав; умные коллекции непрерывно оценивают правила флота.", + "collections.create": "Создать коллекцию", + "collections.edit": "Редактировать коллекцию", + "collections.editorDescription": "Определения коллекций используют стабильные UUID камер, местоположений и тегов.", + "collections.backToList": "Назад к коллекциям", + "collections.type": "Тип коллекции", + "collections.type.static": "Статическая", + "collections.type.smart": "Умная", + "collections.description": "Описание", + "collections.shared": "Общая коллекция", + "collections.sharedHelp": "Разрешить другим авторизованным пользователям видеть эту коллекцию; правила доступа к камерам по-прежнему действуют.", + "collections.typeChangeWarning": "Смена типа коллекции заменяет модель её состава. Статические элементы или правила умной коллекции предыдущего типа больше не будут применяться.", + "collections.selectorError": "Недопустимый селектор: {message}", + "collections.created": "Коллекция создана", + "collections.updated": "Коллекция обновлена", + "collections.saveError": "Не удалось сохранить коллекцию: {message}", + "collections.loadError": "Не удалось загрузить коллекцию: {message}", + "collections.cameras": "камеры", + "collections.visibility.shared": "Общие", + "collections.visibility.private": "Личные", + "collections.selectorRedacted": "Личные правила", + "collections.emptyTitle": "Коллекций пока нет", + "collections.emptyAdmin": "Создайте статическую группу или интеллектуальное представление на основе правил для повторного использования выбранных камер.", + "collections.emptyViewer": "Нет общих коллекций в вашей области доступа к камерам.", + "collections.deleteConfirm": "Удалить коллекцию «{name}»?", + "collections.deleted": "Коллекция удалена", + "collections.deleteError": "Не удалось удалить коллекцию: {message}", + "collections.preview.title": "Предпросмотр правила", + "collections.preview.matches": "{count} подходящих камер", + "collections.preview.action": "Предпросмотр", + "collections.preview.hide": "Скрыть предпросмотр", + "collections.preview.loading": "Вычисление…", + "collections.preview.empty": "Ни одна камера не подходит.", + "collections.preview.sample": "Показана выборка из {count} камер из {total} совпадений.", + "collections.preview.error": "Не удалось выполнить предпросмотр коллекции: {message}", + "collections.members.title": "Статические участники", + "collections.members.selected": "{count} камер выбрано на всех страницах", + "collections.members.search": "Поиск камер…", + "collections.members.selectPage": "Выбрать эту страницу", + "collections.members.empty": "Ни одна камера не найдена.", + "collections.builder.title": "Интеллектуальные правила", + "collections.builder.description": "Правила оцениваются на основе текущей организации, конфигурации, возможностей и состояния камер.", + "collections.builder.match": "Совпадение", + "collections.builder.allRules": "всем правилам", + "collections.builder.anyRule": "любому правилу", + "collections.builder.addRule": "Добавить правило", + "collections.builder.removeRule": "Удалить правило", + "collections.builder.matchesAll": "Без заполненных правил коллекция включает все камеры в области доступа пользователя.", + "collections.builder.incompleteRule": "Завершите или удалите все правила перед сохранением.", + "collections.builder.chooseLocation": "Выберите поддерево расположения", + "collections.builder.vendorPlaceholder": "Названия производителей, разделённые запятой", + "collections.builder.modelPlaceholder": "Названия моделей, разделённые запятой", + "collections.builder.advancedMode": "Расширенный JSON", + "collections.builder.visualMode": "Визуальный конструктор", + "collections.builder.cannotVisualize": "Этот селектор содержит вложенную или сложную логику, которую визуальный конструктор не может корректно отобразить.", + "collections.rule.location_subtree": "Расположение входит в", + "collections.rule.camera_uuid": "Конкретные камеры", + "collections.rule.tag_any": "Имеет любой тег", + "collections.rule.tag_all": "Имеет все теги", + "collections.rule.tag_none": "Не имеет ни одного тега", + "collections.rule.health": "Состояние", + "collections.rule.enabled": "Камера", + "collections.rule.recording_mode": "Режим записи", + "collections.rule.capability_any": "Имеет любую возможность", + "collections.rule.capability_all": "Имеет все возможности", + "collections.rule.vendor": "Производитель", + "collections.rule.model": "Модель", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Обратный аудиоканал", + "streamHealth.observedFps": "Наблюдаемый FPS", + "streamHealth.expectedFps": "Ожидаемый", + "streamHealth.fpsHelp": "Наблюдается LightNVR; ожидаемое значение берётся из метаданных потока камеры.", + "login.passwordChanged": "Пароль успешно изменён. Войдите с новым паролем.", + "passwordChangeRequired.title": "Измените пароль по умолчанию", + "passwordChangeRequired.description": "Эта установка всё ещё использует пароль администратора по умолчанию. Замените его перед продолжением работы с LightNVR. MFA, если включён, будет проверен при следующем входе.", + "passwordChangeRequired.currentPassword": "Текущий пароль", + "passwordChangeRequired.newPassword": "Новый пароль", + "passwordChangeRequired.confirmPassword": "Подтвердите новый пароль", + "passwordChangeRequired.passwordHelp": "Используйте не менее 8 символов. Пароль не может быть «admin».", + "passwordChangeRequired.submit": "Сменить пароль", + "passwordChangeRequired.saving": "Смена пароля...", + "passwordChangeRequired.error.currentRequired": "Введите текущий пароль.", + "passwordChangeRequired.error.tooShort": "Новый пароль должен содержать не менее 8 символов.", + "passwordChangeRequired.error.defaultPassword": "Новый пароль не может быть admin.", + "passwordChangeRequired.error.mismatch": "Новые пароли не совпадают.", + "passwordChangeRequired.error.generic": "Не удалось сменить пароль. Попробуйте ещё раз.", + "settings.tab.health": "Состояние", + "settings.tab.workspaces": "Рабочие области", + "settings.health.title": "Состояние хоста и оборудования", + "settings.health.description": "Настройте ограниченное мониторинг ОС и оборудования без раскрытия путей к устройствам и секретов.", + "settings.health.enabled": "Включить мониторинг состояния", + "settings.health.enabledHelp": "Собирать поддерживаемые сигналы хоста, сервисов, хранилища, сети и оборудования.", + "settings.health.profile": "Профиль политики", + "settings.health.profileHelp": "Сбалансированный — стандартный профиль; консервативный требует более весомых оснований для оповещения.", + "settings.health.profile.balanced": "Сбалансированный", + "settings.health.profile.conservative": "Консервативный", + "settings.health.hardwareProvider": "Поставщик данных оборудования", + "settings.health.provider.auto": "Автоматически (поставщики ядра)", + "settings.health.provider.smartctl": "smartctl (явно)", + "settings.health.providerHelp.auto": "Использует только ограниченные поставщики sysfs, NVMe и ядра; smartctl никогда не определяется автоматически.", + "settings.health.providerHelp.smartctl": "Явно включает необязательный ограниченный JSON-поставщик smartctl для обнаруженных устройств.", + "settings.health.providerHelp.disabled": "Отключает необязательные поставщики оборудования, сохраняя доступным переносимый мониторинг состояния.", + "settings.health.writeProbe": "Включить проверку записи в хранилище", + "settings.health.writeProbeHelp": "Периодически выполняет ограниченную проверку настроенной цели записи.", + "settings.health.cadences": "Частоты опроса", + "settings.health.cadencesHelp": "Интервалы должны быть упорядочены от быстрого до опроса устройств и находиться в пределах, заданных сервером.", + "settings.health.fastInterval": "Быстрый интервал", + "settings.health.normalInterval": "Обычный интервал", + "settings.health.slowInterval": "Медленный интервал", + "settings.health.deviceInterval": "Интервал устройств", + "settings.health.presenceInterval": "Интервал присутствия", + "settings.health.retention": "Хранение инцидентов", + "settings.health.conditions": "Переопределения условий", + "settings.health.conditionsHelp": "Переопределяются только коды условий и единицы, возвращаемые реестром действующих политик.", + "settings.health.conditionOverride": "переопределение условия", + "settings.health.overrideMode": "Режим переопределения", + "settings.health.overrideModeHelp": "Наследовать выбранный профиль, выбрать другой ограниченный профиль, отключить условие или задать проверенные пороги.", + "settings.health.profileDefault": "Использовать выбранный профиль", + "settings.health.custom": "Пользовательские пороги", + "settings.health.warning": "Порог предупреждения", + "settings.health.critical": "Критический порог", + "settings.health.recovery": "Порог восстановления", + "settings.health.warning_for_seconds": "Задержка предупреждения, сек", + "settings.health.critical_for_seconds": "Задержка критического состояния, сек", + "settings.health.recovery_for_seconds": "Задержка восстановления, сек", + "settings.health.clearOverrides": "Очистить переопределения", + "settings.health.registryUnavailable": "Сервер не вернул реестр условий. Перезагрузите перед редактированием переопределений.", + "settings.health.resetDefaults": "Сбросить значения по умолчанию для мониторинга", + "settings.health.reloadGuidance": "Сохранение выполняется атомарно. После успешного сохранения перезагрузите для подтверждения действующей политики; перезапуск требуется только по явному запросу сервера.", + "settings.health.validation.profile": "Выберите поддерживаемый профиль мониторинга.", + "settings.health.validation.provider": "Выберите поддерживаемый поставщик оборудования.", + "settings.health.validation.healthFastIntervalSeconds": "Быстрый интервал должен быть целым числом от 5 до 60 секунд.", + "settings.health.validation.healthNormalIntervalSeconds": "Обычный интервал должен быть целым числом от 15 до 600 секунд.", + "settings.health.validation.healthSlowIntervalSeconds": "Медленный интервал должен быть целым числом от 60 до 3600 секунд.", + "settings.health.validation.healthDeviceIntervalSeconds": "Интервал устройства должен быть целым числом от 300 до 86400 секунд.", + "settings.health.validation.healthPresenceIntervalSeconds": "Интервал присутствия должен быть целым числом от 15 до 3600 секунд.", + "settings.health.validation.healthIncidentRetentionDays": "Срок хранения инцидентов должен быть целым числом от 7 до 3650 дней.", + "settings.health.validation.ordered": "Интервалы опроса должны быть упорядочены: быстрый, обычный, медленный, затем устройства.", + "settings.health.validation.overrides": "Переопределения условий должны использовать уникальные коды и поддерживаемые профили из реестра сервера.", + "settings.health.validation.thresholds": "Пользовательские пороги должны быть конечными значениями в пределах единиц измерения условия.", + "settings.health.validation.thresholdOrder": "Пороги предупреждения, критического состояния и восстановления должны сохранять направление оповещения и гистерезис условия.", + "settings.health.validation.dwell": "Задержки должны быть целыми секундами в пределах семи дней; задержка предупреждения и восстановления не может быть нулевой.", + "workspaces.title": "Рабочие пространства оператора", + "workspaces.description": "Выберите, какие специализированные пространства отображаются в навигации и интерфейсе.", + "workspaces.saved": "Настройки пространств сохранены", + "workspaces.saveError": "Не удалось сохранить настройки пространств: {message}", + "workspaces.loadError": "Не удалось загрузить настройки пространств.", + "workspaces.showWorkspace": "Показать {name}", + "workspaces.authorizationNote": "Это влияет только на отображение. Прямые URL-адреса и доступ через API по-прежнему подчиняются вашей политике авторизации.", + "workspaces.liveNavigator": "Расширенный навигатор", + "workspaces.liveNavigatorDescription": "Дерево местоположений, фильтры доступности, сохранённые макеты и последние события.", + "workspaces.investigation": "Расследование", + "workspaces.investigationDescription": "Поиск, корреляция, защита и экспорт записанных данных.", + "settings.reduceMotion": "Уменьшить анимацию", + "settings.reduceMotionHelp": "Отключает необязательные анимации и переходы. Режим «Авто» следует настройкам операционной системы.", + "settings.reduceMotionPreference": "Предпочтение уменьшения анимации", + "settings.reduceMotionAuto": "Авто", + "settings.reduceMotionOn": "Вкл.", + "settings.reduceMotionOff": "Выкл.", + "settings.audioCompliance": "Соответствие требованиям по аудио", + "settings.disableAudioGlobally": "Отключить аудио на этом экземпляре", + "settings.audioDisabled": "Аудио отключено глобально", + "settings.audioComplianceHelp": "Запрещает прослушивание в реальном времени, двустороннюю связь и запись аудио в новых записях на этом экземпляре. Сохранение перезапускает активные медиа-сессии go2rtc. Существующие записи не изменяются.", + "tokens.manage": "Управление доступом к API", + "tokens.title": "Доступ к API — {username}", + "tokens.description": "Создавайте токены с узкими правами для интеграций и отзывайте каждый независимо.", + "tokens.recommendedTitle": "Рекомендуются токены с ограниченной областью", + "tokens.recommendedDescription": "Каждый токен имеет срок действия, явно указанные действия и область камер, и никогда не может превышать текущую политику доступа пользователя.", + "tokens.coverageNotice": "Доступные разрешения отражают то, что обеспечивает этот сервер. Токен может использовать только те разрешения, которые уже есть у его пользователя.", + "tokens.createTitle": "Создать токен с ограниченной областью", + "tokens.createDescription": "Используйте один токен на каждую интеграцию, чтобы его можно было идентифицировать, ротировать и отзывать без влияния на остальное.", + "tokens.name": "Название интеграции", + "tokens.namePlaceholder": "напр. Мост PTZ для северного гаража", + "tokens.expiry": "Истекает через", + "tokens.expiryDays": "{days} дн.", + "tokens.actions": "Разрешённые действия", + "tokens.actionsHelp": "Выберите только то, что нужно этому интеграционному подключению. Деструктивные действия требуют отдельного токена.", + "tokens.destructive": "Деструктивные", + "tokens.noEnforcedActions": "В этой версии сервера недоступны действия, поддерживающие токены.", + "tokens.scope.label": "Область камер", + "tokens.scope.all": "Все камеры", + "tokens.scope.collection": "Общая коллекция", + "tokens.scope.selector": "Пользовательский селектор", + "tokens.scope.chooseCollection": "Общая коллекция камер", + "tokens.scope.allValue": "Все камеры", + "tokens.scope.collectionValue": "Коллекция: {name}", + "tokens.scope.selectorValue": "Пользовательский динамический селектор", + "tokens.create": "Создать токен", + "tokens.creating": "Создание токена…", + "tokens.createdSuccess": "Токен API с областью доступа создан", + "tokens.createError": "Не удалось создать токен API: {message}", + "tokens.invalidResponse": "Сервер вернул неполный ответ с учётными данными.", + "tokens.existingTitle": "Существующие токены", + "tokens.existingDescription": "После создания доступны только префиксы и метаданные.", + "tokens.emptyTitle": "Нет активных токенов", + "tokens.emptyDescription": "Создайте токен с областью доступа для первого интеграционного подключения, которому нужен доступ к API.", + "tokens.showInactive": "Показать {count} неактивных", + "tokens.status.active": "Активен", + "tokens.status.expired": "Истёк", + "tokens.status.revoked": "Отозван", + "tokens.expires": "Истекает", + "tokens.expiresValue": "Истекает {date}", + "tokens.created": "Создан", + "tokens.lastUsed": "Последнее использование", + "tokens.revoke": "Отозвать", + "tokens.revoking": "Отзыв…", + "tokens.revokeConfirm": "Отозвать «{description}»? Запросы с его использованием немедленно перестанут работать.", + "tokens.revokedSuccess": "Токен API отозван", + "tokens.revokeError": "Не удалось отозвать токен API: {message}", + "tokens.validation.missing_description": "Укажите название интеграции, которая будет использовать этот токен.", + "tokens.validation.description_too_long": "Имя интеграции должно быть не более 128 символов.", + "tokens.validation.invalid_expiry": "Выберите срок действия токена от 1 до 365 дней.", + "tokens.validation.missing_actions": "Выберите хотя бы одно разрешённое действие.", + "tokens.validation.invalid_action": "Одно или несколько выбранных действий не поддерживают токены на этом сервере.", + "tokens.validation.invalid_scope": "Выберите допустимую область камер.", + "tokens.validation.requires_all_scope": "Разрешения, не связанные с камерами, требуют области «Все камеры». Выберите эту область или удалите эти разрешения.", + "tokens.validation.missing_collection": "Выберите доступную общую коллекцию.", + "tokens.validation.invalid_selector": "Заполните или исправьте пользовательский селектор камер.", + "tokens.secret.oneTime": "Показывается один раз", + "tokens.secret.scopedTitle": "Сохраните этот ограниченный токен сейчас", + "tokens.secret.legacyTitle": "Сохраните этот устаревший ключ API сейчас", + "tokens.secret.scopedDescription": "lightNVR хранит только хеш этого токена. Если он утерян, отзовите его и создайте новый.", + "tokens.secret.legacyDescription": "Этот ключ совместимости отображается здесь только один раз. Генерация нового ключа сделает этот недействительным.", + "tokens.secret.value": "Учётные данные API", + "tokens.secret.copied": "Скопировано", + "tokens.secret.copySuccess": "Учётные данные API скопированы", + "tokens.secret.copyError": "Не удалось скопировать автоматически; выделите и скопируйте учётные данные вручную.", + "tokens.secret.savedConfirm": "Я надёжно сохранил(а) эти учётные данные", + "tokens.secret.savedHelp": "Подтверждение закроет это окно. Полное значение больше не будет отображено.", + "tokens.legacy.title": "Устаревший ключ совместимости", + "tokens.legacy.description": "Устаревший ключ имеет полный доступ этого пользователя, не истекает и не может быть ограничен по камере или действию.", + "tokens.legacy.warning": "Генерируйте только для существующей интеграции, чьи конечные точки ещё не перешли на обязательное использование ограниченных токенов. Генерация немедленно делает предыдущий устаревший ключ недействительным.", + "tokens.legacy.generate": "Сгенерировать устаревший ключ", + "tokens.legacy.confirm": "Сгенерировать новый устаревший ключ? Это немедленно сделает текущий устаревший ключ пользователя недействительным.", + "tokens.legacy.createdSuccess": "Устаревший ключ API сгенерирован", + "tokens.legacy.createError": "Не удалось сгенерировать устаревший ключ API: {message}", + "audit.manage": "История аудита", + "audit.title": "Аудит безопасности и доступа", + "audit.description": "Отслеживайте результаты входов, решения о доступе и изменения чувствительных политик без раскрытия учётных данных.", + "audit.retention": "Хранение", + "audit.retentionDescription": "События хранятся в течение {days} дней. Уменьшение этого значения немедленно удалит более старые записи.", + "audit.retentionDays": "Дней", + "audit.retentionInvalid": "Выберите период хранения от 1 до 3650 дней.", + "audit.retentionSaved": "Настройки хранения аудита сохранены; удалено {count} устаревших событий", + "audit.retentionError": "Не удалось сохранить настройки хранения аудита: {message}", + "audit.filters": "Фильтры", + "audit.clearFilters": "Сбросить фильтры", + "audit.applyFilters": "Применить фильтры", + "audit.actor": "Субъект", + "audit.unauthenticated": "Неаутентифицированный", + "audit.outcome": "Результат", + "audit.action": "Точное действие", + "audit.filterToAction": "Фильтровать по этому действию", + "audit.since": "С", + "audit.until": "По", + "audit.invalidDateRange": "Дата «С» должна быть раньше даты «По».", + "audit.source": "Адрес источника", + "audit.target": "Объект", + "audit.targetUuid": "UUID объекта", + "audit.noTarget": "Общесистемное", + "audit.requestId": "ID запроса", + "audit.apiToken": "ID токена области", + "audit.showDetails": "Показать подробности", + "audit.hideDetails": "Скрыть подробности", + "audit.pageSize": "На странице", + "audit.resultRange": "Показано {start}–{end} из {total}", + "audit.empty": "Нет совпадающих событий аудита", + "audit.emptyDescription": "Попробуйте сбросить один или несколько фильтров или дождитесь новой активности безопасности.", + "audit.exportPage": "Экспортировать эту страницу", + "audit.exporting": "Экспорт…", + "audit.exported": "Страница аудита экспортирована", + "audit.exportError": "Не удалось экспортировать события аудита: {message}", + "audit.pagination": "Страницы истории аудита", + "audit.page": "Страница {page}", + "audit.modesTitle": "Разрешённые решения", + "audit.modesDescription": "Выберите, как записывать разрешённый доступ только для чтения для каждого действия. Запросы, изменяющие данные, отказы, ошибки и входы в систему записываются всегда. Режим «Сводка» создаёт одну запись на пользователя, камеру и клиент каждые {minutes} мин. с указанием количества.", + "audit.mode.record": "Записывать каждое", + "audit.mode.summarize": "Сводка", + "audit.mode.off": "Выкл.", + "audit.modeOffWarning": "Разрешённый доступ для этого действия больше не будет отображаться в истории аудита.", + "audit.modesSaved": "Режимы решений аудита сохранены", + "audit.modesError": "Не удалось сохранить режимы решений аудита: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Тип события", + "audit.eventTypeSummary": "Сводки", + "audit.eventTypeDecision": "Отдельные решения", + "access.cameraSearch": "Поиск камер", + "access.cameraSearchPlaceholder": "Введите не менее двух символов для поиска…", + "access.cameraSearchHint": "Поиск по имени камеры, UUID, адресу, местоположению, тегу, производителю или модели.", + "access.cameraSelected": "Выбрано", + "access.cameraAdd": "Добавить", + "access.cameraLimit": "Селектор может содержать не более 64 явно указанных камер. Для больших диапазонов используйте правило по местоположению или тегу.", + "access.roles.manage": "Управление ролями", + "access.roles.title": "Роли авторизации", + "access.roles.description": "Объединяйте действия в переиспользуемые роли, затем назначайте эти роли на диапазоны камер.", + "access.roles.create": "Создать роль", + "access.roles.newRole": "Новая роль", + "access.roles.copyName": "{name} (копия)", + "access.roles.clone": "Клонировать", + "access.roles.builtin": "Встроенная", + "access.roles.builtinHelp": "Встроенные роли — это фиксированные шаблоны, безопасные при обновлении. Клонируйте роль для настройки.", + "access.roles.actionCount": "{count} действий", + "access.roles.destructive": "Чувствительное действие", + "access.roles.notEnforced": "Пока не применяется ни на одном эндпоинте", + "access.roles.destructiveWarning": "Эта роль может изменять конфигурацию или доказательства. Назначайте её только в тех областях, где требуется такое право.", + "access.roles.created": "Роль создана", + "access.roles.updated": "Роль обновлена", + "access.roles.deleted": "Роль удалена", + "access.roles.saveError": "Не удалось сохранить роль: {message}", + "access.roles.deleteError": "Не удалось удалить роль: {message}", + "access.roles.deleteConfirm": "Удалить роль \"{name}\"? Роли, на которые ссылаются назначения, не могут быть удалены.", + "access.policy.manage": "Управление доступом", + "access.policy.column": "Доступ", + "access.policy.scopedShort": "С ограничением области", + "access.policy.title": "Политика доступа — {username}", + "access.policy.description": "Управление назначениями ролей с запретом по умолчанию и просмотр их областей камер.", + "access.policy.tab.grants": "Назначения", + "access.policy.tab.test": "Проверить доступ", + "access.policy.scopedWarning": "Работать будут только действия, разрешённые подходящим назначением и областью камер.", + "access.policy.grants": "Назначения ролей", + "access.policy.grantsDescription": "Назначение объединяет одну роль со всем парком камер, общей коллекцией или пользовательским селектором камер.", + "access.policy.addGrant": "Добавить назначение", + "access.policy.noGrants": "Назначения не настроены", + "access.policy.noGrantsHelp": "Добавьте хотя бы одно назначение перед активацией политики с ограничением области, если только этот пользователь не должен остаться без доступа.", + "access.policy.role": "Роль", + "access.policy.chooseRole": "Выберите роль", + "access.policy.scope": "Область камер", + "access.policy.allCameras": "Весь парк камер", + "access.policy.collectionScope": "Общая коллекция", + "access.policy.collection": "Коллекция камер", + "access.policy.chooseCollection": "Выберите общую коллекцию", + "access.policy.collectionHelp": "Доступ отслеживает коллекцию при добавлении, удалении или совпадении камер по её правилам.", + "access.policy.dynamicScope": "Динамический селектор", + "access.policy.activateConfirm": "Активировать политику с запретом по умолчанию для {username}? Действия без подходящего назначения будут отклонены.", + "access.policy.emptyConfirm": "Активировать политику с ограничением области для {username} без назначений? Это намеренно удалит весь доступ, контролируемый политикой.", + "access.policy.saved": "Политика доступа сохранена", + "access.policy.saveError": "Не удалось сохранить политику доступа: {message}", + "access.policy.version": "Версия политики {version}", + "access.policy.unsaved": "Несохранённые изменения", + "access.policy.validation.invalid_mode": "Выберите допустимый режим оценки.", + "access.policy.validation.missing_role": "Каждое разрешение должно ссылаться на доступную роль.", + "access.policy.validation.invalid_scope": "Каждое разрешение должно использовать область «весь парк», «общая коллекция» или «селектор».", + "access.policy.validation.invalid_selector": "Заполните или исправьте все селекторы камер перед сохранением.", + "access.policy.validation.missing_collection": "Выберите доступную общую коллекцию для каждого разрешения на коллекцию.", + "access.policy.validation.duplicate_grant": "Удалите дублирующиеся разрешения ролей и областей перед сохранением.", + "access.test.title": "Проверить эффективный доступ", + "access.test.description": "Оценить сохранённое действие и камеру от имени {username} без выполнения.", + "access.test.saveFirst": "Сохраните или отмените изменения разрешений перед проверкой, чтобы результат отражал показанную здесь политику.", + "access.test.action": "Действие", + "access.test.camera": "Камера", + "access.test.run": "Проверить доступ", + "access.test.running": "Проверка…", + "access.test.allowed": "Разрешено", + "access.test.denied": "Запрещено", + "access.test.version": "Версия {version}", + "access.test.source": "Источник: {source} · Роль: {role}", + "recordings.pullToRefresh": "Потяните для обновления записей", + "recordings.releaseToRefresh": "Отпустите для обновления записей", + "recordings.refreshing": "Обновление записей…", + "recordings.refreshed": "Записи обновлены", + "recordings.refreshFailed": "Не удалось обновить записи: {message}", + "recordings.download": "Скачать", + "recordings.tags": "Теги", + "recordings.selectRecording": "Выберите запись", + "timeline.legend.recording": "Запись", + "timeline.legend.detection": "Событие обнаружения", + "timeline.detectionEvent": "Событие обнаружения", + "streams.showCredentials": "Показать учётные данные", + "streams.hideCredentials": "Скрыть учётные данные", + "streams.streamSuccessfullyEnabled": "Поток успешно включён.", + "streams.errorEnablingStream": "Ошибка включения потока: {message}", + "system.health.tab": "Состояние", + "system.health.operatorView": "Рабочее состояние", + "system.health.title": "Состояние системы", + "system.health.loading": "Загрузка состояния системы…", + "system.health.loadError": "Не удалось загрузить состояние системы.", + "system.health.refreshing": "Обновление…", + "system.health.activeIncidentCount": "{count} активных инцидентов", + "system.health.coverage": "Покрытие", + "system.health.monitoringDisabled": "Мониторинг состояния отключён", + "system.health.lastRecordedValue": "Последнее записанное значение", + "system.health.monitoringDisabledHelp": "Текущие данные о состоянии не собираются. Включите мониторинг состояния в «Настройки → Состояние»; при необходимости перезапустите после сохранения. История инцидентов отображает прошлые события, а не текущее использование ресурсов.", + "system.health.monitoringRestartRequired": "Мониторинг состояния включён в сохранённой конфигурации, но запущенный сборщик данных по-прежнему отключён. Перезапустите LightNVR для применения изменений. История инцидентов отображает прошлые события.", + "system.health.containerCoverage": "Ограниченное покрытие хоста", + "system.health.hostHardwareUnavailable": "Данная установка видит состояние контейнеров и смонтированных ресурсов, но аппаратное обеспечение хоста недоступно. Отсутствующие значения хоста считаются неизвестными, а не нормальными.", + "system.health.coverageUnknown": "Завершённый снимок состояния пока недоступен. Значения остаются неизвестными до завершения сбора.", + "system.health.coverageComplete": "Все данные, доступные данной установке, успешно собраны.", + "system.health.coveragePartial": "Покрытие частичное. {count} наблюдений или проверок сбора недоступны, устарели или неполны.", + "system.health.effectiveScope": "Фактическая область", + "system.health.activeIncidents": "Активные инциденты", + "system.health.noActiveIncidents": "Активные инциденты для видимого покрытия не зафиксированы.", + "system.health.duration": "Длительность", + "system.health.currentValue": "Текущее значение", + "system.health.thresholds": "Порог и выдержка", + "system.health.thresholdSummary": "Предупреждение {warning}, критическое {critical}, восстановление {recovery} {unit}; выдержка предупреждения {seconds} с", + "system.health.remediation": "Рекомендуемое действие", + "system.health.facts": "Данные о состоянии", + "system.health.group.resources": "Ресурсы", + "system.health.group.storage": "Хранилище", + "system.health.group.hardware": "Оборудование", + "system.health.group.network": "Сеть", + "system.health.group.clock": "Время", + "system.health.group.components": "Компоненты", + "system.health.noFacts": "В этой группе нет видимых данных.", + "system.health.observationState": "Возможности и актуальность", + "system.health.valueUnavailable": "Одно или несколько значений неизвестны", + "system.health.componentStatus": "Компоненты мониторинга", + "system.health.collectors": "Сборщики", + "system.health.collectorSummary": "{total} зарегистрировано · {attention} требуют внимания", + "system.health.collectorsNeedingAttention": "Сборщики, требующие внимания", + "system.health.collectionFailures": "{count} сбоев или тайм-аутов", + "system.health.stale": "устаревшие", + "system.health.eventDelivery": "Доставка событий", + "system.health.degraded": "Деградировано", + "system.health.circularDelivery": "Это единственный настроенный канал оповещений, поэтому он не может независимо сообщить о собственном сбое.", + "system.health.incidentPersistence": "Сохранение инцидентов", + "system.health.persistenceSummary": "{pending} в ожидании · {failures} сбоев · {retries} повторных попыток", + "system.health.recentSamples": "Последняя активность сбора", + "system.health.recentSamplesHelp": "До {count} ограниченных серверных сводок генераций; это активность покрытия, а не график значений.", + "system.health.sampleSequence": "Генерация {sequence}", + "system.health.sampleCoverage": "{observations} наблюдений · {dropped} отброшено", + "system.health.noSamples": "Нет доступных завершённых генераций сбора.", + "system.health.incidentHistory": "История инцидентов", + "system.health.incidentHistoryHelp": "Сначала новые инциденты. История загружается ограниченными страницами.", + "system.health.loadingHistory": "Загрузка истории инцидентов…", + "system.health.historyError": "Не удалось загрузить историю инцидентов.", + "system.health.emptyHistory": "Инциденты не зафиксированы.", + "system.health.firstSeen": "Первое обнаружение", + "system.health.lastSeen": "Последнее обнаружение", + "system.health.deliveryState": "Состояние доставки", + "system.health.historyPagination": "Страницы истории инцидентов", + "system.health.pageCount": "{count} инцидентов на этой странице", + "system.health.remediation.memory": "Снизьте нагрузку на память, проверьте лимиты процессов и cgroup, просмотрите недавнюю активность OOM.", + "system.health.remediation.cpu": "Определите процессы с длительной нагрузкой на ЦП и проверьте пропускную способность сервиса перед изменением лимитов.", + "system.health.remediation.io": "Проверьте задержку хранилища и активных записывающих процессов; сохраните записи перед прерывающим обслуживанием.", + "system.health.remediation.filesystem": "Проверьте указанный логический файловый раздел, свободное место или иноды, убедитесь, что он доступен для записи.", + "system.health.remediation.thermal": "Улучшите охлаждение и снизьте нагрузку; проверьте вентиляторы и вентиляционные отверстия до достижения критических температур.", + "system.health.remediation.network": "Проверьте видимый интерфейс, линк, коммутатор и счётчики ошибок по независимому сетевому пути.", + "system.health.remediation.clock": "Восстановите синхронизацию времени и проверьте источник часов хоста перед использованием временных меток событий.", + "system.health.remediation.process": "Проверьте лимиты ресурсов LightNVR и журналы, затем снизьте нагрузку или увеличьте проверенные лимиты.", + "system.health.remediation.storage": "Создайте резервную копию важных записей и проверьте подключённое устройство хранения перед заменой или ремонтом.", + "system.health.remediation.hardware": "Проверьте затронутое оборудование и журналы платформы; запланируйте обслуживание, если проблема сохраняется.", + "system.health.remediation.health": "Восстановите доступ и права коллектора, чтобы оценить отсутствующие данные о состоянии.", + "system.health.remediation.system": "Проверьте предыдущий запуск и журналы хоста, чтобы отличить перезапуск процесса от перезагрузки хоста.", + "system.health.remediation.event": "Используйте локальный API или представление метрик, снимите нагрузку с устойчивой очереди и восстановите независимое назначение оповещений.", + "system.health.remediation.default": "Проверьте затронутый компонент и недавние журналы, затем убедитесь в восстановлении в новом цикле проверки состояния.", + "system.capacityTarget": "Целевая ёмкость", + "system.capacityTargetValue": "Свободно {pct}%", + "system.fillRate": "Скорость заполнения", + "system.fillRateValue": "{value} / день", + "system.projectedToTarget": "Прогноз до целевого значения", + "system.projectedNow": "Цель достигнута/превышена", + "system.projectedDays": "~{count} дн.", + "system.projectedHours": "~{count} ч.", + "system.projectedUnknown": "—", + "common.description": "Описание", + "common.remove": "Удалить", + "streams.selectStream": "Выбрать {name}", + "streams.search": "Поиск потоков", + "streams.searchPlaceholder": "Поиск камер, местоположений или тегов", + "streams.noStreamsMatchFilters": "Нет потоков, соответствующих текущим фильтрам.", + "streamHealth.sourceConnected": "Источник подключён", + "streamHealth.videoAdvancing": "Видео воспроизводится", + "streamHealth.recorderWriting": "Идёт запись", + "streamHealth.detectorOperating": "Детектор работает", + "streamHealth.lastSegment": "Последний завершённый сегмент", + "streams.disablingStreamsProgress": "Отключение потоков…", + "streams.onvifInvalidAddress": "IP-адрес устройства ONVIF отсутствует или недействителен.", + "streams.warningFallingBackToHttp": "Подключение по HTTPS не удалось; повторная попытка через HTTP. Учётные данные могут передаваться в открытом виде.", + "streamsConfig.playbackTransport": "Транспорт воспроизведения", + "streamsConfig.playbackTransportHelp": "Выберите способ воспроизведения в браузере для этой камеры и, при необходимости, порядок резервных вариантов.", + "streamsConfig.playbackTransportUnavailable": "Недоступно на сервере: {transports}. Включите транспорт глобально или выберите другой профиль.", + "streamsConfig.audioDisabledByPolicy": "Аудио отключено политикой экземпляра", + "streamsConfig.audioDisabledByPolicyHelp": "Запись, прослушивание в реальном времени и двусторонняя связь недоступны при включённой глобальной политике соответствия требованиям к аудио.", + "streamsConfig.audioVoiceEnhancement": "Улучшение голоса (записи)", + "streamsConfig.customApiModel": "Обнаружение через пользовательский API", + "streamsConfig.modelNotSupportedByBuild": "не поддерживается в этой сборке", + "streamsConfig.tierCriticalMultiplier": "Критический уровень ×", + "streamsConfig.tierImportantMultiplier": "Важный уровень ×", + "streamsConfig.tierEphemeralMultiplier": "Временный уровень ×", + "streamsConfig.tierMultipliersHelp": "Множители базового срока хранения по уровням. Записи более высокого уровня хранятся дольше и удаляются последними при нехватке места на диске.", + "streamsConfig.storagePriority": "Приоритет хранения (1–10)", + "streamsConfig.storagePriorityHelp": "Относительная важность записей этого потока при освобождении места; записи с более высоким приоритетом сохраняются дольше.", + "streamsConfig.restream": "Ретрансляция / Публикация (RTMP)", + "streamsConfig.publishUrl": "URL публикации (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "Ретрансляция этой камеры на сервис вроде YouTube Live через go2rtc. Вставьте полный URL приёма RTMP с ключом потока (например, rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Для ретрансляции на несколько сервисов одновременно разделяйте URL запятыми. YouTube требует видео H264 и аудио AAC; LightNVR теперь выполняет транскодирование автоматически (H264 для не-H264 камер, AAC для не-AAC аудио), поэтому большинство камер работают без дополнительных настроек. Примечание: YouTube также требует аудиодорожку — камера без аудио всё равно будет отклонена. Оставьте пустым для отключения.", + "streams.lastSeen": "Последний раз в сети: {time}", + "streams.claimed": "Занято", + "streams.duplicateSuspected": "Возможный дубликат", + "streams.duplicateSuspectedHelp": "Стабильный идентификатор или данные конечной точки конфликтуют с другой записью обнаружения.", + "streams.onvifClaimWarning": "Поток добавлен, но его запись обнаружения не удалось пометить как занятую: {message}", + "common.online": "В сети", + "common.offline": "Не в сети", + "settings.storageTargets.title": "Цели хранения записей", + "settings.storageTargets.description": "Зарегистрируйте локальные диски и смонтированные администратором файловые системы NFS или SMB как независимо отслеживаемые места хранения записей.", + "settings.storageTargets.foundationNotice": "Запись использует целевые хранилища файловой системы. Корзины S3 и смонтированные целевые хранилища NFS/SAN могут содержать проверенные копии архива. Приоритет горячего хранилища сохраняет архивные записи до истечения их логического срока хранения.", + "settings.storageTargets.add": "Добавить целевое хранилище", + "settings.storageTargets.edit": "Изменить целевое хранилище", + "settings.storageTargets.editorHelp": "Включённые хранилища должны существовать и проходить тест записи, fsync и очистки. Сохраните недоступную будущую точку монтирования в отключённом состоянии, затем включите её после монтирования.", + "settings.storageTargets.name": "Имя целевого хранилища", + "settings.storageTargets.root": "Корневой путь монтирования", + "settings.storageTargets.rootLocked": "Хранилище по умолчанию или непустое хранилище сохраняет неизменяемый корень, чтобы существующие записи не были потеряны.", + "settings.storageTargets.class": "Класс производительности", + "settings.storageTargets.hot": "Горячее — активная запись", + "settings.storageTargets.warm": "Тёплое — смонтированный архив", + "settings.storageTargets.cold": "Холодное — редкий доступ", + "settings.storageTargets.reserveGb": "Зарезервированный запас (ГБ)", + "settings.storageTargets.lowWatermark": "Нижний порог (% использования)", + "settings.storageTargets.highWatermark": "Верхний порог (% использования)", + "settings.storageTargets.migrationBandwidth": "Пропускная способность жизненного цикла (Мбит/с)", + "settings.storageTargets.migrationBandwidthHelp": "0 — без ограничений. Ограничение фиксируется при создании задачи перемещения или копирования.", + "settings.storageTargets.archiveStart": "Начало окна архивирования", + "settings.storageTargets.archiveEnd": "Конец окна архивирования", + "settings.storageTargets.archiveWindowHelp": "Местное время. Совпадающие начало и конец разрешают задачи жизненного цикла в течение всего дня; ночное окно может пересекать полночь.", + "settings.storageTargets.enabled": "Включено (политики размещения могут выбрать это хранилище)", + "settings.storageTargets.notRouted": "Ни одна включённая политика размещения не направляет камеры сюда. Новые записи продолжают поступать в хранилище по умолчанию, пока политика не назначит это хранилище основным, членом пула или целевым хранилищем архива.", + "settings.storageTargets.degradedNotice": "Превышен верхний порог или исчерпан резерв. Политики размещения пропускают это хранилище, пока не будет освобождено место.", + "settings.storageTargets.probePassedIneligible": "Тест записи пройден, но хранилище имеет статус {status}: политики размещения не будут его выбирать.", + "settings.storageTargets.mountRequired": "Требовать смонтированную файловую систему", + "settings.storageTargets.mountRequiredHelp": "Закрепить это хранилище за текущей нерулевой точкой монтирования. Если монтирование NFS, SMB, bind или PVC исчезнет, запись приостановится вместо записи в базовый каталог хоста.", + "settings.storageTargets.mountGuard": "Требуемое монтирование", + "settings.storageTargets.mountPending": "Будет обнаружено при включении целевого хранилища", + "settings.storageTargets.default": "По умолчанию", + "settings.storageTargets.capacity": "Ёмкость", + "settings.storageTargets.available": "Доступно", + "settings.storageTargets.recordings": "Индексированные записи", + "settings.storageTargets.replicas": "{count} проверенных копий · {bytes}", + "settings.storageTargets.reserve": "Зарезервировано", + "settings.storageTargets.pressure.normal": "Давление в норме", + "settings.storageTargets.pressure.high": "Верхний порог", + "settings.storageTargets.pressure.reserve": "Резерв исчерпан", + "settings.storageTargets.pressure.unavailable": "Давление недоступно", + "settings.storageTargets.cleanupActive": "Очистка в рамках цели активна и будет стремиться к {target} свободного места без удаления записей, назначенных другой цели.", + "settings.storageTargets.test": "Проверить цель", + "settings.storageTargets.probing": "Проверка…", + "settings.storageTargets.probePassed": "Тест записи в хранилище пройден", + "settings.storageTargets.duplicateFilesystem": "Этот корень использует ту же файловую систему, что и другая цель. При включённом размещении объём не должен учитываться дважды.", + "settings.storageTargets.deleteLocked": "Цели по умолчанию и непустые цели не могут быть удалены.", + "settings.storageTargets.deleteConfirm": "Удалить пустую цель хранилища «{name}»? Файлы не будут удалены.", + "settings.storageTargets.created": "Цель хранилища создана", + "settings.storageTargets.updated": "Цель хранилища обновлена", + "settings.storageTargets.deleted": "Цель хранилища удалена", + "settings.storageTargets.invalidThresholds": "Проверьте пороги, резерв, пропускную способность жизненного цикла и временные окна архива.", + "settings.storageTargets.loadError": "Не удалось загрузить цели хранилища", + "settings.storagePools.title": "Пулы хранилища", + "settings.storagePools.description": "Группируйте здоровые цели для автоматического перелива и репликации на разные цели.", + "settings.storagePools.add": "Добавить пул", + "settings.storagePools.strategy": "Стратегия распределения", + "settings.storagePools.mostFree": "Больше свободного места", + "settings.storagePools.roundRobin": "По кругу", + "settings.storagePools.priority": "Явный приоритет", + "settings.storagePools.members": "Цели (порядок отображения — приоритет распределения)", + "settings.storagePools.enabled": "Пул включён", + "settings.storagePools.active": "Активен", + "settings.storagePools.inactive": "Отключён", + "settings.storagePools.strategyValue.most_free": "больше свободного", + "settings.storagePools.strategyValue.round_robin": "по кругу", + "settings.storagePools.strategyValue.priority": "по приоритету", + "settings.storagePools.created": "Пул хранилища создан", + "settings.storagePools.updated": "Пул хранилища обновлён", + "settings.storagePools.deleted": "Пул хранилища удалён", + "settings.storagePools.deleteConfirm": "Удалить пул хранилища «{name}»?", + "settings.storagePools.empty": "Пул хранилища ещё не настроены.", + "settings.storageMigrations.title": "Задачи миграции записей", + "settings.storageMigrations.description": "Надёжные перемещения и копии с сохранением учитывают окно архивирования и ограничение пропускной способности каждой цели, проверяют SHA-256 и безопасно восстанавливаются после перезапуска.", + "settings.storageMigrations.empty": "Задач миграции записей пока нет.", + "settings.storageMigrations.loadError": "Не удалось загрузить задачи миграции записей", + "settings.storageMigrations.recording": "Запись #{id}", + "settings.storageMigrations.attempt": "Попытка {current}/{max}", + "settings.storageMigrations.operation.move": "Перемещение", + "settings.storageMigrations.operation.copy": "Копия с сохранением", + "settings.storageMigrations.cancelled": "Отмена миграции принята", + "settings.storageMigrations.cancelling": "Отмена…", + "settings.storageMigrations.retried": "Миграция поставлена в очередь на повтор", + "settings.storageMigrations.state.queued": "В очереди", + "settings.storageMigrations.state.copying": "Копирование", + "settings.storageMigrations.state.verifying": "Проверка", + "settings.storageMigrations.state.committing": "Фиксация", + "settings.storageMigrations.state.cleanup_pending": "Очистка источника", + "settings.storageMigrations.state.retry_wait": "Ожидание повтора", + "settings.storageMigrations.state.completed": "Завершено", + "settings.storageMigrations.state.failed": "Ошибка", + "settings.storageMigrations.state.cancelled": "Отменено", + "settings.storagePolicies.title": "Политики размещения камер", + "settings.storagePolicies.description": "Направляют подходящие камеры на основную цель записи в порядке приоритета. Камера использует первую включённую политику, которая совпадает.", + "settings.storagePolicies.add": "Добавить политику размещения", + "settings.storagePolicies.edit": "Изменить политику размещения", + "settings.storagePolicies.editorHelp": "Политика применяется к новым сегментам. Изменения не перемещают уже существующие записи.", + "settings.storagePolicies.priority": "Приоритет (выше — раньше)", + "settings.storagePolicies.priorityValue": "Приоритет {priority}", + "settings.storagePolicies.primary": "Основная цель", + "settings.storagePolicies.primaryPool": "Пул размещения (необязательно)", + "settings.storagePolicies.exactTarget": "Использовать точную основную цель", + "settings.storagePolicies.fallback": "Если основная цель недоступна", + "settings.storagePolicies.fallbackDefault": "Использовать цель по умолчанию", + "settings.storagePolicies.fallbackTarget": "Использовать именованную резервную цель", + "settings.storagePolicies.fallbackPause": "Приостановить запись", + "settings.storagePolicies.fallbackFail": "Завершить запуск записи ошибкой", + "settings.storagePolicies.namedFallback": "Резервная цель", + "settings.storagePolicies.chooseTarget": "Выберите цель", + "settings.storagePolicies.choosePool": "Выберите пул", + "settings.storagePolicies.minimumDays": "Минимальный срок хранения (дней)", + "settings.storagePolicies.desiredDays": "Целевой срок хранения (дней)", + "settings.storagePolicies.maximumDays": "Максимальный срок хранения (дней)", + "settings.storagePolicies.copyCount": "Требуемое количество проверенных копий", + "settings.storagePolicies.replicationPool": "Пул репликации", + "settings.storagePolicies.migrateAfter": "Переместить через (дней)", + "settings.storagePolicies.migrationTarget": "Цель архивирования", + "settings.storagePolicies.pressurePriority": "Приоритет удаления при нехватке места (меньший — раньше)", + "settings.storagePolicies.disabledTarget": "отключено", + "settings.storagePolicies.enabled": "Политика включена", + "settings.storagePolicies.selector": "Совпадающие камеры", + "settings.storagePolicies.preview": "Предпросмотр приоритета", + "settings.storagePolicies.previewing": "Вычисляется…", + "settings.storagePolicies.previewRequired": "Просмотрите текущий черновик перед сохранением, чтобы увидеть пересечение камер и действующую приоритетную политику.", + "settings.storagePolicies.previewSummary": "Совпадает с {matched} камерами; этот черновик действует для {effective}.", + "settings.storagePolicies.previewShadowed": "Политика с более высоким приоритетом действует для {count} совпадающих камер.", + "settings.storagePolicies.previewWins": "Приоритетнее «{policy}» (приоритет {priority}) для {count} камер.", + "settings.storagePolicies.previewLoses": "Уступает «{policy}» (приоритет {priority}) для {count} камер.", + "settings.storagePolicies.previewNoMatches": "Этот селектор сейчас не совпадает ни с одной камерой.", + "settings.storagePolicies.invalidPriority": "Приоритет должен быть целым числом от -1 000 000 до 1 000 000.", + "settings.storagePolicies.invalidLifecycle": "Проверьте порядок хранения, количество копий и пул репликации, а также возраст и цель перемещения.", + "settings.storagePolicies.created": "Политика размещения создана", + "settings.storagePolicies.updated": "Политика размещения обновлена", + "settings.storagePolicies.deleted": "Политика размещения удалена", + "settings.storagePolicies.deleteConfirm": "Удалить политику размещения «{name}»? Существующие записи не будут затронуты.", + "settings.storagePolicies.active": "Активна", + "settings.storagePolicies.inactive": "Отключена", + "settings.storagePolicies.routesTo": "Основная цель: {target}", + "settings.storagePolicies.lifecycleSummary": "Хранение мин./желат./макс.: {minimum}/{desired}/{maximum} дн. · {copies} проверенная копия/копии", + "settings.storagePolicies.fallsBackTo": "Резервная цель: {target}", + "settings.storagePolicies.mode.default": "Резерв: цель по умолчанию", + "settings.storagePolicies.mode.pause": "Резерв: приостановить запись", + "settings.storagePolicies.mode.fail": "Резерв: отклонить запуск записи", + "settings.storagePolicies.empty": "Политики размещения отсутствуют. Камеры продолжают использовать цель по умолчанию; другие цели не получают записи, пока политика не направит камеры к ним.", + "settings.storagePolicies.archiveNoTrigger": "Цель архивирования задана, но перемещение не запускается. Укажите «Перемещать после (дней)», возраст архивирования или параметр архивирования; иначе записи не будут перемещены.", + "settings.storageCompliance.title": "Ёмкость и соответствие политике", + "settings.storageCompliance.description": "Наблюдаемые 30-дневные показатели прогнозируют нагрузку на цель и достигнутое хранение; активные нарушения жизненного цикла остаются видимыми до устранения.", + "settings.storageCompliance.loadError": "Не удалось загрузить соответствие хранилища", + "settings.storageCompliance.unknown": "Неизвестно", + "settings.storageCompliance.days": "{days} дн.", + "settings.storageCompliance.day": "день", + "settings.storageCompliance.targetForecasts": "Прогнозы по целям", + "settings.storageCompliance.target": "Цель", + "settings.storageCompliance.dailyRate": "Наблюдаемая скорость", + "settings.storageCompliance.toHigh": "До верхнего порога", + "settings.storageCompliance.expected": "Ожидаемое хранение", + "settings.storageCompliance.confidence": "Уверенность", + "settings.storageCompliance.policyCompliance": "Соответствие политике", + "settings.storageCompliance.compliant": "Нет активных нарушений", + "settings.storageCompliance.violationCount": "{count} нарушение(й)", + "settings.storageCompliance.policyForecast": "Достигнуто {achieved}; прогноз {expected}; желаемое {desired} дн.", + "settings.storageCompliance.copyDeficits": "Требуется ещё одна проверенная копия для {count} записи(ей)", + "settings.storageCompliance.activeViolations": "Активные нарушения", + "settings.storageCompliance.type.copy_count": "Количество копий", + "settings.storageCompliance.type.minimum_retention": "Минимальная ёмкость хранения", + "settings.storageCompliance.type.target_unavailable": "Цель недоступна", + "settings.storageCompliance.type.migration_failed": "Сбой задачи жизненного цикла", + "settings.recordingDirectoryFormat": "Структура папок записей", + "settings.recordingDirectoryFormatHelp": "Новые MP4-записи размещаются в подпапках каждой камеры. Существующие записи не перемещаются.", + "settings.recordingDirectoryFlat": "Плоская (только папка камеры)", + "settings.recordingDirectoryMonth": "По месяцам (ГГГГ/ММ)", + "settings.recordingDirectoryDay": "По дням (ГГГГ/ММ/ДД)", + "settings.minFreePct": "Минимальное свободное место (%)", + "settings.minFreePctHelp": "Поддерживать не менее указанного процента свободного места на томе, автоматически удаляя самые старые записи независимо от срока хранения. Это ограничивает использование размером диска — задайте значение, и диск не заполнится. 0 отключает ограничение по ёмкости.", + "settings.pressureThresholds": "Пороги давления на диск (%)", + "settings.pressureThresholdsHelp": "Диапазоны свободного места для эскалации автоматической очистки. Должно выполняться: аварийный < критический < предупреждение.", + "settings.pressureWarningPct": "Предупреждение ниже (% свободно)", + "settings.pressureCriticalPct": "Критический ниже (% свободно)", + "settings.pressureEmergencyPct": "Аварийный ниже (% свободно)", + "settings.databaseBackupVerify": "Проверка резервных копий", + "settings.databaseBackupVerifyFull": "Полная (integrity_check, перекрёстная проверка каждого индекса)", + "settings.databaseBackupVerifyQuick": "Быстрая (quick_check, только структура страниц)", + "settings.databaseBackupVerifyOff": "Выкл. (без сканирования после копирования)", + "settings.databaseBackupVerifyHelp": "Сканирование применяется к каждой скопированной резервной копии перед публикацией. Полная проверка может занять больше времени, чем само копирование, на большой базе данных с механическим диском и привести к срабатыванию 30-минутного предохранителя с отбраковкой копии; быстрая проверка при этом всё равно обнаруживает повреждённые или усечённые страницы при значительно меньшем количестве обращений к диску.", + "settings.viewMethodAuto": "Авто — настройка для каждой камеры с резервным вариантом", + "settings.resetWizardPending": "Запуск мастера…", + "settings.apiDetectionFormat": "Формат API-запроса", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (загрузка изображения в формате multipart)", + "settings.apiDetectionFormatDoods2": "DOODS2 (тело JSON с изображением в base64)", + "settings.apiDetectionFormatHelp": "Формат передачи, который LightNVR использует при отправке снимков в API детекции. Оставьте light-object-detect для light-object-detect или любого сервера, реализующего его контракт; выберите DOODS2 для сервера DOODS2.", + "settings.apiDetectionUrlHelpDoods2": "Конечная точка DOODS2 /detect, например http://localhost:8080/detect. Запрос отправляется в формате JSON, параметры запроса не добавляются.", + "settings.apiDetectionDetectorName": "Имя детектора DOODS2", + "settings.apiDetectionDetectorNameHelp": "Передаётся как detector_name в каждом запросе. Должно совпадать с именем детектора из списка сервера GET /detectors; «default» использует детектор по умолчанию.", + "settings.defaultPlaybackTransport": "Транспорт воспроизведения по умолчанию", + "settings.defaultPlaybackTransportHelp": "Профиль воспроизведения, применяемый к новым потокам. Существующие потоки сохраняют свой выбор.", + "playbackTransport.auto": "Авто (рекомендуется)", + "playbackTransport.webrtcOnly": "Только WebRTC", + "playbackTransport.mseOnly": "Только MSE", + "playbackTransport.hlsOnly": "Только HLS", + "playbackTransport.webrtcThenMse": "WebRTC, затем MSE", + "playbackTransport.mseThenHls": "MSE, затем HLS", + "investigation.experimental": "Экспериментальное рабочее пространство", + "investigation.title": "Расследование", + "investigation.description": "Просмотр нескольких камер с общим курсором UTC без скрытия пропусков в записи.", + "investigation.query": "Окно расследования", + "investigation.queryHelp": "Выберите до 16 камер. Одновременно активно не более четырёх видеоплееров.", + "investigation.cameras": "камер", + "investigation.cameraSelection": "Выбор камер", + "investigation.start": "Начало", + "investigation.end": "Конец", + "investigation.load": "Загрузить расследование", + "investigation.applyWindow": "Применить временной интервал", + "investigation.loading": "Загрузка расследования…", + "investigation.eventType": "Тип события", + "investigation.anyEventType": "Любой тип события", + "investigation.eventType.detection": "Обнаружение", + "investigation.eventType.motion": "Движение", + "investigation.location": "Местоположение", + "investigation.anyLocation": "Любое местоположение", + "investigation.objectLabel": "Метка объекта", + "investigation.anyLabel": "Любая метка", + "investigation.zone": "Зона", + "investigation.anyZone": "Любая зона", + "investigation.source": "Источник обнаружения", + "investigation.anySource": "Любой источник", + "investigation.captureMethod": "Способ захвата", + "investigation.anyCaptureMethod": "Любой способ захвата", + "investigation.recordingTag": "Метка записи", + "investigation.anyRecordingTag": "Любой тег записи", + "investigation.protection": "Защита", + "investigation.anyProtection": "Любая защита", + "investigation.protected": "Защищённая", + "investigation.unprotected": "Незащищённая", + "investigation.minimumConfidence": "Минимальная уверенность", + "investigation.confidenceError": "Минимальная уверенность должна быть от 0 до 1.", + "investigation.metadataRegionSearch": "Поиск по области метаданных", + "investigation.regionSearchHelp": "Выберите основную камеру с записями, затем выделите область на её видео.", + "investigation.regionActive": "Поиск сохранённых объектов из {camera}. Отсутствие результата не означает, что область не пересекалась.", + "investigation.regionMatch": "Сопоставление объектов", + "investigation.regionMatch.center": "Центр внутри", + "investigation.regionMatch.intersects": "Любое пересечение", + "investigation.regionMatch.minimumIntersection": "Минимальное перекрытие", + "investigation.regionMinimumOverlap": "Минимальное перекрытие (%)", + "investigation.regionLeft": "Слева (%)", + "investigation.regionTop": "Сверху (%)", + "investigation.regionWidth": "Ширина (%)", + "investigation.regionHeight": "Высота (%)", + "investigation.drawRegion": "Выделить область поиска", + "investigation.drawingRegion": "Выделение области поиска…", + "investigation.clearRegion": "Очистить область", + "investigation.useFullFrame": "Использовать весь кадр", + "investigation.drawRegionPrompt": "Проведите по видео, чтобы задать область поиска", + "investigation.applyFilters": "Применить фильтры", + "investigation.searching": "Поиск событий…", + "investigation.searchResults": "Результаты событий", + "investigation.searchHelp": "Загрузите расследование для поиска сохранённых метаданных событий.", + "investigation.resultCount": "{count} совпадающих событий", + "investigation.results": "результатов", + "investigation.resultHistogram": "Гистограмма событий", + "investigation.histogramHelp": "Выберите столбец для перемещения общего курсора.", + "investigation.previousResult": "Предыдущее событие", + "investigation.nextResult": "Следующее событие", + "investigation.previousResultShortcut": "Предыдущее событие ([)", + "investigation.nextResultShortcut": "Следующее событие (])", + "investigation.noResults": "Сохранённые события не соответствуют выбранной камере, времени и фильтрам.", + "investigation.noThumbnail": "Нет миниатюры", + "investigation.exploreThumbnails": "Просмотр миниатюр", + "investigation.exploreSelectedThumbnails": "Обзор вокруг события", + "investigation.thumbnailDrilldown": "Детальный просмотр миниатюр", + "investigation.thumbnailDrilldownHelp": "Выберите любой момент, включая пропуск, чтобы переместить общий курсор и сгенерировать более узкий набор образцов.", + "investigation.selectThumbnailSample": "Обзор вокруг {time}", + "investigation.loadingThumbnail": "Загрузка миниатюры…", + "investigation.thumbnailUnavailable": "Миниатюра недоступна", + "investigation.loadingSamples": "Загрузка образцов миниатюр…", + "investigation.thumbnailCoverageTruncated": "В этом интервале больше записей, чем анализатор может обработать. Сузьте временное окно для полного охвата.", + "investigation.bookmarks.save": "Сохранить закладку", + "investigation.bookmarks.open": "Закладки", + "investigation.bookmarks.saveTitle": "Сохранить закладку расследования", + "investigation.bookmarks.listTitle": "Закладки расследования", + "investigation.bookmarks.notHold": "Закладка восстанавливает этот вид, но не защищает записи от удаления по политике хранения.", + "investigation.bookmarks.title": "Название закладки", + "investigation.bookmarks.note": "Приватная заметка (необязательно)", + "investigation.bookmarks.titleRequired": "Введите название закладки.", + "investigation.bookmarks.empty": "У вас нет сохранённых закладок расследования.", + "investigation.bookmarks.cameraCount": "{count} камер", + "investigation.bookmarks.restore": "Открыть", + "investigation.bookmarks.confirmDelete": "Удалить закладку?", + "investigation.actions.open": "Защитить / скачать", + "investigation.actions.title": "Записи расследования", + "investigation.actions.notEvidenceExport": "Защита предотвращает удаление по политике хранения. Скачивание ZIP — это удобный экспорт, а не верифицированный пакет доказательств.", + "investigation.actions.scope": "Область записи", + "investigation.actions.selectedResult": "Выбранное событие и камера", + "investigation.actions.fullWindow": "Все камеры в окне расследования", + "investigation.actions.preview": "Предпросмотр записей", + "investigation.actions.previewing": "Поиск пересекающихся записей…", + "investigation.actions.invalidRange": "Укажите корректный временной диапазон, где конец позже начала.", + "investigation.actions.recordingCount": "{count} пересекающихся записей", + "investigation.actions.protectedCount": "{count} уже защищены", + "investigation.actions.noRecordings": "Нет завершённых записей, пересекающихся с выбранной камерой и временем.", + "investigation.actions.protectDenied": "{count} незащищённых записей вне области вашей защиты и исключены из этого действия.", + "investigation.actions.exportDenied": "Отсутствует разрешение на экспорт для {count} записей. Загрузка выполняется целиком или не выполняется, поэтому этот набор нельзя экспортировать.", + "investigation.actions.camera": "Камера", + "investigation.actions.recording": "Запись", + "investigation.actions.size": "Размер", + "investigation.actions.notPermitted": "Не разрешено", + "investigation.actions.protectButton": "Защитить {count}", + "investigation.actions.protecting": "Защита…", + "investigation.actions.protectUnavailable": "Нет незащищённых записей, которые вы можете защитить.", + "investigation.actions.protectResult": "Защита завершена: успешно — {success}, с ошибкой — {failed}.", + "investigation.actions.downloadButton": "Скачать {count}", + "investigation.actions.downloadUnavailable": "Для каждой записи требуется разрешение на экспорт перед созданием ZIP.", + "investigation.actions.buildingArchive": "Создание ZIP…", + "investigation.actions.downloadFailed": "Не удалось создать ZIP на сервере.", + "investigation.actions.downloadTimedOut": "Создание ZIP не завершилось за пять минут. Попробуйте более узкий интервал.", + "investigation.actions.downloadStarted": "Загрузка ZIP начата.", + "investigation.backOneLevel": "На уровень выше", + "investigation.thumbnailMinimumWindow": "Это самый узкий доступный интервал в одну секунду. Общий курсор всё равно переместился к выбранному моменту.", + "investigation.localSource": "локально", + "investigation.mediaAvailable": "Медиа доступно", + "investigation.durationSeconds": "Длительность {count} с", + "investigation.pageNumber": "Страница {count}", + "investigation.incompleteCoverage": "{count} устаревших строк событий не удалось привязать к неизменяемому идентификатору камеры.", + "investigation.spatialCoverageGap": "{count} строк событий в области не имели ограничивающей рамки и не были найдены пространственным поиском.", + "investigation.noSpatialMetadata": "Ни одно событие в области не имеет ограничивающей рамки для данного поиска по метаданным.", + "investigation.selectCameraError": "Выберите хотя бы одну камеру.", + "investigation.selectRecordingError": "Выберите хотя бы одну запись.", + "investigation.investigateSelectedCount": "Исследовать {count} выбранных записей", + "investigation.missingCameraIdentity": "Невозможно исследовать: у {count} выбранных записей отсутствует идентификатор камеры.", + "investigation.recordingTimeError": "У выбранных записей отсутствует корректный временной диапазон.", + "investigation.windowLimit": "Выбранные записи превышают лимит исследования в 31 день.", + "investigation.timeRangeError": "Время окончания должно быть позже времени начала.", + "investigation.cameraLimit": "Исследование может включать не более {count} камер.", + "investigation.decoderLimit": "Одновременно может быть активно не более {count} проигрывателей камер.", + "investigation.playbackControls": "Синхронизированные элементы управления воспроизведением", + "investigation.play": "Воспроизвести", + "investigation.pause": "Пауза", + "investigation.mode": "Режим воспроизведения", + "investigation.wallClock": "Реальное время", + "investigation.skipCommonGaps": "Пропускать общие разрывы", + "investigation.speed": "Скорость", + "investigation.sharedCursor": "Общий курсор UTC", + "investigation.activePlayers": "активных проигрывателей", + "investigation.timeline": "общая временная шкала", + "investigation.segments": "сегменты", + "investigation.truncated": "обрезано", + "investigation.gap": "Нет записей", + "investigation.players": "Синхронизированные проигрыватели камер", + "investigation.activateCamera": "Активируйте хотя бы одну строку временной шкалы для загрузки видео.", + "investigation.noFootage": "Нет записей", + "investigation.noFootageAtTime": "Нет записей на общем времени", + "investigation.primaryAudio": "Основной аудиопоток", + "investigation.makePrimary": "Сделать основным", + "investigation.status.loading": "Загрузка медиа", + "investigation.status.synchronizing": "Синхронизация", + "investigation.status.ready": "Синхронизировано", + "investigation.status.late": "Отставание — восстановление", + "investigation.status.error": "Медиа недоступно", + "investigation.status.paused-by-browser": "Нажмите «Воспроизведение», чтобы разрешить медиа", + "streamsConfig.eptzTitle": "Fisheye ePTZ", + "streamsConfig.eptzEnable": "Включить fisheye ePTZ на стороне браузера", + "streamsConfig.eptzHelp": "Исправление искажений исходного fisheye-потока в режиме реального времени, воспроизведении на временной шкале и расследовании. Это не влияет на записи или вывод камеры.", + "streamsConfig.eptzModelHelp": "Проекция: равноотстоящая круговая fisheye · Крепление: потолочное. Центр и радиус используют нормализованные координаты исходного изображения.", + "streamsConfig.eptzCenterX": "Оптический центр X", + "streamsConfig.eptzCenterY": "Оптический центр Y", + "streamsConfig.eptzRadius": "Радиус круга изображения", + "streamsConfig.eptzLensFov": "Угол обзора объектива (градусы)", + "streamsConfig.eptzRotation": "Поворот объектива (градусы)", + "streamsConfig.eptzDefaultYaw": "Панорамирование по умолчанию (градусы)", + "streamsConfig.eptzDefaultTilt": "Наклон по умолчанию (градусы)", + "streamsConfig.eptzViewFov": "Угол обзора по умолчанию", + "streamsConfig.eptzCalibrationHelp": "Перетаскивайте для обзора, используйте колесо мыши или щипок для масштабирования, нажмите Home для сброса виртуальной камеры. Точно настройте центр и радиус, если край круга изображения не совпадает.", + "settings.archive.targetType": "Тип хранилища", + "settings.archive.filesystem": "Локальная или смонтированная файловая система (NFS/SAN)", + "settings.archive.s3": "S3-совместимый архивный бакет", + "settings.archive.endpoint": "Точка доступа HTTPS", + "settings.archive.region": "Регион", + "settings.archive.bucket": "Выделенный бакет", + "settings.archive.credential_ref": "Ссылка на учётные данные", + "settings.archive.budget": "Бюджет архива (ГиБ, 0 = без ограничений)", + "settings.archive.connectionHelp": "Используйте приватный бакет без версионирования и правил истечения жизненного цикла. Ссылка на учётные данные указывает на секретный файл, смонтированный на сервере. Укажите управляемое расположение в формате s3://bucket/instance-prefix.", + "settings.archive.policy": "Политика внешнего архива", + "settings.archive.archive_after_seconds": "Архивировать после записи (секунды, -1 = отключено)", + "settings.archive.hot_residency_seconds": "Хранить горячую копию (секунды, -1 = переместить после архивирования)", + "settings.archive.archive_protected": "Приоритетное архивирование защищённых записей", + "settings.archive.archive_on_pressure": "Раннее архивирование при нехватке горячего хранилища", + "settings.archive.policyHelp": "Время архивирования определяется возрастом записи; запись должна быть завершена. -1 отключает архивирование по возрасту или убирает минимальный срок хранения в горячем хранилище; 0 означает немедленно. Изменения применяются к новым записям. Для применения новой ревизии к существующим записям выполните их пересмотр.", + "settings.archive.deletion_pending": "Ожидает удаления", + "settings.archive.archived": "Архивировано", + "settings.archive.hot": "Горячее", + "settings.archive.hot_and_archive": "Горячее + архив", + "settings.archive.archiving": "Архивирование", + "settings.archive.preparing": "Подготовка воспроизведения", + "settings.archive.unavailable": "Недоступно", + "settings.archive.operations": "Операции архива", + "settings.archive.readOnly": "Режим восстановления: миграция и удаление записей приостановлены.", + "settings.archive.disabledBuild": "Поддержка S3 отключена в этой сборке. Целевые точки с примонтированной файловой системой остаются доступными.", + "settings.archive.stored": "Хранится в бакетах", + "settings.archive.backlog": "Очередь передачи", + "settings.archive.cache": "Кэш извлечения", + "settings.archive.objectsRemaining": "объектов осталось", + "settings.archive.waitingForReaders": "В очереди или ожидает активных читателей.", + "settings.archive.applied": "Ревизия политики применена к существующим записям", + "settings.archive.reviewExisting": "Проверить существующие записи", + "settings.archive.applySummary": "{count} записей ({bytes}) будут использовать эту ревизию. {expired} уже превысили лимит хранения.", + "settings.archive.applyHelp": "Защита и переопределения записи по-прежнему действуют. Также действуют правила хранения потока и системы. Новые параметры архивирования и назначения вступят в силу при следующем сканировании жизненного цикла.", + "settings.archive.applyBlocked": "Завершите или разрешите связанные передачи перед применением этой ревизии.", + "settings.archive.apply": "Применить к существующим записям", + "common.fullscreenUnsupported": "Полноэкранный режим не поддерживается в этом браузере.", + "recordings.viewInTimelineTitle": "Просмотреть этот поток в данный момент времени в представлении «Временная шкала»", + "recordings.clickToRetry": "Нажмите для повторной попытки", + "timeline.previousDay": "Предыдущий день", + "timeline.nextDay": "Следующий день", + "timeline.previousMonth": "Предыдущий месяц", + "timeline.nextMonth": "Следующий месяц", + "settings.searchLabel": "Поиск настроек", + "settings.clearSearch": "Очистить поиск", + "recordings.addTagPlaceholder": "Добавить тег...", + "recordings.addNewTagPlaceholder": "Добавить новый тег..." } diff --git a/web/public/locales/tr.json b/web/public/locales/tr.json index 82df10fc..89d88722 100644 --- a/web/public/locales/tr.json +++ b/web/public/locales/tr.json @@ -759,9 +759,9 @@ "streamsConfig.streamNameImmutable": "Akış adı oluşturulduktan sonra değiştirilemez", "streamsConfig.streamNameAllowedChars": "Yalnızca harflere, rakamlara, '.', '-' ve '_'ye izin verilir (boşluksuz).", "streamsConfig.streamUrl": "Akış URL", - "streamsConfig.streamUrlPlaceholder": "rtsp://kullanıcı adı:şifre@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "Alt akış URL (isteğe bağlı)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://kullanıcı adı:şifre@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "Kontrol paneli ızgara görünümü için düşük çözünürlüklü akış URL. Ana akışı her yerde kullanmak için boş bırakın. Alt akış yalnızca ızgara modunda canlı önizleme için kullanılır; kayıt ve tam ekran her zaman ana akışı kullanır.", "streamsConfig.urlCredentialsHiddenTitle": "URL kimlik bilgileri demo/görüntüleyici modunda gizlenir", "streamsConfig.urlCredentialsHidden": "Güvenlik için URL kimlik bilgileri gizlendi", @@ -819,7 +819,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "Light-object-detect'in bu uç noktada çalıştığından emin olun", "streamsConfig.customApiEndpointUrl": "Özel API Uç Nokta URL", "streamsConfig.useDefaultEndpoint": "Varsayılan Uç Noktayı Kullan", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "URL'nin tamamını özel algılama API uç noktanıza girin", "streamsConfig.overrideWithCustomEndpoint": "Özel Uç Noktayla Geçersiz Kıl", "streamsConfig.detectionThreshold": "Tespit Eşiği", @@ -1056,7 +1056,7 @@ "settings.detectionModelsPath": "Algılama Modelleri Yolu", "settings.detectionModelsPathHelp": "Algılama modellerinin saklandığı dizin", "settings.apiDetectionUrl": "API Algılama URL", - "settings.apiDetectionUrlHelp": "URL harici nesne algılama API uç noktasının", + "settings.apiDetectionUrlHelp": "light-object-detect uç noktası, örn. http://localhost:8000/api/v1/detect. Anlık görüntü, backend ve confidence_threshold sorgu parametreleri eklenerek multipart form data olarak yüklenir.", "settings.apiDetectionBackend": "API Algılama Arka Ucu", "settings.apiDetectionBackendOnnx": "ONNX Çalışma Zamanı", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1156,5 +1156,1492 @@ "settings.discoveryIntervalSecondsRangeHelp": "Kameraların ne sıklıkta taranacağı (30–3600 saniye)", "settings.discoveryNetwork": "Keşif Ağı", "settings.discoveryNetworkExamples": "Örnekler: 192.168.1.0/24, 10.0.0.0/16, auto", - "settings.saveSettings": "Ayarları Kaydet" + "settings.saveSettings": "Ayarları Kaydet", + "live.navigator.title": "Navigatör", + "live.navigator.subtitle": "Konumlar, düzenler ve etkinlik", + "live.navigator.cameras": "Kameralar", + "live.navigator.plans": "Plan", + "live.navigator.views": "Görünümler", + "live.navigator.events": "Olaylar", + "live.navigator.search": "Kamera bul…", + "live.navigator.allCameras": "Tüm kameralar", + "live.navigator.unassigned": "Atanmamış", + "live.navigator.noCameras": "Bu kapsama uygun kamera yok.", + "live.navigator.saveCurrent": "Mevcut düzeni kaydet", + "live.navigator.noLayouts": "Henüz kaydedilmiş düzen yok.", + "live.navigator.layoutNamePrompt": "Bu Canlı düzenine ad verin", + "live.navigator.shareLayoutPrompt": "Bu düzeni diğer operatörlerle paylaş?", + "live.navigator.layoutSaved": "{name} kaydedildi", + "live.navigator.layoutLoaded": "{name} yüklendi", + "live.navigator.deleteLayoutConfirm": "{name} silinsin mi?", + "live.navigator.shared": "Paylaşılan", + "live.navigator.loadingEvents": "Son olaylar yükleniyor…", + "live.navigator.noRecentEvents": "Son bir saatte algılama yok.", + "live.navigator.expand": "Navigatörü genişlet", + "live.navigator.collapse": "Navigatörü daralt", + "live.plan.navigatorHelp": "Bir bina veya kat seçin. Kamera önizlemeleri yalnızca istendiğinde açılır.", + "live.plan.noPlans": "Henüz bina planı yok. Plan çalışma alanında bir tane oluşturun.", + "live.plan.emptyTitle": "Mekânsal kamera görünümü oluşturun", + "live.plan.emptyDescription": "Plan, tüm tesis için durum işaretçilerini gösterir ve yalnızca operatör talep ettiğinde video açar. Odaları ve duvarları doğrudan buraya çizin veya taranmış bir kat planı, tesis çizimi ya da NVR yazılımınızdan bir anlık görüntü yükleyin, ardından kameraları gerçek odalara eşleştirin.", + "live.plan.sketch.tools": "Yerleşim araçları", + "live.plan.sketch.tool.select": "Seç", + "live.plan.sketch.tool.room": "Oda", + "live.plan.sketch.tool.wall": "Duvar", + "live.plan.sketch.tool.area": "Alan", + "live.plan.sketch.tool.label": "Etiket", + "live.plan.sketch.undo": "Çizimi geri al", + "live.plan.sketch.redo": "Çizimi yinele", + "live.plan.sketch.snap": "Izgaraya yapıştır", + "live.plan.sketch.hint.select": "Şekilleri veya kameraları sürükleyerek taşıyın. Bir şekli düzenlemek için tıklayın; ızgarayı atlamak için Alt tuşunu basılı tutun.", + "live.plan.sketch.hint.room": "Oda veya bina dış çizimi çizmek için planda sürükleyin.", + "live.plan.sketch.hint.wall": "Duvar noktaları eklemek için tıklayın. Bitirmek için çift tıklayın veya Enter'a basın, iptal etmek için Escape'e basın.", + "live.plan.sketch.hint.area": "Bir alanı çevrelemek için tıklayın. Kapatmak için ilk noktaya tıklayın veya Enter'a basın.", + "live.plan.sketch.hint.label": "Metin etiketi yerleştirmek için plana tıklayın.", + "live.plan.sketch.type.rect": "Oda", + "live.plan.sketch.type.wall": "Duvar", + "live.plan.sketch.type.area": "Alan", + "live.plan.sketch.type.label": "Etiket", + "live.plan.sketch.pointCount": "{count} nokta", + "live.plan.sketch.defaultLabel": "Etiket", + "live.plan.sketch.shapes": "Yerleşim şekilleri", + "live.plan.sketch.noShapes": "Henüz bir şey çizilmedi. Başlamak için planın üstünden bir araç seçin.", + "live.plan.sketch.tone": "Renk", + "live.plan.sketch.tone.slate": "Koyu Gri", + "live.plan.sketch.tone.blue": "Mavi", + "live.plan.sketch.tone.green": "Yeşil", + "live.plan.sketch.tone.amber": "Kehribar", + "live.plan.sketch.tone.red": "Kırmızı", + "live.plan.sketch.tone.violet": "Mor", + "live.plan.sketch.labelText": "Etiket", + "live.plan.sketch.text": "Metin", + "live.plan.sketch.size": "Boyut", + "live.plan.sketch.size.sm": "Küçük", + "live.plan.sketch.size.md": "Orta", + "live.plan.sketch.size.lg": "Büyük", + "live.plan.sketch.filled": "Odayı Doldur", + "live.plan.sketch.left": "Sol %", + "live.plan.sketch.top": "Üst %", + "live.plan.sketch.width": "Genişlik %", + "live.plan.sketch.height": "Yükseklik %", + "live.plan.sketch.points": "Noktalar", + "live.plan.sketch.point": "Nokta {index}", + "live.plan.sketch.delete": "Şekli Sil", + "live.plan.sketch.duplicate": "Kopyala", + "live.plan.sketch.deselect": "Bitti", + "live.plan.sketch.emptyTitle": "Bu planda henüz bir şey yok", + "live.plan.sketch.emptyBody": "Odalari, duvarlari ve etiketleri buraya cizin veya taranmis bir plan, saha cizimi ya da PNG/JPEG disa aktarimi yukleyin (en fazla 768 KB).", + "live.plan.sketch.emptyBodyReadOnly": "Bir yonetici duzen cizebilir veya gercek binanin planini yukleyebilir.", + "live.plan.sketch.drawLayout": "Duzen ciz", + "live.plan.sketch.uploadImage": "Gorsel yukle", + "live.plan.sketch.limitReached": "Sekil sinirina ulasildi ({max})", + "live.plan.sketch.discardDrawing": "Cizim iptal edildi", + "live.favorites": "Favoriler", + "live.favoritesOnly": "Sadece favori kameralari goster", + "live.addFavorite": "{stream} akisini favorilere ekle", + "live.removeFavorite": "{stream} akisini favorilerden cikar", + "live.noFavorites": "Henuz favori kamera yok. Eklemek icin kamera karonun uzerindeki yildizi kullanin.", + "live.favoriteUpdateError": "Favoriler guncellenemedi: {message}", + "live.resetZoom": "Yakinlastirmayi sifirla", + "live.audioPlaybackBlocked": "Tarayici kamera sesini engelledi. Tekrar denemek icin hoporl dugmesine tekrar tiklayin.", + "live.fullscreenSubStreamFallback": "{stream}: Tam ekran modunda tam cozunurluklu akis icin bant genisligi yetersiz — alt akisa gecildi.", + "live.tileActions": "Kamera islemleri", + "live.takeSnapshot": "Anlik goruntu al", + "live.openStreamRecordings": "Bu akisin kayitlarini ac", + "live.enterReorderMode": "Kameralari sirala", + "live.pullToRefresh": "Akislari yenilemek icin asagi cekin", + "live.releaseToRefresh": "Akislari yenilemek icin birakin", + "live.refreshingStreams": "Akislar yenileniyor…", + "live.streamsRefreshed": "Akislar yenilendi", + "live.refreshStreamsFailed": "Akislar yenilenemedi: {message}", + "live.tipDoubleTapFullscreen": "İpucu: Bir kareyi tam ekran açmak için çift dokunun.", + "live.dayNightControl": "Gündüz/Gece modu", + "live.dayNightLoading": "Yükleniyor…", + "live.dayNightApplying": "Uygulanıyor…", + "live.dayNightMode_auto": "Otomatik", + "live.dayNightMode_day": "Gündüz", + "live.dayNightMode_night": "Gece", + "live.dayNightMode_unknown": "Bilinmiyor", + "live.dayNightApplied": "Gündüz/Gece modu {mode} olarak ayarlandı", + "live.dayNightApplyFailed": "Gündüz/Gece modu ayarlanamadı", + "live.dayNightLoadFailed": "Gündüz/Gece modu okunamadı", + "live.playbackFallbackUsed": "Yedek: {transport}", + "live.playbackTransportUnavailable": "{transport} bu akış için sunucuda devre dışı bırakılmış.", + "live.recordingMode.constant": "Sürekli kayıt", + "live.recordingMode.detection": "Algılama kaydı", + "live.recordingMode.schedule": "Zamanlanmış kayıt", + "live.recordingMode.none": "Kayıt yok", + "live.health.healthy": "Akış sağlıklı", + "live.health.degraded": "Akış tamponluyor veya toparlanıyor", + "live.health.offline": "Akış kullanılamıyor", + "live.enterPictureInPicture": "Resim içinde resim aç", + "live.exitPictureInPicture": "Resim içinde resmi kapat", + "live.pictureInPictureError": "Resim içinde resim başarısız oldu: {message}", + "live.alwaysFullscreenOnTapEnable": "Tek dokunuşla tam ekranı etkinleştir", + "live.alwaysFullscreenOnTapDisable": "Tek dokunuşta tam ekranı devre dışı bırak", + "live.displayMode": "Görüntüleme modu", + "live.displayModeFit": "Sığdır", + "live.displayModeFill": "Doldur", + "live.displayModeFitDescription": "Sığdır: Tüm kareyi siyah kenarlıklarla göster", + "live.displayModeFillDescription": "Doldur: Kiremiti doldur ve kenarları kırp", + "live.slideshowStartCameras": "Slayt gösterisi başlat: Kameralar arasında geçiş yap", + "live.slideshowStartPages": "Slayt gösterisi başlat: Izgara sayfaları arasında geçiş yap", + "live.slideshowStop": "Slayt gösterisini durdur", + "live.slideshowInterval": "Slayt gösterisi aralığı", + "live.slideshowSeconds": "{seconds} sn", + "live.plan.previewUnavailable": "Kamera önizlemesi kullanılamıyor", + "live.plan.previewAlt": "{name} adlı kameranın mevcut görünümü", + "live.plan.degreesValue": "{value} derece", + "live.plan.inDegrees": "{label} (derece)", + "live.plan.imageDimensionsError": "Görüntü boyutları okunamadı", + "live.plan.loading": "Bina planları yükleniyor…", + "live.plan.created": "{name} oluşturuldu", + "live.plan.renamed": "{name} olarak yeniden adlandırıldı", + "live.plan.deleted": "{name} silindi", + "live.plan.backgroundType": "Arka plan PNG veya JPEG formatında olmalıdır", + "live.plan.backgroundTooLarge": "Arka plan görüntüsü çok büyük; en fazla 768 KB olmalıdır", + "live.plan.backgroundAspect": "Yüklendi, ancak görüntü en-boy oranı geçerli bir tuval boyutuna uymuyor", + "live.plan.backgroundUpdatedSave": "{name} için arka plan güncellendi; tuval boyutunu uygulamak için düzeni kaydedin", + "live.plan.backgroundNotResized": "Arka plan yüklendi, ancak tuval yeniden boyutlandırılmadı: {error}", + "live.plan.backgroundUpdated": "{name} için arka plan güncellendi", + "live.plan.backgroundRemoved": "Arka plan kaldırıldı", + "live.plan.saved": "{name} kaydedildi", + "live.plan.createTitle": "Bina planı oluştur", + "live.plan.createDescription": "Bu bina veya kat için açık bir ad verin. Yerleşimi çizin veya kat planı görseli yükleyin, ardından kameraları yerleştirin.", + "live.plan.nameLabel": "Plan adı", + "live.plan.namePlaceholder": "Ana bina · 1. kat", + "live.plan.createConfirm": "Plan oluştur", + "live.plan.eyebrow": "Bina planı", + "live.plan.placedSummary": "{placed} yerleştirildi · {live} şu an canlı", + "live.plan.zoomAndPan": "Plan yakınlaştırma ve kaydırma", + "live.plan.panLeft": "Sola kaydır", + "live.plan.panUp": "Yukarı kaydır", + "live.plan.panDown": "Aşağı kaydır", + "live.plan.panRight": "Sağa kaydır", + "live.plan.zoomOut": "Uzaklaştır", + "live.plan.zoomIn": "Yakınlaştır", + "live.plan.fitTitle": "Planı sığdır", + "live.plan.fit": "Sığdır", + "live.plan.backgroundMenu": "Arka plan…", + "live.plan.save": "Planı kaydet", + "live.plan.uploadBackgroundTitle": "Plan arka planı olarak bir PNG veya JPEG görseli yükleyin", + "live.plan.replaceBackground": "Arka planı değiştir", + "live.plan.uploadBackground": "Arka plan yükle", + "live.plan.removeBackground": "Arka planı kaldır", + "live.plan.rename": "Yeniden adlandır", + "live.plan.newPlan": "Yeni plan", + "live.plan.editLayout": "Düzeni düzenle", + "live.plan.placementHint": "{name} konumlandırmak için plana tıklayın", + "live.plan.clusterLabel": "{count} kamera; yakınlaştırın", + "live.plan.markerLabel": "{name}; {availability}; {rotation}° yönünde, {fov}° görüş açısı", + "live.plan.cameraFallback": "Kamera", + "live.plan.legendLive": "Canlı", + "live.plan.canvas": "Plan tuvali", + "live.plan.width": "Genişlik", + "live.plan.height": "Yükseklik", + "live.plan.canvasHint": "Arka plan görseli yüklemek tuvali görselle eşleşecek şekilde yeniden boyutlandırır.", + "live.plan.canvasInvalid": "Genişlik 400–4000, yükseklik 300–4000 olmalıdır.", + "live.plan.openLive": "Canlı kamerayı aç", + "live.plan.direction": "Kamera yönü", + "live.plan.fov": "Görüş açısı", + "live.plan.coverageNote": "Kama şekilleri yalnızca yön ve açıyı gösterir; plandaki mesafe kalibre edilmemiştir.", + "live.plan.removeCamera": "Plandan kaldır", + "live.plan.selectCamera": "Bir kamera seçin", + "live.plan.selectHintEditing": "Yerleştirilen işaretçileri sürükleyerek ince ayar yapın. Durumu inceleyin ve istediğinizde canlı görünümü açın.", + "live.plan.selectHint": "Durumu inceleyin ve istediğinizde canlı görünümü açın.", + "live.plan.cameras": "Plan kameraları", + "live.plan.findPlaceholder": "Bu planda ara…", + "live.plan.findLabel": "Bu planda bir kamera bul", + "live.plan.unplaced": "Yerleştirilmemiş kameralar", + "live.plan.unplacedHint": "Bir kamera seçin, ardından plandaki konumuna tıklayın.", + "live.plan.renameTitle": "Planı yeniden adlandır", + "live.plan.renameDescription": "Planlar bu sitedeki tüm operatörlerle paylaşılır.", + "live.plan.deleteTitle": "Planı sil", + "live.plan.deleteMessage": "“{name}” ve yüklenen arka planı silinsin mi? Bu plandaki kamera yerleşimleri kaldırılır; kameraların kendisi etkilenmez.", + "setupWizard.welcomeTitle": "LightNVR'a hoş geldiniz", + "setupWizard.welcomeIntro": "NVR'ınızı birkaç hızlı adımda yapılandıralım. Bu ayarlara daha sonra Ayarlar sayfasından dönebilirsiniz.", + "setupWizard.welcomeStorage": "Depolama yolu ve boyut sınırları", + "setupWizard.welcomePerformance": "Kamera sayınıza göre performans sınırları", + "setupWizard.welcomeSecurity": "Güvenli yönetici girişi", + "setupWizard.storageTitle": "Depolama ve Veritabanı", + "setupWizard.storageIntro": "Kayıtlar ve veritabanı nerede saklanmalı?", + "setupWizard.storagePath": "Kayıt depolama yolu", + "setupWizard.storagePathHint": "Video dosyalarının yazılacağı mutlak yol.", + "setupWizard.maxStorage": "Maksimum depolama boyutu (GB)", + "setupWizard.maxStorageHint": "0 = sınırsız.", + "setupWizard.dbPath": "Veritabanı yolu", + "setupWizard.dbPathHint": "SQLite veritabanı dosyasının konumu.", + "setupWizard.performanceTitle": "Performans", + "setupWizard.performanceIntro": "Bu ayarlar kapasiteyi kontrol eder, video kalitesini değil. Çoğu kullanıcı varsayılan değerleri koruyabilir.", + "setupWizard.threadPool": "Çalışan iş parçacığı havuzu boyutu", + "setupWizard.threadPoolInfo": "arka plan web/sunucu işlerini etkiler. Performans ayarı yapmıyorsanız, önerilen varsayılan değer genellikle en iyisidir.", + "setupWizard.maxStreams": "Maksimum eşzamanlı akış", + "setupWizard.maxStreamsInfo": "bu çalışan örnek için kamera kapasite sınırıdır. Eklemeyi planladığınız kamera sayısından biraz fazla olacak şekilde ayarlayın.", + "setupWizard.important": "Önemli:", + "setupWizard.restartWarning": "bu ayarlardan herhangi birini değiştirirseniz, yeni değer şimdi kaydedilir ancak LightNVR yeniden başlatılana kadar kullanılmaz. Örneğin, mevcut akış sınırı 1 ise ve bunu 32'ye yükseltirseniz, eski sınırın ötesinde daha fazla kamera eklemek için yeniden başlatmanız gerekir.", + "setupWizard.threadPoolHintCores": "Önerilen: {recommended} ({cores} çekirdekli CPU'nuzun 2 katı). Bu, libuv arka plan iş parçacıklarını kontrol eder. Aralık: 2–128.", + "setupWizard.threadPoolHint": "Önerilen: {recommended} (CPU çekirdek sayınızın 2 katı). Bu, libuv arka plan iş parçacıklarını kontrol eder. Aralık: 2–128.", + "setupWizard.maxStreamsHint": "LightNVR'ın aynı anda aktif tutabileceği kamera sayısı. Varsayılan 32, maksimum {max}. 8 kamera bekliyorsanız en az 8 seçin. Etkili olması için yeniden başlatma gerekir.", + "setupWizard.completeTitle": "Kurulum Tamamlandı!", + "setupWizard.saved": "Ayarlarınız başarıyla kaydedildi.", + "setupWizard.notSaved": "Hiçbir ayar değiştirilmedi — varsayılan değerler kullanılacak.", + "setupWizard.restartRequired": "Yeniden başlatma gerekli", + "setupWizard.restartRequiredInfo": "iş parçacığı havuzu boyutu ve/veya maksimum akış değişiklikleri kaydedildi, ancak hizmet yeniden başlatılana kadar etkili olmayacak. Daha fazla kamera eklemeden veya yeni kapasite sınırının uygulanmasını beklemeden önce yeniden başlatın.", + "setupWizard.saveFailed": "Ayarlar kaydedilemedi: {error}", + "setupWizard.back": "Geri", + "setupWizard.saving": "Kaydediliyor…", + "setupWizard.saveContinue": "Kaydet ve Devam Et", + "setupWizard.next": "İleri →", + "setupWizard.finish": "Panele Git", + "setupWizard.skip": "Kurulum sihirbazını atla", + "live.eptzCanvasLabel": "Balıkgözü elektronik kaydırma, eğme ve yakınlaştırma görünümü", + "live.eptzCanvasHint": "Kaydırmak için sürükleyin; yakınlaştırmak için tekerlek veya sıkıştırma kullanın; Home sıfırlar", + "live.eptzReset": "ePTZ görünümünü sıfırla", + "live.autoShort": "Otomatik", + "live.webrtcShort": "WebRTC", + "nav.investigation": "İnceleme", + "availability.label": "Kamera erişilebilirliği", + "availability.live": "Şu an canlı", + "availability.offline": "Çevrimdışı (daha önce bağlıydı)", + "availability.neverConnected": "Hiç bağlanmadı", + "availability.disabled": "Devre dışı", + "availability.all": "Tüm kameralar", + "streams.inventory": "Envanter", + "streams.configuration": "Yapılandırma", + "events.tab": "Olaylar", + "events.eyebrow": "Olay tabanlı entegrasyonlar", + "events.title": "Olaylar ve Yönlendirme", + "events.description": "Kamera ve sistem olaylarını otomasyon, bildirim servisleri ve harici işleme için kalıcı MQTT akışlarına dönüştürün. LightNVR olay arayüzünü sağlar; e-posta ve SMS iletimi alt servislerde kalır.", + "events.routes": "Yönlendirmeler", + "events.destinations": "Hedefler", + "events.catalog": "Olay kataloğu", + "events.enable": "Etkinleştir", + "events.loadError": "Olay yönlendirme yapılandırması yüklenemedi", + "events.accessDenied": "Erişim reddedildi - yetersiz yetki", + "events.summary.routes": "Yönlendirmeler", + "events.summary.enabled": "{count} etkin", + "events.summary.destinations": "Hedefler", + "events.summary.managedActive": "{count} yönetilen ve etkin", + "events.summary.types": "Kayıtlı türler", + "events.summary.registry": "Sürümlü olay kataloğu", + "events.summary.interface": "Arayüz", + "events.summary.interfaceHelp": "Kalıcı olay çıkışı", + "events.route.add": "Yönlendirme ekle", + "events.route.addTitle": "Olay yönlendirmesi oluştur", + "events.route.editTitle": "Olay yönlendirmesini düzenle", + "events.route.create": "Yönlendirme oluştur", + "events.route.editorDescription": "Hangi olayların uygun olduğunu, hangi kameraların kapsama dahil olduğunu, nereye yönlendirileceğini ve gürültülü kaynakların nasıl kontrol edileceğini seçin.", + "events.route.emptyTitle": "Yapılandırılmış olay rotası yok", + "events.route.emptyDescription": "Olay türlerini, kamera kapsamını, zamanlamayı, bastırma politikasını ve MQTT hedefini seçmek için bir rota oluşturun.", + "events.route.enabled": "Rota etkin", + "events.route.enabledHelp": "Eşleşen olaylar kalıcı teslimat için kabul edilir", + "events.route.destination": "Hedef", + "events.route.destinationHelp": "Eşleşen bir olay, her benzersiz hedef için bir kez kalıcı olarak saklanır.", + "events.route.eventTypes": "Olay türleri", + "events.route.eventTypesHelp": "Kayıttan bir veya daha fazla sürümlü olay sözleşmesi seçin.", + "events.route.detectionFilters": "Nesne tespitlerini filtrele", + "events.route.detectionFiltersHelp": "Nesne tespit olayları için isteğe bağlı olarak etiket, bölge veya minimum güven gerektirin.", + "events.route.healthFilters": "Sistem sağlığı olaylarını filtrele", + "events.route.healthFiltersHelp": "İsteğe bağlı olarak kayıtlı sağlık durumu kodlarını veya önem derecelerini eşleştirin. Kullanılabilir değerler bu kaydediciden gelir.", + "events.route.healthConditions": "Sağlık durumları (herhangi biri)", + "events.route.healthSeverities": "Önem dereceleri (herhangi biri)", + "events.route.healthRegistryUnavailable": "Sağlık durumu kaydı kullanılamıyor. Durum filtrelerini yapılandırmadan önce sayfayı yenileyin.", + "events.route.labels": "Etiketler (herhangi biri)", + "events.route.zones": "Bölge kimlikleri (herhangi biri)", + "events.route.listHelp": "Değerleri virgülle ayırın.", + "events.route.minConfidence": "Minimum güven", + "events.route.confidenceHelp": "0 ile 1 arasında bir değer.", + "events.route.cameraScope": "Kamera kapsamı", + "events.route.cameraScopeHelp": "Tüm filosu yüklemeden filo konumlarını, etiketleri, öznitelik koleksiyonlarını veya açık kameraları yeniden kullanın.", + "events.route.allCameras": "Tüm kameralar", + "events.route.dynamicScope": "Dinamik kamera seçici", + "events.route.systemScopeHelp": "Sistem olayları kamera değildir. Bu rota sistem kapsamlı olaylar içerdiğinde kamera seçiciler kullanılamaz.", + "events.route.schedule": "Zamanlama", + "events.route.scheduleHelp": "Olayın gerçekleşme zamanını bir IANA saat diliminde kullanın; gece boyunca pencereler desteklenir.", + "events.route.restrictSchedule": "Yalnızca yapılandırılmış pencerelerde", + "events.route.suppression": "Gürültü ve teslimat politikası", + "events.route.suppressionHelp": "Sıfır bir kontrolü devre dışı bırakır. Bastırma, yalnızca hedef kalıcı olayı kabul ettikten sonra ilerler.", + "events.route.debounce": "Debounce saniye", + "events.route.debounceHelp": "Tekrarlanan gözlemler bu sessiz aralığı uzatır.", + "events.route.cooldown": "Bekleme süresi (saniye)", + "events.route.cooldownHelp": "Kabul edilen bir olaydan sonraki minimum aralık.", + "events.route.grouping": "Gruplama penceresi (saniye)", + "events.route.groupingHelp": "İlk olayı koru ve tekrarları birleştir.", + "events.route.rateLimit": "Dakika başına olay sayısı", + "events.route.rateLimitHelp": "Rota ve kamera başına sabit pencere üst sınırı.", + "events.route.deliveryPolicy": "Teslimat politikası", + "events.route.suppressionActive": "Gürültü kontrolleri etkin", + "events.route.everyMatch": "Her eşleşme", + "events.route.preview": "Rotayı önizle", + "events.route.previewing": "Önizleniyor…", + "events.route.previewResult": "Rota önizlemesi", + "events.route.cameraMatches": "{count} kamera eşleşiyor", + "events.route.previewNoPublish": "Önizleme, kuralın tamamını doğrular ve bir kamera örneği çözümler; hiçbir zaman olay yayınlamaz.", + "events.route.systemPreviewHelp": "Sistem olayları kamera seçimini atlar ve bu nedenle bu önizlemede sıfır eşleşen kamera bildirir.", + "events.route.created": "Olay rotası oluşturuldu", + "events.route.updated": "Olay rotası güncellendi", + "events.route.deleted": "Olay rotası silindi", + "events.route.disabled": "Olay rotası devre dışı bırakıldı", + "events.route.enabledMessage": "Olay rotası etkinleştirildi", + "events.route.deleteConfirm": "{name} olay rotası silinsin mi?", + "events.route.validation.name": "Bir rota adı girin.", + "events.route.validation.destination": "Bir hedef seçin.", + "events.route.validation.event_types": "En az bir olay türü seçin.", + "events.route.validation.selector": "Kamera seçiciyi tamamlayın veya düzeltin.", + "events.route.validation.system_scope": "Kamera seçiciler, sistem kapsamlı olaylarla kullanılamaz.", + "events.route.validation.detection_type": "Algılama filtreleri, nesne algılama olay türünü gerektirir.", + "events.route.validation.detection_filter": "En az bir algılama etiketi, bölge veya güven eşiği ekleyin.", + "events.route.validation.confidence": "Minimum güven değeri 0 ile 1 arasında olmalıdır.", + "events.route.validation.predicate_mix": "Algılama ve sağlık filtreleri tek bir rotada birleştirilemez.", + "events.route.validation.health_type": "Sağlık filtreleri yalnızca kayıtlı sistem sağlığı olay türlerini gerektirir.", + "events.route.validation.health_filter": "En az bir kayıtlı sağlık durumu veya önem derecesi seçin.", + "events.route.validation.health_condition": "Sadece kaydedicinin sağlık kayıt defterinin döndürdüğü durum kodlarını seçin.", + "events.route.validation.health_severity": "Sadece seçili sağlık olayı türlerinin desteklediği önem düzeylerini seçin.", + "events.route.validation.timezone": "UTC veya America/New_York gibi yüklü bir IANA saat dilimi girin.", + "events.route.validation.schedule_window": "Her zaman aralığı en az bir gün ve farklı geçerli başlangıç ve bitiş saatleri gerektirir.", + "events.route.validation.suppression": "Bastırma değerleri, izin verilen aralıklar içinde tam sayı olmalıdır.", + "events.schedule.timezone": "Saat Dilimi", + "events.schedule.timezoneHelp": "Kaydedicinin saat dilimi veritabanında bulunmalıdır.", + "events.schedule.addWindow": "Zaman aralığı ekle", + "events.schedule.windowNumber": "Aralık {number}", + "events.schedule.start": "Başlangıç", + "events.schedule.end": "Bitiş", + "events.schedule.sunday": "Paz", + "events.schedule.monday": "Pzt", + "events.schedule.tuesday": "Sal", + "events.schedule.wednesday": "Çar", + "events.schedule.thursday": "Per", + "events.schedule.friday": "Cum", + "events.schedule.saturday": "Cmt", + "events.destination.add": "Hedef ekle", + "events.destination.addTitle": "MQTT hedefi ekle", + "events.destination.editTitle": "MQTT hedefini düzenle", + "events.destination.create": "Hedef oluştur", + "events.destination.editorDescription": "Kalıcı bir olay çıkışı yapılandırın. Kimlik bilgileri yalnızca yazılabilir kalır ve API tarafından asla döndürülmez.", + "events.destination.default": "Varsayılan MQTT ayarları", + "events.destination.settingsManaged": "Ayarlar yönetiliyor", + "events.destination.defaultDescription": "Mevcut MQTT yapılandırması mqtt:default olarak kullanılabilir durumda kalmaya devam eder ve {count} yönlendirme tarafından kullanılır.", + "events.destination.openSettings": "MQTT ayarlarını aç", + "events.destination.emptyTitle": "Yönetilen hedef yok", + "events.destination.emptyDescription": "Bulut bağlayıcı, otomasyon sistemi veya bildirim servisine bağımsız olay iletimi için başka bir MQTT aracı sunucusu ekleyin.", + "events.destination.identity": "Hedef kimliği", + "events.destination.enabled": "Hedef etkin", + "events.destination.enabledHelp": "Kalıcı kuyruğuna bağlan ve boşalt", + "events.destination.active": "Aktif", + "events.destination.paused": "Duraklatıldı", + "events.destination.pause": "Duraklat", + "events.destination.broker": "Broker", + "events.destination.host": "Broker sunucusu", + "events.destination.hostHelp": "Yalnızca ana bilgisayar adı veya IP adresi girin; URL şeması eklemeyin.", + "events.destination.port": "Port", + "events.destination.clientId": "İstemci Kimliği", + "events.destination.clientIdHelp": "Bu broker bağlantısı için benzersiz olmalıdır.", + "events.destination.topic": "Konu", + "events.destination.topicTemplate": "Konu şablonu", + "events.destination.topicHelp": "Olay türü ve özne kimliği belirteçlerini içermelidir; MQTT joker karakterlerine izin verilmez.", + "events.destination.keepalive": "Keepalive süresi (saniye)", + "events.destination.statusTopicTemplate": "Varlık durumu konusu", + "events.destination.statusTopicHelp": "İsteğe bağlı. {installation_uuid} içermelidir; {destination_uuid} da kullanılabilir. MQTT joker karakterlerine izin verilmez.", + "events.destination.statusTopicEnabled": "Varlık bu hedef için açıkça etkinleştirildi. Konu, olay konusundan asla çıkarılmaz.", + "events.destination.statusTopicDisabled": "Varlık bu hedef için devre dışı bırakıldı. Devre dışı bırakmak için bu alanı boş bırakın.", + "events.destination.qos": "Hizmet kalitesi", + "events.destination.qos0": "bir kez gönder", + "events.destination.qos1": "en az bir kez", + "events.destination.qos2": "tam olarak bir kez", + "events.destination.authentication": "Kimlik doğrulama", + "events.destination.passwordPreserved": "Kaydedilen salt yazılabilir parolayı korumak için boş bırakın.", + "events.destination.passwordOptional": "Broker anonim istemcilere izin verdiğinde isteğe bağlıdır.", + "events.destination.clearPassword": "Kaydedilen parolayı temizle", + "events.destination.transportSecurity": "Aktarım güvenliği", + "events.destination.tlsMode": "TLS modu", + "events.destination.tlsSystem": "Sistem güven deposu", + "events.destination.tlsCustomCa": "Özel sertifika yetkilisi", + "events.destination.tlsMutual": "Karşılıklı TLS", + "events.destination.tlsDisabled": "Devre dışı (düz metin)", + "events.destination.tlsHelp.system": "Broker sertifikasını işletim sistemi güven deposuna karşı doğrulayın.", + "events.destination.tlsHelp.custom_ca": "Broker'ı açık bir PEM sertifika yetkilisi dosyasına karşı doğrula.", + "events.destination.tlsHelp.mutual": "Broker'ı açık bir CA ile doğrula ve bir istemci sertifikası ve anahtarı sun.", + "events.destination.tlsHelp.disabled": "Taşıma şifrelemesi veya broker kimlik doğrulaması yok.", + "events.destination.caFile": "CA dosyası", + "events.destination.certFile": "İstemci sertifika dosyası", + "events.destination.keyFile": "İstemci anahtar dosyası", + "events.destination.absolutePathHelp": "LightNVR hizmeti tarafından okunabilen mutlak bir yol kullanın.", + "events.destination.plaintextWarning": "Düz metin MQTT, olay üst verilerini ve kimlik bilgilerini ifşa edebilir. Yalnızca güvenilir, izole bir ağda kullanın.", + "events.destination.security": "Güvenlik", + "events.destination.tls.system": "Sistem güveni", + "events.destination.tls.custom_ca": "Özel CA", + "events.destination.tls.mutual": "Karşılıklı TLS", + "events.destination.tls.disabled": "Düz metin", + "events.destination.routes": "Yönlendirmeler", + "events.destination.presence": "Varlık konusu", + "events.destination.deleteInUse": "Bu hedefi silmeden önce yönlendirmeleri kaldırın veya yeniden yönlendirin.", + "events.destination.created": "MQTT hedefi oluşturuldu", + "events.destination.updated": "MQTT hedefi güncellendi", + "events.destination.deleted": "MQTT hedefi silindi", + "events.destination.pausedMessage": "MQTT hedefi duraklatıldı; kuyruğa alınan olaylar süresi dolana kadar kalıcı olarak saklanır.", + "events.destination.enabledMessage": "MQTT hedefi etkinleştirildi", + "events.destination.deleteConfirm": "\"{name}\" MQTT hedefi silinsin mi?", + "events.destination.validation.name": "Bir hedef adı girin.", + "events.destination.validation.host": "Bir broker ana bilgisayar adı veya IP adresi girin.", + "events.destination.validation.client_id": "Bir broker istemci kimliği girin.", + "events.destination.validation.topic": "Konu, olay türü ve özne kimliği belirteçlerini içermeli ve MQTT joker karakterleri içermemelidir.", + "events.destination.validation.status_topic": "İsteğe bağlı varlık konusu, kurulum UUID belirtecini içermeli, yalnızca desteklenen belirteçleri kullanmalı ve MQTT joker karakterleri içermemelidir.", + "events.destination.validation.port": "Port, 1 ile 65535 arasında bir tam sayı olmalıdır.", + "events.destination.validation.keepalive": "Keepalive, 5 ile 3600 saniye arasında bir tam sayı olmalıdır.", + "events.destination.validation.qos": "MQTT QoS 0, 1 veya 2 seçin.", + "events.destination.validation.username": "Yapılandırılmış bir parola, bir kullanıcı adı gerektirir.", + "events.destination.validation.ca_file": "Bu TLS modu, mutlak bir CA dosya yolu gerektirir.", + "events.destination.validation.mutual_files": "Karşılıklı TLS, mutlak CA, istemci sertifikası ve istemci anahtarı yolları gerektirir.", + "fleet.eyebrow": "Kamera İşlemleri", + "fleet.title": "Kamera Envanteri", + "fleet.description": "Büyük dağıtımlarda tüm envanteri tarayıcıya yüklemeden kameraları bulun, değerlendirin ve düzenleyin.", + "fleet.summary": "Filo sağlık özeti", + "fleet.totalCameras": "Eşleşen kameralar", + "fleet.needsAttention": "Kısıtlı", + "fleet.searchLabel": "Kamera ara", + "fleet.searchPlaceholder": "Ad, adres, konum, etiket, üretici veya model ara…", + "fleet.resultCount": "{count} kamera", + "fleet.filters": "Filtreler", + "fleet.clearFilters": "Filtreleri temizle", + "fleet.filter.health": "Sağlık", + "fleet.filter.enabled": "Kamera durumu", + "fleet.filter.anyState": "Herhangi bir durum", + "fleet.filter.recording": "Kayıt modu", + "fleet.filter.location": "Konum alt ağacı", + "fleet.filter.allLocations": "Tüm konumlar", + "fleet.filter.tags": "Etiketler (herhangi bir eşleşme)", + "fleet.filter.collection": "Kamera koleksiyonu", + "fleet.health.unknown": "Bilinmiyor", + "fleet.health.up": "Çevrimiçi", + "fleet.health.degraded": "Kısıtlı", + "fleet.health.down": "Çevrimdışı", + "fleet.health.disabled": "Devre dışı", + "fleet.recording.off": "Kapalı", + "fleet.recording.continuous": "Sürekli", + "fleet.recording.detection": "Algılama", + "fleet.recordingActive": "Şu anda kaydediliyor", + "fleet.recordingInactive": "Kayıt yok", + "fleet.column.camera": "Kamera", + "fleet.column.health": "Sağlık", + "fleet.column.location": "Konum", + "fleet.column.tags": "Etiketler", + "fleet.column.recording": "Kayıt", + "fleet.viewLive": "Canlı", + "fleet.lastFrame": "Son kare", + "fleet.noAddress": "Adres kullanılamıyor", + "fleet.unassigned": "Atanmamış", + "fleet.loading": "Kamera filosu yükleniyor…", + "fleet.refreshing": "Yenileniyor…", + "fleet.loadError": "Kamera filosu yüklenemedi", + "fleet.emptyTitle": "Hiç kamera yapılandırılmamış", + "fleet.emptyDescription": "Filo çalışma alanında kullanılabilir olması için bir akış ekleyin.", + "fleet.emptyFilteredTitle": "Bu görünüme uyan kamera yok", + "fleet.emptyFilteredDescription": "Aramayı genişletmeyi veya bir veya daha fazla filtreyi temizlemeyi deneyin.", + "fleet.paginationSummary": "{total} sonuçtan {first}–{last} arası gösteriliyor", + "fleet.perPage": "Sayfa başına", + "fleet.pageOf": "{pages} sayfadan {page}.", + "fleet.selectPage": "Bu sayfadaki tüm kameraları seç", + "fleet.selectCamera": "{name} seç", + "fleet.selectedCount": "{count} kamera seçildi", + "fleet.organizeSelected": "Seçilenleri düzenle", + "fleet.clearSelection": "Seçimi temizle", + "fleet.organization.manage": "Organizasyonu yönet", + "fleet.organization.title": "Kamera organizasyonu", + "fleet.organization.description": "Kamera filosu için yeniden kullanılabilir bir konum hiyerarşisi ve normalize edilmiş bir etiket sözlüğü oluşturun.", + "fleet.organization.locations": "Konumlar", + "fleet.organization.tags": "Etiketler", + "fleet.organization.locationsDescription": "Siteleri, binaları, katları ve operasyonel alanları gezilebilir bir hiyerarşi olarak modelleyin.", + "fleet.organization.tagsDescription": "Tutarlı olmayan serbest biçimli etiketler yerine yönetilen bir etiket sözlüğü kullanın.", + "fleet.organization.addRoot": "Üst düzey konum ekle", + "fleet.organization.addLocation": "Konum ekle", + "fleet.organization.editLocation": "Konumu düzenle", + "fleet.organization.addChild": "Alt öğe ekle", + "fleet.organization.type": "Tür", + "fleet.organization.parent": "Üst konum", + "fleet.organization.topLevel": "Üst seviye", + "fleet.organization.sortOrder": "Sıralama", + "fleet.organization.contents": "İçerikler", + "fleet.organization.cameras": "Kameralar", + "fleet.organization.system": "Sistem", + "fleet.organization.contentCounts": "{cameras} kamera · {children} alt öğe", + "fleet.organization.locationNotEmpty": "Önce kameraları taşıyın ve alt konumları silin", + "fleet.organization.noLocations": "Hiç konum yapılandırılmamış.", + "fleet.organization.locationCreated": "Konum oluşturuldu", + "fleet.organization.locationUpdated": "Konum güncellendi", + "fleet.organization.locationDeleted": "Konum silindi", + "fleet.organization.deleteLocationConfirm": "“{name}” konumunu silmek istiyor musunuz?", + "fleet.organization.addTag": "Etiket ekle", + "fleet.organization.editTag": "Etiketi düzenle", + "fleet.organization.tagLabel": "Etiket", + "fleet.organization.color": "Renk (#RRGGBB)", + "fleet.organization.tagDescription": "Açıklama", + "fleet.organization.noTags": "Hiç normalize edilmiş etiket yapılandırılmamış.", + "fleet.organization.tagCreated": "Etiket oluşturuldu", + "fleet.organization.tagUpdated": "Etiket güncellendi", + "fleet.organization.tagDeleted": "Etiket silindi", + "fleet.organization.deleteTagConfirm": "“{name}” silinsin mi? Şu anda {count} kameraya atanmış.", + "fleet.organization.merge": "Birleştir", + "fleet.organization.mergeTagNamed": "“{name}” birleştir", + "fleet.organization.mergeInto": "Birleştirilecek etiket", + "fleet.organization.chooseTag": "Korunacak etiketi seçin", + "fleet.organization.mergeWarning": "Tüm kamera atamaları korunan etikete taşınır; kaynak etiket ardından kaldırılır.", + "fleet.organization.tagsMerged": "Etiketler birleştirildi", + "fleet.organization.saveError": "Kaydedilemedi: {message}", + "fleet.organization.deleteError": "Silinemedi: {message}", + "fleet.locationType.site": "Site", + "fleet.locationType.building": "Bina", + "fleet.locationType.floor": "Kat", + "fleet.locationType.area": "Alan", + "fleet.locationType.zone": "Bölge", + "fleet.locationType.system": "Sistem", + "fleet.bulk.title": "Seçili kameraları düzenle", + "fleet.bulk.description": "Konum ve etiket değişikliklerini {count} kameraya sınırlı eşzamanlılıkla uygulayın.", + "fleet.bulk.location": "Konum ataması", + "fleet.bulk.locationHelp": "Seçilen tüm kameralar seçilen konuma taşınacak.", + "fleet.bulk.keepLocations": "Mevcut konumları koru", + "fleet.bulk.tags": "Etiket ataması", + "fleet.bulk.tagsHelp": "Diğer atamaları bozmadan etiket ekleyin veya kaldırın ya da tüm etiket setini açıkça değiştirin.", + "fleet.bulk.tagOperation.none": "Koru", + "fleet.bulk.tagOperation.add": "Ekle", + "fleet.bulk.tagOperation.remove": "Kaldır", + "fleet.bulk.tagOperation.replace": "Tümünü değiştir", + "fleet.bulk.replaceWarning": "Tümünü değiştir, bu seçimi uygulamadan önce mevcut tüm etiketleri kaldırır. Boş seçim tüm etiketleri temizler.", + "fleet.bulk.apply": "Değişiklikleri uygula", + "fleet.bulk.working": "Değişiklikler uygulanıyor…", + "fleet.bulk.success": "{count} kamera güncellendi", + "fleet.bulk.partial": "{succeeded} kamera güncellendi; {failed} başarısız", + "fleet.bulk.error": "Kameralar düzenlenemedi: {message}", + "fleet.bulk.failures": "Güncellenemeyen kameralar", + "fleet.queues.degraded": "Düşük kaliteli akışlar", + "fleet.queues.offline": "Çevrimdışı kameralar", + "fleet.queues.oldest": "En eski: {time}", + "fleet.queues.noneActive": "Aktif koşul yok", + "fleet.views.title": "Kaydedilmiş görünümler", + "fleet.views.choose": "Kaydedilmiş bir görünüm seçin", + "fleet.views.none": "Henüz kaydedilmiş görünüm yok", + "fleet.views.shared": "Paylaşılan", + "fleet.views.saveCurrent": "Mevcut görünümü kaydet", + "fleet.views.name": "Görünüm adı", + "fleet.views.share": "Tüm operatörlerle paylaş", + "fleet.views.saved": "Filo görünümü kaydedildi", + "fleet.views.saveError": "Görünüm kaydedilemedi: {message}", + "fleet.views.deleted": "Filo görünümü silindi", + "fleet.views.deleteConfirm": "Kaydedilen \"{name}\" görünümü silinsin mi?", + "fleet.views.deleteError": "Görünüm silinemedi: {message}", + "fleet.views.unsupported": "Bu kaydedilmiş seçici, mevcut filtre kontrolleriyle temsil edilemiyor.", + "collections.manage": "Koleksiyonlar", + "collections.all": "Tüm koleksiyonlar", + "collections.filter": "Koleksiyon", + "collections.loadMembersError": "Koleksiyon kameraları yüklenemedi: {message}", + "collections.title": "Kamera koleksiyonları", + "collections.subtitle": "Operasyonlar, kaydedilmiş görünümler ve sonraki iş akışları için yeniden kullanılabilir kamera grupları oluşturun.", + "collections.listDescription": "Statik koleksiyonlar açık üyeliği korur; akıllı koleksiyonlar filo kurallarını sürekli değerlendirir.", + "collections.create": "Koleksiyon oluştur", + "collections.edit": "Koleksiyonu düzenle", + "collections.editorDescription": "Koleksiyon tanımları sabit kamera, konum ve etiket UUID'lerini kullanır.", + "collections.backToList": "Koleksiyonlara dön", + "collections.type": "Koleksiyon türü", + "collections.type.static": "Statik", + "collections.type.smart": "Akıllı", + "collections.description": "Açıklama", + "collections.shared": "Paylaşılan koleksiyon", + "collections.sharedHelp": "Diğer yetkili kullanıcıların bu koleksiyonu görmesine izin verin; kamera erişim kuralları geçerlidir.", + "collections.typeChangeWarning": "Koleksiyon türünü değiştirmek üyelik modelini değiştirir. Önceki türden statik üyeler veya akıllı kurallar artık geçerli olmayacaktır.", + "collections.selectorError": "Seçici geçerli değil: {message}", + "collections.created": "Koleksiyon oluşturuldu", + "collections.updated": "Koleksiyon güncellendi", + "collections.saveError": "Koleksiyon kaydedilemedi: {message}", + "collections.loadError": "Koleksiyon yüklenemedi: {message}", + "collections.cameras": "kameralar", + "collections.visibility.shared": "Paylaşılan", + "collections.visibility.private": "Özel", + "collections.selectorRedacted": "Kurallar özel", + "collections.emptyTitle": "Henüz koleksiyon yok", + "collections.emptyAdmin": "Kamera seçimlerini yeniden kullanmak için statik bir grup veya akıllı kural tabanlı bir görünüm oluşturun.", + "collections.emptyViewer": "Kamera kapsamınız için paylaşılan koleksiyon bulunmuyor.", + "collections.deleteConfirm": "{name} koleksiyonu silinsin mi?", + "collections.deleted": "Koleksiyon silindi", + "collections.deleteError": "Koleksiyon silinemedi: {message}", + "collections.preview.title": "Kural önizlemesi", + "collections.preview.matches": "{count} eşleşen kamera", + "collections.preview.action": "Önizleme", + "collections.preview.hide": "Önizlemeyi gizle", + "collections.preview.loading": "Değerlendiriliyor…", + "collections.preview.empty": "Şu anda eşleşen kamera yok.", + "collections.preview.sample": "{total} eşleşme arasından {count} kamera örneği gösteriliyor.", + "collections.preview.error": "Koleksiyon önizlenemedi: {message}", + "collections.members.title": "Statik üyeler", + "collections.members.selected": "Tüm sayfalarda {count} kamera seçildi", + "collections.members.search": "Kamera ara…", + "collections.members.selectPage": "Bu sayfayı seç", + "collections.members.empty": "Bu aramaya uygun kamera yok.", + "collections.builder.title": "Akıllı kurallar", + "collections.builder.description": "Kurallar, mevcut kamera organizasyonu, yapılandırması, yetenekleri ve durumu üzerinden değerlendirilir.", + "collections.builder.match": "Eşleşme", + "collections.builder.allRules": "tüm kurallar", + "collections.builder.anyRule": "herhangi bir kural", + "collections.builder.addRule": "Kural ekle", + "collections.builder.removeRule": "Kuralı kaldır", + "collections.builder.matchesAll": "Tamamlanmış kural olmadığında, bu koleksiyon kullanıcının yetkili kapsamındaki tüm kameralarla eşleşir.", + "collections.builder.incompleteRule": "Kaydetmeden önce tüm kuralları tamamlayın veya kaldırın.", + "collections.builder.chooseLocation": "Bir konum alt ağacı seçin", + "collections.builder.vendorPlaceholder": "Üretici adları, virgülle ayrılmış", + "collections.builder.modelPlaceholder": "Model adları, virgülle ayrılmış", + "collections.builder.advancedMode": "Gelişmiş JSON", + "collections.builder.visualMode": "Görsel oluşturucu", + "collections.builder.cannotVisualize": "Bu seçici, görsel oluşturucunun güvenli bir şekilde temsil edemeyeceği iç içe geçmiş veya gelişmiş mantık içeriyor.", + "collections.rule.location_subtree": "Konum şu aralıkta", + "collections.rule.camera_uuid": "Belirli kameralar", + "collections.rule.tag_any": "Herhangi bir etikete sahip", + "collections.rule.tag_all": "Tüm etiketlere sahip", + "collections.rule.tag_none": "Hiçbir etikete sahip değil", + "collections.rule.health": "Sağlık durumu", + "collections.rule.enabled": "Kamera durumu", + "collections.rule.recording_mode": "Kayıt modu", + "collections.rule.capability_any": "Herhangi bir yeteneğe sahip", + "collections.rule.capability_all": "Tüm yeteneklere sahip", + "collections.rule.vendor": "Üretici", + "collections.rule.model": "Model", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Ses geri kanalı", + "streamHealth.observedFps": "Gözlemlenen FPS", + "streamHealth.expectedFps": "Beklenen", + "streamHealth.fpsHelp": "LightNVR tarafından gözlemlenir; beklenen değer kamera akışı üst verisinden gelir.", + "login.passwordChanged": "Parola başarıyla değiştirildi. Yeni parolanızla giriş yapın.", + "passwordChangeRequired.title": "Varsayılan parolayı değiştirin", + "passwordChangeRequired.description": "Bu kurulum hâlâ varsayılan yönetici parolasını kullanıyor. LightNVR'a devam etmeden önce değiştirin. MFA etkinleştirildiğinde, bir sonraki girişinizde kontrol edilir.", + "passwordChangeRequired.currentPassword": "Mevcut parola", + "passwordChangeRequired.newPassword": "Yeni parola", + "passwordChangeRequired.confirmPassword": "Yeni parolayı onaylayın", + "passwordChangeRequired.passwordHelp": "En az 8 karakter kullanın. Parola admin olamaz.", + "passwordChangeRequired.submit": "Parola Değiştir", + "passwordChangeRequired.saving": "Parola değiştiriliyor...", + "passwordChangeRequired.error.currentRequired": "Mevcut parolanızı girin.", + "passwordChangeRequired.error.tooShort": "Yeni parola en az 8 karakter olmalıdır.", + "passwordChangeRequired.error.defaultPassword": "Yeni parola admin olamaz.", + "passwordChangeRequired.error.mismatch": "Yeni parolalar eşleşmiyor.", + "passwordChangeRequired.error.generic": "Parola değiştirilemedi. Tekrar deneyin.", + "settings.tab.health": "Sağlık", + "settings.tab.workspaces": "Çalışma Alanları", + "settings.health.title": "Sunucu ve donanım sağlığı", + "settings.health.description": "Cihaz yollarını veya gizli bilgileri ifşa etmeden sınırlı işletim sistemi ve donanım izlemeyi yapılandırın.", + "settings.health.enabled": "Sağlık izlemeyi etkinleştir", + "settings.health.enabledHelp": "Desteklenen sunucu, servis, depolama, ağ ve donanım sinyallerini toplayın.", + "settings.health.profile": "Politika profili", + "settings.health.profileHelp": "Dengeli normal varsayılandır; muhafazakâr, uyarı vermeden önce daha güçlü kanıt gerektirir.", + "settings.health.profile.balanced": "Dengeli", + "settings.health.profile.conservative": "Muhafazakâr", + "settings.health.hardwareProvider": "Donanım sağlayıcısı", + "settings.health.provider.auto": "Otomatik (çekirdek sağlayıcıları)", + "settings.health.provider.smartctl": "smartctl (açık)", + "settings.health.providerHelp.auto": "Yalnızca sınırlı sysfs, NVMe ve çekirdek sağlayıcılarını kullanır; smartctl asla çıkarılmaz.", + "settings.health.providerHelp.smartctl": "Keşfedilen cihazlar için isteğe bağlı sınırlı smartctl JSON sağlayıcısını açıkça etkinleştirir.", + "settings.health.providerHelp.disabled": "Taşınabilir sağlık izlemeyi kullanılabilir bırakarak isteğe bağlı donanım sağlayıcılarını devre dışı bırakır.", + "settings.health.writeProbe": "Depolama yazma kontrolünü etkinleştir", + "settings.health.writeProbeHelp": "Yapılandırılmış sınırlı kayıt hedefi kontrolünü periyodik olarak gerçekleştirir.", + "settings.health.cadences": "Örnekleme aralıkları", + "settings.health.cadencesHelp": "Aralıklar, hızlıdan cihaz örnekleme sırasına göre düzenli kalmalı ve sunucu sınırları içinde olmalıdır.", + "settings.health.fastInterval": "Hızlı aralık", + "settings.health.normalInterval": "Normal aralık", + "settings.health.slowInterval": "Yavaş aralık", + "settings.health.deviceInterval": "Cihaz aralığı", + "settings.health.presenceInterval": "Varlık aralığı", + "settings.health.retention": "Olay saklama", + "settings.health.conditions": "Koşul geçersiz kılmaları", + "settings.health.conditionsHelp": "Yalnızca etkin ilke kayıt defterinin döndürdüğü koşul kodlarını ve birimlerini geçersiz kılın.", + "settings.health.conditionOverride": "koşul geçersiz kılma", + "settings.health.overrideMode": "Geçersiz kılma modu", + "settings.health.overrideModeHelp": "Seçilen profili devralın, başka bir sınırlı profil seçin, koşulu devre dışı bırakın veya doğrulanmış eşikler belirleyin.", + "settings.health.profileDefault": "Seçilen profili kullan", + "settings.health.custom": "Özel eşikler", + "settings.health.warning": "Uyarı eşiği", + "settings.health.critical": "Kritik eşik", + "settings.health.recovery": "Kurtarma eşiği", + "settings.health.warning_for_seconds": "Uyarı bekleme süresi (sn)", + "settings.health.critical_for_seconds": "Kritik bekleme süresi (sn)", + "settings.health.recovery_for_seconds": "Kurtarma bekleme süresi (sn)", + "settings.health.clearOverrides": "Geçersiz kılmaları temizle", + "settings.health.registryUnavailable": "Sunucu bir koşul kayıt defteri döndürmedi. Geçersiz kılmaları düzenlemeden önce yeniden yükleyin.", + "settings.health.resetDefaults": "Sağlık varsayılanlarını sıfırla", + "settings.health.reloadGuidance": "Kaydetme atomiktir. Etkin ilkeyi onaylamak için başarılı bir kaydetme sonrası yeniden yükleyin; yalnızca sunucu açıkça istediğinde yeniden başlatın.", + "settings.health.validation.profile": "Desteklenen bir sağlık profili seçin.", + "settings.health.validation.provider": "Desteklenen bir donanım sağlayıcısı seçin.", + "settings.health.validation.healthFastIntervalSeconds": "Hızlı aralık 5 ile 60 saniye arasında tam sayı olmalıdır.", + "settings.health.validation.healthNormalIntervalSeconds": "Normal aralık 15 ile 600 saniye arasında tam sayı olmalıdır.", + "settings.health.validation.healthSlowIntervalSeconds": "Yavaş aralık 60 ile 3600 saniye arasında tam sayı olmalıdır.", + "settings.health.validation.healthDeviceIntervalSeconds": "Cihaz aralığı 300 ile 86400 saniye arasında tam sayı olmalıdır.", + "settings.health.validation.healthPresenceIntervalSeconds": "Varlık aralığı 15 ile 3600 saniye arasında tam sayı olmalıdır.", + "settings.health.validation.healthIncidentRetentionDays": "Olay saklama süresi 7 ile 3650 gün arasında tam sayı olmalıdır.", + "settings.health.validation.ordered": "Örnekleme aralıkları hızlı, normal, yavaş ve cihaz sırasıyla düzenlenmelidir.", + "settings.health.validation.overrides": "Koşul geçersiz kılmaları, sunucu kayıt defterindeki benzersiz kodları ve desteklenen profilleri kullanmalıdır.", + "settings.health.validation.thresholds": "Özel eşikler, koşulun birim sınırları içinde sonlu değerler olmalıdır.", + "settings.health.validation.thresholdOrder": "Uyarı, kritik ve kurtarma eşikleri, koşulun uyarı yönünü ve histerezisini korumalıdır.", + "settings.health.validation.dwell": "Bekleme süreleri yedi gün içinde tam saniye olmalıdır; uyarı ve kurtarma bekleme süresi sıfır olamaz.", + "workspaces.title": "Operatör çalışma alanları", + "workspaces.description": "Navigasyon ve sayfa arayüzünde hangi uzmanlaşmış çalışma alanlarının görüneceğini seçin.", + "workspaces.saved": "Çalışma alanı tercihleri kaydedildi", + "workspaces.saveError": "Çalışma alanı tercihleri kaydedilemedi: {message}", + "workspaces.loadError": "Çalışma alanı tercihleri yüklenemedi.", + "workspaces.showWorkspace": "{name} göster", + "workspaces.authorizationNote": "Bu yalnızca sunumu kontrol eder. Doğrudan URL'ler ve API erişimi yetkilendirme politikanıza tabi olmaya devam eder.", + "workspaces.liveNavigator": "Gelişmiş Canlı Navigatör", + "workspaces.liveNavigatorDescription": "Konum ağacı, kullanılabilirlik filtreleri, kaydedilmiş düzenler ve son olaylar.", + "workspaces.investigation": "Araştırma", + "workspaces.investigationDescription": "Kaydedilmiş kanıtları arayın, ilişkilendirin, koruyun ve dışa aktarın.", + "settings.reduceMotion": "Hareketi azalt", + "settings.reduceMotionHelp": "Zorunlu olmayan animasyonları ve geçişleri devre dışı bırakır. Otomatik, işletim sistemi tercihinizi takip eder.", + "settings.reduceMotionPreference": "Hareket azaltma tercihi", + "settings.reduceMotionAuto": "Otomatik", + "settings.reduceMotionOn": "Açık", + "settings.reduceMotionOff": "Kapalı", + "settings.audioCompliance": "Ses Uyumu", + "settings.disableAudioGlobally": "Bu örnek genelinde sesi devre dışı bırak", + "settings.audioDisabled": "Ses genel olarak devre dışı bırakıldı", + "settings.audioComplianceHelp": "Bu örnek genelinde canlı dinlemeyi, iki yönlü konuşmayı ve yeni kayıtlardaki sesi engeller. Kaydetme, etkin go2rtc medya oturumlarını yeniden başlatır. Mevcut kayıtlar değiştirilmez.", + "tokens.manage": "API erişimini yönet", + "tokens.title": "API Erişimi — {username}", + "tokens.description": "Entegrasyonlar için dar kapsamlı kimlik bilgileri oluşturun ve her birini bağımsız olarak iptal edin.", + "tokens.recommendedTitle": "Kapsamlı token'lar önerilir", + "tokens.recommendedDescription": "Her token süresi dolar, açık eylemlere ve kamera kapsamına sahiptir ve kullanıcının mevcut erişim politikasını aşamaz.", + "tokens.coverageNotice": "Kullanılabilir izinler, bu sunucunun uyguladığı kuralları yansıtır. Bir token yalnızca kullanıcısının zaten sahip olduğu izinleri kullanabilir.", + "tokens.createTitle": "Kapsamlı token oluştur", + "tokens.createDescription": "Her entegrasyon için bir token kullanın; böylece başka hiçbir şeyi aksatmadan tanımlanabilir, döndürülebilir ve iptal edilebilir.", + "tokens.name": "Entegrasyon adı", + "tokens.namePlaceholder": "örn. Kuzey garaj PTZ köprüsü", + "tokens.expiry": "Süre dolumu", + "tokens.expiryDays": "{days} gün", + "tokens.actions": "İzin Verilen İşlemler", + "tokens.actionsHelp": "Bu entegrasyonun yalnızca ihtiyaç duyduklarını seçin. Yıkıcı işlemler kendi token'ını hak eder.", + "tokens.destructive": "Yıkıcı", + "tokens.noEnforcedActions": "Bu sunucu sürümünde token ile kullanılabilen işlem bulunmuyor.", + "tokens.scope.label": "Kamera Kapsamı", + "tokens.scope.all": "Tüm Kamera Filosu", + "tokens.scope.collection": "Paylaşılan Koleksiyon", + "tokens.scope.selector": "Özel Seçici", + "tokens.scope.chooseCollection": "Paylaşılan Kamera Koleksiyonu", + "tokens.scope.allValue": "Tüm Filo", + "tokens.scope.collectionValue": "Koleksiyon: {name}", + "tokens.scope.selectorValue": "Özel Dinamik Seçici", + "tokens.create": "Token Oluştur", + "tokens.creating": "Token oluşturuluyor…", + "tokens.createdSuccess": "Kapsamlı API token oluşturuldu", + "tokens.createError": "API token oluşturulamadı: {message}", + "tokens.invalidResponse": "Sunucu eksik bir kimlik bilgisi yanıtı döndürdü.", + "tokens.existingTitle": "Mevcut Token'lar", + "tokens.existingDescription": "Oluşturma sonrası yalnızca önekler ve meta veriler erişilebilir kalır.", + "tokens.emptyTitle": "Aktif token yok", + "tokens.emptyDescription": "API erişimine ihtiyaç duyan ilk entegrasyon için kapsamlı bir token oluşturun.", + "tokens.showInactive": "{count} pasif göster", + "tokens.status.active": "Aktif", + "tokens.status.expired": "Süresi Dolmuş", + "tokens.status.revoked": "İptal Edilmiş", + "tokens.expires": "Bitiş Tarihi", + "tokens.expiresValue": "Bitiş: {date}", + "tokens.created": "Oluşturulma", + "tokens.lastUsed": "Son Kullanım", + "tokens.revoke": "İptal Et", + "tokens.revoking": "İptal ediliyor…", + "tokens.revokeConfirm": "\"{description}\" iptal edilsin mi? Bu token ile yapılan istekler hemen çalışmayı durduracak.", + "tokens.revokedSuccess": "API tokenı iptal edildi", + "tokens.revokeError": "API tokenı iptal edilemedi: {message}", + "tokens.validation.missing_description": "Bu tokenı kullanacak entegrasyonun adını girin.", + "tokens.validation.description_too_long": "Entegrasyon adı 128 karakterden kısa olmalıdır.", + "tokens.validation.invalid_expiry": "Token ömrünü 1 ile 365 gün arasında seçin.", + "tokens.validation.missing_actions": "En az bir izinli eylem seçin.", + "tokens.validation.invalid_action": "Seçilen eylemlerden biri veya birkaçı bu sunucuda token ile desteklenmiyor.", + "tokens.validation.invalid_scope": "Geçerli bir kamera kapsamı seçin.", + "tokens.validation.requires_all_scope": "Kamera dışı izinler Tüm kamera filosu kapsamını gerektirir. Bu kapsamı seçin veya bu izinleri kaldırın.", + "tokens.validation.missing_collection": "Mevcut bir paylaşılan koleksiyon seçin.", + "tokens.validation.invalid_selector": "Özel kamera seçicisini tamamlayın veya düzeltin.", + "tokens.secret.oneTime": "Bir kez gösterilir", + "tokens.secret.scopedTitle": "Bu kapsamlı tokenı şimdi kaydedin", + "tokens.secret.legacyTitle": "Bu eski API anahtarını şimdi kaydedin", + "tokens.secret.scopedDescription": "lightNVR bu tokenın yalnızca hash değerini saklar. Kaybederseniz iptal edip yenisini oluşturun.", + "tokens.secret.legacyDescription": "Bu uyumluluk anahtarı yalnızca burada bir kez gösterilir. Yeni bir anahtar oluşturmak mevcut olanı geçersiz kılar.", + "tokens.secret.value": "API kimlik bilgisi", + "tokens.secret.copied": "Kopyalandı", + "tokens.secret.copySuccess": "API kimlik bilgisi kopyalandı", + "tokens.secret.copyError": "Otomatik olarak kopyalanamadı; kimlik bilgisini elle seçip kopyalayın.", + "tokens.secret.savedConfirm": "Bu kimlik bilgisini güvenli bir şekilde kaydettim", + "tokens.secret.savedHelp": "Onaylamak bu pencereyi kapatır. Tam değer bir daha görüntülenemez.", + "tokens.legacy.title": "Eski uyumluluk anahtarı", + "tokens.legacy.description": "Eski anahtar, bu kullanıcının tüm erişim haklarına sahiptir, süresi dolmaz ve kamera veya eylem bazında kapsamlandırılamaz.", + "tokens.legacy.warning": "Yalnızca uç noktaları kapsamlı token zorunluluğuna henüz geçmemiş mevcut bir entegrasyon için oluşturun. Oluşturmak, önceki eski anahtarı hemen geçersiz kılar.", + "tokens.legacy.generate": "Eski anahtar oluştur", + "tokens.legacy.confirm": "Yeni bir eski anahtar oluşturulsun mu? Bu, kullanıcının mevcut eski anahtarını hemen geçersiz kılar.", + "tokens.legacy.createdSuccess": "Eski API anahtarı oluşturuldu", + "tokens.legacy.createError": "Eski API anahtarı oluşturulamadı: {message}", + "audit.manage": "Denetim Geçmişi", + "audit.title": "Güvenlik ve Erişim Denetimi", + "audit.description": "Kimlik bilgilerini ifşa etmeden oturum açma sonuçlarını, erişim kararlarını ve hassas politika değişikliklerini izleyin.", + "audit.retention": "Saklama", + "audit.retentionDescription": "Etkinlikler şu anda {days} gün süreyle saklanmaktadır. Bu değeri azaltmak eski geçmişi hemen siler.", + "audit.retentionDays": "Gün", + "audit.retentionInvalid": "1 ile 3650 gün arasında bir saklama süresi seçin.", + "audit.retentionSaved": "Denetim saklama kaydedildi; {count} süresi dolmuş etkinlik silindi", + "audit.retentionError": "Denetim saklama kaydedilemedi: {message}", + "audit.filters": "Filtreler", + "audit.clearFilters": "Filtreleri temizle", + "audit.applyFilters": "Filtreleri uygula", + "audit.actor": "Aktör", + "audit.unauthenticated": "Kimliği doğrulanmamış", + "audit.outcome": "Sonuç", + "audit.action": "Tam eylem", + "audit.filterToAction": "Bu eyleme göre filtrele", + "audit.since": "Başlangıç", + "audit.until": "Bitiş", + "audit.invalidDateRange": "Başlangıç tarihi, bitiş tarihinden önce olmalıdır.", + "audit.source": "Kaynak adresi", + "audit.target": "Hedef", + "audit.targetUuid": "Hedef UUID", + "audit.noTarget": "Sistem genelinde", + "audit.requestId": "İstek Kimliği", + "audit.apiToken": "Kapsamlı token kimliği", + "audit.showDetails": "Ayrıntıları göster", + "audit.hideDetails": "Ayrıntıları gizle", + "audit.pageSize": "Sayfa başına", + "audit.resultRange": "{total} sonuçtan {start}–{end} arası gösteriliyor", + "audit.empty": "Eşleşen denetim etkinliği yok", + "audit.emptyDescription": "Bir veya daha fazla filtreyi temizlemeyi deneyin veya yeni güvenlik etkinliğini bekleyin.", + "audit.exportPage": "Bu sayfayı dışa aktar", + "audit.exporting": "Dışa aktarılıyor…", + "audit.exported": "Denetim sayfası dışa aktarıldı", + "audit.exportError": "Denetim olayları dışa aktarılamadı: {message}", + "audit.pagination": "Denetim geçmişi sayfaları", + "audit.page": "Sayfa {page}", + "audit.modesTitle": "İzin verilen kararlar", + "audit.modesDescription": "İzin verilen salt okunur erişimin her eylem için nasıl kaydedileceğini seçin. Bir şeyi değiştiren istekler, reddetmeler, hatalar ve oturum açmalar her zaman kaydedilir. Özetle, her {minutes} dakikada bir kullanıcı, kamera ve istemci başına bir adet giriş ve sayı tutar.", + "audit.mode.record": "Her birini kaydet", + "audit.mode.summarize": "Özetle", + "audit.mode.off": "Kapalı", + "audit.modeOffWarning": "Bu eylem için izin verilen erişim artık denetim geçmişinde görünmeyecek.", + "audit.modesSaved": "Denetim karar modları kaydedildi", + "audit.modesError": "Denetim karar modları kaydedilemedi: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Olay türü", + "audit.eventTypeSummary": "Özetler", + "audit.eventTypeDecision": "Bireysel kararlar", + "access.cameraSearch": "Kamera ara", + "access.cameraSearchPlaceholder": "Aramak için en az iki karakter girin…", + "access.cameraSearchHint": "Kamera adı, UUID, adres, konum, etiket, üretici veya modele göre arayın.", + "access.cameraSelected": "Seçildi", + "access.cameraAdd": "Ekle", + "access.cameraLimit": "Bir seçici en fazla 64 açık kamera içerebilir. Daha geniş kapsamlar için konum veya etiket kuralı kullanın.", + "access.roles.manage": "Rolleri Yönet", + "access.roles.title": "Yetkilendirme Rolleri", + "access.roles.description": "Eylemleri yeniden kullanılabilir rollerde toplayın, ardından bu rolleri kamera kapsamlarına atayın.", + "access.roles.create": "Rol Oluştur", + "access.roles.newRole": "Yeni rol", + "access.roles.copyName": "{name} kopyası", + "access.roles.clone": "Klonla", + "access.roles.builtin": "Yerleşik", + "access.roles.builtinHelp": "Yerleşik roller, yükseltme güvenli sabit şablonlardır. Özelleştirmek için birini klonlayın.", + "access.roles.actionCount": "{count} eylem", + "access.roles.destructive": "Hassas eylem", + "access.roles.notEnforced": "Henüz herhangi bir uç nokta tarafından uygulanmıyor", + "access.roles.destructiveWarning": "Bu rol yapılandırmayı veya kanıtları değiştirebilir. Yalnızca bu yetkinin gerekli olduğu kapsamlarda verin.", + "access.roles.created": "Rol oluşturuldu", + "access.roles.updated": "Rol güncellendi", + "access.roles.deleted": "Rol silindi", + "access.roles.saveError": "Rol kaydedilemedi: {message}", + "access.roles.deleteError": "Rol silinemedi: {message}", + "access.roles.deleteConfirm": "\"{name}\" rolü silinsin mi? Yetkilendirmeler tarafından referans verilen roller silinemez.", + "access.policy.manage": "Erişimi Yönet", + "access.policy.column": "Erişim", + "access.policy.scopedShort": "Kapsamlı", + "access.policy.title": "Erişim Politikası — {username}", + "access.policy.description": "Varsayılan-red rol yetkilendirmelerini yönetin ve kamera kapsamlarını önizleyin.", + "access.policy.tab.grants": "Yetkilendirmeler", + "access.policy.tab.test": "Erişimi Test Et", + "access.policy.scopedWarning": "Yalnızca eşleşen bir yetkilendirme ve kamera kapsamı tarafından izin verilen işlemler çalışır.", + "access.policy.grants": "Rol yetkilendirmeleri", + "access.policy.grantsDescription": "Bir yetkilendirme, bir rolü tüm filo, paylaşılan bir koleksiyon veya özel bir kamera seçici ile birleştirir.", + "access.policy.addGrant": "Yetkilendirme Ekle", + "access.policy.noGrants": "Yetkilendirme yapılandırılmamış", + "access.policy.noGrantsHelp": "Bu kullanıcının erişimi olmaması gerekmiyorsa, kapsamlı politikayı etkinleştirmeden önce en az bir yetkilendirme ekleyin.", + "access.policy.role": "Rol", + "access.policy.chooseRole": "Bir rol seçin", + "access.policy.scope": "Kamera kapsamı", + "access.policy.allCameras": "Tüm kamera filosu", + "access.policy.collectionScope": "Paylaşılan koleksiyon", + "access.policy.collection": "Kamera koleksiyonu", + "access.policy.chooseCollection": "Paylaşılan bir koleksiyon seçin", + "access.policy.collectionHelp": "Erişim, kameralar eklendikçe, çıkarıldıkça veya kurallarıyla eşleştikçe koleksiyonu takip eder.", + "access.policy.dynamicScope": "Dinamik seçici", + "access.policy.activateConfirm": "{username} için varsayılan-red kapsamlı politikası etkinleştirilsin mi? Eşleşen bir yetkilendirmesi olmayan işlemler reddedilecek.", + "access.policy.emptyConfirm": "{username} için yetkilendirme olmadan kapsamlı politika etkinleştirilsin mi? Bu, politika kontrollü tüm erişimi bilinçli olarak kaldırır.", + "access.policy.saved": "Erişim politikası kaydedildi", + "access.policy.saveError": "Erişim politikası kaydedilemedi: {message}", + "access.policy.version": "Politika sürümü {version}", + "access.policy.unsaved": "Kaydedilmemiş değişiklikler", + "access.policy.validation.invalid_mode": "Geçerli bir değerlendirme modu seçin.", + "access.policy.validation.missing_role": "Her yetkilendirme mevcut bir role başvurmalıdır.", + "access.policy.validation.invalid_scope": "Her yetkilendirme tüm filo, paylaşılan koleksiyon veya seçici kapsamı kullanmalıdır.", + "access.policy.validation.invalid_selector": "Kaydetmeden önce tüm kamera seçicilerini tamamlayın veya düzeltin.", + "access.policy.validation.missing_collection": "Her koleksiyon yetkilendirmesi için mevcut bir paylaşılan koleksiyon seçin.", + "access.policy.validation.duplicate_grant": "Kaydetmeden önce yinelenen rol ve kapsam yetkilendirmelerini kaldırın.", + "access.test.title": "Etkin erişimi test et", + "access.test.description": "Kaydedilmiş bir eylemi ve kamerayı {username} olarak yürütmeden değerlendirin.", + "access.test.saveFirst": "Sonucun burada gösterilen politikayı yansıtması için test etmeden önce yetkilendirme değişikliklerini kaydedin veya atın.", + "access.test.action": "Eylem", + "access.test.camera": "Kamera", + "access.test.run": "Erişimi Test Et", + "access.test.running": "Test ediliyor…", + "access.test.allowed": "İzin verildi", + "access.test.denied": "Reddedildi", + "access.test.version": "Sürüm {version}", + "access.test.source": "Kaynak: {source} · Rol: {role}", + "recordings.pullToRefresh": "Kayıtları yenilemek için çekin", + "recordings.releaseToRefresh": "Kayıtları yenilemek için bırakın", + "recordings.refreshing": "Kayıtlar yenileniyor…", + "recordings.refreshed": "Kayıtlar yenilendi", + "recordings.refreshFailed": "Kayıtlar yenilenemedi: {message}", + "recordings.download": "İndir", + "recordings.tags": "Etiketler", + "recordings.selectRecording": "Kayıt seçin", + "timeline.legend.recording": "Kayıt", + "timeline.legend.detection": "Algılama olayı", + "timeline.detectionEvent": "Algılama olayı", + "streams.showCredentials": "Kimlik bilgilerini göster", + "streams.hideCredentials": "Kimlik bilgilerini gizle", + "streams.streamSuccessfullyEnabled": "Akış başarıyla etkinleştirildi.", + "streams.errorEnablingStream": "Akış etkinleştirilemedi: {message}", + "system.health.tab": "Sağlık", + "system.health.operatorView": "Operasyonel sağlık", + "system.health.title": "Sistem Sağlığı", + "system.health.loading": "Sistem sağlığı yükleniyor…", + "system.health.loadError": "Sistem sağlığı yüklenemedi.", + "system.health.refreshing": "Yenileniyor…", + "system.health.activeIncidentCount": "{count} aktif olay", + "system.health.coverage": "Kapsam", + "system.health.monitoringDisabled": "Sağlık izleme devre dışı", + "system.health.lastRecordedValue": "Son kaydedilen değer", + "system.health.monitoringDisabledHelp": "Güncel sağlık bilgileri toplanmıyor. Ayarlar → Sağlık bölümünden sağlık izlemeyi etkinleştirin; kaydetme sonrası istenirse yeniden başlatın. Olay geçmişi geçmiş olayları gösterir, güncel kaynak kullanımını değil.", + "system.health.monitoringRestartRequired": "Sağlık izleme kayıtlı yapılandırmada etkin, ancak çalışan örnekleyici hâlâ devre dışı. Değişikliği uygulamak için LightNVR'yi yeniden başlatın. Olay geçmişi geçmiş olayları gösterir.", + "system.health.containerCoverage": "Sınırlı ana makine kapsamı", + "system.health.hostHardwareUnavailable": "Bu kurulum konteyner ve bağlı kaynak sağlığını görebilir, ancak ana makine donanımı kullanılamıyor. Eksik ana makine değerleri sağlıklı değil, bilinmiyor olarak kabul edilir.", + "system.health.coverageUnknown": "Henüz tamamlanmış bir sağlık anlık görüntüsü yok. Toplama tamamlanana kadar değerler bilinmiyor olarak kalır.", + "system.health.coverageComplete": "Bu kurulumun görebildiği tüm bilgiler başarıyla toplandı.", + "system.health.coveragePartial": "Kapsam kısmi. {count} gözlem veya toplama kontrolü kullanılamıyor, güncel değil veya eksik.", + "system.health.effectiveScope": "Etkili kapsam", + "system.health.activeIncidents": "Aktif olaylar", + "system.health.noActiveIncidents": "Görünür kapsam için aktif olay bildirimi yok.", + "system.health.duration": "Süre", + "system.health.currentValue": "Güncel değer", + "system.health.thresholds": "Eşik ve bekleme", + "system.health.thresholdSummary": "Uyarı {warning}, kritik {critical}, kurtarma {recovery} {unit}; uyarı bekleme {seconds}s", + "system.health.remediation": "Önerilen yanıt", + "system.health.facts": "Sağlık bilgileri", + "system.health.group.resources": "Kaynaklar", + "system.health.group.storage": "Depolama", + "system.health.group.hardware": "Donanım", + "system.health.group.network": "Ağ", + "system.health.group.clock": "Saat", + "system.health.group.components": "Bileşenler", + "system.health.noFacts": "Bu grupta görünür bilgi yok.", + "system.health.observationState": "Yetenek ve güncellik", + "system.health.valueUnavailable": "Bir veya daha fazla değer bilinmiyor", + "system.health.componentStatus": "İzleme bileşenleri", + "system.health.collectors": "Toplayıcılar", + "system.health.collectorSummary": "{total} kayıtlı · {attention} dikkat gerektiriyor", + "system.health.collectorsNeedingAttention": "Dikkat gerektiren toplayıcılar", + "system.health.collectionFailures": "{count} hata veya zaman aşımı", + "system.health.stale": "güncel değil", + "system.health.eventDelivery": "Olay iletimi", + "system.health.degraded": "Bozulmuş", + "system.health.circularDelivery": "Bu, yapılandırılmış tek uyarı yolu olduğundan kendi arızasını bağımsız olarak bildiremez.", + "system.health.incidentPersistence": "Olay kalıcılığı", + "system.health.persistenceSummary": "{pending} bekliyor · {failures} hata · {retries} yeniden deneme", + "system.health.recentSamples": "Son toplama etkinliği", + "system.health.recentSamplesHelp": "En fazla {count} sınırlı sunucu tarafı üretim özeti; bu kapsama etkinliğidir, değer grafiği değildir.", + "system.health.sampleSequence": "Üretim {sequence}", + "system.health.sampleCoverage": "{observations} gözlem · {dropped} düşürüldü", + "system.health.noSamples": "Tamamlanmış toplama üretimi bulunmuyor.", + "system.health.incidentHistory": "Olay geçmişi", + "system.health.incidentHistoryHelp": "En yeni olaylar önce. Geçmiş sınırlı sayfalarda yüklenir.", + "system.health.loadingHistory": "Olay geçmişi yükleniyor…", + "system.health.historyError": "Olay geçmişi yüklenemedi.", + "system.health.emptyHistory": "Kaydedilmiş olay yok.", + "system.health.firstSeen": "İlk görülme", + "system.health.lastSeen": "Son görülme", + "system.health.deliveryState": "İletim durumu", + "system.health.historyPagination": "Olay geçmişi sayfaları", + "system.health.pageCount": "Bu sayfada {count} olay", + "system.health.remediation.memory": "Bellek baskısını azaltın, işlem ve cgroup sınırlarını kontrol edin ve son OOM etkinliğini inceleyin.", + "system.health.remediation.cpu": "Sürekli CPU tüketen süreçleri belirleyin ve sınırları değiştirmeden önce servis verimini doğrulayın.", + "system.health.remediation.io": "Depolama gecikmesini ve aktif yazıcıları kontrol edin; kesintili bakımdan önce kayıtları koruyun.", + "system.health.remediation.filesystem": "Adlandırılmış mantıksal dosya sistemini, boş alanı veya inode'ları kontrol edin ve yazılabilir kaldığını doğrulayın.", + "system.health.remediation.thermal": "Soğutmayı iyileştirin ve yükü azaltın; sıcaklıklar kapanma sınırlarına ulaşmadan önce fanları ve havalandırmaları kontrol edin.", + "system.health.remediation.network": "Bağımsız bir ağ yolu üzerinden görünen arayüzü, bağlantıyı, anahtarı ve hata sayaçlarını kontrol edin.", + "system.health.remediation.clock": "Olay zaman damgalarına güvenmeden önce zaman senkronizasyonunu geri yükleyin ve ana makine saat kaynağını doğrulayın.", + "system.health.remediation.process": "LightNVR kaynak sınırlarını ve günlüklerini inceleyin, ardından yükü azaltın veya doğrulanmış sınırları yükseltin.", + "system.health.remediation.storage": "Değiştirme veya onarımdan önce önemli görüntüleri yedekleyin ve eşlenmiş depolama aygıtını inceleyin.", + "system.health.remediation.hardware": "Etkilenen donanımı ve platform günlüklerini inceleyin; durum devam ederse bakım planlayın.", + "system.health.remediation.health": "Eksik sağlık kanıtlarının değerlendirilebilmesi için toplayıcı erişimini ve izinlerini geri yükleyin.", + "system.health.remediation.system": "İşlem yeniden başlatmasını ana makine yeniden başlatmasından ayırt etmek için önceki çalıştırmayı ve ana makine günlüklerini inceleyin.", + "system.health.remediation.event": "Yerel API veya metrik görünümünü kullanın, kalıcı kuyruk baskısını giderin ve bağımsız bir uyarı hedefini geri yükleyin.", + "system.health.remediation.default": "Etkilenen bileşeni ve son günlükleri inceleyin, ardından yeni bir sağlık döngüsünde kurtarmayı doğrulayın.", + "system.capacityTarget": "Kapasite hedefi", + "system.capacityTargetValue": "{pct}% boş tut", + "system.fillRate": "Dolma hızı", + "system.fillRateValue": "{value} / gün", + "system.projectedToTarget": "Hedefe tahmini süre", + "system.projectedNow": "Şu anda hedefte veya üzerinde", + "system.projectedDays": "~{count}g", + "system.projectedHours": "~{count}sa", + "system.projectedUnknown": "—", + "common.description": "Açıklama", + "common.remove": "Kaldır", + "streams.selectStream": "{name} seç", + "streams.search": "Akış ara", + "streams.searchPlaceholder": "Kamera, konum veya etiket ara", + "streams.noStreamsMatchFilters": "Mevcut filtrelerle eşleşen akış yok.", + "streamHealth.sourceConnected": "Kaynak bağlı", + "streamHealth.videoAdvancing": "Video ilerliyor", + "streamHealth.recorderWriting": "Kaydedici yazıyor", + "streamHealth.detectorOperating": "Algılayıcı çalışıyor", + "streamHealth.lastSegment": "Son tamamlanan segment", + "streams.disablingStreamsProgress": "Akışlar devre dışı bırakılıyor…", + "streams.onvifInvalidAddress": "ONVIF cihaz IP adresi eksik veya geçersiz.", + "streams.warningFallingBackToHttp": "HTTPS bağlantısı başarısız oldu; HTTP üzerinden yeniden deneniyor. Kimlik bilgileri düz metin olarak gönderilebilir.", + "streamsConfig.playbackTransport": "Oynatma aktarımı", + "streamsConfig.playbackTransportHelp": "Bu kamera için tarayıcı oynatma yöntemini ve seçildiğinde yedek sırasını belirleyin.", + "streamsConfig.playbackTransportUnavailable": "Sunucuda kullanılamıyor: {transports}. Aktarımı genel olarak etkinleştirin veya başka bir profil seçin.", + "streamsConfig.audioDisabledByPolicy": "Ses, örnek politikası tarafından devre dışı bırakıldı", + "streamsConfig.audioDisabledByPolicyHelp": "Genel ses uyum politikası etkinken kayıt, canlı dinleme ve çift yönlü konuşma kullanılamaz.", + "streamsConfig.audioVoiceEnhancement": "Ses İyileştirme (kayıtlar)", + "streamsConfig.customApiModel": "Özel API algılama", + "streamsConfig.modelNotSupportedByBuild": "bu derleme tarafından desteklenmiyor", + "streamsConfig.tierCriticalMultiplier": "Kritik seviye ×", + "streamsConfig.tierImportantMultiplier": "Önemli seviye ×", + "streamsConfig.tierEphemeralMultiplier": "Geçici seviye ×", + "streamsConfig.tierMultipliersHelp": "Temel saklama süresine göre seviye başına çarpanlar. Daha yüksek seviyedeki görüntüler daha uzun süre saklanır ve disk baskısı altında en son silinir.", + "streamsConfig.storagePriority": "Depolama Önceliği (1-10)", + "streamsConfig.storagePriorityHelp": "Alan geri kazanılırken bu akışın görüntülerinin göreli önemi; daha yüksek öncelik daha uzun süre korunur.", + "streamsConfig.restream": "Yeniden Yayınla / Yayınla (RTMP)", + "streamsConfig.publishUrl": "Yayın URL'si (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "Bu kamerayı go2rtc üzerinden YouTube Live gibi bir servise yeniden yayınlayın. Akış anahtarı dahil tam RTMP aktarım URL'sini yapıştırın (örn. rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Aynı anda birden fazla servise yeniden yayınlamak için URL'leri virgülle ayırın. YouTube H264 video ve AAC ses gerektirir; LightNVR artık otomatik olarak dönüştürme yapar (H264 olmayan kameralar için H264, AAC olmayan ses için AAC), böylece çoğu kamera olduğu gibi çalışır. Not: YouTube ayrıca bir ses parçası gerektirir — hiç sesi olmayan bir kamera yine de reddedilecektir. Devre dışı bırakmak için boş bırakın.", + "streams.lastSeen": "Son görülme {time}", + "streams.claimed": "Sahiplenildi", + "streams.duplicateSuspected": "Olası yinelenen", + "streams.duplicateSuspectedHelp": "Kararlı kimlik veya uç nokta kanıtı başka bir keşif kaydıyla çakışıyor.", + "streams.onvifClaimWarning": "Akış eklendi, ancak keşif kaydı sahiplenilmiş olarak işaretlenemedi: {message}", + "common.online": "Çevrimiçi", + "common.offline": "Çevrimdışı", + "settings.storageTargets.title": "Kayıt depolama hedefleri", + "settings.storageTargets.description": "Yerel diskleri ve yönetici tarafından bağlanmış NFS veya SMB dosya sistemlerini bağımsız olarak izlenen kayıt hedefleri olarak tanımlayın.", + "settings.storageTargets.foundationNotice": "Kayıt alma, dosya sistemi hedeflerini kullanır. S3 kovaları ve bağlı NFS/SAN hedefleri doğrulanmış arşiv kopyalarını barındırabilir. Sıcak baskı, mantıksal saklama süresi dolana kadar arşivlenmiş kayıtları korur.", + "settings.storageTargets.add": "Depolama hedefi ekle", + "settings.storageTargets.edit": "Depolama hedefini düzenle", + "settings.storageTargets.editorHelp": "Etkin hedefler zaten mevcut olmalı ve yazma, fsync ve temizlik testini geçmelidir. Kullanılamayan bir gelecekteki bağlama noktasını devre dışı olarak kaydedin, ardından bağlandıktan sonra etkinleştirin.", + "settings.storageTargets.name": "Hedef adı", + "settings.storageTargets.root": "Bağlı kök yolu", + "settings.storageTargets.rootLocked": "Varsayılan veya boş olmayan bir hedef, mevcut görüntülerin sahipsiz kalmasını önlemek için değiştirilemez bir kök tutar.", + "settings.storageTargets.class": "Performans sınıfı", + "settings.storageTargets.hot": "Sıcak — aktif kayıt", + "settings.storageTargets.warm": "Ilık — bağlı arşiv", + "settings.storageTargets.cold": "Soğuk — seyrek erişim", + "settings.storageTargets.reserveGb": "Ayrılmış alan payı (GB)", + "settings.storageTargets.lowWatermark": "Düşük su işareti (% kullanılan)", + "settings.storageTargets.highWatermark": "Yüksek su işareti (% kullanılan)", + "settings.storageTargets.migrationBandwidth": "Yaşam döngüsü bant genişliği (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 sınırsız demektir. Sınır, bir taşıma veya kopyalama işi oluşturulduğunda anlık olarak kaydedilir.", + "settings.storageTargets.archiveStart": "Arşiv penceresi başlangıcı", + "settings.storageTargets.archiveEnd": "Arşiv penceresi bitişi", + "settings.storageTargets.archiveWindowHelp": "Yerel saat. Eşit başlangıç ve bitiş saatleri yaşam döngüsü işlerinin tüm gün çalışmasına izin verir; gece penceresi gece yarısını aşabilir.", + "settings.storageTargets.enabled": "Etkin (yerleştirme politikaları bu hedefi seçebilir)", + "settings.storageTargets.notRouted": "Etkin bir yerleştirme politikası kameraları buraya yönlendirmiyor. Bir politika bu hedefi birincil, havuz üyesi veya arşiv hedefi olarak belirtene kadar yeni kayıtlar varsayılan hedefe gitmeye devam eder.", + "settings.storageTargets.degradedNotice": "Yüksek su işaretinin üzerinde veya ayrılmış alanın içinde. Yerleştirme politikaları, alan boşaltılana kadar bu hedefi atlar.", + "settings.storageTargets.probePassedIneligible": "Yazma testi başarılı, ancak hedef {status}: yerleştirme politikaları bu hedefi seçmeyecek.", + "settings.storageTargets.mountRequired": "Bağlı bir dosya sistemi gerektir", + "settings.storageTargets.mountRequiredHelp": "Bu hedefi mevcut kök olmayan bağlama noktasına sabitleyin. NFS, SMB, bind veya PVC bağlama noktası kaybolursa, kayıt alttaki ana dizine yazmak yerine duraklar.", + "settings.storageTargets.mountGuard": "Gerekli bağlama noktası", + "settings.storageTargets.mountPending": "Hedef etkinleştirildiğinde algılanacak", + "settings.storageTargets.default": "Varsayılan", + "settings.storageTargets.capacity": "Kapasite", + "settings.storageTargets.available": "Kullanılabilir", + "settings.storageTargets.recordings": "Dizinlenmiş kayıtlar", + "settings.storageTargets.replicas": "{count} doğrulanmış kopya · {bytes}", + "settings.storageTargets.reserve": "Ayrılmış", + "settings.storageTargets.pressure.normal": "Baskı normal", + "settings.storageTargets.pressure.high": "Yüksek eşik", + "settings.storageTargets.pressure.reserve": "Ayrılan alan aşıldı", + "settings.storageTargets.pressure.unavailable": "Baskı bilgisi yok", + "settings.storageTargets.cleanupActive": "Hedef kapsamlı temizleme etkin ve başka bir hedefe atanmış kayıtları silmeden {target} kullanılabilir alan hedefine çalışacak.", + "settings.storageTargets.test": "Test hedefi", + "settings.storageTargets.probing": "Test ediliyor…", + "settings.storageTargets.probePassed": "Depolama hedefi yazma testi başarılı", + "settings.storageTargets.duplicateFilesystem": "Bu kök, başka bir hedefle aynı alt dosya sistemini paylaşıyor. Yerleştirme etkin olduğunda kapasite iki kez sayılmamalıdır.", + "settings.storageTargets.deleteLocked": "Varsayılan ve boş olmayan hedefler silinemez.", + "settings.storageTargets.deleteConfirm": "Boş depolama hedefi \"{name}\" silinsin mi? Hiçbir dosya kaldırılmayacak.", + "settings.storageTargets.created": "Depolama hedefi oluşturuldu", + "settings.storageTargets.updated": "Depolama hedefi güncellendi", + "settings.storageTargets.deleted": "Depolama hedefi silindi", + "settings.storageTargets.invalidThresholds": "Eşikleri, ayrılan alanı, yaşam döngüsü bant genişliğini ve arşiv penceresi sürelerini kontrol edin.", + "settings.storageTargets.loadError": "Depolama hedefleri yüklenemedi", + "settings.storagePools.title": "Depolama havuzları", + "settings.storagePools.description": "Otomatik taşma ve farklı hedefe çoğaltma için sağlıklı hedefleri gruplayın.", + "settings.storagePools.add": "Havuz ekle", + "settings.storagePools.strategy": "Tahsis stratejisi", + "settings.storagePools.mostFree": "En fazla boş alan", + "settings.storagePools.roundRobin": "Sırayla", + "settings.storagePools.priority": "Açık öncelik", + "settings.storagePools.members": "Hedefler (görüntüleme sırası tahsis önceliğidir)", + "settings.storagePools.enabled": "Havuz etkin", + "settings.storagePools.active": "Aktif", + "settings.storagePools.inactive": "Devre dışı", + "settings.storagePools.strategyValue.most_free": "en fazla boş", + "settings.storagePools.strategyValue.round_robin": "sırayla", + "settings.storagePools.strategyValue.priority": "öncelik sırası", + "settings.storagePools.created": "Depolama havuzu oluşturuldu", + "settings.storagePools.updated": "Depolama havuzu güncellendi", + "settings.storagePools.deleted": "Depolama havuzu silindi", + "settings.storagePools.deleteConfirm": "Depolama havuzu \"{name}\" silinsin mi?", + "settings.storagePools.empty": "Henüz depolama havuzu yok.", + "settings.storageMigrations.title": "Kayıt taşıma işleri", + "settings.storageMigrations.description": "Kalıcı taşıma ve saklanan kopyalar, her hedefin arşiv penceresine ve bant genişliği sınırına uyar, SHA-256 doğrulaması yapar ve yeniden başlatma sonrası güvenle kurtarılır.", + "settings.storageMigrations.empty": "Henüz kayıt taşıma işi yok.", + "settings.storageMigrations.loadError": "Kayıt taşıma işleri yüklenemedi", + "settings.storageMigrations.recording": "Kayıt #{id}", + "settings.storageMigrations.attempt": "Deneme {current}/{max}", + "settings.storageMigrations.operation.move": "Taşı", + "settings.storageMigrations.operation.copy": "Saklanan kopya", + "settings.storageMigrations.cancelled": "Taşıma iptali kabul edildi", + "settings.storageMigrations.cancelling": "İptal ediliyor…", + "settings.storageMigrations.retried": "Taşıma yeniden deneme için sıraya alındı", + "settings.storageMigrations.state.queued": "Sırada", + "settings.storageMigrations.state.copying": "Kopyalanıyor", + "settings.storageMigrations.state.verifying": "Doğrulanıyor", + "settings.storageMigrations.state.committing": "Uygulanıyor", + "settings.storageMigrations.state.cleanup_pending": "Kaynak temizleniyor", + "settings.storageMigrations.state.retry_wait": "Yeniden deneme bekleniyor", + "settings.storageMigrations.state.completed": "Tamamlandı", + "settings.storageMigrations.state.failed": "Başarısız", + "settings.storageMigrations.state.cancelled": "İptal edildi", + "settings.storagePolicies.title": "Kamera yerleştirme politikaları", + "settings.storagePolicies.description": "Eşleşen kameraları öncelik sırasına göre birincil kayıt hedefine yönlendirir. Bir kamera, eşleşen ilk etkin politikayı kullanır.", + "settings.storagePolicies.add": "Yerleştirme politikası ekle", + "settings.storagePolicies.edit": "Yerleştirme politikasını düzenle", + "settings.storagePolicies.editorHelp": "Politika yeni segmentler için yeniden değerlendirilir. Değişiklikler mevcut kayıtları taşımaz.", + "settings.storagePolicies.priority": "Öncelik (yüksek önce)", + "settings.storagePolicies.priorityValue": "Öncelik {priority}", + "settings.storagePolicies.primary": "Birincil hedef", + "settings.storagePolicies.primaryPool": "Yerleştirme havuzu (isteğe bağlı)", + "settings.storagePolicies.exactTarget": "Tam birincil hedefi kullan", + "settings.storagePolicies.fallback": "Birincil hedef kullanılamıyorsa", + "settings.storagePolicies.fallbackDefault": "Varsayılan hedefi kullan", + "settings.storagePolicies.fallbackTarget": "Adlandırılmış yedek hedefi kullan", + "settings.storagePolicies.fallbackPause": "Kaydı duraklat", + "settings.storagePolicies.fallbackFail": "Kayıt başlatmayı başarısız say", + "settings.storagePolicies.namedFallback": "Yedek hedef", + "settings.storagePolicies.chooseTarget": "Bir hedef seçin", + "settings.storagePolicies.choosePool": "Bir havuz seçin", + "settings.storagePolicies.minimumDays": "Minimum saklama (gün)", + "settings.storagePolicies.desiredDays": "İstenen saklama (gün)", + "settings.storagePolicies.maximumDays": "Maksimum saklama (gün)", + "settings.storagePolicies.copyCount": "Gerekli doğrulanmış kopya sayısı", + "settings.storagePolicies.replicationPool": "Çoğaltma havuzu", + "settings.storagePolicies.migrateAfter": "Şu süre sonunda taşı (gün)", + "settings.storagePolicies.migrationTarget": "Arşiv hedefi", + "settings.storagePolicies.pressurePriority": "Baskı silme önceliği (düşük önce)", + "settings.storagePolicies.disabledTarget": "devre dışı", + "settings.storagePolicies.enabled": "Politika etkin", + "settings.storagePolicies.selector": "Eşleşen kameralar", + "settings.storagePolicies.preview": "Önizleme önceliği", + "settings.storagePolicies.previewing": "Değerlendiriliyor…", + "settings.storagePolicies.previewRequired": "Kamera örtüşmesini ve geçerli kazanan politikayı görmek için taslağı kaydetmeden önce önizleyin.", + "settings.storagePolicies.previewSummary": "{matched} kamerayla eşleşiyor; bu taslak {effective} için geçerli.", + "settings.storagePolicies.previewShadowed": "Daha yüksek öncelikli bir politika {count} eşleşen kamera için üstün geliyor.", + "settings.storagePolicies.previewWins": "{count} kamera için \"{policy}\" (öncelik {priority}) politikasına üstün geliyor.", + "settings.storagePolicies.previewLoses": "{count} kamera için \"{policy}\" (öncelik {priority}) politikasına yeniliyor.", + "settings.storagePolicies.previewNoMatches": "Bu seçici şu anda hiçbir kamerayla eşleşmiyor.", + "settings.storagePolicies.invalidPriority": "Öncelik, -1.000.000 ile 1.000.000 arasında bir tam sayı olmalıdır.", + "settings.storagePolicies.invalidLifecycle": "Saklama sıralamasını, kopya sayısını ve çoğaltma havuzunu, taşıma süresini ve hedefini kontrol edin.", + "settings.storagePolicies.created": "Yerleştirme politikası oluşturuldu", + "settings.storagePolicies.updated": "Yerleştirme politikası güncellendi", + "settings.storagePolicies.deleted": "Yerleştirme politikası silindi", + "settings.storagePolicies.deleteConfirm": "Yerleştirme politikası \"{name}\" silinsin mi? Mevcut kayıtlar etkilenmez.", + "settings.storagePolicies.active": "Aktif", + "settings.storagePolicies.inactive": "Devre dışı", + "settings.storagePolicies.routesTo": "Birincil hedef: {target}", + "settings.storagePolicies.lifecycleSummary": "Saklama min/istenen/maks: {minimum}/{desired}/{maximum} gün · {copies} doğrulanmış kopya", + "settings.storagePolicies.fallsBackTo": "Yedek hedef: {target}", + "settings.storagePolicies.mode.default": "Yedek: varsayılan hedef", + "settings.storagePolicies.mode.pause": "Yedek: kaydı duraklat", + "settings.storagePolicies.mode.fail": "Yedek: kayıt başlatmayı reddet", + "settings.storagePolicies.empty": "Yerleştirme politikası yok. Kameralar varsayılan hedefi kullanmaya devam eder; bir politika kameraları diğer hedeflere yönlendirinceye kadar diğer hedeflere hiçbir şey gitmez.", + "settings.storagePolicies.archiveNoTrigger": "Bir arşiv hedefi ayarlanmış ancak bir taşımayı tetikleyen bir şey yok. 'Gün sonra taşı', bir arşivleme yaşı veya bir arşiv seçeneği ayarlayın; aksi takdirde hiçbir kayıt taşınmaz.", + "settings.storageCompliance.title": "Kapasite ve politika uyumu", + "settings.storageCompliance.description": "Gözlemlenen 30 günlük oranlar hedef baskısını ve elde edilen saklamayı öngörür; aktif yaşam döngüsü ihlalleri çözülene kadar görünür kalır.", + "settings.storageCompliance.loadError": "Depolama uyumu yüklenemedi", + "settings.storageCompliance.unknown": "Bilinmiyor", + "settings.storageCompliance.days": "{days} gün", + "settings.storageCompliance.day": "gün", + "settings.storageCompliance.targetForecasts": "Hedef tahminleri", + "settings.storageCompliance.target": "Hedef", + "settings.storageCompliance.dailyRate": "Gözlemlenen oran", + "settings.storageCompliance.toHigh": "Üst eşik değerine", + "settings.storageCompliance.expected": "Beklenen saklama", + "settings.storageCompliance.confidence": "Güven", + "settings.storageCompliance.policyCompliance": "Politika uyumu", + "settings.storageCompliance.compliant": "Aktif ihlal yok", + "settings.storageCompliance.violationCount": "{count} ihlal", + "settings.storageCompliance.policyForecast": "Elde edilen {achieved}; tahmin {expected}; istenen {desired} gün.", + "settings.storageCompliance.copyDeficits": "{count} kayıt için başka bir doğrulanmış kopya gerekiyor.", + "settings.storageCompliance.activeViolations": "Aktif ihlaller", + "settings.storageCompliance.type.copy_count": "Kopya sayısı", + "settings.storageCompliance.type.minimum_retention": "Minimum saklama kapasitesi", + "settings.storageCompliance.type.target_unavailable": "Hedef kullanılamıyor", + "settings.storageCompliance.type.migration_failed": "Yaşam döngüsü görevi başarısız", + "settings.recordingDirectoryFormat": "Kayıt Klasör Düzeni", + "settings.recordingDirectoryFormatHelp": "Yeni MP4 kayıtlarını her kamera klasörü altında alt klasörlere ayırır. Mevcut kayıtlar taşınmaz.", + "settings.recordingDirectoryFlat": "Düz (yalnızca kamera klasörü)", + "settings.recordingDirectoryMonth": "Aya göre (YYYY/MM)", + "settings.recordingDirectoryDay": "Güne göre (YYYY/MM/DD)", + "settings.minFreePct": "Minimum Boş Alan (%)", + "settings.minFreePctHelp": "Saklama günlerinden bağımsız olarak en eski kayıtları otomatik silerek birimin en az bu yüzdesini boş tutar. Bu, kullanımı disk boyutuyla sınırlar — ayarladığınızda disk asla dolmaz. 0 kapasite sınırını devre dışı bırakır.", + "settings.pressureThresholds": "Disk Baskı Eşikleri (%)", + "settings.pressureThresholdsHelp": "Otomatik temizlemeyi kademeli olarak artıran boş alan bantları. acil < kritik < uyarı koşulunu sağlamalıdır.", + "settings.pressureWarningPct": "Uyarı altı (% boş)", + "settings.pressureCriticalPct": "Kritik altı (% boş)", + "settings.pressureEmergencyPct": "Acil altı (% boş)", + "settings.databaseBackupVerify": "Yedek Doğrulama", + "settings.databaseBackupVerifyFull": "Tam (integrity_check, her dizini çapraz kontrol eder)", + "settings.databaseBackupVerifyQuick": "Hızlı (quick_check, yalnızca sayfa yapısı)", + "settings.databaseBackupVerifyOff": "Kapalı (kopya sonrası tarama yok)", + "settings.databaseBackupVerifyHelp": "Kopyalanan her yedek yayımlanmadan önce bu tarama uygulanır. Tam tarama, büyük bir veritabanında mekanik disk üzerinde kopyalama işleminin kendisinden uzun sürebilir ve 30 dakikalık güvenlik valfine takılarak o yedeği atabilir; Hızlı tarama ise çok daha az aramayla yırtık veya kesik sayfaları yakalar.", + "settings.viewMethodAuto": "Otomatik — kamera başına tercih, yedekli", + "settings.resetWizardPending": "Sihirbaz başlatılıyor…", + "settings.apiDetectionFormat": "API İstek Formatı", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (multipart görüntü yükleme)", + "settings.apiDetectionFormatDoods2": "DOODS2 (base64 görüntü içeren JSON gövdesi)", + "settings.apiDetectionFormatHelp": "LightNVR'ın anlık görüntüleri algılama API'sine gönderirken kullandığı tel formatı. light-object-detect veya sözleşmesini uygulayan bir sunucu için light-object-detect seçin; DOODS2 sunucusu için DOODS2 seçin.", + "settings.apiDetectionUrlHelpDoods2": "DOODS2 /detect uç noktası, örn. http://localhost:8080/detect. İstek JSON olarak gönderilir ve sorgu parametresi eklenmez.", + "settings.apiDetectionDetectorName": "DOODS2 Dedektör Adı", + "settings.apiDetectionDetectorNameHelp": "Her istekte detector_name olarak gönderilir. Sunucunun GET /detectors yanıtında listelenen bir dedektörle eşleşmelidir; \"default\" sunucunun varsayılan dedektörünü kullanır.", + "settings.defaultPlaybackTransport": "Varsayılan Oynatma Taşıyıcısı", + "settings.defaultPlaybackTransportHelp": "Yeni oluşturulan akışlara uygulanan oynatma profili. Mevcut akışlar kendi seçimlerini korur.", + "playbackTransport.auto": "Otomatik (önerilen)", + "playbackTransport.webrtcOnly": "Yalnızca WebRTC", + "playbackTransport.mseOnly": "Yalnızca MSE", + "playbackTransport.hlsOnly": "Yalnızca HLS", + "playbackTransport.webrtcThenMse": "WebRTC, ardından MSE", + "playbackTransport.mseThenHls": "MSE, ardından HLS", + "investigation.experimental": "Deneysel Çalışma Alanı", + "investigation.title": "Araştırma", + "investigation.description": "Görüntüdeki boşlukları gizlemeden birden fazla kamerayı ortak bir UTC imleciyle inceleyin.", + "investigation.query": "Araştırma penceresi", + "investigation.queryHelp": "En fazla 16 kamera seçin. Aynı anda en fazla dört video oynatıcı aktiftir.", + "investigation.cameras": "kamera", + "investigation.cameraSelection": "Kamera seçimi", + "investigation.start": "Başlangıç", + "investigation.end": "Bitiş", + "investigation.load": "Araştırma yükle", + "investigation.applyWindow": "Zaman aralığını uygula", + "investigation.loading": "Araştırma yükleniyor…", + "investigation.eventType": "Olay türü", + "investigation.anyEventType": "Herhangi bir olay türü", + "investigation.eventType.detection": "Algılama", + "investigation.eventType.motion": "Hareket", + "investigation.location": "Konum", + "investigation.anyLocation": "Herhangi bir konum", + "investigation.objectLabel": "Nesne etiketi", + "investigation.anyLabel": "Herhangi bir etiket", + "investigation.zone": "Bölge", + "investigation.anyZone": "Herhangi bir bölge", + "investigation.source": "Algılama kaynağı", + "investigation.anySource": "Herhangi bir kaynak", + "investigation.captureMethod": "Yakalama yöntemi", + "investigation.anyCaptureMethod": "Herhangi bir yakalama yöntemi", + "investigation.recordingTag": "Kayıt etiketi", + "investigation.anyRecordingTag": "Herhangi bir kayıt etiketi", + "investigation.protection": "Koruma", + "investigation.anyProtection": "Herhangi bir koruma", + "investigation.protected": "Korumalı", + "investigation.unprotected": "Korumasız", + "investigation.minimumConfidence": "Minimum güven", + "investigation.confidenceError": "Minimum güven 0 ile 1 arasında olmalıdır.", + "investigation.metadataRegionSearch": "Üstveri bölgesi araması", + "investigation.regionSearchHelp": "Görüntüsü olan bir ana kamera seçin, ardından videosunun üzerine bir alan çizin.", + "investigation.regionActive": "{camera} kayıtlı kutuları aranıyor. Sonuç bulunamaması, alanın hiç geçilmediğinin kanıtı değildir.", + "investigation.regionMatch": "Kutu eşleştirme", + "investigation.regionMatch.center": "Merkez içeride", + "investigation.regionMatch.intersects": "Herhangi bir kesişim", + "investigation.regionMatch.minimumIntersection": "Minimum örtüşme", + "investigation.regionMinimumOverlap": "Minimum örtüşme (%)", + "investigation.regionLeft": "Sol (%)", + "investigation.regionTop": "Üst (%)", + "investigation.regionWidth": "Genişlik (%)", + "investigation.regionHeight": "Yükseklik (%)", + "investigation.drawRegion": "Arama alanı çiz", + "investigation.drawingRegion": "Arama alanı çiziliyor…", + "investigation.clearRegion": "Alanı temizle", + "investigation.useFullFrame": "Tüm kareyi kullan", + "investigation.drawRegionPrompt": "Arama alanını tanımlamak için video üzerinde sürükleyin", + "investigation.applyFilters": "Filtreleri uygula", + "investigation.searching": "Olaylar aranıyor…", + "investigation.searchResults": "Olay sonuçları", + "investigation.searchHelp": "Kalıcı olay üstverilerini aramak için bir soruşturma yükleyin.", + "investigation.resultCount": "{count} eşleşen olay", + "investigation.results": "sonuç", + "investigation.resultHistogram": "Olay histogramı", + "investigation.histogramHelp": "Paylaşılan imleci hareket ettirmek için bir çubuk seçin.", + "investigation.previousResult": "Önceki olay", + "investigation.nextResult": "Sonraki olay", + "investigation.previousResultShortcut": "Önceki olay ([)", + "investigation.nextResultShortcut": "Sonraki olay (])", + "investigation.noResults": "Bu kamera, zaman ve filtre seçimiyle eşleşen kalıcı olay bulunamadı.", + "investigation.noThumbnail": "Küçük resim yok", + "investigation.exploreThumbnails": "Küçük resimleri keşfet", + "investigation.exploreSelectedThumbnails": "Olay çevresinde keşfet", + "investigation.thumbnailDrilldown": "Küçük resim ayrıntılandırma", + "investigation.thumbnailDrilldownHelp": "Paylaşılan imleci taşımak ve daha dar bir örnek kümesi oluşturmak için bir boşluk dahil herhangi bir anı seçin.", + "investigation.selectThumbnailSample": "{time} çevresinde incele", + "investigation.loadingThumbnail": "Küçük resim yükleniyor…", + "investigation.thumbnailUnavailable": "Küçük resim kullanılamıyor", + "investigation.loadingSamples": "Küçük resim örnekleri yükleniyor…", + "investigation.thumbnailCoverageTruncated": "Bu aralık, örnekleyicinin inceleyebileceğinden daha fazla kayıt içeriyor. Tam kapsama için zaman aralığını daraltın.", + "investigation.bookmarks.save": "Yer imi kaydet", + "investigation.bookmarks.open": "Yer imleri", + "investigation.bookmarks.saveTitle": "Soruşturma yer imi kaydet", + "investigation.bookmarks.listTitle": "Soruşturma yer imleri", + "investigation.bookmarks.notHold": "Bir yer imi bu görünümü geri yükler, ancak kayıtları normal saklama veya silme işleminden korumaz.", + "investigation.bookmarks.title": "Yer imi adı", + "investigation.bookmarks.note": "Özel not (isteğe bağlı)", + "investigation.bookmarks.titleRequired": "Bir yer imi adı girin.", + "investigation.bookmarks.empty": "Kaydedilmiş soruşturma yer iminiz yok.", + "investigation.bookmarks.cameraCount": "{count} kamera", + "investigation.bookmarks.restore": "Aç", + "investigation.bookmarks.confirmDelete": "Yer imi silinsin mi?", + "investigation.actions.open": "Koru / indir", + "investigation.actions.title": "Soruşturma kayıtları", + "investigation.actions.notEvidenceExport": "Koruma, normal saklama silme işlemini engeller. ZIP indirme, kolaylık amaçlı bir dışa aktarımdır, doğrulanmış bir kanıt paketi değildir.", + "investigation.actions.scope": "Kayıt kapsamı", + "investigation.actions.selectedResult": "Seçili olay ve kamera", + "investigation.actions.fullWindow": "Araştırma penceresindeki tüm kameralar", + "investigation.actions.preview": "Kayıtları Önizle", + "investigation.actions.previewing": "Örtüşen kayıtlar aranıyor…", + "investigation.actions.invalidRange": "Bitiş tarihi başlangıçtan sonra olacak geçerli bir zaman aralığı seçin.", + "investigation.actions.recordingCount": "{count} örtüşen kayıt", + "investigation.actions.protectedCount": "{count} zaten korumalı", + "investigation.actions.noRecordings": "Tamamlanmış kayıtlar bu kamera ve zaman seçimiyle örtüşmüyor.", + "investigation.actions.protectDenied": "{count} korumasız kayıt koruma kapsamınızın dışında ve bu işlemden hariç tutuldu.", + "investigation.actions.exportDenied": "{count} kayıt için dışa aktarma izni yok. İndirmeler hepsi ya da hiç şeklinde çalışır, bu nedenle bu seçim dışa aktarılamaz.", + "investigation.actions.camera": "Kamera", + "investigation.actions.recording": "Kayıt", + "investigation.actions.size": "Boyut", + "investigation.actions.notPermitted": "İzin yok", + "investigation.actions.protectButton": "{count} kaydı koru", + "investigation.actions.protecting": "Korunuyor…", + "investigation.actions.protectUnavailable": "Korumaya yetkili olduğunuz korumasız kayıt yok.", + "investigation.actions.protectResult": "Koruma tamamlandı: {success} başarılı, {failed} başarısız.", + "investigation.actions.downloadButton": "{count} kaydı indir", + "investigation.actions.downloadUnavailable": "ZIP oluşturulabilmesi için her kaydın dışa aktarma iznine sahip olması gerekir.", + "investigation.actions.buildingArchive": "ZIP oluşturuluyor…", + "investigation.actions.downloadFailed": "ZIP oluşturma sunucuda başarısız oldu.", + "investigation.actions.downloadTimedOut": "ZIP oluşturma beş dakika içinde tamamlanamadı. Daha dar bir aralık deneyin.", + "investigation.actions.downloadStarted": "ZIP indirme başladı.", + "investigation.backOneLevel": "Bir üst seviyeye dön", + "investigation.thumbnailMinimumWindow": "Bu, mevcut en dar bir saniyelik aralıktır. Ortak imleç yine de seçilen ana taşındı.", + "investigation.localSource": "yerel", + "investigation.mediaAvailable": "Medya mevcut", + "investigation.durationSeconds": "{count} sn süre", + "investigation.pageNumber": "Sayfa {count}", + "investigation.incompleteCoverage": "{count} eski olay satırı değişmez bir kamera kimliğine atanamadı.", + "investigation.spatialCoverageGap": "{count} kapsam içi olay satırında sınır kutusu yoktu ve mekânsal olarak aranmadı.", + "investigation.noSpatialMetadata": "Bu üstveri araması için kapsam içi olaylarda sınır kutusu yok.", + "investigation.selectCameraError": "En az bir kamera seçin.", + "investigation.selectRecordingError": "En az bir kayıt seçin.", + "investigation.investigateSelectedCount": "{count} seçili kaydı incele", + "investigation.missingCameraIdentity": "İncelenemiyor: {count} seçili kaydın kamera kimliği yok.", + "investigation.recordingTimeError": "Seçili kayıtların geçerli bir zaman aralığı yok.", + "investigation.windowLimit": "Seçili kayıtlar 31 günlük inceleme sınırını aşıyor.", + "investigation.timeRangeError": "Bitiş zamanı, başlangıç zamanından sonra olmalıdır.", + "investigation.cameraLimit": "Bir inceleme en fazla {count} kamera içerebilir.", + "investigation.decoderLimit": "Aynı anda yalnızca {count} kamera oynatıcı etkin olabilir.", + "investigation.playbackControls": "Senkronize oynatma kontrolleri", + "investigation.play": "Oynat", + "investigation.pause": "Duraklat", + "investigation.mode": "Oynatma modu", + "investigation.wallClock": "Gerçek zaman", + "investigation.skipCommonGaps": "Ortak boşlukları atla", + "investigation.speed": "Hız", + "investigation.sharedCursor": "Paylaşılan UTC imleci", + "investigation.activePlayers": "etkin oynatıcı", + "investigation.timeline": "paylaşılan zaman çizelgesi", + "investigation.segments": "parça", + "investigation.truncated": "kırpıldı", + "investigation.gap": "Görüntü yok", + "investigation.players": "Senkronize kamera oynatıcıları", + "investigation.activateCamera": "Video yüklemek için en az bir zaman çizelgesi satırını etkinleştirin.", + "investigation.noFootage": "Görüntü yok", + "investigation.noFootageAtTime": "Paylaşılan zamanda görüntü yok", + "investigation.primaryAudio": "Birincil ses", + "investigation.makePrimary": "Birincil yap", + "investigation.status.loading": "Medya yükleniyor", + "investigation.status.synchronizing": "Senkronize ediliyor", + "investigation.status.ready": "Senkronize edildi", + "investigation.status.late": "Gecikme — toparlanıyor", + "investigation.status.error": "Medya kullanılamıyor", + "investigation.status.paused-by-browser": "Medyaya izin vermek için oynat'ı seçin", + "streamsConfig.eptzTitle": "Balıkgözü ePTZ", + "streamsConfig.eptzEnable": "Tarayıcı tarafı balıkgözü ePTZ'yi etkinleştir", + "streamsConfig.eptzHelp": "Canlı Görünüm, Zaman Çizelgesi oynatma ve İnceleme'de ham balıkgözü akışını düzeltin. Bu, kayıtları veya kamera çıkışını değiştirmez.", + "streamsConfig.eptzModelHelp": "Projeksiyon: eşit aralıklı dairesel balıkgözü · Montaj: tavan. Merkez ve yarıçap normalize edilmiş kaynak görüntü koordinatlarını kullanır.", + "streamsConfig.eptzCenterX": "Optik merkez X", + "streamsConfig.eptzCenterY": "Optik merkez Y", + "streamsConfig.eptzRadius": "Görüntü dairesi yarıçapı", + "streamsConfig.eptzLensFov": "Lens FOV (derece)", + "streamsConfig.eptzRotation": "Lens dönüşü (derece)", + "streamsConfig.eptzDefaultYaw": "Varsayılan pan (derece)", + "streamsConfig.eptzDefaultTilt": "Varsayılan tilt (derece)", + "streamsConfig.eptzViewFov": "Varsayılan görünüm FOV", + "streamsConfig.eptzCalibrationHelp": "Etrafa bakmak için sürükleyin, yakınlaştırmak için fare tekerleğini veya sıkıştırmayı kullanın, sanal kamerayı sıfırlamak için Home tuşuna basın. Görüntü dairesi kenarı hizalanmıyorsa merkez ve yarıçapı ince ayarlayın.", + "settings.archive.targetType": "Depolama türü", + "settings.archive.filesystem": "Yerel veya bağlanmış dosya sistemi (NFS/SAN)", + "settings.archive.s3": "S3 uyumlu arşiv kovası", + "settings.archive.endpoint": "HTTPS uç noktası", + "settings.archive.region": "Bölge", + "settings.archive.bucket": "Özel kova", + "settings.archive.credential_ref": "Kimlik bilgisi referansı", + "settings.archive.budget": "Arşiv bütçesi (GiB, 0 = sınırsız)", + "settings.archive.connectionHelp": "Özel, sürümsüz ve yaşam döngüsü sona erme kuralları olmayan bir kova kullanın. Kimlik bilgisi referansı, sunucuya bağlanmış bir gizli dosyayı seçer. Yönetilen konumu s3://bucket/instance-prefix olarak girin.", + "settings.archive.policy": "Harici arşiv politikası", + "settings.archive.archive_after_seconds": "Yakalamadan sonra arşivle (saniye, -1 = devre dışı)", + "settings.archive.hot_residency_seconds": "Sıcak kopyayı tut (saniye, -1 = arşivlendikten sonra taşı)", + "settings.archive.archive_protected": "Korunan kayıtların arşivlenmesine öncelik ver", + "settings.archive.archive_on_pressure": "Sıcak depolama baskı altındayken erken arşivle", + "settings.archive.policyHelp": "Arşiv zamanlaması yakalama yaşını kullanır ve tamamlanmış bir kayıt gerektirir. -1, yaş tabanlı arşivlemeyi devre dışı bırakır veya sıcak kalış minimumunu kaldırır; 0 hemen anlamına gelir. Düzenlemeler yeni kayıtlara uygulanır. Mevcut kayıtlara yeni bir revizyon uygulamak için bunları inceleyin.", + "settings.archive.deletion_pending": "Silme bekliyor", + "settings.archive.archived": "Arşivlendi", + "settings.archive.hot": "Sıcak", + "settings.archive.hot_and_archive": "Sıcak + Arşiv", + "settings.archive.archiving": "Arşivleniyor", + "settings.archive.preparing": "Oynatma hazırlanıyor", + "settings.archive.unavailable": "Kullanılamıyor", + "settings.archive.operations": "Arşiv işlemleri", + "settings.archive.readOnly": "Kurtarma modu: kayıt taşıma ve silme işlemleri duraklatıldı.", + "settings.archive.disabledBuild": "Bu derlemede S3 desteği devre dışı. Bağlı dosya sistemi hedefleri kullanılabilir durumda.", + "settings.archive.stored": "Kovalarda saklanıyor", + "settings.archive.backlog": "Aktarım birikimi", + "settings.archive.cache": "Getirme önbelleği", + "settings.archive.objectsRemaining": "nesne kaldı", + "settings.archive.waitingForReaders": "Sırada veya aktif okuyucuları bekliyor.", + "settings.archive.applied": "Mevcut kayıtlara uygulanan politika revizyonu", + "settings.archive.reviewExisting": "Mevcut kayıtları incele", + "settings.archive.applySummary": "{count} kayıt ({bytes}) bu revizyonu kullanacak. {expired} tanesi zaten saklama sınırını aştı.", + "settings.archive.applyHelp": "Koruma ve kayıt ezme kuralları uygulanmaya devam eder. Akış ve sistem saklama kuralları da geçerlidir. Yeni arşiv zamanlaması ve hedefi, sonraki yaşam döngüsü taramasında etkili olur.", + "settings.archive.applyBlocked": "Bu revizyonu uygulamadan önce ilişkili aktarımları tamamlayın veya çözün.", + "settings.archive.apply": "Mevcut kayıtlara uygula", + "common.fullscreenUnsupported": "Tam ekran modu bu tarayıcıda desteklenmiyor.", + "recordings.viewInTimelineTitle": "Bu akışı bu zaman noktasında Zaman Çizelgesi görünümünde görüntüle", + "recordings.clickToRetry": "Yeniden denemek için tıklayın", + "timeline.previousDay": "Önceki gün", + "timeline.nextDay": "Sonraki gün", + "timeline.previousMonth": "Önceki ay", + "timeline.nextMonth": "Sonraki ay", + "settings.searchLabel": "Ayarları ara", + "settings.clearSearch": "Aramayı temizle", + "recordings.addTagPlaceholder": "Etiket ekle…", + "recordings.addNewTagPlaceholder": "Yeni etiket ekle…" } diff --git a/web/public/locales/uk.json b/web/public/locales/uk.json index 630f987a..9bb5b1c5 100644 --- a/web/public/locales/uk.json +++ b/web/public/locales/uk.json @@ -325,7 +325,7 @@ "timeline.help.clickSegment": "Натисніть сегмент (кольорова смуга), щоб відтворити цей запис", "timeline.help.arrowKeys": "Для переходу між записами використовуйте клавіші зі стрілками вліво та вправо; клацніть відео, щоб перемкнути клавіші зі стрілками на 1-секундний пошук", "timeline.help.playFromCursor": "Використовуйте зелену кнопку відтворення, щоб почати відтворення з поточної позиції курсору", - "timeline.help.zoomControls": "Використовуйте кнопки «Підібрати», «+» і «−» або __ P0__ +, щоб збільшити часову шкалу", + "timeline.help.zoomControls": "Використовуйте кнопки «Вмістити», «+» і «−» або Ctrl/Cmd + коліщатко миші для масштабування шкали часу", "timeline.help.panControls": "Панорамування ліворуч/праворуч на поточному рівні масштабування за допомогою Shift + коліщатка миші або горизонтального жесту прокручування трекпада", "timeline.help.actions": "Використовувати знімок, завантаження, захист або видалення для поточного відтворюваного запису", "timeline.arrowKeysHelpTitle": "Натисніть відео, щоб перемкнути клавіші зі стрілками на 1-секундний пошук. Натисніть в іншому місці, щоб знову переходити між записами.", @@ -819,7 +819,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "Переконайтеся, що на цій кінцевій точці запущено функцію виявлення світлового об’єкта", "streamsConfig.customApiEndpointUrl": "Спеціальний API Кінцева точка URL", "streamsConfig.useDefaultEndpoint": "Використовувати кінцеву точку за умовчанням", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/detect", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "Введіть повний URL до вашої кінцевої точки користувацького виявлення API", "streamsConfig.overrideWithCustomEndpoint": "Перевизначення за допомогою спеціальної кінцевої точки", "streamsConfig.detectionThreshold": "Поріг виявлення", @@ -1056,7 +1056,7 @@ "settings.detectionModelsPath": "Шлях моделей виявлення", "settings.detectionModelsPathHelp": "Каталог, де зберігаються моделі виявлення", "settings.apiDetectionUrl": "API Виявлення URL", - "settings.apiDetectionUrlHelp": "URL кінцевої точки виявлення зовнішнього об’єкта API", + "settings.apiDetectionUrlHelp": "Кінцева точка light-object-detect, наприклад http://localhost:8000/api/v1/detect. Знімок надсилається як multipart form data з доданими параметрами рядка запиту backend та confidence_threshold.", "settings.apiDetectionBackend": "API Сервер виявлення", "settings.apiDetectionBackendOnnx": "ONNX Час виконання", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1084,7 +1084,7 @@ "settings.enableGo2rtc": "Увімкнути go2rtc", "settings.enableGo2rtcHelp": "Якщо вимкнути цю функцію, go2rtc не буде запущено, а HLS підключиться безпосередньо до потоків камери. Це заощаджує пропускну здатність для камер WiFi, але вимикає перегляд у реальному часі WebRTC.", "settings.forceNativeHls": "Примусовий рідний HLS", - "settings.forceNativeHlsHelp": "Використовуйте рідний NVR __ P3 __ на основі Light __ P2 __ замість __ P0 __ __ P3__ для перегляду в реальному часі. Корисно, якщо go2rtc HLS має проблеми з сумісністю. WebRTC не впливає.", + "settings.forceNativeHlsHelp": "Використовувати вбудований HLS на основі FFmpeg у lightNVR замість go2rtc HLS для перегляду наживо. Корисно, якщо go2rtc HLS має проблеми сумісності. WebRTC не зачіпається.", "settings.binaryPath": "Двійковий шлях", "settings.go2rtcBinaryPathHelp": "Шлях до двійкового файлу go2rtc", "settings.configDirectory": "Каталог конфігурацій", @@ -1156,5 +1156,1492 @@ "settings.discoveryIntervalSecondsRangeHelp": "Як часто шукати камери (30–3600 секунд)", "settings.discoveryNetwork": "Мережа пошуку", "settings.discoveryNetworkExamples": "Приклади: 192.168.1.0/24, 10.0.0.0/16, авто", - "settings.saveSettings": "Зберегти налаштування" + "settings.saveSettings": "Зберегти налаштування", + "live.navigator.title": "Навігатор", + "live.navigator.subtitle": "Розташування, макети та активність", + "live.navigator.cameras": "Камери", + "live.navigator.plans": "План", + "live.navigator.views": "Перегляди", + "live.navigator.events": "Події", + "live.navigator.search": "Знайти камеру…", + "live.navigator.allCameras": "Усі камери", + "live.navigator.unassigned": "Не призначені", + "live.navigator.noCameras": "Немає камер, що відповідають цій області.", + "live.navigator.saveCurrent": "Зберегти поточний макет", + "live.navigator.noLayouts": "Ще немає збережених макетів.", + "live.navigator.layoutNamePrompt": "Назвати цей макет перегляду наживо", + "live.navigator.shareLayoutPrompt": "Поділитися цим макетом з іншими операторами?", + "live.navigator.layoutSaved": "Збережено {name}", + "live.navigator.layoutLoaded": "Завантажено {name}", + "live.navigator.deleteLayoutConfirm": "Видалити {name}?", + "live.navigator.shared": "Спільний", + "live.navigator.loadingEvents": "Завантаження останніх подій…", + "live.navigator.noRecentEvents": "Немає виявлень за останню годину.", + "live.navigator.expand": "Розгорнути навігатор", + "live.navigator.collapse": "Згорнути навігатор", + "live.plan.navigatorHelp": "Виберіть будівлю або поверх. Попередній перегляд камер відкривається лише за запитом.", + "live.plan.noPlans": "Ще немає планів будівель. Створіть план у робочій області планів.", + "live.plan.emptyTitle": "Створіть просторовий вигляд камер", + "live.plan.emptyDescription": "План відображає маркери стану для всього об'єкта та відкриває відео лише на запит оператора. Намалюйте кімнати та стіни прямо тут або завантажте сканований план поверху, креслення об'єкта чи знімок із вашого ПЗ NVR, а потім прив'яжіть камери до реальних кімнат.", + "live.plan.sketch.tools": "Інструменти планування", + "live.plan.sketch.tool.select": "Вибір", + "live.plan.sketch.tool.room": "Кімната", + "live.plan.sketch.tool.wall": "Стіна", + "live.plan.sketch.tool.area": "Зона", + "live.plan.sketch.tool.label": "Підпис", + "live.plan.sketch.undo": "Скасувати малювання", + "live.plan.sketch.redo": "Повторити малювання", + "live.plan.sketch.snap": "Прив'язка до сітки", + "live.plan.sketch.hint.select": "Перетягуйте фігури або камери для переміщення. Натисніть на фігуру для редагування; утримуйте Alt, щоб ігнорувати сітку.", + "live.plan.sketch.hint.room": "Перетягніть на плані, щоб намалювати кімнату або контур будівлі.", + "live.plan.sketch.hint.wall": "Натисніть, щоб додати точки стіни. Подвійне натискання або Enter для завершення, Escape для скасування.", + "live.plan.sketch.hint.area": "Натисніть, щоб окреслити зону. Натисніть першу точку або Enter для замикання.", + "live.plan.sketch.hint.label": "Натисніть на план, щоб розмістити текстовий підпис.", + "live.plan.sketch.type.rect": "Кімната", + "live.plan.sketch.type.wall": "Стіна", + "live.plan.sketch.type.area": "Зона", + "live.plan.sketch.type.label": "Підпис", + "live.plan.sketch.pointCount": "{count} точок", + "live.plan.sketch.defaultLabel": "Підпис", + "live.plan.sketch.shapes": "Фігури планування", + "live.plan.sketch.noShapes": "Ще нічого не намальовано. Оберіть інструмент над планом, щоб почати.", + "live.plan.sketch.tone": "Колір", + "live.plan.sketch.tone.slate": "Сланець", + "live.plan.sketch.tone.blue": "Синій", + "live.plan.sketch.tone.green": "Зелений", + "live.plan.sketch.tone.amber": "Бурштиновий", + "live.plan.sketch.tone.red": "Червоний", + "live.plan.sketch.tone.violet": "Фіолетовий", + "live.plan.sketch.labelText": "Підпис", + "live.plan.sketch.text": "Текст", + "live.plan.sketch.size": "Розмір", + "live.plan.sketch.size.sm": "Малий", + "live.plan.sketch.size.md": "Середній", + "live.plan.sketch.size.lg": "Великий", + "live.plan.sketch.filled": "Заповнити кімнату", + "live.plan.sketch.left": "Зліва %", + "live.plan.sketch.top": "Зверху %", + "live.plan.sketch.width": "Ширина %", + "live.plan.sketch.height": "Висота %", + "live.plan.sketch.points": "Точки", + "live.plan.sketch.point": "Точка {index}", + "live.plan.sketch.delete": "Видалити фігуру", + "live.plan.sketch.duplicate": "Дублювати", + "live.plan.sketch.deselect": "Готово", + "live.plan.sketch.emptyTitle": "На цьому плані ще нічого немає", + "live.plan.sketch.emptyBody": "Намалюйте кімнати, стіни та підписи тут, або завантажте сканований план, креслення об'єкта або експорт PNG/JPEG (до 768 КБ).", + "live.plan.sketch.emptyBodyReadOnly": "Адміністратор може намалювати планування або завантажити план реальної будівлі.", + "live.plan.sketch.drawLayout": "Намалювати планування", + "live.plan.sketch.uploadImage": "Завантажити зображення", + "live.plan.sketch.limitReached": "Досягнуто ліміт фігур ({max})", + "live.plan.sketch.discardDrawing": "Креслення скасовано", + "live.favorites": "Обрані", + "live.favoritesOnly": "Показати лише обрані камери", + "live.addFavorite": "Додати {stream} до обраних", + "live.removeFavorite": "Видалити {stream} з обраних", + "live.noFavorites": "Ще немає обраних камер. Натисніть зірочку на плитці камери, щоб додати.", + "live.favoriteUpdateError": "Не вдалося оновити обрані: {message}", + "live.resetZoom": "Скинути масштаб", + "live.audioPlaybackBlocked": "Браузер заблокував аудіо камери. Натисніть кнопку динаміка ще раз для повторної спроби.", + "live.fullscreenSubStreamFallback": "{stream}: недостатньо пропускної здатності для потоку повної роздільної здатності в повноекранному режимі — перемкнено на субпотік.", + "live.tileActions": "Дії з камерою", + "live.takeSnapshot": "Зробити знімок", + "live.openStreamRecordings": "Відкрити записи для цього потоку", + "live.enterReorderMode": "Змінити порядок камер", + "live.pullToRefresh": "Потягніть для оновлення потоків", + "live.releaseToRefresh": "Відпустіть для оновлення потоків", + "live.refreshingStreams": "Оновлення потоків…", + "live.streamsRefreshed": "Потоки оновлено", + "live.refreshStreamsFailed": "Не вдалося оновити потоки: {message}", + "live.tipDoubleTapFullscreen": "Порада: двічі торкніться плитки, щоб відкрити її на весь екран.", + "live.dayNightControl": "Режим день/ніч", + "live.dayNightLoading": "Завантаження…", + "live.dayNightApplying": "Застосування…", + "live.dayNightMode_auto": "Авто", + "live.dayNightMode_day": "День", + "live.dayNightMode_night": "Ніч", + "live.dayNightMode_unknown": "Невідомо", + "live.dayNightApplied": "Режим день/ніч встановлено: {mode}", + "live.dayNightApplyFailed": "Не вдалося встановити режим день/ніч", + "live.dayNightLoadFailed": "Не вдалося отримати режим день/ніч", + "live.playbackFallbackUsed": "Резервний: {transport}", + "live.playbackTransportUnavailable": "{transport} вимкнено на сервері для цього потоку.", + "live.recordingMode.constant": "Безперервний запис", + "live.recordingMode.detection": "Запис за детекцією", + "live.recordingMode.schedule": "Запис за розкладом", + "live.recordingMode.none": "Запис відсутній", + "live.health.healthy": "Потік у нормальному стані", + "live.health.degraded": "Потік буферизується або відновлюється", + "live.health.offline": "Потік недоступний", + "live.enterPictureInPicture": "Відкрити вікно у вікні", + "live.exitPictureInPicture": "Закрити вікно у вікні", + "live.pictureInPictureError": "Не вдалося відкрити вікно у вікні: {message}", + "live.alwaysFullscreenOnTapEnable": "Увімкнути повноекранний режим при одному натисканні на плитку", + "live.alwaysFullscreenOnTapDisable": "Вимкнути повноекранний режим при натисканні на плитку", + "live.displayMode": "Режим відображення", + "live.displayModeFit": "Вмістити", + "live.displayModeFill": "Заповнити", + "live.displayModeFitDescription": "Вмістити: показати весь кадр із чорними смугами", + "live.displayModeFillDescription": "Заповнити: заповнити плитку та обрізати краї кадру", + "live.slideshowStartCameras": "Почати слайд-шоу: перемикання камер", + "live.slideshowStartPages": "Почати слайд-шоу: перемикання сторінок сітки", + "live.slideshowStop": "Зупинити слайд-шоу", + "live.slideshowInterval": "Інтервал слайд-шоу", + "live.slideshowSeconds": "{seconds} с", + "live.plan.previewUnavailable": "Попередній перегляд камери недоступний", + "live.plan.previewAlt": "Поточний вигляд з {name}", + "live.plan.degreesValue": "{value}°", + "live.plan.inDegrees": "{label} у градусах", + "live.plan.imageDimensionsError": "Не вдалося прочитати розміри зображення", + "live.plan.loading": "Завантаження планів будівлі…", + "live.plan.created": "Створено {name}", + "live.plan.renamed": "Перейменовано на {name}", + "live.plan.deleted": "Видалено {name}", + "live.plan.backgroundType": "Фон має бути зображенням PNG або JPEG", + "live.plan.backgroundTooLarge": "Зображення фону занадто велике; максимум 768 КБ", + "live.plan.backgroundAspect": "Завантажено, але співвідношення сторін зображення не відповідає жодному допустимому розміру полотна", + "live.plan.backgroundUpdatedSave": "Фон оновлено для {name}; збережіть макет, щоб застосувати розмір полотна", + "live.plan.backgroundNotResized": "Фон завантажено, але розмір полотна не змінено: {error}", + "live.plan.backgroundUpdated": "Фон оновлено для {name}", + "live.plan.backgroundRemoved": "Фон видалено", + "live.plan.saved": "Збережено {name}", + "live.plan.createTitle": "Створити план будівлі", + "live.plan.createDescription": "Дайте цій будівлі або поверху чітку назву. Намалюйте планування або завантажте зображення плану поверху, потім розмістіть камери.", + "live.plan.nameLabel": "Назва плану", + "live.plan.namePlaceholder": "Головна будівля · Перший поверх", + "live.plan.createConfirm": "Створити план", + "live.plan.eyebrow": "План будівлі", + "live.plan.placedSummary": "{placed} розміщено · {live} наживо", + "live.plan.zoomAndPan": "Масштабування та переміщення плану", + "live.plan.panLeft": "Вліво", + "live.plan.panUp": "Вгору", + "live.plan.panDown": "Вниз", + "live.plan.panRight": "Вправо", + "live.plan.zoomOut": "Зменшити", + "live.plan.zoomIn": "Збільшити", + "live.plan.fitTitle": "Підігнати план", + "live.plan.fit": "Підігнати", + "live.plan.backgroundMenu": "Фон…", + "live.plan.save": "Зберегти план", + "live.plan.uploadBackgroundTitle": "Завантажте зображення PNG або JPEG як фон плану", + "live.plan.replaceBackground": "Замінити фон", + "live.plan.uploadBackground": "Завантажити фон", + "live.plan.removeBackground": "Видалити фон", + "live.plan.rename": "Перейменувати", + "live.plan.newPlan": "Новий план", + "live.plan.editLayout": "Редагувати розташування", + "live.plan.placementHint": "Натисніть на план, щоб розмістити {name}", + "live.plan.clusterLabel": "{count} камер; збільште масштаб", + "live.plan.markerLabel": "{name}; {availability}; напрямок {rotation}°, кут огляду {fov}°", + "live.plan.cameraFallback": "Камера", + "live.plan.legendLive": "Наживо", + "live.plan.canvas": "Полотно плану", + "live.plan.width": "Ширина", + "live.plan.height": "Висота", + "live.plan.canvasHint": "Завантаження фонового зображення змінює розмір полотна відповідно до нього.", + "live.plan.canvasInvalid": "Ширина має бути 400–4000, а висота — 300–3000.", + "live.plan.openLive": "Відкрити камеру наживо", + "live.plan.direction": "Напрямок камери", + "live.plan.fov": "Кут огляду", + "live.plan.coverageNote": "Сектори показують лише напрямок і кут; відстань на плані не калібрована.", + "live.plan.removeCamera": "Видалити з плану", + "live.plan.selectCamera": "Вибрати камеру", + "live.plan.selectHintEditing": "Перетягуйте розміщені маркери для точного налаштування. Переглядайте статус і відкривайте перегляд наживо за потреби.", + "live.plan.selectHint": "Переглядайте статус і відкривайте перегляд наживо за потреби.", + "live.plan.cameras": "Камери плану", + "live.plan.findPlaceholder": "Знайти на цьому плані…", + "live.plan.findLabel": "Знайти камеру на цьому плані", + "live.plan.unplaced": "Не розташовані камери", + "live.plan.unplacedHint": "Виберіть камеру, потім клацніть її розташування на плані.", + "live.plan.renameTitle": "Перейменувати план", + "live.plan.renameDescription": "Плани доступні всім операторам на цьому об'єкті.", + "live.plan.deleteTitle": "Видалити план", + "live.plan.deleteMessage": "Видалити «{name}» та завантажене тло? Розташування камер на цьому плані буде видалено; самі камери залишаться без змін.", + "setupWizard.welcomeTitle": "Ласкаво просимо до LightNVR", + "setupWizard.welcomeIntro": "Налаштуйте ваш NVR за кілька простих кроків. Ви завжди зможете повернутися до цих налаштувань на сторінці Налаштування.", + "setupWizard.welcomeStorage": "Шлях зберігання та обмеження розміру", + "setupWizard.welcomePerformance": "Обмеження продуктивності для кількості камер", + "setupWizard.welcomeSecurity": "Безпечний вхід адміністратора", + "setupWizard.storageTitle": "Сховище та база даних", + "setupWizard.storageIntro": "Де зберігати записи та базу даних?", + "setupWizard.storagePath": "Шлях зберігання записів", + "setupWizard.storagePathHint": "Абсолютний шлях для запису відеофайлів.", + "setupWizard.maxStorage": "Максимальний розмір сховища (ГБ)", + "setupWizard.maxStorageHint": "0 = без обмежень.", + "setupWizard.dbPath": "Шлях до бази даних", + "setupWizard.dbPathHint": "Розташування файлу бази даних SQLite.", + "setupWizard.performanceTitle": "Продуктивність", + "setupWizard.performanceIntro": "Ці налаштування визначають місткість, а не якість відео. Більшість користувачів можуть залишити значення за замовчуванням.", + "setupWizard.threadPool": "Розмір пулу робочих потоків", + "setupWizard.threadPoolInfo": "впливає на фонову роботу веб-сервера. Рекомендоване значення зазвичай є найкращим, якщо ви не оптимізуєте продуктивність.", + "setupWizard.maxStreams": "Максимальна кількість одночасних потоків", + "setupWizard.maxStreamsInfo": "визначає ліміт ємності камер для цього запущеного екземпляра. Встановіть значення не менше кількості камер, які ви плануєте додати, з невеликим запасом.", + "setupWizard.important": "Важливо:", + "setupWizard.restartWarning": "якщо ви зміните будь-яке з цих налаштувань, нове значення буде збережено зараз, але застосоване лише після перезапуску LightNVR. Наприклад, якщо поточний ліміт потоків дорівнює 1 і ви збільшите його до 32, потрібно перезапустити перед додаванням камер понад старий ліміт.", + "setupWizard.threadPoolHintCores": "Рекомендовано: {recommended} (2× ваш {cores}-ядерний процесор). Це керує фоновими потоками libuv. Діапазон: 2–128.", + "setupWizard.threadPoolHint": "Рекомендовано: {recommended} (2× кількість ядер процесора). Це керує фоновими потоками libuv. Діапазон: 2–128.", + "setupWizard.maxStreamsHint": "Скільки камер LightNVR може підтримувати активними одночасно. За замовчуванням 32, максимум {max}. Якщо ви очікуєте 8 камер, оберіть щонайменше 8. Потребує перезапуску для застосування.", + "setupWizard.completeTitle": "Налаштування завершено!", + "setupWizard.saved": "Налаштування успішно збережено.", + "setupWizard.notSaved": "Налаштування не змінено — буде використано значення за замовчуванням.", + "setupWizard.restartRequired": "Потрібен перезапуск", + "setupWizard.restartRequiredInfo": "зміни розміру пулу потоків та/або максимальної кількості потоків збережено, але вони набудуть чинності лише після перезапуску служби. Перезапустіть перед додаванням нових камер або очікуванням нового ліміту ємності.", + "setupWizard.saveFailed": "Не вдалося зберегти налаштування: {error}", + "setupWizard.back": "Назад", + "setupWizard.saving": "Збереження…", + "setupWizard.saveContinue": "Зберегти та продовжити", + "setupWizard.next": "Далі →", + "setupWizard.finish": "Перейти на панель", + "setupWizard.skip": "Пропустити майстер налаштування", + "live.eptzCanvasLabel": "Електронне панорамування, нахил та масштабування риб'ячого ока", + "live.eptzCanvasHint": "Перетягніть для панорамування та нахилу; колесо миші або щипок для масштабування; Home скидає", + "live.eptzReset": "Скинути вигляд ePTZ", + "live.autoShort": "Авто", + "live.webrtcShort": "WebRTC", + "nav.investigation": "Розслідування", + "availability.label": "Доступність камер", + "availability.live": "Зараз наживо", + "availability.offline": "Офлайн (раніше підключалась)", + "availability.neverConnected": "Ніколи не підключалась", + "availability.disabled": "Вимкнено", + "availability.all": "Усі камери", + "streams.inventory": "Інвентар", + "streams.configuration": "Конфігурація", + "events.tab": "Події", + "events.eyebrow": "Інтеграції на основі подій", + "events.title": "Події та маршрутизація", + "events.description": "Перетворюйте події камери та системи на надійні MQTT-потоки для автоматизації, сервісів сповіщень та зовнішньої обробки. LightNVR надає інтерфейс подій; доставка електронної пошти та SMS залишається у сервісах нижчого рівня.", + "events.routes": "Маршрути", + "events.destinations": "Призначення", + "events.catalog": "Каталог подій", + "events.enable": "Увімкнути", + "events.loadError": "Не вдалося завантажити конфігурацію маршрутизації подій", + "events.accessDenied": "Доступ заборонено — недостатньо прав", + "events.summary.routes": "Маршрути", + "events.summary.enabled": "{count} увімкнено", + "events.summary.destinations": "Призначення", + "events.summary.managedActive": "{count} керованих та активних", + "events.summary.types": "Зареєстровані типи", + "events.summary.registry": "Каталог подій із версіонуванням", + "events.summary.interface": "Інтерфейс", + "events.summary.interfaceHelp": "Надійний вивід подій", + "events.route.add": "Додати маршрут", + "events.route.addTitle": "Створити маршрут подій", + "events.route.editTitle": "Редагувати маршрут подій", + "events.route.create": "Створити маршрут", + "events.route.editorDescription": "Виберіть, які події підходять, які камери входять у область дії, куди вони надходять і як контролюються надмірно активні джерела.", + "events.route.emptyTitle": "Маршрути подій не налаштовано", + "events.route.emptyDescription": "Створіть маршрут для вибору типів подій, охоплення камер, розкладу, політики придушення та призначення MQTT.", + "events.route.enabled": "Маршрут увімкнено", + "events.route.enabledHelp": "Відповідні події приймаються для надійної доставки", + "events.route.destination": "Призначення", + "events.route.destinationHelp": "Відповідна подія зберігається один раз для кожного унікального призначення.", + "events.route.eventTypes": "Типи подій", + "events.route.eventTypesHelp": "Виберіть один або кілька версіонованих контрактів подій з реєстру.", + "events.route.detectionFilters": "Фільтр виявлення об'єктів", + "events.route.detectionFiltersHelp": "За бажанням вкажіть мітки, зони або мінімальну впевненість для подій виявлення об'єктів.", + "events.route.healthFilters": "Фільтр подій стану системи", + "events.route.healthFiltersHelp": "За бажанням зіставте зареєстровані коди станів або рівні тяжкості. Доступні значення надходять із цього реєстратора.", + "events.route.healthConditions": "Стани системи (будь-який)", + "events.route.healthSeverities": "Рівні тяжкості (будь-який)", + "events.route.healthRegistryUnavailable": "Реєстр станів недоступний. Перезавантажте перед налаштуванням фільтрів станів.", + "events.route.labels": "Мітки (будь-яка)", + "events.route.zones": "Ідентифікатори зон (будь-який)", + "events.route.listHelp": "Розділяйте значення комами.", + "events.route.minConfidence": "Мінімальна впевненість", + "events.route.confidenceHelp": "Значення від 0 до 1.", + "events.route.cameraScope": "Охоплення камер", + "events.route.cameraScopeHelp": "Використовуйте розташування парку, теги, набори атрибутів або конкретні камери без завантаження всього парку.", + "events.route.allCameras": "Усі камери", + "events.route.dynamicScope": "Динамічний селектор камер", + "events.route.systemScopeHelp": "Системні події не є камерами. Селектори камер недоступні, коли цей маршрут включає події системного рівня.", + "events.route.schedule": "Розклад", + "events.route.scheduleHelp": "Використовуйте час настання події в часовому поясі IANA; нічні інтервали підтримуються.", + "events.route.restrictSchedule": "Лише в налаштованих інтервалах", + "events.route.suppression": "Політика шуму та доставки", + "events.route.suppressionHelp": "Нуль вимикає керування. Придушення активується лише після того, як призначення прийме надійну подію.", + "events.route.debounce": "Секунди дебаунсу", + "events.route.debounceHelp": "Повторні спостереження подовжують цей інтервал тиші.", + "events.route.cooldown": "Секунди охолодження", + "events.route.cooldownHelp": "Мінімальний інтервал після прийнятої події.", + "events.route.grouping": "Секунди вікна групування", + "events.route.groupingHelp": "Зберігає першу подію та об'єднує повторення.", + "events.route.rateLimit": "Подій за хвилину", + "events.route.rateLimitHelp": "Максимум за фіксоване вікно для маршруту та камери.", + "events.route.deliveryPolicy": "Політика доставки", + "events.route.suppressionActive": "Керування шумом активне", + "events.route.everyMatch": "Кожен збіг", + "events.route.preview": "Попередній перегляд маршруту", + "events.route.previewing": "Попередній перегляд…", + "events.route.previewResult": "Попередній перегляд маршруту", + "events.route.cameraMatches": "{count} камер збігається", + "events.route.previewNoPublish": "Попередній перегляд перевіряє повне правило та визначає зразок камери; він ніколи не публікує подію.", + "events.route.systemPreviewHelp": "Системні події не враховують вибір камери, тому в цьому попередньому перегляді показують нуль збігів камер.", + "events.route.created": "Маршрут подій створено", + "events.route.updated": "Маршрут подій оновлено", + "events.route.deleted": "Маршрут подій видалено", + "events.route.disabled": "Маршрут подій вимкнено", + "events.route.enabledMessage": "Маршрут подій увімкнено", + "events.route.deleteConfirm": "Видалити маршрут подій «{name}»?", + "events.route.validation.name": "Введіть назву маршруту.", + "events.route.validation.destination": "Виберіть призначення.", + "events.route.validation.event_types": "Виберіть принаймні один тип події.", + "events.route.validation.selector": "Заповніть або виправте селектор камери.", + "events.route.validation.system_scope": "Селектори камер не можна використовувати з системними подіями.", + "events.route.validation.detection_type": "Фільтри виявлення потребують типу події виявлення об'єктів.", + "events.route.validation.detection_filter": "Додайте принаймні одну мітку виявлення, зону або поріг впевненості.", + "events.route.validation.confidence": "Мінімальна впевненість має бути від 0 до 1.", + "events.route.validation.predicate_mix": "Фільтри виявлення та стану не можна поєднувати в одному маршруті.", + "events.route.validation.health_type": "Фільтри стану потребують лише зареєстровані типи подій системного стану.", + "events.route.validation.health_filter": "Виберіть принаймні одну зареєстровану умову стану або рівень серйозності.", + "events.route.validation.health_condition": "Виберіть лише коди станів, повернуті реєстром стану реєстратора.", + "events.route.validation.health_severity": "Виберіть лише рівні критичності, що підтримуються вибраними типами подій стану.", + "events.route.validation.timezone": "Введіть встановлений часовий пояс IANA, наприклад UTC або America/New_York.", + "events.route.validation.schedule_window": "Кожне вікно розкладу потребує щонайменше одного дня та різних дійсних часів початку та закінчення.", + "events.route.validation.suppression": "Значення придушення мають бути цілими числами в межах допустимих діапазонів.", + "events.schedule.timezone": "Часовий пояс", + "events.schedule.timezoneHelp": "Має бути наявний у базі часових поясів реєстратора.", + "events.schedule.addWindow": "Додати вікно часу", + "events.schedule.windowNumber": "Вікно {number}", + "events.schedule.start": "Початок", + "events.schedule.end": "Кінець", + "events.schedule.sunday": "Нд", + "events.schedule.monday": "Пн", + "events.schedule.tuesday": "Вт", + "events.schedule.wednesday": "Ср", + "events.schedule.thursday": "Чт", + "events.schedule.friday": "Пт", + "events.schedule.saturday": "Сб", + "events.destination.add": "Додати призначення", + "events.destination.addTitle": "Додати призначення MQTT", + "events.destination.editTitle": "Редагувати призначення MQTT", + "events.destination.create": "Створити призначення", + "events.destination.editorDescription": "Налаштуйте надійний вихід подій. Облікові дані доступні лише для запису та ніколи не повертаються API.", + "events.destination.default": "Налаштування MQTT за замовчуванням", + "events.destination.settingsManaged": "Керовані налаштування", + "events.destination.defaultDescription": "Наявна конфігурація MQTT залишається доступною як mqtt:default і використовується {count} маршрутами.", + "events.destination.openSettings": "Відкрити налаштування MQTT", + "events.destination.emptyTitle": "Немає керованих призначень", + "events.destination.emptyDescription": "Додайте інший брокер MQTT для незалежної доставки подій до хмарного конектора, системи автоматизації або сервісу сповіщень.", + "events.destination.identity": "Ідентифікатор призначення", + "events.destination.enabled": "Призначення увімкнено", + "events.destination.enabledHelp": "Підключитися та спорожнити його надійну чергу", + "events.destination.active": "Активний", + "events.destination.paused": "Призупинено", + "events.destination.pause": "Призупинити", + "events.destination.broker": "Брокер", + "events.destination.host": "Хост брокера", + "events.destination.hostHelp": "Тільки ім'я хоста або IP-адреса; не включайте схему URL.", + "events.destination.port": "Порт", + "events.destination.clientId": "Ідентифікатор клієнта", + "events.destination.clientIdHelp": "Має бути унікальним для цього з'єднання з брокером.", + "events.destination.topic": "Тема", + "events.destination.topicTemplate": "Шаблон теми", + "events.destination.topicHelp": "Має містити токени типу події та ідентифікатора суб'єкта; підстановочні символи MQTT не допускаються.", + "events.destination.keepalive": "Інтервал keepalive (секунди)", + "events.destination.statusTopicTemplate": "Тема статусу присутності", + "events.destination.statusTopicHelp": "Необов'язково. Має містити {installation_uuid}; {destination_uuid} також доступний. Підстановочні символи MQTT не допускаються.", + "events.destination.statusTopicEnabled": "Присутність явно увімкнено для цього призначення. Тема ніколи не визначається з теми події.", + "events.destination.statusTopicDisabled": "Присутність вимкнено для цього призначення. Залиште це поле порожнім, щоб залишити його вимкненим.", + "events.destination.qos": "Якість обслуговування", + "events.destination.qos0": "відправити один раз", + "events.destination.qos1": "принаймні один раз", + "events.destination.qos2": "рівно один раз", + "events.destination.authentication": "Автентифікація", + "events.destination.passwordPreserved": "Залиште порожнім, щоб зберегти збережений пароль лише для запису.", + "events.destination.passwordOptional": "Необов'язково, якщо брокер дозволяє анонімних клієнтів.", + "events.destination.clearPassword": "Очистити збережений пароль", + "events.destination.transportSecurity": "Захист транспорту", + "events.destination.tlsMode": "Режим TLS", + "events.destination.tlsSystem": "Системне сховище довіри", + "events.destination.tlsCustomCa": "Власний центр сертифікації", + "events.destination.tlsMutual": "Взаємний TLS", + "events.destination.tlsDisabled": "Вимкнено (відкритий текст)", + "events.destination.tlsHelp.system": "Перевіряти сертифікат брокера за системним сховищем довіри.", + "events.destination.tlsHelp.custom_ca": "Перевіряти брокера за явним файлом центру сертифікації PEM.", + "events.destination.tlsHelp.mutual": "Перевіряти брокера за явним CA та надавати сертифікат і ключ клієнта.", + "events.destination.tlsHelp.disabled": "Без шифрування транспорту та перевірки ідентичності брокера.", + "events.destination.caFile": "Файл CA", + "events.destination.certFile": "Файл сертифіката клієнта", + "events.destination.keyFile": "Файл ключа клієнта", + "events.destination.absolutePathHelp": "Використовуйте абсолютний шлях, доступний для читання службою LightNVR.", + "events.destination.plaintextWarning": "MQTT без шифрування може розкрити метадані подій та облікові дані. Використовуйте лише в довіреній ізольованій мережі.", + "events.destination.security": "Безпека", + "events.destination.tls.system": "Системна довіра", + "events.destination.tls.custom_ca": "Власний CA", + "events.destination.tls.mutual": "Взаємний TLS", + "events.destination.tls.disabled": "Без шифрування", + "events.destination.routes": "Маршрути", + "events.destination.presence": "Тема присутності", + "events.destination.deleteInUse": "Видаліть або перенаправте маршрути перед видаленням цього призначення.", + "events.destination.created": "Призначення MQTT створено", + "events.destination.updated": "Призначення MQTT оновлено", + "events.destination.deleted": "Призначення MQTT видалено", + "events.destination.pausedMessage": "Призначення MQTT призупинено; події в черзі зберігаються до закінчення терміну.", + "events.destination.enabledMessage": "Призначення MQTT увімкнено", + "events.destination.deleteConfirm": "Видалити призначення MQTT \"{name}\"?", + "events.destination.validation.name": "Введіть назву призначення.", + "events.destination.validation.host": "Введіть ім'я хоста або IP-адресу брокера.", + "events.destination.validation.client_id": "Введіть ідентифікатор клієнта брокера.", + "events.destination.validation.topic": "Тема повинна містити токени event-type та subject-ID і не може містити MQTT-шаблони.", + "events.destination.validation.status_topic": "Необов'язкова тема присутності повинна містити токен installation UUID, використовувати лише підтримувані токени та не може містити MQTT-шаблони.", + "events.destination.validation.port": "Порт повинен бути цілим числом від 1 до 65535.", + "events.destination.validation.keepalive": "Keepalive повинен бути цілим числом від 5 до 3600 секунд.", + "events.destination.validation.qos": "Виберіть MQTT QoS 0, 1 або 2.", + "events.destination.validation.username": "Для налаштованого пароля потрібне ім'я користувача.", + "events.destination.validation.ca_file": "Цей режим TLS вимагає абсолютного шляху до файлу CA.", + "events.destination.validation.mutual_files": "Для взаємного TLS потрібні абсолютні шляхи до CA, сертифіката клієнта та ключа клієнта.", + "fleet.eyebrow": "Операції з камерами", + "fleet.title": "Інвентар камер", + "fleet.description": "Знаходьте, оцінюйте та організовуйте камери у великих розгортаннях без завантаження всього інвентарю в браузер.", + "fleet.summary": "Зведення стану парку", + "fleet.totalCameras": "Відповідні камери", + "fleet.needsAttention": "Деградований", + "fleet.searchLabel": "Пошук камер", + "fleet.searchPlaceholder": "Пошук за назвою, адресою, розташуванням, тегом, виробником або моделлю…", + "fleet.resultCount": "{count} камер", + "fleet.filters": "Фільтри", + "fleet.clearFilters": "Очистити фільтри", + "fleet.filter.health": "Стан", + "fleet.filter.enabled": "Стан камери", + "fleet.filter.anyState": "Будь-який стан", + "fleet.filter.recording": "Режим запису", + "fleet.filter.location": "Піддерево розташувань", + "fleet.filter.allLocations": "Усі розташування", + "fleet.filter.tags": "Теги (будь-який збіг)", + "fleet.filter.collection": "Колекція камер", + "fleet.health.unknown": "Невідомо", + "fleet.health.up": "Онлайн", + "fleet.health.degraded": "Деградований", + "fleet.health.down": "Офлайн", + "fleet.health.disabled": "Вимкнено", + "fleet.recording.off": "Вимк.", + "fleet.recording.continuous": "Безперервний", + "fleet.recording.detection": "Виявлення", + "fleet.recordingActive": "Записується зараз", + "fleet.recordingInactive": "Не записується", + "fleet.column.camera": "Камера", + "fleet.column.health": "Стан", + "fleet.column.location": "Розташування", + "fleet.column.tags": "Теги", + "fleet.column.recording": "Запис", + "fleet.viewLive": "Наживо", + "fleet.lastFrame": "Останній кадр", + "fleet.noAddress": "Адреса недоступна", + "fleet.unassigned": "Не призначено", + "fleet.loading": "Завантаження парку камер…", + "fleet.refreshing": "Оновлення…", + "fleet.loadError": "Не вдалося завантажити парк камер", + "fleet.emptyTitle": "Камери не налаштовані", + "fleet.emptyDescription": "Додайте потік, щоб зробити його доступним у робочому просторі парку камер.", + "fleet.emptyFilteredTitle": "Немає камер, що відповідають цьому перегляду", + "fleet.emptyFilteredDescription": "Спробуйте розширити пошук або зняти один або кілька фільтрів.", + "fleet.paginationSummary": "Показано {first}–{last} з {total}", + "fleet.perPage": "На сторінці", + "fleet.pageOf": "Сторінка {page} з {pages}", + "fleet.selectPage": "Вибрати всі камери на цій сторінці", + "fleet.selectCamera": "Вибрати {name}", + "fleet.selectedCount": "Вибрано камер: {count}", + "fleet.organizeSelected": "Організувати вибрані", + "fleet.clearSelection": "Зняти вибір", + "fleet.organization.manage": "Керування організацією", + "fleet.organization.title": "Організація камер", + "fleet.organization.description": "Підтримуйте багаторазову ієрархію розташувань і нормалізований словник тегів для парку камер.", + "fleet.organization.locations": "Розташування", + "fleet.organization.tags": "Теги", + "fleet.organization.locationsDescription": "Моделюйте об'єкти, будівлі, поверхи та операційні зони як навіговану ієрархію.", + "fleet.organization.tagsDescription": "Використовуйте керований словник тегів замість непослідовних міток вільної форми.", + "fleet.organization.addRoot": "Додати розташування верхнього рівня", + "fleet.organization.addLocation": "Додати розташування", + "fleet.organization.editLocation": "Редагувати розташування", + "fleet.organization.addChild": "Додати дочірню", + "fleet.organization.type": "Тип", + "fleet.organization.parent": "Батьківська локація", + "fleet.organization.topLevel": "Верхній рівень", + "fleet.organization.sortOrder": "Порядок сортування", + "fleet.organization.contents": "Вміст", + "fleet.organization.cameras": "Камери", + "fleet.organization.system": "Система", + "fleet.organization.contentCounts": "{cameras} камер · {children} дочірніх", + "fleet.organization.locationNotEmpty": "Спочатку перемістіть камери та видаліть дочірні локації", + "fleet.organization.noLocations": "Локації не налаштовані.", + "fleet.organization.locationCreated": "Локацію створено", + "fleet.organization.locationUpdated": "Локацію оновлено", + "fleet.organization.locationDeleted": "Локацію видалено", + "fleet.organization.deleteLocationConfirm": "Видалити локацію «{name}»?", + "fleet.organization.addTag": "Додати тег", + "fleet.organization.editTag": "Редагувати тег", + "fleet.organization.tagLabel": "Тег", + "fleet.organization.color": "Колір (#RRGGBB)", + "fleet.organization.tagDescription": "Опис", + "fleet.organization.noTags": "Нормалізовані теги не налаштовані.", + "fleet.organization.tagCreated": "Тег створено", + "fleet.organization.tagUpdated": "Тег оновлено", + "fleet.organization.tagDeleted": "Тег видалено", + "fleet.organization.deleteTagConfirm": "Видалити «{name}»? Він зараз призначений {count} камерам.", + "fleet.organization.merge": "Об'єднати", + "fleet.organization.mergeTagNamed": "Об'єднати «{name}»", + "fleet.organization.mergeInto": "Об'єднати з", + "fleet.organization.chooseTag": "Виберіть тег для збереження", + "fleet.organization.mergeWarning": "Усі призначення камер буде перенесено до збереженого тега; вихідний тег буде видалено.", + "fleet.organization.tagsMerged": "Теги об'єднано", + "fleet.organization.saveError": "Не вдалося зберегти: {message}", + "fleet.organization.deleteError": "Не вдалося видалити: {message}", + "fleet.locationType.site": "Об'єкт", + "fleet.locationType.building": "Будівля", + "fleet.locationType.floor": "Поверх", + "fleet.locationType.area": "Ділянка", + "fleet.locationType.zone": "Зона", + "fleet.locationType.system": "Система", + "fleet.bulk.title": "Організувати вибрані камери", + "fleet.bulk.description": "Застосувати зміни розташування та тегів до {count} камер із обмеженою паралельністю.", + "fleet.bulk.location": "Призначення розташування", + "fleet.bulk.locationHelp": "Усі вибрані камери буде переміщено до обраного розташування.", + "fleet.bulk.keepLocations": "Зберегти поточні розташування", + "fleet.bulk.tags": "Призначення тегів", + "fleet.bulk.tagsHelp": "Додавайте або видаляйте теги, не впливаючи на інші призначення, або явно замініть повний набір тегів.", + "fleet.bulk.tagOperation.none": "Зберегти", + "fleet.bulk.tagOperation.add": "Додати", + "fleet.bulk.tagOperation.remove": "Видалити", + "fleet.bulk.tagOperation.replace": "Замінити всі", + "fleet.bulk.replaceWarning": "«Замінити всі» видаляє всі поточні теги перед застосуванням вибраного. Порожній вибір очищає всі теги.", + "fleet.bulk.apply": "Застосувати зміни", + "fleet.bulk.working": "Застосування змін…", + "fleet.bulk.success": "Оновлено {count} камер", + "fleet.bulk.partial": "Оновлено {succeeded} камер; {failed} не вдалося", + "fleet.bulk.error": "Не вдалося організувати камери: {message}", + "fleet.bulk.failures": "Камери, які не вдалося оновити", + "fleet.queues.degraded": "Деградовані потоки", + "fleet.queues.offline": "Недоступні камери", + "fleet.queues.oldest": "Найстаріший: {time}", + "fleet.queues.noneActive": "Немає активних умов", + "fleet.views.title": "Збережені перегляди", + "fleet.views.choose": "Оберіть збережений перегляд", + "fleet.views.none": "Ще немає збережених переглядів", + "fleet.views.shared": "Спільний", + "fleet.views.saveCurrent": "Зберегти поточний вигляд", + "fleet.views.name": "Назва вигляду", + "fleet.views.share": "Поділитися з усіма операторами", + "fleet.views.saved": "Груповий вигляд збережено", + "fleet.views.saveError": "Не вдалося зберегти вигляд: {message}", + "fleet.views.deleted": "Груповий вигляд видалено", + "fleet.views.deleteConfirm": "Видалити збережений вигляд \"{name}\"?", + "fleet.views.deleteError": "Не вдалося видалити вигляд: {message}", + "fleet.views.unsupported": "Цей збережений селектор неможливо відобразити за допомогою поточних елементів фільтрації.", + "collections.manage": "Колекції", + "collections.all": "Усі колекції", + "collections.filter": "Колекція", + "collections.loadMembersError": "Не вдалося завантажити камери колекції: {message}", + "collections.title": "Колекції камер", + "collections.subtitle": "Створюйте багаторазові групи камер для операцій, збережених виглядів та подальших робочих процесів.", + "collections.listDescription": "Статичні колекції зберігають явний склад; розумні колекції постійно оцінюють групові правила.", + "collections.create": "Створити колекцію", + "collections.edit": "Редагувати колекцію", + "collections.editorDescription": "Визначення колекцій використовують стабільні UUID камер, розташувань і тегів.", + "collections.backToList": "Назад до колекцій", + "collections.type": "Тип колекції", + "collections.type.static": "Статична", + "collections.type.smart": "Розумна", + "collections.description": "Опис", + "collections.shared": "Спільна колекція", + "collections.sharedHelp": "Дозволити іншим авторизованим користувачам бачити цю колекцію; правила доступу до камер залишаються чинними.", + "collections.typeChangeWarning": "Зміна типу колекції замінює модель її складу. Статичні елементи або розумні правила попереднього типу більше не застосовуватимуться.", + "collections.selectorError": "Селектор недійсний: {message}", + "collections.created": "Колекцію створено", + "collections.updated": "Колекцію оновлено", + "collections.saveError": "Не вдалося зберегти колекцію: {message}", + "collections.loadError": "Не вдалося завантажити колекцію: {message}", + "collections.cameras": "камери", + "collections.visibility.shared": "Спільні", + "collections.visibility.private": "Приватні", + "collections.selectorRedacted": "Приватні правила", + "collections.emptyTitle": "Колекцій ще немає", + "collections.emptyAdmin": "Створіть статичну групу або розумний перегляд на основі правил для повторного використання вибору камер.", + "collections.emptyViewer": "Для вашого діапазону камер немає доступних спільних колекцій.", + "collections.deleteConfirm": "Видалити колекцію «{name}»?", + "collections.deleted": "Колекцію видалено", + "collections.deleteError": "Не вдалося видалити колекцію: {message}", + "collections.preview.title": "Попередній перегляд правила", + "collections.preview.matches": "{count} відповідних камер", + "collections.preview.action": "Попередній перегляд", + "collections.preview.hide": "Приховати попередній перегляд", + "collections.preview.loading": "Обчислення…", + "collections.preview.empty": "Зараз немає відповідних камер.", + "collections.preview.sample": "Показано вибірку з {count} камер із {total} відповідників.", + "collections.preview.error": "Не вдалося переглянути колекцію: {message}", + "collections.members.title": "Статичні елементи", + "collections.members.selected": "Вибрано {count} камер на всіх сторінках", + "collections.members.search": "Знайти камери…", + "collections.members.selectPage": "Вибрати цю сторінку", + "collections.members.empty": "За цим запитом камер не знайдено.", + "collections.builder.title": "Розумні правила", + "collections.builder.description": "Правила оцінюються на основі поточної організації, конфігурації, можливостей та стану камер.", + "collections.builder.match": "Відповідність", + "collections.builder.allRules": "усіх правил", + "collections.builder.anyRule": "будь-якого правила", + "collections.builder.addRule": "Додати правило", + "collections.builder.removeRule": "Видалити правило", + "collections.builder.matchesAll": "Без заповнених правил ця колекція відповідає кожній камері в авторизованому діапазоні користувача.", + "collections.builder.incompleteRule": "Завершіть або видаліть кожне правило перед збереженням.", + "collections.builder.chooseLocation": "Виберіть піддерево розташування", + "collections.builder.vendorPlaceholder": "Назви виробників, розділені комою", + "collections.builder.modelPlaceholder": "Назви моделей, розділені комою", + "collections.builder.advancedMode": "Розширений JSON", + "collections.builder.visualMode": "Візуальний конструктор", + "collections.builder.cannotVisualize": "Цей селектор містить вкладену або розширену логіку, яку візуальний конструктор не може безпечно відобразити.", + "collections.rule.location_subtree": "Розташування в межах", + "collections.rule.camera_uuid": "Конкретні камери", + "collections.rule.tag_any": "Має будь-який тег", + "collections.rule.tag_all": "Має всі теги", + "collections.rule.tag_none": "Не має жодного з тегів", + "collections.rule.health": "Стан", + "collections.rule.enabled": "Камера", + "collections.rule.recording_mode": "Режим запису", + "collections.rule.capability_any": "Має будь-яку можливість", + "collections.rule.capability_all": "Має всі можливості", + "collections.rule.vendor": "Виробник", + "collections.rule.model": "Модель", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "Зворотний аудіоканал", + "streamHealth.observedFps": "Спостережуваний FPS", + "streamHealth.expectedFps": "Очікуваний", + "streamHealth.fpsHelp": "Спостерігається LightNVR; очікуване значення надходить із метаданих потоку камери.", + "login.passwordChanged": "Пароль успішно змінено. Увійдіть із новим паролем.", + "passwordChangeRequired.title": "Змініть пароль за замовчуванням", + "passwordChangeRequired.description": "Ця інсталяція досі використовує пароль адміністратора за замовчуванням. Змініть його перед продовженням роботи в LightNVR. MFA, якщо увімкнено, буде перевірено при наступному вході.", + "passwordChangeRequired.currentPassword": "Поточний пароль", + "passwordChangeRequired.newPassword": "Новий пароль", + "passwordChangeRequired.confirmPassword": "Підтвердіть новий пароль", + "passwordChangeRequired.passwordHelp": "Використовуйте щонайменше 8 символів. Пароль не може бути admin.", + "passwordChangeRequired.submit": "Змінити пароль", + "passwordChangeRequired.saving": "Зміна пароля...", + "passwordChangeRequired.error.currentRequired": "Введіть поточний пароль.", + "passwordChangeRequired.error.tooShort": "Новий пароль повинен містити щонайменше 8 символів.", + "passwordChangeRequired.error.defaultPassword": "Новий пароль не може бути admin.", + "passwordChangeRequired.error.mismatch": "Нові паролі не збігаються.", + "passwordChangeRequired.error.generic": "Не вдалося змінити пароль. Спробуйте ще раз.", + "settings.tab.health": "Стан", + "settings.tab.workspaces": "Робочі простори", + "settings.health.title": "Стан хоста та апаратного забезпечення", + "settings.health.description": "Налаштуйте обмежений моніторинг операційної системи та апаратного забезпечення без розкриття шляхів до пристроїв або секретів.", + "settings.health.enabled": "Увімкнути моніторинг стану", + "settings.health.enabledHelp": "Збір підтримуваних сигналів хоста, служб, сховища, мережі та апаратного забезпечення.", + "settings.health.profile": "Профіль політики", + "settings.health.profileHelp": "Збалансований — стандартне значення; консервативний потребує більш переконливих даних перед сповіщенням.", + "settings.health.profile.balanced": "Збалансований", + "settings.health.profile.conservative": "Консервативний", + "settings.health.hardwareProvider": "Провайдер апаратного забезпечення", + "settings.health.provider.auto": "Автоматично (провайдери ядра)", + "settings.health.provider.smartctl": "smartctl (явно)", + "settings.health.providerHelp.auto": "Використовує лише обмежені провайдери sysfs, NVMe та ядра; smartctl ніколи не визначається автоматично.", + "settings.health.providerHelp.smartctl": "Явно вмикає додатковий обмежений провайдер smartctl JSON для виявлених пристроїв.", + "settings.health.providerHelp.disabled": "Вимикає додаткові провайдери апаратного забезпечення, залишаючи доступним портативний моніторинг стану.", + "settings.health.writeProbe": "Увімкнути перевірку запису на сховище", + "settings.health.writeProbeHelp": "Періодично виконує обмежену перевірку налаштованої цілі запису.", + "settings.health.cadences": "Інтервали опитування", + "settings.health.cadencesHelp": "Інтервали повинні бути впорядковані від швидкого до опитування пристроїв і в межах обмежень сервера.", + "settings.health.fastInterval": "Швидкий інтервал", + "settings.health.normalInterval": "Звичайний інтервал", + "settings.health.slowInterval": "Повільний інтервал", + "settings.health.deviceInterval": "Інтервал пристрою", + "settings.health.presenceInterval": "Інтервал присутності", + "settings.health.retention": "Зберігання інцидентів", + "settings.health.conditions": "Перевизначення умов", + "settings.health.conditionsHelp": "Перевизначайте лише коди умов та одиниці, повернуті реєстром чинної політики.", + "settings.health.conditionOverride": "перевизначення умови", + "settings.health.overrideMode": "Режим перевизначення", + "settings.health.overrideModeHelp": "Успадкувати вибраний профіль, вибрати інший обмежений профіль, вимкнути умову або встановити перевірені пороги.", + "settings.health.profileDefault": "Використовувати вибраний профіль", + "settings.health.custom": "Власні пороги", + "settings.health.warning": "Поріг попередження", + "settings.health.critical": "Критичний поріг", + "settings.health.recovery": "Поріг відновлення", + "settings.health.warning_for_seconds": "Тривалість попередження (сек)", + "settings.health.critical_for_seconds": "Тривалість критичного стану (сек)", + "settings.health.recovery_for_seconds": "Тривалість відновлення (сек)", + "settings.health.clearOverrides": "Очистити перевизначення", + "settings.health.registryUnavailable": "Сервер не повернув реєстр умов. Перезавантажте перед редагуванням перевизначень.", + "settings.health.resetDefaults": "Скинути типові значення стану", + "settings.health.reloadGuidance": "Збереження є атомарним. Перезавантажте після успішного збереження для підтвердження чинної політики; перезапускайте лише за явним запитом сервера.", + "settings.health.validation.profile": "Виберіть підтримуваний профіль стану.", + "settings.health.validation.provider": "Виберіть підтримуваного постачальника апаратного забезпечення.", + "settings.health.validation.healthFastIntervalSeconds": "Швидкий інтервал має бути цілим числом від 5 до 60 секунд.", + "settings.health.validation.healthNormalIntervalSeconds": "Звичайний інтервал має бути цілим числом від 15 до 600 секунд.", + "settings.health.validation.healthSlowIntervalSeconds": "Повільний інтервал має бути цілим числом від 60 до 3600 секунд.", + "settings.health.validation.healthDeviceIntervalSeconds": "Інтервал пристрою має бути цілим числом від 300 до 86400 секунд.", + "settings.health.validation.healthPresenceIntervalSeconds": "Інтервал присутності має бути цілим числом від 15 до 3600 секунд.", + "settings.health.validation.healthIncidentRetentionDays": "Термін зберігання інцидентів має бути цілим числом від 7 до 3650 днів.", + "settings.health.validation.ordered": "Інтервали вибірки мають бути впорядковані: швидкий, звичайний, повільний, потім пристрій.", + "settings.health.validation.overrides": "Перевизначення умов мають використовувати унікальні коди та підтримувані профілі з реєстру сервера.", + "settings.health.validation.thresholds": "Власні пороги мають бути скінченними значеннями в межах одиниць умови.", + "settings.health.validation.thresholdOrder": "Пороги попередження, критичного стану та відновлення мають зберігати напрямок тривоги та гістерезис умови.", + "settings.health.validation.dwell": "Тривалості мають бути цілими секундами в межах семи днів; тривалість попередження та відновлення не може дорівнювати нулю.", + "workspaces.title": "Робочі простори оператора", + "workspaces.description": "Виберіть, які спеціалізовані робочі простори відображаються в навігації та інтерфейсі сторінки.", + "workspaces.saved": "Налаштування робочих просторів збережено", + "workspaces.saveError": "Не вдалося зберегти налаштування робочих просторів: {message}", + "workspaces.loadError": "Не вдалося завантажити налаштування робочих просторів.", + "workspaces.showWorkspace": "Показати {name}", + "workspaces.authorizationNote": "Це впливає лише на відображення. Прямі URL-адреси та доступ через API продовжують відповідати вашій політиці авторизації.", + "workspaces.liveNavigator": "Розширений навігатор наживо", + "workspaces.liveNavigatorDescription": "Дерево розташувань, фільтри доступності, збережені макети та останні події.", + "workspaces.investigation": "Розслідування", + "workspaces.investigationDescription": "Пошук, кореляція, захист та експорт записаних доказів.", + "settings.reduceMotion": "Зменшити анімацію", + "settings.reduceMotionHelp": "Вимикає необов'язкові анімації та переходи. Режим «Авто» дотримується налаштувань вашої операційної системи.", + "settings.reduceMotionPreference": "Налаштування зменшення анімації", + "settings.reduceMotionAuto": "Авто", + "settings.reduceMotionOn": "Увімкнено", + "settings.reduceMotionOff": "Вимкнено", + "settings.audioCompliance": "Відповідність щодо аудіо", + "settings.disableAudioGlobally": "Вимкнути аудіо на цьому екземплярі", + "settings.audioDisabled": "Аудіо глобально вимкнено", + "settings.audioComplianceHelp": "Забороняє прослуховування наживо, двосторонній зв'язок та аудіо в нових записах на цьому екземплярі. Збереження перезапускає активні медіасесії go2rtc. Наявні записи не змінюються.", + "tokens.manage": "Керування доступом до API", + "tokens.title": "Доступ до API — {username}", + "tokens.description": "Створюйте вузькоспрямовані облікові дані для інтеграцій та відкликайте кожну окремо.", + "tokens.recommendedTitle": "Рекомендуються токени з обмеженими правами", + "tokens.recommendedDescription": "Кожен токен має термін дії, явні дії та область камер, і ніколи не може перевищувати поточну політику доступу користувача.", + "tokens.coverageNotice": "Доступні дозволи відображають те, що застосовує цей сервер. Токен може використовувати лише дозволи, які вже має його користувач.", + "tokens.createTitle": "Створити токен з обмеженими правами", + "tokens.createDescription": "Використовуйте один токен на інтеграцію, щоб його можна було ідентифікувати, ротаціювати та відкликати без впливу на інші.", + "tokens.name": "Назва інтеграції", + "tokens.namePlaceholder": "напр. PTZ-міст північного гаража", + "tokens.expiry": "Термін дії", + "tokens.expiryDays": "{days} дн.", + "tokens.actions": "Дозволені дії", + "tokens.actionsHelp": "Оберіть лише те, що потрібно цьому інтегруванню. Руйнівні дії потребують власного токена.", + "tokens.destructive": "Руйнівні", + "tokens.noEnforcedActions": "У цій версії сервера немає дій, доступних через токен.", + "tokens.scope.label": "Обсяг камер", + "tokens.scope.all": "Усі камери", + "tokens.scope.collection": "Спільна колекція", + "tokens.scope.selector": "Власний селектор", + "tokens.scope.chooseCollection": "Спільна колекція камер", + "tokens.scope.allValue": "Усі камери", + "tokens.scope.collectionValue": "Колекція: {name}", + "tokens.scope.selectorValue": "Власний динамічний селектор", + "tokens.create": "Створити токен", + "tokens.creating": "Створення токена…", + "tokens.createdSuccess": "Токен API з обмеженнями створено", + "tokens.createError": "Не вдалося створити токен API: {message}", + "tokens.invalidResponse": "Сервер повернув неповну відповідь щодо облікових даних.", + "tokens.existingTitle": "Наявні токени", + "tokens.existingDescription": "Після створення залишаються доступними лише префікси та метадані.", + "tokens.emptyTitle": "Немає активних токенів", + "tokens.emptyDescription": "Створіть токен з обмеженнями для першого інтегрування, якому потрібен доступ до API.", + "tokens.showInactive": "Показати {count} неактивних", + "tokens.status.active": "Активний", + "tokens.status.expired": "Прострочений", + "tokens.status.revoked": "Відкликаний", + "tokens.expires": "Термін дії", + "tokens.expiresValue": "Діє до {date}", + "tokens.created": "Створено", + "tokens.lastUsed": "Останнє використання", + "tokens.revoke": "Відкликати", + "tokens.revoking": "Відкликання…", + "tokens.revokeConfirm": "Відкликати «{description}»? Запити з його використанням негайно припинять роботу.", + "tokens.revokedSuccess": "Токен API відкликано", + "tokens.revokeError": "Не вдалося відкликати токен API: {message}", + "tokens.validation.missing_description": "Вкажіть назву інтеграції, яка використовуватиме цей токен.", + "tokens.validation.description_too_long": "Назва інтеграції має бути не довшою за 128 символів.", + "tokens.validation.invalid_expiry": "Виберіть термін дії токена від 1 до 365 днів.", + "tokens.validation.missing_actions": "Виберіть принаймні одну дозволену дію.", + "tokens.validation.invalid_action": "Одна або кілька вибраних дій не підтримують токени на цьому сервері.", + "tokens.validation.invalid_scope": "Виберіть дійсний обсяг доступу до камер.", + "tokens.validation.requires_all_scope": "Дозволи, що не стосуються камер, потребують обсягу доступу «Усі камери». Виберіть цей обсяг або видаліть ці дозволи.", + "tokens.validation.missing_collection": "Виберіть доступну спільну колекцію.", + "tokens.validation.invalid_selector": "Заповніть або виправте власний селектор камер.", + "tokens.secret.oneTime": "Показано один раз", + "tokens.secret.scopedTitle": "Збережіть цей токен з обмеженим доступом зараз", + "tokens.secret.legacyTitle": "Збережіть цей застарілий ключ API зараз", + "tokens.secret.scopedDescription": "lightNVR зберігає лише хеш цього токена. Якщо він втрачений, відкличте його та створіть новий.", + "tokens.secret.legacyDescription": "Цей ключ сумісності відображається тут лише один раз. Генерація нового ключа зробить його недійсним.", + "tokens.secret.value": "Облікові дані API", + "tokens.secret.copied": "Скопійовано", + "tokens.secret.copySuccess": "Облікові дані API скопійовано", + "tokens.secret.copyError": "Не вдалося скопіювати автоматично; виділіть і скопіюйте облікові дані вручну.", + "tokens.secret.savedConfirm": "Я безпечно зберіг ці облікові дані", + "tokens.secret.savedHelp": "Підтвердження закриє це діалогове вікно. Повне значення не можна буде відобразити повторно.", + "tokens.legacy.title": "Застарілий ключ сумісності", + "tokens.legacy.description": "Застарілий ключ має повний доступ цього користувача, не має терміну дії та не може бути обмежений за камерою чи дією.", + "tokens.legacy.warning": "Генеруйте лише для існуючої інтеграції, кінцеві точки якої ще не перейшли на обов'язкове використання токенів з обмеженим доступом. Генерація негайно робить попередній застарілий ключ недійсним.", + "tokens.legacy.generate": "Згенерувати застарілий ключ", + "tokens.legacy.confirm": "Згенерувати новий застарілий ключ? Це негайно зробить поточний застарілий ключ користувача недійсним.", + "tokens.legacy.createdSuccess": "Застарілий ключ API згенеровано", + "tokens.legacy.createError": "Не вдалося згенерувати застарілий ключ API: {message}", + "audit.manage": "Історія аудиту", + "audit.title": "Аудит безпеки та доступу", + "audit.description": "Відстежуйте результати входу, рішення щодо доступу та зміни конфіденційних політик без розкриття облікових даних.", + "audit.retention": "Зберігання", + "audit.retentionDescription": "Події зберігаються протягом {days} днів. Зменшення цього значення негайно видаляє старішу історію.", + "audit.retentionDays": "Днів", + "audit.retentionInvalid": "Оберіть період зберігання від 1 до 3650 днів.", + "audit.retentionSaved": "Налаштування зберігання аудиту збережено; видалено {count} прострочених подій", + "audit.retentionError": "Не вдалося зберегти налаштування зберігання аудиту: {message}", + "audit.filters": "Фільтри", + "audit.clearFilters": "Очистити фільтри", + "audit.applyFilters": "Застосувати фільтри", + "audit.actor": "Суб'єкт", + "audit.unauthenticated": "Неавтентифікований", + "audit.outcome": "Результат", + "audit.action": "Точна дія", + "audit.filterToAction": "Фільтрувати за цією дією", + "audit.since": "Від", + "audit.until": "До", + "audit.invalidDateRange": "Дата «Від» повинна бути раніше за дату «До».", + "audit.source": "Адреса джерела", + "audit.target": "Ціль", + "audit.targetUuid": "UUID цілі", + "audit.noTarget": "Загальносистемний", + "audit.requestId": "ID запиту", + "audit.apiToken": "ID обмеженого токена", + "audit.showDetails": "Показати деталі", + "audit.hideDetails": "Приховати деталі", + "audit.pageSize": "На сторінці", + "audit.resultRange": "Показано {start}–{end} з {total}", + "audit.empty": "Немає відповідних подій аудиту", + "audit.emptyDescription": "Спробуйте очистити один або кілька фільтрів або зачекайте на нову активність безпеки.", + "audit.exportPage": "Експортувати цю сторінку", + "audit.exporting": "Експортування…", + "audit.exported": "Сторінку аудиту експортовано", + "audit.exportError": "Не вдалося експортувати події аудиту: {message}", + "audit.pagination": "Сторінки історії аудиту", + "audit.page": "Сторінка {page}", + "audit.modesTitle": "Дозволені рішення", + "audit.modesDescription": "Виберіть, як записувати дозволений доступ лише для читання для кожної дії. Запити, що змінюють щось, відмови, помилки та входи в систему записуються завжди. Режим «Узагальнювати» зберігає один запис на користувача, камеру та клієнт кожні {minutes} хвилин із лічильником.", + "audit.mode.record": "Записувати кожну", + "audit.mode.summarize": "Узагальнювати", + "audit.mode.off": "Вимкнено", + "audit.modeOffWarning": "Дозволений доступ для цієї дії більше не відображатиметься в історії аудиту.", + "audit.modesSaved": "Режими рішень аудиту збережено", + "audit.modesError": "Не вдалося зберегти режими рішень аудиту: {message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "Тип події", + "audit.eventTypeSummary": "Узагальнення", + "audit.eventTypeDecision": "Індивідуальні рішення", + "access.cameraSearch": "Пошук камер", + "access.cameraSearchPlaceholder": "Введіть щонайменше два символи для пошуку…", + "access.cameraSearchHint": "Пошук за назвою камери, UUID, адресою, розташуванням, тегом, виробником або моделлю.", + "access.cameraSelected": "Вибрано", + "access.cameraAdd": "Додати", + "access.cameraLimit": "Селектор може містити щонайбільше 64 явно вказані камери. Для більших обсягів використовуйте правило за розташуванням або тегом.", + "access.roles.manage": "Керування ролями", + "access.roles.title": "Ролі авторизації", + "access.roles.description": "Групуйте дії в багаторазові ролі, потім надавайте ці ролі для обсягів камер.", + "access.roles.create": "Створити роль", + "access.roles.newRole": "Нова роль", + "access.roles.copyName": "{name} (копія)", + "access.roles.clone": "Клонувати", + "access.roles.builtin": "Вбудована", + "access.roles.builtinHelp": "Вбудовані ролі — це незмінні шаблони, безпечні при оновленні. Клонуйте роль, щоб налаштувати її.", + "access.roles.actionCount": "{count} дій", + "access.roles.destructive": "Чутлива дія", + "access.roles.notEnforced": "Ще не застосовується жодним ендпоінтом", + "access.roles.destructiveWarning": "Ця роль може змінювати конфігурацію або докази. Надавайте її лише в межах областей, де потрібні такі повноваження.", + "access.roles.created": "Роль створено", + "access.roles.updated": "Роль оновлено", + "access.roles.deleted": "Роль видалено", + "access.roles.saveError": "Не вдалося зберегти роль: {message}", + "access.roles.deleteError": "Не вдалося видалити роль: {message}", + "access.roles.deleteConfirm": "Видалити роль «{name}»? Ролі, на які посилаються надання, не можна видалити.", + "access.policy.manage": "Керування доступом", + "access.policy.column": "Доступ", + "access.policy.scopedShort": "З обмеженнями", + "access.policy.title": "Політика доступу — {username}", + "access.policy.description": "Керуйте наданнями ролей із політикою заборони за замовчуванням та переглядайте їхні області камер.", + "access.policy.tab.grants": "Надання", + "access.policy.tab.test": "Перевірити доступ", + "access.policy.scopedWarning": "Працюватимуть лише дії, дозволені відповідним наданням та областю камер.", + "access.policy.grants": "Надання ролей", + "access.policy.grantsDescription": "Надання поєднує одну роль з усім парком камер, спільною колекцією або власним селектором камер.", + "access.policy.addGrant": "Додати надання", + "access.policy.noGrants": "Надання не налаштовано", + "access.policy.noGrantsHelp": "Додайте принаймні одне надання перед активацією політики з обмеженнями, якщо цей користувач не повинен мати доступу.", + "access.policy.role": "Роль", + "access.policy.chooseRole": "Оберіть роль", + "access.policy.scope": "Область камер", + "access.policy.allCameras": "Увесь парк камер", + "access.policy.collectionScope": "Спільна колекція", + "access.policy.collection": "Колекція камер", + "access.policy.chooseCollection": "Оберіть спільну колекцію", + "access.policy.collectionHelp": "Доступ відстежує колекцію під час додавання, видалення або відповідності камер за її правилами.", + "access.policy.dynamicScope": "Динамічний селектор", + "access.policy.activateConfirm": "Активувати політику з обмеженнями (заборона за замовчуванням) для {username}? Дії без відповідного надання будуть відхилені.", + "access.policy.emptyConfirm": "Активувати політику з обмеженнями для {username} без надань? Це навмисно видаляє весь доступ, контрольований політикою.", + "access.policy.saved": "Політику доступу збережено", + "access.policy.saveError": "Не вдалося зберегти політику доступу: {message}", + "access.policy.version": "Версія політики {version}", + "access.policy.unsaved": "Незбережені зміни", + "access.policy.validation.invalid_mode": "Виберіть дійсний режим оцінювання.", + "access.policy.validation.missing_role": "Кожне надання має посилатися на доступну роль.", + "access.policy.validation.invalid_scope": "Кожне надання має використовувати область для всього парку, спільної колекції або селектора.", + "access.policy.validation.invalid_selector": "Заповніть або виправте кожен селектор камери перед збереженням.", + "access.policy.validation.missing_collection": "Виберіть доступну спільну колекцію для кожного надання колекції.", + "access.policy.validation.duplicate_grant": "Видаліть дублікати надань ролей і областей перед збереженням.", + "access.test.title": "Перевірити фактичний доступ", + "access.test.description": "Оцінити збережену дію та камеру від імені {username} без її виконання.", + "access.test.saveFirst": "Збережіть або відхиліть зміни надань перед перевіркою, щоб результат відповідав політиці, показаній тут.", + "access.test.action": "Дія", + "access.test.camera": "Камера", + "access.test.run": "Перевірити доступ", + "access.test.running": "Перевірка…", + "access.test.allowed": "Дозволено", + "access.test.denied": "Заборонено", + "access.test.version": "Версія {version}", + "access.test.source": "Джерело: {source} · Роль: {role}", + "recordings.pullToRefresh": "Потягніть для оновлення записів", + "recordings.releaseToRefresh": "Відпустіть для оновлення записів", + "recordings.refreshing": "Оновлення записів…", + "recordings.refreshed": "Записи оновлено", + "recordings.refreshFailed": "Не вдалося оновити записи: {message}", + "recordings.download": "Завантажити", + "recordings.tags": "Теги", + "recordings.selectRecording": "Вибрати запис", + "timeline.legend.recording": "Запис", + "timeline.legend.detection": "Подія виявлення", + "timeline.detectionEvent": "Подія виявлення", + "streams.showCredentials": "Показати облікові дані", + "streams.hideCredentials": "Приховати облікові дані", + "streams.streamSuccessfullyEnabled": "Потік успішно увімкнено.", + "streams.errorEnablingStream": "Помилка ввімкнення потоку: {message}", + "system.health.tab": "Стан", + "system.health.operatorView": "Операційний стан", + "system.health.title": "Стан системи", + "system.health.loading": "Завантаження стану системи…", + "system.health.loadError": "Не вдалося завантажити стан системи.", + "system.health.refreshing": "Оновлення…", + "system.health.activeIncidentCount": "{count} активних інцидентів", + "system.health.coverage": "Покриття", + "system.health.monitoringDisabled": "Моніторинг стану вимкнено", + "system.health.lastRecordedValue": "Останнє записане значення", + "system.health.monitoringDisabledHelp": "Поточні дані про стан не збираються. Увімкніть моніторинг стану в Налаштування → Стан; за потреби перезавантажте після збереження. Історія інцидентів відображає минулі події, а не поточне використання ресурсів.", + "system.health.monitoringRestartRequired": "Моніторинг стану ввімкнено в збереженій конфігурації, але запущений збирач досі вимкнено. Перезапустіть LightNVR, щоб застосувати зміни. Історія інцидентів відображає минулі події.", + "system.health.containerCoverage": "Обмежене покриття хоста", + "system.health.hostHardwareUnavailable": "Ця інсталяція бачить стан контейнерів і монтованих ресурсів, але апаратне забезпечення хоста недоступне. Відсутні значення хоста є невідомими, а не справними.", + "system.health.coverageUnknown": "Завершений знімок стану ще недоступний. Значення залишаються невідомими до завершення збору.", + "system.health.coverageComplete": "Усі дані, доступні цій інсталяції, зібрано успішно.", + "system.health.coveragePartial": "Покриття неповне. {count} спостережень або перевірок збору недоступні, застарілі або неповні.", + "system.health.effectiveScope": "Фактична область", + "system.health.activeIncidents": "Активні інциденти", + "system.health.noActiveIncidents": "Для видимого покриття активних інцидентів не зафіксовано.", + "system.health.duration": "Тривалість", + "system.health.currentValue": "Поточне значення", + "system.health.thresholds": "Поріг і час утримання", + "system.health.thresholdSummary": "Попередження {warning}, критичний {critical}, відновлення {recovery} {unit}; час утримання попередження {seconds} с", + "system.health.remediation": "Рекомендовані дії", + "system.health.facts": "Дані про стан", + "system.health.group.resources": "Ресурси", + "system.health.group.storage": "Зберігання", + "system.health.group.hardware": "Апаратне забезпечення", + "system.health.group.network": "Мережа", + "system.health.group.clock": "Годинник", + "system.health.group.components": "Компоненти", + "system.health.noFacts": "У цій групі немає видимих фактів.", + "system.health.observationState": "Можливості та актуальність", + "system.health.valueUnavailable": "Одне або кілька значень невідомі", + "system.health.componentStatus": "Компоненти моніторингу", + "system.health.collectors": "Збирачі", + "system.health.collectorSummary": "{total} зареєстровано · {attention} потребують уваги", + "system.health.collectorsNeedingAttention": "Збирачі, що потребують уваги", + "system.health.collectionFailures": "{count} збоїв або тайм-аутів", + "system.health.stale": "застарілі", + "system.health.eventDelivery": "Доставка подій", + "system.health.degraded": "Деградовано", + "system.health.circularDelivery": "Це єдиний налаштований шлях оповіщення, тому він не може незалежно повідомити про власну несправність.", + "system.health.incidentPersistence": "Збереження інцидентів", + "system.health.persistenceSummary": "{pending} у черзі · {failures} збоїв · {retries} повторних спроб", + "system.health.recentSamples": "Остання активність збору", + "system.health.recentSamplesHelp": "До {count} обмежених серверних зведень генерацій; це активність покриття, а не графік значень.", + "system.health.sampleSequence": "Генерація {sequence}", + "system.health.sampleCoverage": "{observations} спостережень · {dropped} відкинуто", + "system.health.noSamples": "Немає завершених генерацій збору.", + "system.health.incidentHistory": "Історія інцидентів", + "system.health.incidentHistoryHelp": "Спочатку найновіші інциденти. Історія завантажується обмеженими сторінками.", + "system.health.loadingHistory": "Завантаження історії інцидентів…", + "system.health.historyError": "Не вдалося завантажити історію інцидентів.", + "system.health.emptyHistory": "Інциденти не зафіксовані.", + "system.health.firstSeen": "Вперше виявлено", + "system.health.lastSeen": "Востаннє виявлено", + "system.health.deliveryState": "Стан доставки", + "system.health.historyPagination": "Сторінки історії інцидентів", + "system.health.pageCount": "{count} інцидентів на цій сторінці", + "system.health.remediation.memory": "Зменшіть тиск на пам'ять, перевірте ліміти процесів і cgroup, перегляньте останню активність OOM.", + "system.health.remediation.cpu": "Визначте постійних споживачів CPU та перевірте пропускну здатність служби перед зміною лімітів.", + "system.health.remediation.io": "Перевірте затримку сховища та активних записувачів; збережіть записи перед обслуговуванням із перериванням роботи.", + "system.health.remediation.filesystem": "Перевірте вказану логічну файлову систему, вільний простір або inode-и та підтвердіть, що вона залишається доступною для запису.", + "system.health.remediation.thermal": "Покращіть охолодження та зменшіть навантаження; перевірте вентилятори та вентиляційні отвори до досягнення температур вимкнення.", + "system.health.remediation.network": "Перевірте видимий інтерфейс, з'єднання, комутатор і лічильники помилок з незалежного мережевого шляху.", + "system.health.remediation.clock": "Відновіть синхронізацію часу та перевірте джерело годинника хоста перед використанням часових міток подій.", + "system.health.remediation.process": "Перевірте ліміти ресурсів LightNVR та журнали, потім зменшіть навантаження або підвищте підтверджені ліміти.", + "system.health.remediation.storage": "Зробіть резервну копію важливих записів і перевірте підключений пристрій зберігання перед заміною або ремонтом.", + "system.health.remediation.hardware": "Перевірте відповідне апаратне забезпечення та журнали платформи; заплануйте обслуговування, якщо стан не змінюється.", + "system.health.remediation.health": "Відновіть доступ і дозволи збирача, щоб оцінити відсутні дані про стан.", + "system.health.remediation.system": "Перегляньте попередній запуск і журнали хоста, щоб відрізнити перезапуск процесу від перезавантаження хоста.", + "system.health.remediation.event": "Використовуйте локальний API або перегляд метрик, зніміть тиск на стійку чергу та відновіть незалежне призначення сповіщень.", + "system.health.remediation.default": "Перегляньте відповідний компонент і останні журнали, потім підтвердіть відновлення у новому циклі перевірки стану.", + "system.capacityTarget": "Цільова місткість", + "system.capacityTargetValue": "Тримати {pct}% вільними", + "system.fillRate": "Швидкість заповнення", + "system.fillRateValue": "{value} / день", + "system.projectedToTarget": "Прогнозований час до цілі", + "system.projectedNow": "Зараз на/вище цілі", + "system.projectedDays": "~{count} дн.", + "system.projectedHours": "~{count} год", + "system.projectedUnknown": "—", + "common.description": "Опис", + "common.remove": "Видалити", + "streams.selectStream": "Вибрати {name}", + "streams.search": "Пошук потоків", + "streams.searchPlaceholder": "Пошук камер, розташувань або тегів", + "streams.noStreamsMatchFilters": "Немає потоків, що відповідають поточним фільтрам.", + "streamHealth.sourceConnected": "Джерело підключено", + "streamHealth.videoAdvancing": "Відео відтворюється", + "streamHealth.recorderWriting": "Записувач записує", + "streamHealth.detectorOperating": "Детектор працює", + "streamHealth.lastSegment": "Останній завершений сегмент", + "streams.disablingStreamsProgress": "Вимкнення потоків…", + "streams.onvifInvalidAddress": "IP-адреса пристрою ONVIF відсутня або недійсна.", + "streams.warningFallingBackToHttp": "Підключення HTTPS не вдалося; повторна спроба через HTTP. Облікові дані можуть передаватися у відкритому вигляді.", + "streamsConfig.playbackTransport": "Транспорт відтворення", + "streamsConfig.playbackTransportHelp": "Виберіть метод відтворення у браузері для цієї камери та, за наявності, порядок резервних варіантів.", + "streamsConfig.playbackTransportUnavailable": "Недоступно на сервері: {transports}. Увімкніть транспорт глобально або виберіть інший профіль.", + "streamsConfig.audioDisabledByPolicy": "Аудіо вимкнено політикою екземпляра", + "streamsConfig.audioDisabledByPolicyHelp": "Запис, прослуховування наживо та двосторонній зв'язок недоступні, доки увімкнено глобальну політику відповідності аудіо.", + "streamsConfig.audioVoiceEnhancement": "Покращення голосу (записи)", + "streamsConfig.customApiModel": "Виявлення через власний API", + "streamsConfig.modelNotSupportedByBuild": "не підтримується цією збіркою", + "streamsConfig.tierCriticalMultiplier": "Критичний рівень ×", + "streamsConfig.tierImportantMultiplier": "Важливий рівень ×", + "streamsConfig.tierEphemeralMultiplier": "Тимчасовий рівень ×", + "streamsConfig.tierMultipliersHelp": "Множники для кожного рівня щодо базового терміну зберігання. Відео вищих рівнів зберігається довше і видаляється останнім при нестачі місця на диску.", + "streamsConfig.storagePriority": "Пріоритет зберігання (1-10)", + "streamsConfig.storagePriorityHelp": "Відносна важливість відео цього потоку при звільненні місця; вищий пріоритет зберігається довше.", + "streamsConfig.restream": "Ретрансляція / Публікація (RTMP)", + "streamsConfig.publishUrl": "URL публікації (RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "Ретранслюйте цю камеру на сервіс, наприклад YouTube Live, через go2rtc. Вставте повну URL-адресу приймання RTMP разом із ключем потоку (наприклад, rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx). Щоб ретранслювати на кілька сервісів одночасно, розділіть URL-адреси комами. YouTube вимагає відео H264 та аудіо AAC; LightNVR тепер автоматично перекодує (H264 для камер без H264, AAC для аудіо без AAC), тому більшість камер працюють без додаткових налаштувань. Примітка: YouTube також вимагає аудіодоріжку — камера без аудіо взагалі все одно буде відхилена. Залиште порожнім, щоб вимкнути.", + "streams.lastSeen": "Востаннє видно {time}", + "streams.claimed": "Заявлено", + "streams.duplicateSuspected": "Можливий дублікат", + "streams.duplicateSuspectedHelp": "Стабільна ідентичність або докази кінцевої точки конфліктують з іншим записом виявлення.", + "streams.onvifClaimWarning": "Потік додано, але його запис виявлення не вдалося позначити як зайнятий: {message}", + "common.online": "Онлайн", + "common.offline": "Офлайн", + "settings.storageTargets.title": "Цілі зберігання записів", + "settings.storageTargets.description": "Зареєструйте локальні диски та файлові системи NFS або SMB, змонтовані адміністратором, як незалежно відстежувані місця зберігання записів.", + "settings.storageTargets.foundationNotice": "Запис використовує цілі файлової системи. Контейнери S3 та змонтовані цілі NFS/SAN можуть зберігати перевірені архівні копії. Тиск на гарячий шар зберігає архівовані записи до закінчення терміну їхнього логічного зберігання.", + "settings.storageTargets.add": "Додати ціль зберігання", + "settings.storageTargets.edit": "Редагувати ціль зберігання", + "settings.storageTargets.editorHelp": "Увімкнені цілі мають вже існувати та проходити перевірку запису, fsync та очищення. Збережіть недоступне майбутнє монтування як вимкнене, а потім увімкніть після монтування.", + "settings.storageTargets.name": "Назва цілі", + "settings.storageTargets.root": "Шлях змонтованого кореня", + "settings.storageTargets.rootLocked": "Ціль за замовчуванням або непорожня ціль зберігає незмінний корінь, щоб наявні записи не стали ізольованими.", + "settings.storageTargets.class": "Клас продуктивності", + "settings.storageTargets.hot": "Гарячий — активний запис", + "settings.storageTargets.warm": "Теплий — змонтований архів", + "settings.storageTargets.cold": "Холодний — рідкісний доступ", + "settings.storageTargets.reserveGb": "Зарезервований запас (ГБ)", + "settings.storageTargets.lowWatermark": "Нижній поріг (% використання)", + "settings.storageTargets.highWatermark": "Верхній поріг (% використання)", + "settings.storageTargets.migrationBandwidth": "Пропускна здатність життєвого циклу (Мбіт/с)", + "settings.storageTargets.migrationBandwidthHelp": "0 — без обмежень. Обмеження фіксується при створенні завдання переміщення або копіювання.", + "settings.storageTargets.archiveStart": "Початок вікна архівування", + "settings.storageTargets.archiveEnd": "Закінчення вікна архівування", + "settings.storageTargets.archiveWindowHelp": "Місцевий час. Однакові часи початку та закінчення дозволяють завдання життєвого циклу цілодобово; нічне вікно може перетинати північ.", + "settings.storageTargets.enabled": "Увімкнено (політики розміщення можуть обрати цю ціль)", + "settings.storageTargets.notRouted": "Жодна увімкнена політика розміщення не спрямовує камери сюди. Нові записи продовжують надходити на ціль за замовчуванням, доки політика не призначить цю ціль як основну, учасника пулу або ціль архівування.", + "settings.storageTargets.degradedNotice": "Вище верхнього порогу або в межах резерву. Політики розміщення пропускають цю ціль, доки не буде звільнено місце.", + "settings.storageTargets.probePassedIneligible": "Перевірка запису пройдена, але ціль має статус {status}: політики розміщення не будуть її обирати.", + "settings.storageTargets.mountRequired": "Вимагати змонтовану файлову систему", + "settings.storageTargets.mountRequiredHelp": "Закріпити цю ціль за поточною некореневою точкою монтування. Якщо це монтування NFS, SMB, bind або PVC зникне, запис зупиниться замість запису в базовий каталог хоста.", + "settings.storageTargets.mountGuard": "Обов'язкове монтування", + "settings.storageTargets.mountPending": "Буде виявлено при увімкненні цілі", + "settings.storageTargets.default": "За замовчуванням", + "settings.storageTargets.capacity": "Ємність", + "settings.storageTargets.available": "Доступно", + "settings.storageTargets.recordings": "Індексовані записи", + "settings.storageTargets.replicas": "{count} перевірені копії · {bytes}", + "settings.storageTargets.reserve": "Зарезервовано", + "settings.storageTargets.pressure.normal": "Тиск у нормі", + "settings.storageTargets.pressure.high": "Верхня позначка", + "settings.storageTargets.pressure.reserve": "Резерв вичерпано", + "settings.storageTargets.pressure.unavailable": "Тиск недоступний", + "settings.storageTargets.cleanupActive": "Очищення в межах цілі активне та працюватиме до досягнення {target} вільного місця без видалення записів, призначених іншій цілі.", + "settings.storageTargets.test": "Перевірити ціль", + "settings.storageTargets.probing": "Перевірка…", + "settings.storageTargets.probePassed": "Тест запису на ціль зберігання пройдено", + "settings.storageTargets.duplicateFilesystem": "Цей корінь використовує ту саму файлову систему, що й інша ціль. Місткість не повинна враховуватися двічі, коли увімкнено розміщення.", + "settings.storageTargets.deleteLocked": "Цілі за замовчуванням та непорожні цілі не можна видалити.", + "settings.storageTargets.deleteConfirm": "Видалити порожню ціль зберігання «{name}»? Файли не буде видалено.", + "settings.storageTargets.created": "Ціль зберігання створено", + "settings.storageTargets.updated": "Ціль зберігання оновлено", + "settings.storageTargets.deleted": "Ціль зберігання видалено", + "settings.storageTargets.invalidThresholds": "Перевірте позначки, резерв, пропускну здатність життєвого циклу та часи архівного вікна.", + "settings.storageTargets.loadError": "Не вдалося завантажити цілі зберігання", + "settings.storagePools.title": "Пули зберігання", + "settings.storagePools.description": "Групуйте справні цілі для автоматичного переливання та реплікації на різні цілі.", + "settings.storagePools.add": "Додати пул", + "settings.storagePools.strategy": "Стратегія розподілу", + "settings.storagePools.mostFree": "Найбільше вільного місця", + "settings.storagePools.roundRobin": "Ротація", + "settings.storagePools.priority": "Явний пріоритет", + "settings.storagePools.members": "Цілі (порядок відображення — пріоритет розподілу)", + "settings.storagePools.enabled": "Пул увімкнено", + "settings.storagePools.active": "Активний", + "settings.storagePools.inactive": "Вимкнено", + "settings.storagePools.strategyValue.most_free": "найбільше вільного", + "settings.storagePools.strategyValue.round_robin": "ротація", + "settings.storagePools.strategyValue.priority": "за пріоритетом", + "settings.storagePools.created": "Пул зберігання створено", + "settings.storagePools.updated": "Сховище оновлено", + "settings.storagePools.deleted": "Сховище видалено", + "settings.storagePools.deleteConfirm": "Видалити сховище «{name}»?", + "settings.storagePools.empty": "Ще немає сховищ.", + "settings.storageMigrations.title": "Завдання міграції записів", + "settings.storageMigrations.description": "Надійні переміщення та збережені копії дотримуються архівного вікна та обмеження пропускної здатності кожної цілі, перевіряють SHA-256 та безпечно відновлюються після перезапуску.", + "settings.storageMigrations.empty": "Ще немає завдань міграції записів.", + "settings.storageMigrations.loadError": "Не вдалося завантажити завдання міграції записів", + "settings.storageMigrations.recording": "Запис #{id}", + "settings.storageMigrations.attempt": "Спроба {current}/{max}", + "settings.storageMigrations.operation.move": "Переміщення", + "settings.storageMigrations.operation.copy": "Збережена копія", + "settings.storageMigrations.cancelled": "Скасування міграції прийнято", + "settings.storageMigrations.cancelling": "Скасування…", + "settings.storageMigrations.retried": "Міграцію поставлено в чергу для повторної спроби", + "settings.storageMigrations.state.queued": "У черзі", + "settings.storageMigrations.state.copying": "Копіювання", + "settings.storageMigrations.state.verifying": "Перевірка", + "settings.storageMigrations.state.committing": "Застосування", + "settings.storageMigrations.state.cleanup_pending": "Очищення джерела", + "settings.storageMigrations.state.retry_wait": "Очікування повторної спроби", + "settings.storageMigrations.state.completed": "Завершено", + "settings.storageMigrations.state.failed": "Помилка", + "settings.storageMigrations.state.cancelled": "Скасовано", + "settings.storagePolicies.title": "Політики розміщення камер", + "settings.storagePolicies.description": "Маршрутизація відповідних камер до основної цілі запису за пріоритетом. Камера використовує першу увімкнену політику, що відповідає.", + "settings.storagePolicies.add": "Додати політику розміщення", + "settings.storagePolicies.edit": "Редагувати політику розміщення", + "settings.storagePolicies.editorHelp": "Політика повторно оцінюється для нових сегментів. Зміни не переміщують записи, які вже існують.", + "settings.storagePolicies.priority": "Пріоритет (вищий перший)", + "settings.storagePolicies.priorityValue": "Пріоритет {priority}", + "settings.storagePolicies.primary": "Основна ціль", + "settings.storagePolicies.primaryPool": "Пул розміщення (необов'язково)", + "settings.storagePolicies.exactTarget": "Використовувати точну основну ціль", + "settings.storagePolicies.fallback": "Якщо основна недоступна", + "settings.storagePolicies.fallbackDefault": "Використовувати ціль за замовчуванням", + "settings.storagePolicies.fallbackTarget": "Використовувати іменовану резервну ціль", + "settings.storagePolicies.fallbackPause": "Призупинити запис", + "settings.storagePolicies.fallbackFail": "Помилка запуску запису", + "settings.storagePolicies.namedFallback": "Резервна ціль", + "settings.storagePolicies.chooseTarget": "Виберіть ціль", + "settings.storagePolicies.choosePool": "Виберіть пул", + "settings.storagePolicies.minimumDays": "Мінімальне зберігання (днів)", + "settings.storagePolicies.desiredDays": "Бажане зберігання (днів)", + "settings.storagePolicies.maximumDays": "Максимальне зберігання (днів)", + "settings.storagePolicies.copyCount": "Необхідні перевірені копії", + "settings.storagePolicies.replicationPool": "Пул реплікації", + "settings.storagePolicies.migrateAfter": "Перемістити через (днів)", + "settings.storagePolicies.migrationTarget": "Ціль архівування", + "settings.storagePolicies.pressurePriority": "Пріоритет видалення при перевантаженні (спочатку нижчі)", + "settings.storagePolicies.disabledTarget": "вимкнено", + "settings.storagePolicies.enabled": "Політику увімкнено", + "settings.storagePolicies.selector": "Відповідні камери", + "settings.storagePolicies.preview": "Попередній перегляд пріоритету", + "settings.storagePolicies.previewing": "Оцінювання…", + "settings.storagePolicies.previewRequired": "Перегляньте поточний проєкт перед збереженням, щоб побачити перекриття камер і дійсну пріоритетну політику.", + "settings.storagePolicies.previewSummary": "Відповідає {matched} камерам; цей проєкт діє для {effective}.", + "settings.storagePolicies.previewShadowed": "Політика з вищим пріоритетом переважає для {count} відповідних камер.", + "settings.storagePolicies.previewWins": "Переважає над «{policy}» (пріоритет {priority}) для {count} камер.", + "settings.storagePolicies.previewLoses": "Прогріває «{policy}» (пріоритет {priority}) для {count} камер.", + "settings.storagePolicies.previewNoMatches": "Цей селектор наразі не відповідає жодній камері.", + "settings.storagePolicies.invalidPriority": "Пріоритет має бути цілим числом від -1 000 000 до 1 000 000.", + "settings.storagePolicies.invalidLifecycle": "Перевірте порядок зберігання, кількість копій і пул реплікації, а також вік і ціль міграції.", + "settings.storagePolicies.created": "Політику розміщення створено", + "settings.storagePolicies.updated": "Політику розміщення оновлено", + "settings.storagePolicies.deleted": "Політику розміщення видалено", + "settings.storagePolicies.deleteConfirm": "Видалити політику розміщення \"{name}\"? Наявні записи не будуть змінені.", + "settings.storagePolicies.active": "Активна", + "settings.storagePolicies.inactive": "Вимкнено", + "settings.storagePolicies.routesTo": "Основна ціль: {target}", + "settings.storagePolicies.lifecycleSummary": "Зберігання мін./бажане/макс.: {minimum}/{desired}/{maximum} дн. · {copies} перевірених копій", + "settings.storagePolicies.fallsBackTo": "Резервна ціль: {target}", + "settings.storagePolicies.mode.default": "Резервний: ціль за замовчуванням", + "settings.storagePolicies.mode.pause": "Резервний: призупинити запис", + "settings.storagePolicies.mode.fail": "Резервний: відмова при початку запису", + "settings.storagePolicies.empty": "Немає політик розміщення. Камери продовжують використовувати ціль за замовчуванням; інші цілі не отримують нічого, доки політика не направить до них камери.", + "settings.storagePolicies.archiveNoTrigger": "Ціль архівування встановлено, але ніщо не запускає переміщення. Встановіть «Перемістити після віку (днів)», вік архівування або параметр архівування; інакше жодні записи не будуть переміщені.", + "settings.storageCompliance.title": "Ємність і відповідність політиці", + "settings.storageCompliance.description": "Спостережувані 30-денні показники прогнозують тиск на ціль і досягнуте зберігання; активні порушення життєвого циклу залишаються видимими до усунення.", + "settings.storageCompliance.loadError": "Не вдалося завантажити відповідність зберігання", + "settings.storageCompliance.unknown": "Невідомо", + "settings.storageCompliance.days": "{days} дн.", + "settings.storageCompliance.day": "день", + "settings.storageCompliance.targetForecasts": "Прогнози цілей", + "settings.storageCompliance.target": "Ціль", + "settings.storageCompliance.dailyRate": "Спостережуваний показник", + "settings.storageCompliance.toHigh": "До верхнього порогу", + "settings.storageCompliance.expected": "Очікуване зберігання", + "settings.storageCompliance.confidence": "Впевненість", + "settings.storageCompliance.policyCompliance": "Відповідність політиці", + "settings.storageCompliance.compliant": "Немає активних порушень", + "settings.storageCompliance.violationCount": "{count} порушень", + "settings.storageCompliance.policyForecast": "Досягнуто {achieved}; прогноз {expected}; бажано {desired} дн.", + "settings.storageCompliance.copyDeficits": "{count} записів потребують ще однієї перевіреної копії.", + "settings.storageCompliance.activeViolations": "Активні порушення", + "settings.storageCompliance.type.copy_count": "Кількість копій", + "settings.storageCompliance.type.minimum_retention": "Мінімальна місткість зберігання", + "settings.storageCompliance.type.target_unavailable": "Ціль недоступна", + "settings.storageCompliance.type.migration_failed": "Помилка завдання життєвого циклу", + "settings.recordingDirectoryFormat": "Структура папок записів", + "settings.recordingDirectoryFormatHelp": "Розподіляє нові MP4-записи у підпапках кожної камери. Наявні записи не переміщуються.", + "settings.recordingDirectoryFlat": "Плоска (лише папка камери)", + "settings.recordingDirectoryMonth": "За місяцями (РРРР/ММ)", + "settings.recordingDirectoryDay": "За днями (РРРР/ММ/ДД)", + "settings.minFreePct": "Мінімальний вільний простір (%)", + "settings.minFreePctHelp": "Зберігає щонайменше цю частку обсягу вільною, автоматично видаляючи найстаріші записи незалежно від терміну зберігання. Це обмежує використання розміром диска — встановіть значення, і диск ніколи не заповниться. 0 вимикає обмеження місткості.", + "settings.pressureThresholds": "Пороги тиску на диск (%)", + "settings.pressureThresholdsHelp": "Діапазони вільного простору для ескалації автоматичного очищення. Має виконуватися: аварійний < критичний < попередження.", + "settings.pressureWarningPct": "Попередження нижче (% вільно)", + "settings.pressureCriticalPct": "Критичний нижче (% вільно)", + "settings.pressureEmergencyPct": "Аварійний нижче (% вільно)", + "settings.databaseBackupVerify": "Перевірка резервних копій", + "settings.databaseBackupVerifyFull": "Повна (integrity_check, перехресна перевірка кожного індексу)", + "settings.databaseBackupVerifyQuick": "Швидка (quick_check, лише структура сторінок)", + "settings.databaseBackupVerifyOff": "Вимкнено (без сканування після копіювання)", + "settings.databaseBackupVerifyHelp": "Сканування застосовується до кожної скопійованої резервної копії перед публікацією. Повна перевірка може тривати довше за саме копіювання на великій базі даних з механічним диском і вразити 30-хвилинне обмеження, що призведе до відкидання цієї копії; швидка перевірка все одно виявляє пошкоджені або обрізані сторінки з набагато меншою кількістю звернень до диска.", + "settings.viewMethodAuto": "Авто — налаштування для кожної камери з резервним варіантом", + "settings.resetWizardPending": "Запуск майстра…", + "settings.apiDetectionFormat": "Формат API-запиту", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect (багаточастинне завантаження зображення)", + "settings.apiDetectionFormatDoods2": "DOODS2 (JSON-тіло із зображенням у base64)", + "settings.apiDetectionFormatHelp": "Формат передачі, який LightNVR використовує при надсиланні знімків до API детекції. Залиште light-object-detect для light-object-detect або будь-якого сервера, що реалізує його контракт; оберіть DOODS2 для сервера DOODS2.", + "settings.apiDetectionUrlHelpDoods2": "DOODS2 /detect endpoint, напр. http://localhost:8080/detect. Запит надсилається як JSON, параметри рядка запиту не додаються.", + "settings.apiDetectionDetectorName": "Назва детектора DOODS2", + "settings.apiDetectionDetectorNameHelp": "Надсилається як detector_name у кожному запиті. Має збігатися з детектором, зазначеним у GET /detectors сервера; «default» використовує типовий детектор сервера.", + "settings.defaultPlaybackTransport": "Транспорт відтворення за замовчуванням", + "settings.defaultPlaybackTransportHelp": "Профіль відтворення, що застосовується до нових потоків. Наявні потоки зберігають власний вибір.", + "playbackTransport.auto": "Авто (рекомендовано)", + "playbackTransport.webrtcOnly": "Тільки WebRTC", + "playbackTransport.mseOnly": "Тільки MSE", + "playbackTransport.hlsOnly": "Тільки HLS", + "playbackTransport.webrtcThenMse": "WebRTC, потім MSE", + "playbackTransport.mseThenHls": "MSE, потім HLS", + "investigation.experimental": "Експериментальний робочий простір", + "investigation.title": "Розслідування", + "investigation.description": "Переглядайте кілька камер за одним спільним курсором UTC, не приховуючи пропуски у записах.", + "investigation.query": "Вікно розслідування", + "investigation.queryHelp": "Виберіть до 16 камер. Одночасно активні не більше чотирьох відеопрогравачів.", + "investigation.cameras": "камер", + "investigation.cameraSelection": "Вибір камер", + "investigation.start": "Початок", + "investigation.end": "Кінець", + "investigation.load": "Завантажити розслідування", + "investigation.applyWindow": "Застосувати часовий проміжок", + "investigation.loading": "Завантаження розслідування…", + "investigation.eventType": "Тип події", + "investigation.anyEventType": "Будь-який тип події", + "investigation.eventType.detection": "Виявлення", + "investigation.eventType.motion": "Рух", + "investigation.location": "Розташування", + "investigation.anyLocation": "Будь-яке розташування", + "investigation.objectLabel": "Мітка об'єкта", + "investigation.anyLabel": "Будь-яка мітка", + "investigation.zone": "Зона", + "investigation.anyZone": "Будь-яка зона", + "investigation.source": "Джерело виявлення", + "investigation.anySource": "Будь-яке джерело", + "investigation.captureMethod": "Спосіб захоплення", + "investigation.anyCaptureMethod": "Будь-який спосіб захоплення", + "investigation.recordingTag": "Тег запису", + "investigation.anyRecordingTag": "Будь-який тег запису", + "investigation.protection": "Захист", + "investigation.anyProtection": "Будь-який захист", + "investigation.protected": "Захищений", + "investigation.unprotected": "Незахищений", + "investigation.minimumConfidence": "Мінімальна впевненість", + "investigation.confidenceError": "Мінімальна впевненість має бути від 0 до 1.", + "investigation.metadataRegionSearch": "Пошук за областю метаданих", + "investigation.regionSearchHelp": "Виберіть основну камеру з відео та намалюйте область на її відео.", + "investigation.regionActive": "Пошук збережених рамок з {camera}. Відсутність результату не є доказом того, що нічого не перетнуло область.", + "investigation.regionMatch": "Зіставлення рамок", + "investigation.regionMatch.center": "Центр всередині", + "investigation.regionMatch.intersects": "Будь-який перетин", + "investigation.regionMatch.minimumIntersection": "Мінімальне перекриття", + "investigation.regionMinimumOverlap": "Мінімальне перекриття (%)", + "investigation.regionLeft": "Ліворуч (%)", + "investigation.regionTop": "Зверху (%)", + "investigation.regionWidth": "Ширина (%)", + "investigation.regionHeight": "Висота (%)", + "investigation.drawRegion": "Намалювати область пошуку", + "investigation.drawingRegion": "Намалювання області пошуку…", + "investigation.clearRegion": "Очистити область", + "investigation.useFullFrame": "Використовувати весь кадр", + "investigation.drawRegionPrompt": "Перетягніть по відео, щоб визначити область пошуку", + "investigation.applyFilters": "Застосувати фільтри", + "investigation.searching": "Пошук подій…", + "investigation.searchResults": "Результати подій", + "investigation.searchHelp": "Завантажте розслідування для пошуку збережених метаданих подій.", + "investigation.resultCount": "{count} відповідних подій", + "investigation.results": "результатів", + "investigation.resultHistogram": "Гістограма подій", + "investigation.histogramHelp": "Виберіть стовпчик, щоб перемістити спільний курсор.", + "investigation.previousResult": "Попередня подія", + "investigation.nextResult": "Наступна подія", + "investigation.previousResultShortcut": "Попередня подія ([)", + "investigation.nextResultShortcut": "Наступна подія (])", + "investigation.noResults": "Збережені події не відповідають вибраній камері, часу та фільтру.", + "investigation.noThumbnail": "Немає мініатюри", + "investigation.exploreThumbnails": "Перегляд мініатюр", + "investigation.exploreSelectedThumbnails": "Перегляд навколо події", + "investigation.thumbnailDrilldown": "Детальний перегляд мініатюр", + "investigation.thumbnailDrilldownHelp": "Виберіть будь-який момент, включно з проміжком, щоб перемістити спільний курсор і перегенерувати вужчий набір зразків.", + "investigation.selectThumbnailSample": "Перегляд навколо {time}", + "investigation.loadingThumbnail": "Завантаження мініатюри…", + "investigation.thumbnailUnavailable": "Мініатюра недоступна", + "investigation.loadingSamples": "Завантаження зразків мініатюр…", + "investigation.thumbnailCoverageTruncated": "Цей інтервал містить більше записів, ніж семплер зміг обробити. Звужте часовий проміжок для повного охоплення.", + "investigation.bookmarks.save": "Зберегти закладку", + "investigation.bookmarks.open": "Закладки", + "investigation.bookmarks.saveTitle": "Зберегти закладку розслідування", + "investigation.bookmarks.listTitle": "Закладки розслідування", + "investigation.bookmarks.notHold": "Закладка відновлює цей вигляд, але не захищає записи від звичайного видалення за політикою зберігання.", + "investigation.bookmarks.title": "Назва закладки", + "investigation.bookmarks.note": "Приватна нотатка (необов'язково)", + "investigation.bookmarks.titleRequired": "Введіть назву закладки.", + "investigation.bookmarks.empty": "У вас немає збережених закладок розслідування.", + "investigation.bookmarks.cameraCount": "{count} камер(и)", + "investigation.bookmarks.restore": "Відкрити", + "investigation.bookmarks.confirmDelete": "Видалити закладку?", + "investigation.actions.open": "Захистити / завантажити", + "investigation.actions.title": "Записи розслідування", + "investigation.actions.notEvidenceExport": "Захист запобігає звичайному видаленню за політикою зберігання. Завантаження ZIP — це зручний експорт, а не верифікований пакет доказів.", + "investigation.actions.scope": "Обсяг запису", + "investigation.actions.selectedResult": "Вибрана подія та камера", + "investigation.actions.fullWindow": "Усі камери у вікні розслідування", + "investigation.actions.preview": "Попередній перегляд записів", + "investigation.actions.previewing": "Пошук перекритих записів…", + "investigation.actions.invalidRange": "Виберіть коректний часовий діапазон, де кінець пізніше за початок.", + "investigation.actions.recordingCount": "{count} перекритий(і) запис(и)", + "investigation.actions.protectedCount": "{count} уже захищено", + "investigation.actions.noRecordings": "Жоден завершений запис не перекриває вибрану камеру та часовий діапазон.", + "investigation.actions.protectDenied": "{count} незахищений(і) запис(и) поза межами вашої зони захисту та виключено з цієї дії.", + "investigation.actions.exportDenied": "Відсутній дозвіл на експорт для {count} запис(ів). Завантаження виконується повністю або не виконується, тому цей вибір неможливо експортувати.", + "investigation.actions.camera": "Камера", + "investigation.actions.recording": "Запис", + "investigation.actions.size": "Розмір", + "investigation.actions.notPermitted": "Не дозволено", + "investigation.actions.protectButton": "Захистити {count}", + "investigation.actions.protecting": "Захист…", + "investigation.actions.protectUnavailable": "Немає незахищених записів, які ви можете захистити.", + "investigation.actions.protectResult": "Захист завершено: успішно — {success}, з помилками — {failed}.", + "investigation.actions.downloadButton": "Завантажити {count}", + "investigation.actions.downloadUnavailable": "Для кожного запису потрібен дозвіл на експорт перед створенням ZIP-архіву.", + "investigation.actions.buildingArchive": "Створення ZIP…", + "investigation.actions.downloadFailed": "Не вдалося створити ZIP на сервері.", + "investigation.actions.downloadTimedOut": "Створення ZIP не завершилося за п'ять хвилин. Спробуйте вужчий інтервал.", + "investigation.actions.downloadStarted": "Завантаження ZIP розпочато.", + "investigation.backOneLevel": "Назад на один рівень", + "investigation.thumbnailMinimumWindow": "Це найвужчий доступний інтервал в одну секунду. Спільний курсор усе одно перемістився до вибраного моменту.", + "investigation.localSource": "локальний", + "investigation.mediaAvailable": "Медіа доступне", + "investigation.durationSeconds": "Тривалість {count} с", + "investigation.pageNumber": "Сторінка {count}", + "investigation.incompleteCoverage": "{count} рядків застарілих подій не вдалося прив'язати до незмінного ідентифікатора камери.", + "investigation.spatialCoverageGap": "{count} рядків подій у межах діапазону не мали обмежувальної рамки та не були знайдені просторовим пошуком.", + "investigation.noSpatialMetadata": "Жодна подія в межах діапазону не має обмежувальної рамки для цього пошуку за метаданими.", + "investigation.selectCameraError": "Виберіть принаймні одну камеру.", + "investigation.selectRecordingError": "Виберіть принаймні один запис.", + "investigation.investigateSelectedCount": "Дослідити {count} обраних записів", + "investigation.missingCameraIdentity": "Неможливо дослідити: {count} обраних записів не мають ідентифікатора камери.", + "investigation.recordingTimeError": "Обрані записи не мають дійсного часового діапазону.", + "investigation.windowLimit": "Обрані записи перевищують 31-денне обмеження дослідження.", + "investigation.timeRangeError": "Час завершення має бути пізніше за час початку.", + "investigation.cameraLimit": "Дослідження може включати щонайбільше {count} камер.", + "investigation.decoderLimit": "Одночасно можуть бути активними лише {count} програвачів камер.", + "investigation.playbackControls": "Елементи синхронізованого відтворення", + "investigation.play": "Відтворити", + "investigation.pause": "Призупинити", + "investigation.mode": "Режим відтворення", + "investigation.wallClock": "Реальний час", + "investigation.skipCommonGaps": "Пропускати спільні проміжки", + "investigation.speed": "Швидкість", + "investigation.sharedCursor": "Спільний курсор UTC", + "investigation.activePlayers": "активних програвачів", + "investigation.timeline": "спільна шкала часу", + "investigation.segments": "сегментів", + "investigation.truncated": "обрізано", + "investigation.gap": "Немає відео", + "investigation.players": "Синхронізовані програвачі камер", + "investigation.activateCamera": "Активуйте принаймні один рядок шкали часу для завантаження відео.", + "investigation.noFootage": "Немає відео", + "investigation.noFootageAtTime": "Немає відео у спільний час", + "investigation.primaryAudio": "Основне аудіо", + "investigation.makePrimary": "Зробити основним", + "investigation.status.loading": "Завантаження медіа", + "investigation.status.synchronizing": "Синхронізація", + "investigation.status.ready": "Синхронізовано", + "investigation.status.late": "Запізнення — відновлення", + "investigation.status.error": "Медіа недоступне", + "investigation.status.paused-by-browser": "Натисніть відтворення, щоб дозволити медіа", + "streamsConfig.eptzTitle": "Риб'яче око ePTZ", + "streamsConfig.eptzEnable": "Увімкнути ePTZ риб'ячого ока на стороні браузера", + "streamsConfig.eptzHelp": "Виправляти спотворення потоку риб'ячого ока без змін у режимі перегляду наживо, відтворенні на часовій шкалі та розслідуванні. Це не змінює записи або вихідний потік камери.", + "streamsConfig.eptzModelHelp": "Проекція: рівновіддалена кругова риб'яче око · Кріплення: стеля. Центр і радіус використовують нормалізовані координати вихідного зображення.", + "streamsConfig.eptzCenterX": "Оптичний центр X", + "streamsConfig.eptzCenterY": "Оптичний центр Y", + "streamsConfig.eptzRadius": "Радіус зображення-кола", + "streamsConfig.eptzLensFov": "Кут огляду об'єктива (градуси)", + "streamsConfig.eptzRotation": "Поворот об'єктива (градуси)", + "streamsConfig.eptzDefaultYaw": "Панорамування за замовчуванням (градуси)", + "streamsConfig.eptzDefaultTilt": "Нахил за замовчуванням (градуси)", + "streamsConfig.eptzViewFov": "Кут огляду за замовчуванням", + "streamsConfig.eptzCalibrationHelp": "Перетягуйте для огляду, використовуйте колесо або щипок для масштабування, натисніть Home для скидання віртуальної камери. Тонко налаштуйте центр і радіус, якщо край зображення-кола не збігається.", + "settings.archive.targetType": "Тип сховища", + "settings.archive.filesystem": "Локальна або підключена файлова система (NFS/SAN)", + "settings.archive.s3": "S3-сумісний архівний бакет", + "settings.archive.endpoint": "Точка доступу HTTPS", + "settings.archive.region": "Регіон", + "settings.archive.bucket": "Виділений бакет", + "settings.archive.credential_ref": "Посилання на облікові дані", + "settings.archive.budget": "Бюджет архіву (ГіБ, 0 = необмежено)", + "settings.archive.connectionHelp": "Використовуйте приватний бакет без версіонування та правил закінчення терміну дії життєвого циклу. Посилання на облікові дані вказує на секретний файл, змонтований на сервері. Введіть кероване розташування у форматі s3://bucket/instance-prefix.", + "settings.archive.policy": "Політика зовнішнього архівування", + "settings.archive.archive_after_seconds": "Архівувати після захоплення (секунди, -1 = вимкнено)", + "settings.archive.hot_residency_seconds": "Зберігати гарячу копію (секунди, -1 = перемістити після архівування)", + "settings.archive.archive_protected": "Пріоритетне архівування захищених записів", + "settings.archive.archive_on_pressure": "Архівувати достроково при перевантаженні гарячого сховища", + "settings.archive.policyHelp": "Таймінг архівування використовує вік захоплення та потребує завершеного запису. -1 вимикає архівування за віком або видаляє мінімальний термін гарячого зберігання; 0 означає негайно. Зміни застосовуються до нових записів. Перегляньте наявні записи, щоб застосувати до них нову версію.", + "settings.archive.deletion_pending": "Видалення в черзі", + "settings.archive.archived": "Заархівовано", + "settings.archive.hot": "Гарячі", + "settings.archive.hot_and_archive": "Гарячі + архів", + "settings.archive.archiving": "Архівування", + "settings.archive.preparing": "Підготовка відтворення", + "settings.archive.unavailable": "Недоступно", + "settings.archive.operations": "Операції архівування", + "settings.archive.readOnly": "Режим відновлення: міграція та видалення записів призупинені.", + "settings.archive.disabledBuild": "Підтримка S3 вимкнена у цій збірці. Цільові точки змонтованих файлових систем залишаються доступними.", + "settings.archive.stored": "Зберігається у бакетах", + "settings.archive.backlog": "Черга передачі", + "settings.archive.cache": "Кеш отримання", + "settings.archive.objectsRemaining": "об'єктів залишилось", + "settings.archive.waitingForReaders": "У черзі або очікує активних читачів.", + "settings.archive.applied": "Ревізія політики застосована до наявних записів", + "settings.archive.reviewExisting": "Перегляд наявних записів", + "settings.archive.applySummary": "{count} записів ({bytes}) використовуватимуть цю ревизію. {expired} вже перевищили ліміт зберігання.", + "settings.archive.applyHelp": "Захист і перевизначення записів залишаються чинними. Терміни зберігання потоку та системи також діють. Нові терміни та місце архівування набувають чинності під час наступного сканування життєвого циклу.", + "settings.archive.applyBlocked": "Завершіть або вирішіть пов'язані передачі перед застосуванням цієї ревизії.", + "settings.archive.apply": "Застосувати до наявних записів", + "common.fullscreenUnsupported": "Повноекранний режим не підтримується у цьому браузері.", + "recordings.viewInTimelineTitle": "Переглянути цей потік у цей момент часу у часовій шкалі", + "recordings.clickToRetry": "Натисніть, щоб повторити", + "timeline.previousDay": "Попередній день", + "timeline.nextDay": "Наступний день", + "timeline.previousMonth": "Попередній місяць", + "timeline.nextMonth": "Наступний місяць", + "settings.searchLabel": "Пошук налаштувань", + "settings.clearSearch": "Очистити пошук", + "recordings.addTagPlaceholder": "Додати тег...", + "recordings.addNewTagPlaceholder": "Додати новий тег..." } diff --git a/web/public/locales/zh-TW.json b/web/public/locales/zh-TW.json index 9c45dc23..f0642058 100644 --- a/web/public/locales/zh-TW.json +++ b/web/public/locales/zh-TW.json @@ -759,9 +759,9 @@ "streamsConfig.streamNameImmutable": "流名稱創建後無法更改", "streamsConfig.streamNameAllowedChars": "只允許使用字母、數字、「.」、「-」和「_」(不能有空格)。", "streamsConfig.streamUrl": "串流URL", - "streamsConfig.streamUrlPlaceholder": "rtsp://使用者名稱:密碼@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "子碼流URL(可選)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://使用者名稱:密碼@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "儀表板網格視圖的低解析度流URL。留空即可在任何地方使用主流。子碼串流僅用於網格模式下的即時預覽;錄製和全螢幕始終使用主流。", "streamsConfig.urlCredentialsHiddenTitle": "URL 憑證在演示/檢視器模式下隱藏", "streamsConfig.urlCredentialsHidden": "URL 為了安全起見隱藏憑證", @@ -819,7 +819,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "確保 light-object-detect 正在該端點上執行", "streamsConfig.customApiEndpointUrl": "自訂API端點URL", "streamsConfig.useDefaultEndpoint": "使用預設端點", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/檢測", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "輸入完整的URL到您的自訂檢測API端點", "streamsConfig.overrideWithCustomEndpoint": "使用自訂端點覆蓋", "streamsConfig.detectionThreshold": "檢測閾值", @@ -1056,7 +1056,7 @@ "settings.detectionModelsPath": "偵測模型路徑", "settings.detectionModelsPathHelp": "檢測模型存放目錄", "settings.apiDetectionUrl": "API檢測URL", - "settings.apiDetectionUrlHelp": "URL 外部物體偵測 API 端點", + "settings.apiDetectionUrlHelp": "light-object-detect 端點,例如 http://localhost:8000/api/v1/detect。快照以 multipart form data 格式上傳,並附加 backend 和 confidence_threshold 查詢參數。", "settings.apiDetectionBackend": "API檢測後端", "settings.apiDetectionBackendOnnx": "ONNX運行時", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1156,5 +1156,1492 @@ "settings.discoveryIntervalSecondsRangeHelp": "掃描相機的頻率(30–3600 秒)", "settings.discoveryNetwork": "探索網絡", "settings.discoveryNetworkExamples": "範例:192.168.1.0/24、10.0.0.0/16、自動", - "settings.saveSettings": "儲存設定" + "settings.saveSettings": "儲存設定", + "live.navigator.title": "導航器", + "live.navigator.subtitle": "位置、佈局與活動", + "live.navigator.cameras": "攝影機", + "live.navigator.plans": "平面圖", + "live.navigator.views": "檢視", + "live.navigator.events": "事件", + "live.navigator.search": "搜尋攝影機…", + "live.navigator.allCameras": "所有攝影機", + "live.navigator.unassigned": "未指派", + "live.navigator.noCameras": "此範圍內無符合的攝影機。", + "live.navigator.saveCurrent": "儲存目前佈局", + "live.navigator.noLayouts": "尚無已儲存的佈局。", + "live.navigator.layoutNamePrompt": "命名此即時佈局", + "live.navigator.shareLayoutPrompt": "要與其他人員共用此佈局嗎?", + "live.navigator.layoutSaved": "已儲存 {name}", + "live.navigator.layoutLoaded": "已載入 {name}", + "live.navigator.deleteLayoutConfirm": "刪除 {name}?", + "live.navigator.shared": "已共用", + "live.navigator.loadingEvents": "載入近期事件中…", + "live.navigator.noRecentEvents": "過去一小時內無偵測結果。", + "live.navigator.expand": "展開導航器", + "live.navigator.collapse": "收合導航器", + "live.plan.navigatorHelp": "選擇建築或樓層。攝影機預覽僅在要求時開啟。", + "live.plan.noPlans": "尚無建築平面圖。請在平面圖工作區中建立。", + "live.plan.emptyTitle": "建立空間攝影機視圖", + "live.plan.emptyDescription": "平面圖會顯示整個場域的狀態標記,僅在操作員要求時才開啟影像。在此直接繪製房間與牆壁,或上傳掃描的平面圖、場域圖紙或來自 NVR 軟體的截圖,然後將攝影機對應到實際房間。", + "live.plan.sketch.tools": "佈局工具", + "live.plan.sketch.tool.select": "選取", + "live.plan.sketch.tool.room": "房間", + "live.plan.sketch.tool.wall": "牆壁", + "live.plan.sketch.tool.area": "區域", + "live.plan.sketch.tool.label": "標籤", + "live.plan.sketch.undo": "復原繪製", + "live.plan.sketch.redo": "重做繪製", + "live.plan.sketch.snap": "對齊格線", + "live.plan.sketch.hint.select": "拖曳圖形或攝影機以移動。點擊圖形以編輯;按住 Alt 跳過格線。", + "live.plan.sketch.hint.room": "在平面圖上拖曳以繪製房間或建築輪廓。", + "live.plan.sketch.hint.wall": "點擊以新增牆壁節點。雙擊或按 Enter 完成,按 Escape 取消。", + "live.plan.sketch.hint.area": "點擊以繪製區域輪廓。點擊第一個節點或按 Enter 閉合。", + "live.plan.sketch.hint.label": "點擊平面圖以放置文字標籤。", + "live.plan.sketch.type.rect": "房間", + "live.plan.sketch.type.wall": "牆壁", + "live.plan.sketch.type.area": "區域", + "live.plan.sketch.type.label": "標籤", + "live.plan.sketch.pointCount": "{count} 個節點", + "live.plan.sketch.defaultLabel": "標籤", + "live.plan.sketch.shapes": "佈局圖形", + "live.plan.sketch.noShapes": "尚未繪製任何內容。請選擇平面圖上方的工具開始。", + "live.plan.sketch.tone": "顏色", + "live.plan.sketch.tone.slate": "石板灰", + "live.plan.sketch.tone.blue": "藍色", + "live.plan.sketch.tone.green": "綠色", + "live.plan.sketch.tone.amber": "琥珀色", + "live.plan.sketch.tone.red": "紅色", + "live.plan.sketch.tone.violet": "紫色", + "live.plan.sketch.labelText": "標籤", + "live.plan.sketch.text": "文字", + "live.plan.sketch.size": "大小", + "live.plan.sketch.size.sm": "小", + "live.plan.sketch.size.md": "中", + "live.plan.sketch.size.lg": "大", + "live.plan.sketch.filled": "填滿房間", + "live.plan.sketch.left": "左側 %", + "live.plan.sketch.top": "上方 %", + "live.plan.sketch.width": "寬度 %", + "live.plan.sketch.height": "高度 %", + "live.plan.sketch.points": "頂點", + "live.plan.sketch.point": "頂點 {index}", + "live.plan.sketch.delete": "刪除圖形", + "live.plan.sketch.duplicate": "複製", + "live.plan.sketch.deselect": "完成", + "live.plan.sketch.emptyTitle": "此平面圖尚無內容", + "live.plan.sketch.emptyBody": "在此繪製房間、牆壁和標籤,或上傳掃描的平面圖、現場圖或 PNG/JPEG 匯出檔(最大 768 KB)。", + "live.plan.sketch.emptyBodyReadOnly": "管理員可以繪製佈局或上傳實際建築的平面圖。", + "live.plan.sketch.drawLayout": "繪製佈局", + "live.plan.sketch.uploadImage": "上傳圖片", + "live.plan.sketch.limitReached": "已達圖形數量上限({max})", + "live.plan.sketch.discardDrawing": "繪製已取消", + "live.favorites": "我的最愛", + "live.favoritesOnly": "僅顯示我的最愛攝影機", + "live.addFavorite": "將 {stream} 加入我的最愛", + "live.removeFavorite": "從我的最愛中移除 {stream}", + "live.noFavorites": "尚無我的最愛攝影機。使用攝影機圖格上的星號即可加入。", + "live.favoriteUpdateError": "無法更新我的最愛:{message}", + "live.resetZoom": "重設縮放", + "live.audioPlaybackBlocked": "瀏覽器已阻擋攝影機音訊。請再次點擊喇叭按鈕重試。", + "live.fullscreenSubStreamFallback": "{stream}:全螢幕模式下頻寬不足以傳輸全解析度串流——已切換至子串流。", + "live.tileActions": "攝影機操作", + "live.takeSnapshot": "擷取快照", + "live.openStreamRecordings": "開啟此串流的錄音", + "live.enterReorderMode": "重新排列攝影機", + "live.pullToRefresh": "下拉以重新整理串流", + "live.releaseToRefresh": "放開以重新整理串流", + "live.refreshingStreams": "正在重新整理串流…", + "live.streamsRefreshed": "串流已重新整理", + "live.refreshStreamsFailed": "無法重新整理串流:{message}", + "live.tipDoubleTapFullscreen": "提示:雙擊畫面格即可全螢幕開啟。", + "live.dayNightControl": "日夜模式", + "live.dayNightLoading": "載入中…", + "live.dayNightApplying": "套用中…", + "live.dayNightMode_auto": "自動", + "live.dayNightMode_day": "日間", + "live.dayNightMode_night": "夜間", + "live.dayNightMode_unknown": "未知", + "live.dayNightApplied": "日夜模式已設為{mode}", + "live.dayNightApplyFailed": "無法設定日夜模式", + "live.dayNightLoadFailed": "無法讀取日夜模式", + "live.playbackFallbackUsed": "備援:{transport}", + "live.playbackTransportUnavailable": "伺服器已停用此串流的 {transport}。", + "live.recordingMode.constant": "連續記錄", + "live.recordingMode.detection": "偵測記錄", + "live.recordingMode.schedule": "排程記錄", + "live.recordingMode.none": "未記錄", + "live.health.healthy": "串流正常", + "live.health.degraded": "串流緩衝中或恢復中", + "live.health.offline": "串流不可用", + "live.enterPictureInPicture": "開啟子母畫面", + "live.exitPictureInPicture": "關閉子母畫面", + "live.pictureInPictureError": "子母畫面失敗:{message}", + "live.alwaysFullscreenOnTapEnable": "啟用單擊畫面格即全螢幕", + "live.alwaysFullscreenOnTapDisable": "停用單格點擊全螢幕", + "live.displayMode": "顯示模式", + "live.displayModeFit": "適應", + "live.displayModeFill": "填滿", + "live.displayModeFitDescription": "適應:顯示完整畫面,上下或左右加黑邊", + "live.displayModeFillDescription": "填滿:填滿磁貼並裁切畫面邊緣", + "live.slideshowStartCameras": "開始幻燈片:輪播攝影機", + "live.slideshowStartPages": "開始幻燈片:輪播網格頁面", + "live.slideshowStop": "停止幻燈片", + "live.slideshowInterval": "幻燈片間隔", + "live.slideshowSeconds": "{seconds} 秒", + "live.plan.previewUnavailable": "攝影機預覽不可用", + "live.plan.previewAlt": "{name} 的目前畫面", + "live.plan.degreesValue": "{value} 度", + "live.plan.inDegrees": "{label}(度)", + "live.plan.imageDimensionsError": "無法讀取影像尺寸", + "live.plan.loading": "載入建築平面圖…", + "live.plan.created": "已建立 {name}", + "live.plan.renamed": "已重新命名為 {name}", + "live.plan.deleted": "已刪除 {name}", + "live.plan.backgroundType": "背景必須為 PNG 或 JPEG 影像", + "live.plan.backgroundTooLarge": "背景影像過大;最大為 768 KB", + "live.plan.backgroundAspect": "已上傳,但影像長寬比不符合任何有效的畫布尺寸", + "live.plan.backgroundUpdatedSave": "已更新 {name} 的背景;儲存版面配置以套用畫布尺寸", + "live.plan.backgroundNotResized": "背景已上傳,但畫布未調整大小:{error}", + "live.plan.backgroundUpdated": "{name} 的背景已更新", + "live.plan.backgroundRemoved": "背景已移除", + "live.plan.saved": "已儲存 {name}", + "live.plan.createTitle": "建立建築平面圖", + "live.plan.createDescription": "為此建築或樓層命名。繪製佈局或上傳樓層平面圖,然後放置攝影機。", + "live.plan.nameLabel": "平面圖名稱", + "live.plan.namePlaceholder": "主建築 · 一樓", + "live.plan.createConfirm": "建立平面圖", + "live.plan.eyebrow": "建築平面圖", + "live.plan.placedSummary": "已放置 {placed} · 即時 {live}", + "live.plan.zoomAndPan": "平面圖縮放與平移", + "live.plan.panLeft": "向左平移", + "live.plan.panUp": "向上平移", + "live.plan.panDown": "向下平移", + "live.plan.panRight": "向右平移", + "live.plan.zoomOut": "縮小", + "live.plan.zoomIn": "放大", + "live.plan.fitTitle": "符合平面圖", + "live.plan.fit": "符合", + "live.plan.backgroundMenu": "背景…", + "live.plan.save": "儲存平面圖", + "live.plan.uploadBackgroundTitle": "上傳 PNG 或 JPEG 圖片作為平面圖背景", + "live.plan.replaceBackground": "取代背景", + "live.plan.uploadBackground": "上傳背景", + "live.plan.removeBackground": "移除背景", + "live.plan.rename": "重新命名", + "live.plan.newPlan": "新建平面圖", + "live.plan.editLayout": "編輯佈局", + "live.plan.placementHint": "點擊平面圖以放置 {name}", + "live.plan.clusterLabel": "{count} 台攝影機;放大查看", + "live.plan.markerLabel": "{name};{availability};朝向 {rotation}°,視野 {fov}°", + "live.plan.cameraFallback": "攝影機", + "live.plan.legendLive": "即時", + "live.plan.canvas": "平面圖畫布", + "live.plan.width": "寬度", + "live.plan.height": "高度", + "live.plan.canvasHint": "上傳背景圖片後,畫布將自動調整為相同尺寸。", + "live.plan.canvasInvalid": "寬度須為 400–4000,高度須為 300–4000。", + "live.plan.openLive": "開啟即時攝影機", + "live.plan.direction": "攝影機朝向", + "live.plan.fov": "視野", + "live.plan.coverageNote": "扇形僅顯示方向與角度;平面圖上的距離未經校準。", + "live.plan.removeCamera": "從平面圖移除", + "live.plan.selectCamera": "選擇攝影機", + "live.plan.selectHintEditing": "拖曳已放置的標記以微調。可查看狀態並隨時開啟即時畫面。", + "live.plan.selectHint": "可查看狀態並隨時開啟即時畫面。", + "live.plan.cameras": "平面圖攝影機", + "live.plan.findPlaceholder": "在此平面圖上尋找…", + "live.plan.findLabel": "在此平面圖上尋找攝影機", + "live.plan.unplaced": "未放置的攝影機", + "live.plan.unplacedHint": "選擇攝影機,然後點擊平面圖上的位置。", + "live.plan.renameTitle": "重新命名平面圖", + "live.plan.renameDescription": "平面圖會與此站點的所有操作員共用。", + "live.plan.deleteTitle": "刪除平面圖", + "live.plan.deleteMessage": "確定要刪除「{name}」及其上傳的背景?此平面圖上的攝影機配置將被移除,攝影機本身不受影響。", + "setupWizard.welcomeTitle": "歡迎使用 LightNVR", + "setupWizard.welcomeIntro": "讓我們透過幾個快速步驟完成 NVR 設定。您隨時可以從設定頁面重新檢視這些設定。", + "setupWizard.welcomeStorage": "儲存路徑與大小限制", + "setupWizard.welcomePerformance": "攝影機數量的效能限制", + "setupWizard.welcomeSecurity": "管理員登入安全設定", + "setupWizard.storageTitle": "儲存與資料庫", + "setupWizard.storageIntro": "錄音與資料庫應儲存於何處?", + "setupWizard.storagePath": "錄音儲存路徑", + "setupWizard.storagePathHint": "影片檔案寫入的絕對路徑。", + "setupWizard.maxStorage": "最大儲存空間 (GB)", + "setupWizard.maxStorageHint": "0 = 無限制。", + "setupWizard.dbPath": "資料庫路徑", + "setupWizard.dbPathHint": "SQLite 資料庫檔案位置。", + "setupWizard.performanceTitle": "效能", + "setupWizard.performanceIntro": "這些設定控制容量,而非影片品質。大多數使用者可保持預設值。", + "setupWizard.threadPool": "工作執行緒池大小", + "setupWizard.threadPoolInfo": "影響背景網頁/伺服器工作。建議使用預設值,除非您正在調整效能。", + "setupWizard.maxStreams": "最大並行串流數", + "setupWizard.maxStreamsInfo": "是此執行實例的攝影機容量上限。請設定為至少您計畫新增的攝影機數量,並預留一些餘裕。", + "setupWizard.important": "重要:", + "setupWizard.restartWarning": "如果您變更任一設定,新值會立即儲存,但需重新啟動 LightNVR 後才會生效。例如,若目前串流上限為 1 且您將其提高至 32,則必須重新啟動後才能新增超過舊上限的攝影機。", + "setupWizard.threadPoolHintCores": "建議:{recommended}(您的 {cores} 核心 CPU 的 2 倍)。此設定控制 libuv 背景工作執行緒。範圍:2–128。", + "setupWizard.threadPoolHint": "建議:{recommended}(您的 CPU 核心數的 2 倍)。此設定控制 libuv 背景工作執行緒。範圍:2–128。", + "setupWizard.maxStreamsHint": "LightNVR 可同時保持活動的攝影機數量。預設 32,最大 {max}。若您預計使用 8 台攝影機,請至少選擇 8。需重新啟動後生效。", + "setupWizard.completeTitle": "設定完成!", + "setupWizard.saved": "您的設定已成功儲存。", + "setupWizard.notSaved": "未變更任何設定——將使用預設值。", + "setupWizard.restartRequired": "需要重新啟動", + "setupWizard.restartRequiredInfo": "執行緒池大小及/或最大串流數的變更已儲存,但需重新啟動服務後才會生效。請在新增更多攝影機或期望新容量上限生效前重新啟動。", + "setupWizard.saveFailed": "儲存設定失敗:{error}", + "setupWizard.back": "上一步", + "setupWizard.saving": "儲存中…", + "setupWizard.saveContinue": "儲存並繼續", + "setupWizard.next": "下一步 →", + "setupWizard.finish": "前往儀表板", + "setupWizard.skip": "跳過設定精靈", + "live.eptzCanvasLabel": "魚眼電子全景、傾斜及縮放檢視", + "live.eptzCanvasHint": "拖曳以平移及傾斜;滾輪或雙指縮放;Home 鍵重置", + "live.eptzReset": "重置 ePTZ 檢視", + "live.autoShort": "自動", + "live.webrtcShort": "WebRTC", + "nav.investigation": "調查", + "availability.label": "攝影機可用性", + "availability.live": "即時連線中", + "availability.offline": "離線(曾連線)", + "availability.neverConnected": "從未連線", + "availability.disabled": "已停用", + "availability.all": "所有攝影機", + "streams.inventory": "清單", + "streams.configuration": "設定", + "events.tab": "事件", + "events.eyebrow": "事件驅動整合", + "events.title": "事件與路由", + "events.description": "將攝影機與系統事件轉換為持久的 MQTT 串流,供自動化、通知服務及外部處理使用。LightNVR 提供事件介面;電子郵件與 SMS 傳遞由下游服務負責。", + "events.routes": "路由", + "events.destinations": "目的地", + "events.catalog": "事件目錄", + "events.enable": "啟用", + "events.loadError": "無法載入事件路由設定", + "events.accessDenied": "存取被拒 - 權限不足", + "events.summary.routes": "路由", + "events.summary.enabled": "已啟用 {count} 條", + "events.summary.destinations": "目的地", + "events.summary.managedActive": "{count} 個受管且啟用中", + "events.summary.types": "已註冊類型", + "events.summary.registry": "版本化事件目錄", + "events.summary.interface": "介面", + "events.summary.interfaceHelp": "持久事件輸出", + "events.route.add": "新增路由", + "events.route.addTitle": "建立事件路由", + "events.route.editTitle": "編輯事件路由", + "events.route.create": "建立路由", + "events.route.editorDescription": "選擇哪些事件符合條件、哪些攝影機在範圍內、事件送往何處,以及如何控制高噪音來源。", + "events.route.emptyTitle": "尚未設定事件路由", + "events.route.emptyDescription": "建立路由以選擇事件類型、攝影機範圍、排程、抑制策略及 MQTT 目的地。", + "events.route.enabled": "路由已啟用", + "events.route.enabledHelp": "符合條件的事件將被接受以進行持久化遞送", + "events.route.destination": "目的地", + "events.route.destinationHelp": "每個符合條件的事件會針對每個唯一目的地各持久化一次。", + "events.route.eventTypes": "事件類型", + "events.route.eventTypesHelp": "從註冊表中選擇一或多個版本化事件契約。", + "events.route.detectionFilters": "篩選物件偵測", + "events.route.detectionFiltersHelp": "可選設定物件偵測事件的標籤、區域或最低信心分數。", + "events.route.healthFilters": "篩選系統健康事件", + "events.route.healthFiltersHelp": "可選設定符合已註冊的健康狀況代碼或嚴重程度。可用值來自此錄影機。", + "events.route.healthConditions": "健康狀況(任一)", + "events.route.healthSeverities": "嚴重程度(任一)", + "events.route.healthRegistryUnavailable": "健康狀況註冊表無法使用。請重新載入後再設定條件篩選。", + "events.route.labels": "標籤(任一)", + "events.route.zones": "區域 ID(任一)", + "events.route.listHelp": "以逗號分隔各值。", + "events.route.minConfidence": "最低信心分數", + "events.route.confidenceHelp": "0 到 1 之間的值。", + "events.route.cameraScope": "攝影機範圍", + "events.route.cameraScopeHelp": "可重用攝影機群組位置、標籤、屬性集合或明確指定的攝影機,無需載入完整群組。", + "events.route.allCameras": "所有攝影機", + "events.route.dynamicScope": "動態攝影機選擇器", + "events.route.systemScopeHelp": "系統事件不屬於攝影機。當此路由包含系統範圍事件時,攝影機選擇器不可用。", + "events.route.schedule": "排程", + "events.route.scheduleHelp": "使用 IANA 時區中的事件發生時間;支援跨日時段。", + "events.route.restrictSchedule": "僅在設定的時段內", + "events.route.suppression": "雜訊與遞送策略", + "events.route.suppressionHelp": "設為零表示停用該控制。抑制僅在該目的地接受持久化事件後才會推進。", + "events.route.debounce": "去抖動秒數", + "events.route.debounceHelp": "重複觀測會延長此靜默間隔。", + "events.route.cooldown": "冷卻秒數", + "events.route.cooldownHelp": "接受事件後的最小間隔。", + "events.route.grouping": "分組視窗秒數", + "events.route.groupingHelp": "保留第一個事件並合併重複事件。", + "events.route.rateLimit": "每分鐘事件數", + "events.route.rateLimitHelp": "每條路由與攝影機的固定視窗上限。", + "events.route.deliveryPolicy": "遞送策略", + "events.route.suppressionActive": "雜訊控制已啟用", + "events.route.everyMatch": "每次匹配", + "events.route.preview": "預覽路由", + "events.route.previewing": "預覽中…", + "events.route.previewResult": "路由預覽", + "events.route.cameraMatches": "{count} 台攝影機匹配", + "events.route.previewNoPublish": "預覽會驗證完整規則並解析攝影機樣本;絕不會發布事件。", + "events.route.systemPreviewHelp": "系統事件會跳過攝影機選擇,因此在此預覽中回報零台匹配攝影機。", + "events.route.created": "事件路由已建立", + "events.route.updated": "事件路由已更新", + "events.route.deleted": "事件路由已刪除", + "events.route.disabled": "事件路由已停用", + "events.route.enabledMessage": "事件路由已啟用", + "events.route.deleteConfirm": "刪除事件路由「{name}」?", + "events.route.validation.name": "請輸入路由名稱。", + "events.route.validation.destination": "請選擇目的地。", + "events.route.validation.event_types": "請至少選擇一種事件類型。", + "events.route.validation.selector": "請完成或修正攝影機選擇器。", + "events.route.validation.system_scope": "系統範圍事件不能使用攝影機選擇器。", + "events.route.validation.detection_type": "偵測篩選條件需要物件偵測事件類型。", + "events.route.validation.detection_filter": "請至少新增一個偵測標籤、區域或信心度閾值。", + "events.route.validation.confidence": "最低信心度必須介於 0 到 1 之間。", + "events.route.validation.predicate_mix": "偵測與健康狀態篩選條件不能在同一條路由中混合使用。", + "events.route.validation.health_type": "健康狀態篩選條件僅需已註冊的系統健康事件類型。", + "events.route.validation.health_filter": "請至少選擇一個已註冊的健康狀況或嚴重程度。", + "events.route.validation.health_condition": "僅選擇由錄影機健康註冊表回傳的狀態碼。", + "events.route.validation.health_severity": "僅選擇所選健康事件類型支援的嚴重程度。", + "events.route.validation.timezone": "請輸入已安裝的 IANA 時區,例如 UTC 或 America/New_York。", + "events.route.validation.schedule_window": "每個排程時間窗至少需要一天,且開始與結束時間必須有效且不同。", + "events.route.validation.suppression": "抑制值必須為允許範圍內的整數。", + "events.schedule.timezone": "時區", + "events.schedule.timezoneHelp": "必須存在於錄影機的時區資料庫中。", + "events.schedule.addWindow": "新增時間窗", + "events.schedule.windowNumber": "時間窗 {number}", + "events.schedule.start": "開始", + "events.schedule.end": "結束", + "events.schedule.sunday": "日", + "events.schedule.monday": "一", + "events.schedule.tuesday": "二", + "events.schedule.wednesday": "三", + "events.schedule.thursday": "四", + "events.schedule.friday": "五", + "events.schedule.saturday": "六", + "events.destination.add": "新增目的地", + "events.destination.addTitle": "新增 MQTT 目的地", + "events.destination.editTitle": "編輯 MQTT 目的地", + "events.destination.create": "建立目的地", + "events.destination.editorDescription": "設定持久性事件輸出。憑證僅供寫入,API 不會回傳。", + "events.destination.default": "預設 MQTT 設定", + "events.destination.settingsManaged": "設定已託管", + "events.destination.defaultDescription": "現有的 MQTT 設定仍可以 mqtt:default 使用,目前由 {count} 條路由使用。", + "events.destination.openSettings": "開啟 MQTT 設定", + "events.destination.emptyTitle": "無託管目的地", + "events.destination.emptyDescription": "新增另一個 MQTT 代理伺服器,以獨立將事件傳送至雲端連接器、自動化系統或通知服務。", + "events.destination.identity": "目的地識別", + "events.destination.enabled": "目的地已啟用", + "events.destination.enabledHelp": "連線並清空其持久性佇列", + "events.destination.active": "啟用中", + "events.destination.paused": "已暫停", + "events.destination.pause": "暫停", + "events.destination.broker": "Broker", + "events.destination.host": "Broker 主機", + "events.destination.hostHelp": "僅限主機名稱或 IP 位址;不包含 URL 協定。", + "events.destination.port": "通訊埠", + "events.destination.clientId": "Client ID", + "events.destination.clientIdHelp": "在此 Broker 連線中必須唯一。", + "events.destination.topic": "主題", + "events.destination.topicTemplate": "主題範本", + "events.destination.topicHelp": "必須包含事件類型與主體 ID 權杖;不允許使用 MQTT 萬用字元。", + "events.destination.keepalive": "Keepalive 秒數", + "events.destination.statusTopicTemplate": "在線狀態主題", + "events.destination.statusTopicHelp": "選填。必須包含 {installation_uuid};{destination_uuid} 亦可使用。不允許使用 MQTT 萬用字元。", + "events.destination.statusTopicEnabled": "此目的地已明確啟用在線狀態。主題不會從事件主題推斷。", + "events.destination.statusTopicDisabled": "此目的地已停用在線狀態。將此欄位留空以維持停用。", + "events.destination.qos": "服務品質", + "events.destination.qos0": "僅發送一次", + "events.destination.qos1": "至少一次", + "events.destination.qos2": "恰好一次", + "events.destination.authentication": "驗證", + "events.destination.passwordPreserved": "留空以保留已儲存的唯寫密碼。", + "events.destination.passwordOptional": "當 Broker 允許匿名客戶端時為選填。", + "events.destination.clearPassword": "清除已儲存的密碼", + "events.destination.transportSecurity": "傳輸安全", + "events.destination.tlsMode": "TLS 模式", + "events.destination.tlsSystem": "系統信任儲存區", + "events.destination.tlsCustomCa": "自訂憑證授權單位", + "events.destination.tlsMutual": "雙向 TLS", + "events.destination.tlsDisabled": "已停用(純文字)", + "events.destination.tlsHelp.system": "使用作業系統信任儲存區驗證 Broker 憑證。", + "events.destination.tlsHelp.custom_ca": "使用明確的 PEM 憑證授權單位檔案驗證代理伺服器。", + "events.destination.tlsHelp.mutual": "使用明確的 CA 驗證代理伺服器,並提供用戶端憑證與金鑰。", + "events.destination.tlsHelp.disabled": "無傳輸加密或代理伺服器身分驗證。", + "events.destination.caFile": "CA 檔案", + "events.destination.certFile": "用戶端憑證檔案", + "events.destination.keyFile": "用戶端金鑰檔案", + "events.destination.absolutePathHelp": "使用 LightNVR 服務可讀取的絕對路徑。", + "events.destination.plaintextWarning": "明文 MQTT 可能暴露事件中繼資料與憑證。僅在受信任的隔離網路中使用。", + "events.destination.security": "安全性", + "events.destination.tls.system": "系統信任", + "events.destination.tls.custom_ca": "自訂 CA", + "events.destination.tls.mutual": "雙向 TLS", + "events.destination.tls.disabled": "明文", + "events.destination.routes": "路由", + "events.destination.presence": "在線狀態主題", + "events.destination.deleteInUse": "刪除目的地前,請先移除或重新導向相關路由。", + "events.destination.created": "MQTT 目的地已建立", + "events.destination.updated": "MQTT 目的地已更新", + "events.destination.deleted": "MQTT 目的地已刪除", + "events.destination.pausedMessage": "MQTT 目的地已暫停;佇列事件將持續保存至到期。", + "events.destination.enabledMessage": "MQTT 目的地已啟用", + "events.destination.deleteConfirm": "確定要刪除 MQTT 目的地「{name}」?", + "events.destination.validation.name": "請輸入目的地名稱。", + "events.destination.validation.host": "請輸入代理伺服器主機名稱或 IP 位址。", + "events.destination.validation.client_id": "請輸入代理伺服器用戶端 ID。", + "events.destination.validation.topic": "主題必須包含事件類型與主體 ID 權杖,且不得包含 MQTT 萬用字元。", + "events.destination.validation.status_topic": "選填的在線狀態主題必須包含安裝 UUID 權杖,僅使用支援的權杖,且不得包含 MQTT 萬用字元。", + "events.destination.validation.port": "埠號必須為 1 至 65535 的整數。", + "events.destination.validation.keepalive": "保持連線時間必須為 5 至 3600 秒的整數。", + "events.destination.validation.qos": "請選擇 MQTT QoS 0、1 或 2。", + "events.destination.validation.username": "設定密碼時必須同時提供用戶名稱。", + "events.destination.validation.ca_file": "此 TLS 模式需要絕對的 CA 檔案路徑。", + "events.destination.validation.mutual_files": "雙向 TLS 需要 CA、用戶端憑證及用戶端金鑰的絕對路徑。", + "fleet.eyebrow": "攝影機操作", + "fleet.title": "攝影機清單", + "fleet.description": "在大型部署中尋找、評估及整理攝影機,無需將完整清單載入瀏覽器。", + "fleet.summary": "機群健康摘要", + "fleet.totalCameras": "符合條件的攝影機", + "fleet.needsAttention": "效能下降", + "fleet.searchLabel": "搜尋攝影機", + "fleet.searchPlaceholder": "搜尋名稱、位址、位置、標籤、廠商或型號…", + "fleet.resultCount": "{count} 台攝影機", + "fleet.filters": "篩選", + "fleet.clearFilters": "清除篩選", + "fleet.filter.health": "健康狀態", + "fleet.filter.enabled": "攝影機狀態", + "fleet.filter.anyState": "任何狀態", + "fleet.filter.recording": "記錄模式", + "fleet.filter.location": "位置子樹", + "fleet.filter.allLocations": "所有位置", + "fleet.filter.tags": "標籤(符合任一)", + "fleet.filter.collection": "攝影機集合", + "fleet.health.unknown": "未知", + "fleet.health.up": "線上", + "fleet.health.degraded": "效能下降", + "fleet.health.down": "離線", + "fleet.health.disabled": "已停用", + "fleet.recording.off": "關閉", + "fleet.recording.continuous": "連續", + "fleet.recording.detection": "偵測", + "fleet.recordingActive": "記錄中", + "fleet.recordingInactive": "未記錄", + "fleet.column.camera": "攝影機", + "fleet.column.health": "健康狀態", + "fleet.column.location": "位置", + "fleet.column.tags": "標籤", + "fleet.column.recording": "錄音", + "fleet.viewLive": "即時取景", + "fleet.lastFrame": "最後畫面", + "fleet.noAddress": "位址不可用", + "fleet.unassigned": "未指派", + "fleet.loading": "載入攝影機群組…", + "fleet.refreshing": "重新整理中…", + "fleet.loadError": "無法載入攝影機群組", + "fleet.emptyTitle": "尚未設定攝影機", + "fleet.emptyDescription": "新增串流以使其在群組工作區中可用。", + "fleet.emptyFilteredTitle": "沒有符合此檢視的攝影機", + "fleet.emptyFilteredDescription": "嘗試擴大搜尋範圍或清除一個或多個篩選條件。", + "fleet.paginationSummary": "顯示 {first}–{last},共 {total} 筆", + "fleet.perPage": "每頁", + "fleet.pageOf": "第 {page} 頁,共 {pages} 頁", + "fleet.selectPage": "全選本頁攝影機", + "fleet.selectCamera": "選取 {name}", + "fleet.selectedCount": "已選取 {count} 台攝影機", + "fleet.organizeSelected": "整理已選取項目", + "fleet.clearSelection": "清除選取", + "fleet.organization.manage": "管理組織", + "fleet.organization.title": "攝影機組織", + "fleet.organization.description": "維護攝影機群組的可重用位置階層與標準化標籤字典。", + "fleet.organization.locations": "位置", + "fleet.organization.tags": "標籤", + "fleet.organization.locationsDescription": "以可瀏覽的階層結構建模站點、建築、樓層與作業區域。", + "fleet.organization.tagsDescription": "使用受控的標籤字典取代不一致的自由格式標籤。", + "fleet.organization.addRoot": "新增頂層位置", + "fleet.organization.addLocation": "新增位置", + "fleet.organization.editLocation": "編輯位置", + "fleet.organization.addChild": "新增子項", + "fleet.organization.type": "類型", + "fleet.organization.parent": "上層位置", + "fleet.organization.topLevel": "頂層", + "fleet.organization.sortOrder": "排序", + "fleet.organization.contents": "內容", + "fleet.organization.cameras": "攝影機", + "fleet.organization.system": "系統", + "fleet.organization.contentCounts": "{cameras} 台攝影機 · {children} 個子項", + "fleet.organization.locationNotEmpty": "請先移動攝影機並刪除子項位置", + "fleet.organization.noLocations": "尚未設定任何位置。", + "fleet.organization.locationCreated": "位置已建立", + "fleet.organization.locationUpdated": "位置已更新", + "fleet.organization.locationDeleted": "位置已刪除", + "fleet.organization.deleteLocationConfirm": "確定要刪除位置「{name}」?", + "fleet.organization.addTag": "新增標籤", + "fleet.organization.editTag": "編輯標籤", + "fleet.organization.tagLabel": "標籤", + "fleet.organization.color": "顏色 (#RRGGBB)", + "fleet.organization.tagDescription": "描述", + "fleet.organization.noTags": "尚未設定任何標準化標籤。", + "fleet.organization.tagCreated": "標籤已建立", + "fleet.organization.tagUpdated": "標籤已更新", + "fleet.organization.tagDeleted": "標籤已刪除", + "fleet.organization.deleteTagConfirm": "確定要刪除「{name}」?目前已有 {count} 台攝影機使用此標籤。", + "fleet.organization.merge": "合併", + "fleet.organization.mergeTagNamed": "合併「{name}」", + "fleet.organization.mergeInto": "合併至", + "fleet.organization.chooseTag": "選擇要保留的標籤", + "fleet.organization.mergeWarning": "所有攝影機的標籤將移至保留的標籤,來源標籤將被移除。", + "fleet.organization.tagsMerged": "標籤已合併", + "fleet.organization.saveError": "無法儲存:{message}", + "fleet.organization.deleteError": "無法刪除:{message}", + "fleet.locationType.site": "站點", + "fleet.locationType.building": "建築", + "fleet.locationType.floor": "樓層", + "fleet.locationType.area": "區域", + "fleet.locationType.zone": "分區", + "fleet.locationType.system": "系統", + "fleet.bulk.title": "整理選取的攝影機", + "fleet.bulk.description": "以有限並行方式將位置與標籤變更套用至 {count} 台攝影機。", + "fleet.bulk.location": "位置指派", + "fleet.bulk.locationHelp": "所有選取的攝影機將移動至所選位置。", + "fleet.bulk.keepLocations": "保留目前位置", + "fleet.bulk.tags": "標籤指派", + "fleet.bulk.tagsHelp": "新增或移除標籤而不影響其他指派,或明確取代完整標籤集。", + "fleet.bulk.tagOperation.none": "保留", + "fleet.bulk.tagOperation.add": "新增", + "fleet.bulk.tagOperation.remove": "移除", + "fleet.bulk.tagOperation.replace": "全部取代", + "fleet.bulk.replaceWarning": "全部取代會先移除所有目前標籤,再套用此選取。選取為空時將清除所有標籤。", + "fleet.bulk.apply": "套用變更", + "fleet.bulk.working": "正在套用變更…", + "fleet.bulk.success": "已更新 {count} 台攝影機", + "fleet.bulk.partial": "已更新 {succeeded} 台攝影機;{failed} 台失敗", + "fleet.bulk.error": "無法整理攝影機:{message}", + "fleet.bulk.failures": "無法更新的攝影機", + "fleet.queues.degraded": "降級串流", + "fleet.queues.offline": "離線攝影機", + "fleet.queues.oldest": "最早:{time}", + "fleet.queues.noneActive": "無作用中條件", + "fleet.views.title": "已儲存的檢視", + "fleet.views.choose": "選擇已儲存的檢視", + "fleet.views.none": "尚無已儲存的檢視", + "fleet.views.shared": "已共用", + "fleet.views.saveCurrent": "儲存目前檢視", + "fleet.views.name": "檢視名稱", + "fleet.views.share": "與所有操作員共用", + "fleet.views.saved": "機群檢視已儲存", + "fleet.views.saveError": "無法儲存檢視:{message}", + "fleet.views.deleted": "機群檢視已刪除", + "fleet.views.deleteConfirm": "確定要刪除已儲存的檢視「{name}」?", + "fleet.views.deleteError": "無法刪除檢視:{message}", + "fleet.views.unsupported": "此已儲存的選擇器無法由目前的篩選控件表示。", + "collections.manage": "集合", + "collections.all": "所有集合", + "collections.filter": "集合", + "collections.loadMembersError": "無法載入集合攝影機:{message}", + "collections.title": "攝影機集合", + "collections.subtitle": "建立可重複使用的攝影機群組,用於操作、已儲存檢視及下游工作流程。", + "collections.listDescription": "靜態集合維持明確的成員關係;智慧集合持續評估機群規則。", + "collections.create": "建立集合", + "collections.edit": "編輯集合", + "collections.editorDescription": "集合定義使用穩定的攝影機、位置及標籤 UUID。", + "collections.backToList": "返回集合", + "collections.type": "集合類型", + "collections.type.static": "靜態", + "collections.type.smart": "智慧", + "collections.description": "描述", + "collections.shared": "共用集合", + "collections.sharedHelp": "允許其他已授權使用者檢視此集合;攝影機存取規則仍然適用。", + "collections.typeChangeWarning": "變更集合類型將取代其成員模型。先前類型的靜態成員或智慧規則將不再適用。", + "collections.selectorError": "選擇器無效:{message}", + "collections.created": "集合已建立", + "collections.updated": "集合已更新", + "collections.saveError": "無法儲存集合:{message}", + "collections.loadError": "無法載入集合:{message}", + "collections.cameras": "攝影機", + "collections.visibility.shared": "共用", + "collections.visibility.private": "私人", + "collections.selectorRedacted": "規則私人", + "collections.emptyTitle": "尚無集合", + "collections.emptyAdmin": "建立靜態群組或智慧規則檢視,以重複使用攝影機選取。", + "collections.emptyViewer": "您的攝影機範圍內沒有可用的共用集合。", + "collections.deleteConfirm": "刪除集合「{name}」?", + "collections.deleted": "集合已刪除", + "collections.deleteError": "無法刪除集合:{message}", + "collections.preview.title": "規則預覽", + "collections.preview.matches": "{count} 台符合的攝影機", + "collections.preview.action": "預覽", + "collections.preview.hide": "隱藏預覽", + "collections.preview.loading": "評估中…", + "collections.preview.empty": "目前沒有符合的攝影機。", + "collections.preview.sample": "顯示 {total} 筆符合結果中的 {count} 台攝影機範例。", + "collections.preview.error": "無法預覽集合:{message}", + "collections.members.title": "靜態成員", + "collections.members.selected": "已跨所有頁面選取 {count} 台攝影機", + "collections.members.search": "搜尋攝影機…", + "collections.members.selectPage": "選取此頁", + "collections.members.empty": "沒有符合此搜尋的攝影機。", + "collections.builder.title": "智慧規則", + "collections.builder.description": "規則會根據目前的攝影機組織、設定、功能及健康狀態進行評估。", + "collections.builder.match": "符合", + "collections.builder.allRules": "所有規則", + "collections.builder.anyRule": "任一規則", + "collections.builder.addRule": "新增規則", + "collections.builder.removeRule": "移除規則", + "collections.builder.matchesAll": "若無完整規則,此集合將符合使用者授權範圍內的每台攝影機。", + "collections.builder.incompleteRule": "儲存前請完成或移除所有規則。", + "collections.builder.chooseLocation": "選擇位置子樹", + "collections.builder.vendorPlaceholder": "廠商名稱,以逗號分隔", + "collections.builder.modelPlaceholder": "型號名稱,以逗號分隔", + "collections.builder.advancedMode": "進階 JSON", + "collections.builder.visualMode": "視覺化建構器", + "collections.builder.cannotVisualize": "此選擇器包含巢狀或進階邏輯,視覺化建構器無法安全地表示。", + "collections.rule.location_subtree": "位置位於", + "collections.rule.camera_uuid": "特定攝影機", + "collections.rule.tag_any": "包含任一標籤", + "collections.rule.tag_all": "包含所有標籤", + "collections.rule.tag_none": "不包含任何標籤", + "collections.rule.health": "健康狀態為", + "collections.rule.enabled": "攝影機為", + "collections.rule.recording_mode": "記錄模式為", + "collections.rule.capability_any": "包含任一功能", + "collections.rule.capability_all": "包含所有功能", + "collections.rule.vendor": "廠商為", + "collections.rule.model": "型號為", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "音訊回傳通道", + "streamHealth.observedFps": "觀測 FPS", + "streamHealth.expectedFps": "預期", + "streamHealth.fpsHelp": "由 LightNVR 觀測;預期值來自攝影機串流中繼資料。", + "login.passwordChanged": "密碼已成功變更。請使用新密碼登入。", + "passwordChangeRequired.title": "變更預設密碼", + "passwordChangeRequired.description": "此安裝仍使用預設管理員密碼。請在繼續使用 LightNVR 之前更換密碼。若已啟用 MFA,將於下次登入時進行驗證。", + "passwordChangeRequired.currentPassword": "目前密碼", + "passwordChangeRequired.newPassword": "新密碼", + "passwordChangeRequired.confirmPassword": "確認新密碼", + "passwordChangeRequired.passwordHelp": "請使用至少 8 個字元。密碼不可為 admin。", + "passwordChangeRequired.submit": "變更密碼", + "passwordChangeRequired.saving": "正在變更密碼…", + "passwordChangeRequired.error.currentRequired": "請輸入目前密碼。", + "passwordChangeRequired.error.tooShort": "新密碼至少需 8 個字元。", + "passwordChangeRequired.error.defaultPassword": "新密碼不可為 admin。", + "passwordChangeRequired.error.mismatch": "新密碼不一致。", + "passwordChangeRequired.error.generic": "密碼變更失敗,請重試。", + "settings.tab.health": "健康狀態", + "settings.tab.workspaces": "工作區", + "settings.health.title": "主機與硬體健康狀態", + "settings.health.description": "設定受限的作業系統與硬體監控,不暴露裝置路徑或機密資訊。", + "settings.health.enabled": "啟用健康監控", + "settings.health.enabledHelp": "收集支援的主機、服務、儲存、網路與硬體訊號。", + "settings.health.profile": "策略設定檔", + "settings.health.profileHelp": "平衡為預設模式;保守模式需要更強證據才會發出警示。", + "settings.health.profile.balanced": "平衡", + "settings.health.profile.conservative": "保守", + "settings.health.hardwareProvider": "硬體提供者", + "settings.health.provider.auto": "自動(核心提供者)", + "settings.health.provider.smartctl": "smartctl(手動指定)", + "settings.health.providerHelp.auto": "僅使用受限的 sysfs、NVMe 與核心提供者;不會推斷 smartctl。", + "settings.health.providerHelp.smartctl": "明確啟用選用的受限 smartctl JSON 提供者,用於已發現的裝置。", + "settings.health.providerHelp.disabled": "停用選用的硬體提供者,同時保留可攜式健康監控。", + "settings.health.writeProbe": "啟用儲存寫入探測", + "settings.health.writeProbeHelp": "定期執行受限的已設定錄影目標探測。", + "settings.health.cadences": "取樣節奏", + "settings.health.cadencesHelp": "間隔必須從快速到裝置取樣依序排列,且在伺服器範圍內。", + "settings.health.fastInterval": "快速間隔", + "settings.health.normalInterval": "一般間隔", + "settings.health.slowInterval": "慢速間隔", + "settings.health.deviceInterval": "裝置間隔", + "settings.health.presenceInterval": "在線間隔", + "settings.health.retention": "事件保留", + "settings.health.conditions": "條件覆寫", + "settings.health.conditionsHelp": "僅覆寫有效原則註冊表所回傳的條件代碼與單位。", + "settings.health.conditionOverride": "條件覆寫", + "settings.health.overrideMode": "覆寫模式", + "settings.health.overrideModeHelp": "繼承所選設定檔、選擇另一個有界設定檔、停用條件,或設定已驗證的閾值。", + "settings.health.profileDefault": "使用所選設定檔", + "settings.health.custom": "自訂閾值", + "settings.health.warning": "警告閾值", + "settings.health.critical": "嚴重閾值", + "settings.health.recovery": "恢復閾值", + "settings.health.warning_for_seconds": "警告持續秒數", + "settings.health.critical_for_seconds": "嚴重持續秒數", + "settings.health.recovery_for_seconds": "恢復持續秒數", + "settings.health.clearOverrides": "清除覆寫", + "settings.health.registryUnavailable": "伺服器未回傳條件註冊表。請重新載入後再編輯覆寫。", + "settings.health.resetDefaults": "重設健康預設值", + "settings.health.reloadGuidance": "儲存為原子操作。儲存成功後請重新載入以確認有效原則;僅在伺服器明確要求時才重新啟動。", + "settings.health.validation.profile": "選擇支援的健康設定檔。", + "settings.health.validation.provider": "選擇支援的硬體提供者。", + "settings.health.validation.healthFastIntervalSeconds": "快速間隔必須為 5 至 60 秒的整數。", + "settings.health.validation.healthNormalIntervalSeconds": "正常間隔必須為 15 至 600 秒的整數。", + "settings.health.validation.healthSlowIntervalSeconds": "慢速間隔必須為 60 至 3600 秒的整數。", + "settings.health.validation.healthDeviceIntervalSeconds": "裝置間隔必須為 300 至 86400 秒的整數。", + "settings.health.validation.healthPresenceIntervalSeconds": "在線間隔必須為 15 至 3600 秒的整數。", + "settings.health.validation.healthIncidentRetentionDays": "事件保留必須為 7 至 3650 天的整數。", + "settings.health.validation.ordered": "取樣間隔必須依快速、正常、慢速、裝置的順序排列。", + "settings.health.validation.overrides": "條件覆寫必須使用唯一的代碼及伺服器註冊表中支援的設定檔。", + "settings.health.validation.thresholds": "自訂閾值必須為條件單位範圍內的有限值。", + "settings.health.validation.thresholdOrder": "警告、嚴重及恢復閾值必須維持條件的警示方向與滯後。", + "settings.health.validation.dwell": "持續時間必須為七天內的整數秒;警告與恢復持續時間不可為零。", + "workspaces.title": "操作員工作區", + "workspaces.description": "選擇要在導覽列與頁面中顯示的專業工作區。", + "workspaces.saved": "工作區偏好設定已儲存", + "workspaces.saveError": "無法儲存工作區偏好設定:{message}", + "workspaces.loadError": "無法載入工作區偏好設定。", + "workspaces.showWorkspace": "顯示 {name}", + "workspaces.authorizationNote": "此設定僅影響介面顯示。直接網址與 API 存取仍遵循您的授權政策。", + "workspaces.liveNavigator": "進階即時導航器", + "workspaces.liveNavigatorDescription": "位置樹狀結構、可用性篩選、已儲存版面配置與近期事件。", + "workspaces.investigation": "調查", + "workspaces.investigationDescription": "搜尋、關聯、保護並匯出已記錄的證據。", + "settings.reduceMotion": "減少動態效果", + "settings.reduceMotionHelp": "停用非必要動畫與轉場效果。自動模式將遵循作業系統偏好設定。", + "settings.reduceMotionPreference": "減少動態效果偏好", + "settings.reduceMotionAuto": "自動", + "settings.reduceMotionOn": "開啟", + "settings.reduceMotionOff": "關閉", + "settings.audioCompliance": "音訊合規", + "settings.disableAudioGlobally": "停用此實例的所有音訊", + "settings.audioDisabled": "音訊已全域停用", + "settings.audioComplianceHelp": "停用此實例的即時監聽、雙向通話及新錄音中的音訊。儲存後將重新啟動作用中的 go2rtc 媒體工作階段。既有錄音不受影響。", + "tokens.manage": "管理 API 存取", + "tokens.title": "API 存取 — {username}", + "tokens.description": "為整合建立範圍受限的憑證,並可獨立撤銷每一個。", + "tokens.recommendedTitle": "建議使用範圍受限的權杖", + "tokens.recommendedDescription": "每個權杖都有到期時間、明確的動作與攝影機範圍,且絕不會超過使用者目前的存取政策。", + "tokens.coverageNotice": "可用權限反映此伺服器所執行的規則。權杖只能使用其使用者已具備的權限。", + "tokens.createTitle": "建立範圍受限權杖", + "tokens.createDescription": "每個整合使用一個權杖,以便識別、輪換與撤銷,而不影響其他整合。", + "tokens.name": "整合名稱", + "tokens.namePlaceholder": "例如:北側車庫 PTZ 橋接器", + "tokens.expiry": "到期時間", + "tokens.expiryDays": "{days} 天", + "tokens.actions": "允許的操作", + "tokens.actionsHelp": "僅選擇此整合所需的操作。破壞性操作應使用獨立的權杖。", + "tokens.destructive": "破壞性", + "tokens.noEnforcedActions": "此伺服器版本不支援任何權杖操作。", + "tokens.scope.label": "攝影機範圍", + "tokens.scope.all": "全部攝影機", + "tokens.scope.collection": "共用集合", + "tokens.scope.selector": "自訂選擇器", + "tokens.scope.chooseCollection": "共用攝影機集合", + "tokens.scope.allValue": "全部攝影機", + "tokens.scope.collectionValue": "集合:{name}", + "tokens.scope.selectorValue": "自訂動態選擇器", + "tokens.create": "建立權杖", + "tokens.creating": "正在建立權杖…", + "tokens.createdSuccess": "範圍化 API 權杖已建立", + "tokens.createError": "無法建立 API 權杖:{message}", + "tokens.invalidResponse": "伺服器傳回不完整的憑證回應。", + "tokens.existingTitle": "現有權杖", + "tokens.existingDescription": "建立後僅保留前綴與中繼資料。", + "tokens.emptyTitle": "無作用中權杖", + "tokens.emptyDescription": "為第一個需要 API 存取權限的整合建立範圍化權杖。", + "tokens.showInactive": "顯示 {count} 個非作用中", + "tokens.status.active": "作用中", + "tokens.status.expired": "已過期", + "tokens.status.revoked": "已撤銷", + "tokens.expires": "到期", + "tokens.expiresValue": "到期日:{date}", + "tokens.created": "建立時間", + "tokens.lastUsed": "最後使用", + "tokens.revoke": "撤銷", + "tokens.revoking": "正在撤銷…", + "tokens.revokeConfirm": "確定要撤銷「{description}」?使用此權杖的請求將立即失效。", + "tokens.revokedSuccess": "API 權杖已撤銷", + "tokens.revokeError": "無法撤銷 API 權杖:{message}", + "tokens.validation.missing_description": "命名將使用此權杖的整合。", + "tokens.validation.description_too_long": "整合名稱請保持在 128 個字元以內。", + "tokens.validation.invalid_expiry": "請選擇 1 至 365 天的權杖有效期限。", + "tokens.validation.missing_actions": "請至少選擇一個允許的操作。", + "tokens.validation.invalid_action": "所選操作中有部分在此伺服器上未啟用權杖支援。", + "tokens.validation.invalid_scope": "請選擇有效的攝影機範圍。", + "tokens.validation.requires_all_scope": "非攝影機權限需要「全部攝影機」範圍。請選擇該範圍或移除這些權限。", + "tokens.validation.missing_collection": "請選擇可用的共用集合。", + "tokens.validation.invalid_selector": "請完成或修正自訂攝影機選擇器。", + "tokens.secret.oneTime": "僅顯示一次", + "tokens.secret.scopedTitle": "立即儲存此範圍權杖", + "tokens.secret.legacyTitle": "立即儲存此舊版 API 金鑰", + "tokens.secret.scopedDescription": "lightNVR 僅儲存此權杖的雜湊值。若遺失,請撤銷並重新建立。", + "tokens.secret.legacyDescription": "此相容性金鑰僅在此顯示一次。產生新的金鑰將使其失效。", + "tokens.secret.value": "API 憑證", + "tokens.secret.copied": "已複製", + "tokens.secret.copySuccess": "API 憑證已複製", + "tokens.secret.copyError": "無法自動複製;請手動選取並複製憑證。", + "tokens.secret.savedConfirm": "我已安全儲存此憑證", + "tokens.secret.savedHelp": "確認後將關閉此對話框。完整值將無法再次顯示。", + "tokens.legacy.title": "舊版相容性金鑰", + "tokens.legacy.description": "舊版金鑰擁有此使用者的完整存取權限,不會過期,且無法依攝影機或操作進行範圍限制。", + "tokens.legacy.warning": "僅為尚未遷移至範圍權杖強制執行的現有整合產生。產生後將立即使先前的舊版金鑰失效。", + "tokens.legacy.generate": "產生舊版金鑰", + "tokens.legacy.confirm": "要產生新的舊版金鑰嗎?這將立即使使用者目前的舊版金鑰失效。", + "tokens.legacy.createdSuccess": "舊版 API 金鑰已產生", + "tokens.legacy.createError": "無法產生舊版 API 金鑰:{message}", + "audit.manage": "稽核紀錄", + "audit.title": "安全性與存取稽核", + "audit.description": "追蹤登入結果、存取決策及敏感政策變更,且不會暴露憑證。", + "audit.retention": "保留", + "audit.retentionDescription": "事件目前保留 {days} 天。降低此值將立即清除較舊的記錄。", + "audit.retentionDays": "天", + "audit.retentionInvalid": "請選擇 1 至 3650 天的保留期間。", + "audit.retentionSaved": "稽核保留設定已儲存;已清除 {count} 筆過期事件", + "audit.retentionError": "無法儲存稽核保留設定:{message}", + "audit.filters": "篩選", + "audit.clearFilters": "清除篩選", + "audit.applyFilters": "套用篩選", + "audit.actor": "操作者", + "audit.unauthenticated": "未驗證", + "audit.outcome": "結果", + "audit.action": "精確動作", + "audit.filterToAction": "篩選此動作", + "audit.since": "起始", + "audit.until": "結束", + "audit.invalidDateRange": "起始日期必須早於結束日期。", + "audit.source": "來源位址", + "audit.target": "目標", + "audit.targetUuid": "目標 UUID", + "audit.noTarget": "全系統", + "audit.requestId": "請求 ID", + "audit.apiToken": "範圍權杖 ID", + "audit.showDetails": "顯示詳細資訊", + "audit.hideDetails": "隱藏詳細資訊", + "audit.pageSize": "每頁", + "audit.resultRange": "顯示 {start}–{end},共 {total} 筆", + "audit.empty": "無符合的稽核事件", + "audit.emptyDescription": "請嘗試清除一個或多個篩選條件,或等待新的安全活動。", + "audit.exportPage": "匯出本頁", + "audit.exporting": "匯出中…", + "audit.exported": "稽核頁面已匯出", + "audit.exportError": "無法匯出稽核事件:{message}", + "audit.pagination": "稽核歷史頁面", + "audit.page": "第 {page} 頁", + "audit.modesTitle": "允許的決策", + "audit.modesDescription": "選擇如何記錄每個操作的允許唯讀存取。變更請求、拒絕、錯誤和登入將一律記錄。「摘要」每 {minutes} 分鐘為每個使用者、攝影機和用戶端保留一筆記錄並附計數。", + "audit.mode.record": "逐筆記錄", + "audit.mode.summarize": "摘要", + "audit.mode.off": "關閉", + "audit.modeOffWarning": "此操作的允許存取將不再顯示於稽核歷史中。", + "audit.modesSaved": "稽核決策模式已儲存", + "audit.modesError": "無法儲存稽核決策模式:{message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "事件類型", + "audit.eventTypeSummary": "摘要", + "audit.eventTypeDecision": "個別決策", + "access.cameraSearch": "搜尋攝影機", + "access.cameraSearchPlaceholder": "請輸入至少兩個字元以搜尋…", + "access.cameraSearchHint": "可依攝影機名稱、UUID、位址、位置、標籤、供應商或型號搜尋。", + "access.cameraSelected": "已選取", + "access.cameraAdd": "新增", + "access.cameraLimit": "選擇器最多可包含 64 個明確指定的攝影機。若需更大範圍,請使用位置或標籤規則。", + "access.roles.manage": "管理角色", + "access.roles.title": "授權角色", + "access.roles.description": "將操作打包為可重複使用的角色,再授予這些角色於攝影機範圍。", + "access.roles.create": "建立角色", + "access.roles.newRole": "新角色", + "access.roles.copyName": "{name} 副本", + "access.roles.clone": "複製", + "access.roles.builtin": "內建", + "access.roles.builtinHelp": "內建角色為固定且升級安全的範本。複製一份以進行自訂。", + "access.roles.actionCount": "{count} 個操作", + "access.roles.destructive": "敏感操作", + "access.roles.notEnforced": "尚未由任何端點強制執行", + "access.roles.destructiveWarning": "此角色可變更設定或證據。僅在需要該權限的範圍內授予。", + "access.roles.created": "角色已建立", + "access.roles.updated": "角色已更新", + "access.roles.deleted": "角色已刪除", + "access.roles.saveError": "無法儲存角色:{message}", + "access.roles.deleteError": "無法刪除角色:{message}", + "access.roles.deleteConfirm": "刪除角色「{name}」?已被授權引用的角色無法刪除。", + "access.policy.manage": "管理存取", + "access.policy.column": "存取", + "access.policy.scopedShort": "範圍限定", + "access.policy.title": "存取政策 — {username}", + "access.policy.description": "管理預設拒絕的角色授權,並預覽其攝影機範圍。", + "access.policy.tab.grants": "授權", + "access.policy.tab.test": "測試存取", + "access.policy.scopedWarning": "僅符合授權與攝影機範圍的動作可執行。", + "access.policy.grants": "角色授權", + "access.policy.grantsDescription": "授權將一個角色與全部攝影機、共用集合或自訂攝影機選擇器結合。", + "access.policy.addGrant": "新增授權", + "access.policy.noGrants": "尚未設定授權", + "access.policy.noGrantsHelp": "啟用範圍限定政策前請先新增至少一筆授權,除非此使用者不應有任何存取權。", + "access.policy.role": "角色", + "access.policy.chooseRole": "選擇角色", + "access.policy.scope": "攝影機範圍", + "access.policy.allCameras": "全部攝影機", + "access.policy.collectionScope": "共用集合", + "access.policy.collection": "攝影機集合", + "access.policy.chooseCollection": "選擇共用集合", + "access.policy.collectionHelp": "存取權會隨著攝影機新增、移除或符合規則而自動追蹤集合。", + "access.policy.dynamicScope": "動態選擇器", + "access.policy.activateConfirm": "為 {username} 啟用預設拒絕的範圍限定政策?沒有符合授權的動作將被拒絕。", + "access.policy.emptyConfirm": "為 {username} 啟用無授權的範圍限定政策?這將刻意移除所有受政策控管的存取權。", + "access.policy.saved": "存取政策已儲存", + "access.policy.saveError": "無法儲存存取政策:{message}", + "access.policy.version": "政策版本 {version}", + "access.policy.unsaved": "未儲存的變更", + "access.policy.validation.invalid_mode": "請選擇有效的評估模式。", + "access.policy.validation.missing_role": "每項授權必須參照可用的角色。", + "access.policy.validation.invalid_scope": "每項授權必須使用全車隊、共用集合或選擇器範圍。", + "access.policy.validation.invalid_selector": "儲存前請完成或修正所有攝影機選擇器。", + "access.policy.validation.missing_collection": "請為每項集合授權選擇可用的共用集合。", + "access.policy.validation.duplicate_grant": "儲存前請移除重複的角色與範圍授權。", + "access.test.title": "測試有效存取", + "access.test.description": "以 {username} 身分評估已儲存的動作與攝影機,但不執行。", + "access.test.saveFirst": "測試前請儲存或捨棄授權變更,以確保結果反映此處顯示的政策。", + "access.test.action": "動作", + "access.test.camera": "攝影機", + "access.test.run": "測試存取", + "access.test.running": "測試中…", + "access.test.allowed": "已允許", + "access.test.denied": "已拒絕", + "access.test.version": "版本 {version}", + "access.test.source": "來源:{source} · 角色:{role}", + "recordings.pullToRefresh": "下拉以重新整理錄音", + "recordings.releaseToRefresh": "放開以重新整理錄音", + "recordings.refreshing": "正在重新整理錄音…", + "recordings.refreshed": "錄音已重新整理", + "recordings.refreshFailed": "無法重新整理錄音:{message}", + "recordings.download": "下載", + "recordings.tags": "標籤", + "recordings.selectRecording": "選擇錄音", + "timeline.legend.recording": "錄音", + "timeline.legend.detection": "偵測事件", + "timeline.detectionEvent": "偵測事件", + "streams.showCredentials": "顯示憑證", + "streams.hideCredentials": "隱藏憑證", + "streams.streamSuccessfullyEnabled": "串流已成功啟用。", + "streams.errorEnablingStream": "啟用串流時發生錯誤:{message}", + "system.health.tab": "健康狀態", + "system.health.operatorView": "運作健康狀態", + "system.health.title": "系統健康狀態", + "system.health.loading": "載入系統健康狀態…", + "system.health.loadError": "無法載入系統健康狀態。", + "system.health.refreshing": "重新整理中…", + "system.health.activeIncidentCount": "{count} 個進行中的事件", + "system.health.coverage": "涵蓋範圍", + "system.health.monitoringDisabled": "健康監控已停用", + "system.health.lastRecordedValue": "最後記錄值", + "system.health.monitoringDisabledHelp": "目前未收集健康狀態資訊。請前往「設定 → 健康狀態」啟用健康監控;儲存後如需重新啟動請依指示操作。事件歷史記錄顯示過去的事件,而非目前的資源使用情況。", + "system.health.monitoringRestartRequired": "已儲存的設定中健康監控已啟用,但執行中的採樣器仍為停用狀態。請重新啟動 LightNVR 以套用變更。事件歷史記錄顯示過去的事件。", + "system.health.containerCoverage": "主機涵蓋範圍有限", + "system.health.hostHardwareUnavailable": "此安裝可查看容器及掛載資源的健康狀態,但主機硬體資訊無法取得。缺少的主機值為未知,而非健康。", + "system.health.coverageUnknown": "尚無已完成的健康狀態快照。在收集完成前,數值將保持為未知。", + "system.health.coverageComplete": "此安裝可見的所有健康狀態資訊均已成功收集。", + "system.health.coveragePartial": "涵蓋範圍不完整。{count} 項觀測或收集檢查不可用、過時或不完整。", + "system.health.effectiveScope": "有效範圍", + "system.health.activeIncidents": "進行中的事件", + "system.health.noActiveIncidents": "可見涵蓋範圍內未回報進行中的事件。", + "system.health.duration": "持續時間", + "system.health.currentValue": "目前值", + "system.health.thresholds": "閾值與持續時間", + "system.health.thresholdSummary": "警告 {warning},嚴重 {critical},恢復 {recovery} {unit};警告持續時間 {seconds} 秒", + "system.health.remediation": "建議處理方式", + "system.health.facts": "健康狀態資訊", + "system.health.group.resources": "資源", + "system.health.group.storage": "儲存", + "system.health.group.hardware": "硬體", + "system.health.group.network": "網路", + "system.health.group.clock": "時鐘", + "system.health.group.components": "元件", + "system.health.noFacts": "此群組中沒有可見的事實。", + "system.health.observationState": "能力與即時性", + "system.health.valueUnavailable": "一個或多個數值未知", + "system.health.componentStatus": "監控元件", + "system.health.collectors": "收集器", + "system.health.collectorSummary": "{total} 個已註冊 · {attention} 個需要注意", + "system.health.collectorsNeedingAttention": "需要注意的收集器", + "system.health.collectionFailures": "{count} 個失敗或逾時", + "system.health.stale": "過期", + "system.health.eventDelivery": "事件遞送", + "system.health.degraded": "降級", + "system.health.circularDelivery": "這是唯一設定的警示路徑,因此無法獨立回報自身故障。", + "system.health.incidentPersistence": "事件持久化", + "system.health.persistenceSummary": "{pending} 個待處理 · {failures} 個失敗 · {retries} 個重試", + "system.health.recentSamples": "近期收集活動", + "system.health.recentSamplesHelp": "最多 {count} 個伺服器端生成摘要;這是涵蓋活動,非數值圖表。", + "system.health.sampleSequence": "生成 {sequence}", + "system.health.sampleCoverage": "{observations} 筆觀察 · {dropped} 筆遺失", + "system.health.noSamples": "沒有已完成的收集生成。", + "system.health.incidentHistory": "事件歷史", + "system.health.incidentHistoryHelp": "最新事件優先。歷史以有限分頁載入。", + "system.health.loadingHistory": "載入事件歷史…", + "system.health.historyError": "無法載入事件歷史。", + "system.health.emptyHistory": "尚未記錄任何事件。", + "system.health.firstSeen": "首次發現", + "system.health.lastSeen": "最後發現", + "system.health.deliveryState": "遞送狀態", + "system.health.historyPagination": "事件歷史分頁", + "system.health.pageCount": "本頁有 {count} 個事件", + "system.health.remediation.memory": "降低記憶體壓力,檢查程序與 cgroup 限制,並檢視近期 OOM 活動。", + "system.health.remediation.cpu": "辨識持續消耗 CPU 的程序,並在調整限制前確認服務吞吐量。", + "system.health.remediation.io": "檢查儲存延遲與活躍寫入者;在進行中斷性維護前備份錄影。", + "system.health.remediation.filesystem": "檢查指定的邏輯檔案系統、可用空間或 inode,並確認仍可寫入。", + "system.health.remediation.thermal": "改善散熱並降低負載;在溫度達到關機限制前檢查風扇與散熱孔。", + "system.health.remediation.network": "透過獨立網路路徑檢查可見介面、連結、交換器與錯誤計數器。", + "system.health.remediation.clock": "恢復時間同步,並在依賴事件時間戳記前確認主機時鐘來源。", + "system.health.remediation.process": "檢查 LightNVR 資源限制與日誌,然後降低負載或提高已驗證的限制。", + "system.health.remediation.storage": "備份重要錄影,並在更換或維修前檢查對應的儲存裝置。", + "system.health.remediation.hardware": "檢查受影響的硬體與平台日誌;若情況持續請安排維護。", + "system.health.remediation.health": "恢復收集器的存取與權限,以便評估缺失的健康證據。", + "system.health.remediation.system": "檢視上次執行與主機日誌,以區分程序重啟與主機重新開機。", + "system.health.remediation.event": "使用本機 API 或指標檢視,清除持久佇列壓力,並恢復獨立的警示目的地。", + "system.health.remediation.default": "檢視受影響的元件與近期日誌,然後在新的健康世代中確認恢復。", + "system.capacityTarget": "容量目標", + "system.capacityTargetValue": "保留 {pct}% 可用空間", + "system.fillRate": "填充速率", + "system.fillRateValue": "{value} / 天", + "system.projectedToTarget": "預計達到目標時間", + "system.projectedNow": "目前已達/超過目標", + "system.projectedDays": "~{count} 天", + "system.projectedHours": "~{count} 小時", + "system.projectedUnknown": "—", + "common.description": "描述", + "common.remove": "移除", + "streams.selectStream": "選取 {name}", + "streams.search": "搜尋串流", + "streams.searchPlaceholder": "搜尋攝影機、位置或標籤", + "streams.noStreamsMatchFilters": "沒有符合目前篩選條件的串流。", + "streamHealth.sourceConnected": "來源已連線", + "streamHealth.videoAdvancing": "影像進行中", + "streamHealth.recorderWriting": "記錄器寫入中", + "streamHealth.detectorOperating": "偵測器運作中", + "streamHealth.lastSegment": "最後完成的片段", + "streams.disablingStreamsProgress": "正在停用串流…", + "streams.onvifInvalidAddress": "ONVIF 裝置 IP 位址缺失或無效。", + "streams.warningFallingBackToHttp": "HTTPS 連線失敗;正在透過 HTTP 重試。憑證可能以純文字傳送。", + "streamsConfig.playbackTransport": "播放傳輸方式", + "streamsConfig.playbackTransportHelp": "選擇此攝影機的瀏覽器播放方式,以及所選方式的備援順序。", + "streamsConfig.playbackTransportUnavailable": "伺服器上不可用:{transports}。請全域啟用該傳輸方式或選擇其他設定檔。", + "streamsConfig.audioDisabledByPolicy": "音訊已因執行個體政策而停用", + "streamsConfig.audioDisabledByPolicyHelp": "啟用全域音訊合規政策期間,錄音、即時監聽及雙向通話均不可用。", + "streamsConfig.audioVoiceEnhancement": "語音增強(錄音)", + "streamsConfig.customApiModel": "自訂 API 偵測", + "streamsConfig.modelNotSupportedByBuild": "此版本不支援", + "streamsConfig.tierCriticalMultiplier": "關鍵層級 ×", + "streamsConfig.tierImportantMultiplier": "重要層級 ×", + "streamsConfig.tierEphemeralMultiplier": "暫存層級 ×", + "streamsConfig.tierMultipliersHelp": "各層級對基礎保留期的倍數。較高層級的影像保留時間更長,在磁碟空間不足時最後被清除。", + "streamsConfig.storagePriority": "儲存優先順序(1-10)", + "streamsConfig.storagePriorityHelp": "回收空間時此串流影像的相對重要性;優先順序越高,保留時間越長。", + "streamsConfig.restream": "轉播 / 發布(RTMP)", + "streamsConfig.publishUrl": "發布 URL(RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "透過 go2rtc 將此攝影機轉播至 YouTube Live 等服務。請貼上完整的 RTMP 推流 URL(包含串流金鑰,例如 rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx)。若要同時轉播至多個服務,請以逗號分隔各 URL。YouTube 需要 H264 視訊及 AAC 音訊;LightNVR 現已自動轉碼(非 H264 攝影機轉為 H264,非 AAC 音訊轉為 AAC),因此多數攝影機可直接使用。注意:YouTube 也需要音訊軌道——完全沒有音訊的攝影機仍會被拒絕。留空則停用。", + "streams.lastSeen": "最後上線時間 {time}", + "streams.claimed": "已聲明", + "streams.duplicateSuspected": "可能重複", + "streams.duplicateSuspectedHelp": "穩定身分或端點證據與另一筆探索記錄衝突。", + "streams.onvifClaimWarning": "串流已新增,但無法將其探索記錄標記為已聲明:{message}", + "common.online": "線上", + "common.offline": "離線", + "settings.storageTargets.title": "記錄儲存目標", + "settings.storageTargets.description": "註冊本機磁碟及由管理員掛載的 NFS 或 SMB 檔案系統,作為獨立監控的記錄目的地。", + "settings.storageTargets.foundationNotice": "擷取使用檔案系統目標。S3 儲存空間和已掛載的 NFS/SAN 目標可儲存已驗證的封存副本。熱壓力會保留已封存錄影,直到其邏輯保留期限到期。", + "settings.storageTargets.add": "新增儲存目標", + "settings.storageTargets.edit": "編輯儲存目標", + "settings.storageTargets.editorHelp": "已啟用的目標必須已存在並通過寫入、fsync 和清理測試。將尚不可用的未來掛載儲存為已停用,待掛載後再啟用。", + "settings.storageTargets.name": "目標名稱", + "settings.storageTargets.root": "已掛載的根路徑", + "settings.storageTargets.rootLocked": "預設或非空目標會保持不可變的根目錄,以防止現有錄影成為孤兒檔案。", + "settings.storageTargets.class": "效能等級", + "settings.storageTargets.hot": "熱 — 進行中錄影", + "settings.storageTargets.warm": "溫 — 已掛載封存", + "settings.storageTargets.cold": "冷 — 低頻存取", + "settings.storageTargets.reserveGb": "保留空間 (GB)", + "settings.storageTargets.lowWatermark": "低水位線 (% 已用)", + "settings.storageTargets.highWatermark": "高水位線 (% 已用)", + "settings.storageTargets.migrationBandwidth": "生命週期頻寬 (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 表示不限制。建立移動或複製工作時會擷取限制快照。", + "settings.storageTargets.archiveStart": "封存時段開始", + "settings.storageTargets.archiveEnd": "封存時段結束", + "settings.storageTargets.archiveWindowHelp": "本地時間。開始與結束時間相同表示全天允許生命週期工作;跨夜時段可跨越午夜。", + "settings.storageTargets.enabled": "已啟用(放置策略可選取此目標)", + "settings.storageTargets.notRouted": "沒有已啟用的放置策略將攝影機路由至此。新錄影將繼續寫入預設目標,直到某策略將此目標指定為主要、集區成員或封存目標。", + "settings.storageTargets.degradedNotice": "已超過高水位線或進入保留空間。放置策略將跳過此目標,直到釋放空間。", + "settings.storageTargets.probePassedIneligible": "寫入測試通過,但目標狀態為 {status}:放置策略將不會選取它。", + "settings.storageTargets.mountRequired": "需要已掛載的檔案系統", + "settings.storageTargets.mountRequiredHelp": "將此目標釘選至目前非根掛載點。若該 NFS、SMB、bind 或 PVC 掛載消失,錄影將暫停而非寫入底層主機目錄。", + "settings.storageTargets.mountGuard": "必要掛載", + "settings.storageTargets.mountPending": "啟用目標時將自動偵測", + "settings.storageTargets.default": "預設", + "settings.storageTargets.capacity": "容量", + "settings.storageTargets.available": "可用", + "settings.storageTargets.recordings": "已索引錄影", + "settings.storageTargets.replicas": "{count} 份已驗證副本 · {bytes}", + "settings.storageTargets.reserve": "已保留", + "settings.storageTargets.pressure.normal": "壓力正常", + "settings.storageTargets.pressure.high": "高水位線", + "settings.storageTargets.pressure.reserve": "保留空間不足", + "settings.storageTargets.pressure.unavailable": "壓力狀態不可用", + "settings.storageTargets.cleanupActive": "目標範圍清理已啟用,將朝 {target} 可用空間努力,不會刪除指派給其他目標的錄音。", + "settings.storageTargets.test": "測試目標", + "settings.storageTargets.probing": "測試中…", + "settings.storageTargets.probePassed": "儲存目標寫入測試通過", + "settings.storageTargets.duplicateFilesystem": "此根目錄與其他目標共用相同的底層檔案系統。啟用放置時,容量不得重複計算。", + "settings.storageTargets.deleteLocked": "預設及非空目標無法刪除。", + "settings.storageTargets.deleteConfirm": "刪除空的儲存目標「{name}」?不會移除任何檔案。", + "settings.storageTargets.created": "儲存目標已建立", + "settings.storageTargets.updated": "儲存目標已更新", + "settings.storageTargets.deleted": "儲存目標已刪除", + "settings.storageTargets.invalidThresholds": "檢查水位線、保留空間、生命週期頻寬及封存視窗時間。", + "settings.storageTargets.loadError": "無法載入儲存目標", + "settings.storagePools.title": "儲存池", + "settings.storagePools.description": "將健康目標分組,以進行自動溢出及不同目標複製。", + "settings.storagePools.add": "新增池", + "settings.storagePools.strategy": "分配策略", + "settings.storagePools.mostFree": "最多可用空間", + "settings.storagePools.roundRobin": "輪詢", + "settings.storagePools.priority": "明確優先順序", + "settings.storagePools.members": "目標(顯示順序即分配優先順序)", + "settings.storagePools.enabled": "池已啟用", + "settings.storagePools.active": "啟用中", + "settings.storagePools.inactive": "已停用", + "settings.storagePools.strategyValue.most_free": "最多可用", + "settings.storagePools.strategyValue.round_robin": "輪詢", + "settings.storagePools.strategyValue.priority": "優先順序", + "settings.storagePools.created": "儲存池已建立", + "settings.storagePools.updated": "儲存池已更新", + "settings.storagePools.deleted": "儲存池已刪除", + "settings.storagePools.deleteConfirm": "確定要刪除儲存池「{name}」?", + "settings.storagePools.empty": "尚無儲存池。", + "settings.storageMigrations.title": "錄音遷移工作", + "settings.storageMigrations.description": "持久化移動與保留副本會遵循每個目標的封存時間窗口與頻寬限制,驗證 SHA-256,並在重啟後安全恢復。", + "settings.storageMigrations.empty": "尚無錄音遷移工作。", + "settings.storageMigrations.loadError": "無法載入錄音遷移工作", + "settings.storageMigrations.recording": "錄音 #{id}", + "settings.storageMigrations.attempt": "嘗試 {current}/{max}", + "settings.storageMigrations.operation.move": "移動", + "settings.storageMigrations.operation.copy": "保留副本", + "settings.storageMigrations.cancelled": "已接受遷移取消請求", + "settings.storageMigrations.cancelling": "取消中…", + "settings.storageMigrations.retried": "遷移已排入重試佇列", + "settings.storageMigrations.state.queued": "已排入佇列", + "settings.storageMigrations.state.copying": "複製中", + "settings.storageMigrations.state.verifying": "驗證中", + "settings.storageMigrations.state.committing": "提交中", + "settings.storageMigrations.state.cleanup_pending": "清理來源中", + "settings.storageMigrations.state.retry_wait": "等待重試", + "settings.storageMigrations.state.completed": "已完成", + "settings.storageMigrations.state.failed": "失敗", + "settings.storageMigrations.state.cancelled": "已取消", + "settings.storagePolicies.title": "攝影機放置策略", + "settings.storagePolicies.description": "依優先順序將符合的攝影機路由至主要錄音目標。攝影機使用第一個符合的已啟用策略。", + "settings.storagePolicies.add": "新增放置策略", + "settings.storagePolicies.edit": "編輯放置策略", + "settings.storagePolicies.editorHelp": "新片段會重新評估此策略。變更不會移動已存在的錄音。", + "settings.storagePolicies.priority": "優先順序(越高越優先)", + "settings.storagePolicies.priorityValue": "優先順序 {priority}", + "settings.storagePolicies.primary": "主要目標", + "settings.storagePolicies.primaryPool": "放置池(選填)", + "settings.storagePolicies.exactTarget": "使用精確的主要目標", + "settings.storagePolicies.fallback": "若主要目標不可用", + "settings.storagePolicies.fallbackDefault": "使用預設目標", + "settings.storagePolicies.fallbackTarget": "使用具名備援目標", + "settings.storagePolicies.fallbackPause": "暫停記錄", + "settings.storagePolicies.fallbackFail": "記錄啟動失敗", + "settings.storagePolicies.namedFallback": "備援目標", + "settings.storagePolicies.chooseTarget": "選擇目標", + "settings.storagePolicies.choosePool": "選擇池", + "settings.storagePolicies.minimumDays": "最低保留天數", + "settings.storagePolicies.desiredDays": "期望保留天數", + "settings.storagePolicies.maximumDays": "最大保留天數", + "settings.storagePolicies.copyCount": "所需驗證副本數", + "settings.storagePolicies.replicationPool": "複製池", + "settings.storagePolicies.migrateAfter": "遷移年齡(天)", + "settings.storagePolicies.migrationTarget": "封存目標", + "settings.storagePolicies.pressurePriority": "壓力刪除優先級(數值越小越優先)", + "settings.storagePolicies.disabledTarget": "已停用", + "settings.storagePolicies.enabled": "策略已啟用", + "settings.storagePolicies.selector": "符合的攝影機", + "settings.storagePolicies.preview": "預覽優先順序", + "settings.storagePolicies.previewing": "評估中…", + "settings.storagePolicies.previewRequired": "儲存前預覽目前草稿,以檢視攝影機重疊情況及實際生效的策略。", + "settings.storagePolicies.previewSummary": "符合 {matched} 台攝影機;此草稿對 {effective} 生效。", + "settings.storagePolicies.previewShadowed": "較高優先順序的策略對 {count} 台符合的攝影機生效。", + "settings.storagePolicies.previewWins": "對 {count} 台攝影機勝過「{policy}」(優先級 {priority})。", + "settings.storagePolicies.previewLoses": "對 {count} 台攝影機輸給「{policy}」(優先級 {priority})。", + "settings.storagePolicies.previewNoMatches": "此選擇器目前未符合任何攝影機。", + "settings.storagePolicies.invalidPriority": "優先級必須為 -1,000,000 至 1,000,000 之間的整數。", + "settings.storagePolicies.invalidLifecycle": "請檢查保留順序、副本數與複製池,以及遷移年齡與目標。", + "settings.storagePolicies.created": "放置策略已建立", + "settings.storagePolicies.updated": "放置策略已更新", + "settings.storagePolicies.deleted": "放置策略已刪除", + "settings.storagePolicies.deleteConfirm": "刪除放置策略「{name}」?現有錄音不受影響。", + "settings.storagePolicies.active": "啟用中", + "settings.storagePolicies.inactive": "已停用", + "settings.storagePolicies.routesTo": "主要目標:{target}", + "settings.storagePolicies.lifecycleSummary": "保留天數 最小/期望/最大:{minimum}/{desired}/{maximum} 天 · {copies} 份已驗證副本", + "settings.storagePolicies.fallsBackTo": "備援目標:{target}", + "settings.storagePolicies.mode.default": "備援:預設目標", + "settings.storagePolicies.mode.pause": "備援:暫停記錄", + "settings.storagePolicies.mode.fail": "備援:記錄啟動失敗", + "settings.storagePolicies.empty": "無放置策略。攝影機將繼續使用預設目標;在策略將攝影機路由至其他目標之前,其他目標不會收到任何資料。", + "settings.storagePolicies.archiveNoTrigger": "已設定封存目標,但無任何條件觸發搬移。請設定「超過天數後搬移」、封存期限或封存選項;否則不會搬移任何錄音。", + "settings.storageCompliance.title": "容量與策略合規", + "settings.storageCompliance.description": "根據觀察到的 30 天速率預測目標壓力與實際保留天數;未解決的生命週期違規將持續顯示。", + "settings.storageCompliance.loadError": "無法載入儲存合規資訊", + "settings.storageCompliance.unknown": "未知", + "settings.storageCompliance.days": "{days} 天", + "settings.storageCompliance.day": "天", + "settings.storageCompliance.targetForecasts": "目標預測", + "settings.storageCompliance.target": "目標", + "settings.storageCompliance.dailyRate": "觀察速率", + "settings.storageCompliance.toHigh": "距高水位線", + "settings.storageCompliance.expected": "預期保留天數", + "settings.storageCompliance.confidence": "信心度", + "settings.storageCompliance.policyCompliance": "策略合規", + "settings.storageCompliance.compliant": "無進行中的違規", + "settings.storageCompliance.violationCount": "{count} 項違規", + "settings.storageCompliance.policyForecast": "實際 {achieved};預測 {expected};期望 {desired} 天。", + "settings.storageCompliance.copyDeficits": "{count} 筆錄音需要另一份已驗證副本。", + "settings.storageCompliance.activeViolations": "進行中的違規", + "settings.storageCompliance.type.copy_count": "副本數量", + "settings.storageCompliance.type.minimum_retention": "最小保留容量", + "settings.storageCompliance.type.target_unavailable": "目標不可用", + "settings.storageCompliance.type.migration_failed": "生命週期任務失敗", + "settings.recordingDirectoryFormat": "記錄資料夾佈局", + "settings.recordingDirectoryFormatHelp": "將新的 MP4 記錄按攝影機資料夾分區存放。現有記錄不會被移動。", + "settings.recordingDirectoryFlat": "平面(僅攝影機資料夾)", + "settings.recordingDirectoryMonth": "按月(YYYY/MM)", + "settings.recordingDirectoryDay": "按日(YYYY/MM/DD)", + "settings.minFreePct": "最小可用空間 (%)", + "settings.minFreePctHelp": "透過自動淘汰最舊的記錄,至少保留此百分比的磁碟空間,不受保留天數限制。這將使用量限制在磁碟大小內——設定後磁碟將不會填滿。設為 0 則停用容量上限。", + "settings.pressureThresholds": "磁碟壓力閾值 (%)", + "settings.pressureThresholdsHelp": "觸發自動清理升級的可用空間區間。必須滿足:緊急 < 嚴重 < 警告。", + "settings.pressureWarningPct": "警告低於(剩餘 %)", + "settings.pressureCriticalPct": "嚴重低於(剩餘 %)", + "settings.pressureEmergencyPct": "緊急低於(剩餘 %)", + "settings.databaseBackupVerify": "備份驗證", + "settings.databaseBackupVerifyFull": "完整(integrity_check,交叉檢查每個索引)", + "settings.databaseBackupVerifyQuick": "快速(quick_check,僅檢查頁面結構)", + "settings.databaseBackupVerifyOff": "關閉(不進行複製後掃描)", + "settings.databaseBackupVerifyHelp": "每次複製備份後、發布前套用的掃描。在大型資料庫搭配機械硬碟時,完整掃描可能比複製本身更耗時,並可能觸發 30 分鐘安全閾值而丟棄該備份;快速掃描仍能以遠少的磁碟搜尋捕捉損毀或截斷的頁面。", + "settings.viewMethodAuto": "自動——依攝影機偏好設定並提供備援", + "settings.resetWizardPending": "正在啟動精靈…", + "settings.apiDetectionFormat": "API 請求格式", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect(multipart 圖片上傳)", + "settings.apiDetectionFormatDoods2": "DOODS2(JSON 內容含 base64 圖片)", + "settings.apiDetectionFormatHelp": "LightNVR 向偵測 API 發送快照時使用的傳輸格式。若使用 light-object-detect 或任何實作其協定的伺服器,請選擇 light-object-detect;若使用 DOODS2 伺服器,請選擇 DOODS2。", + "settings.apiDetectionUrlHelpDoods2": "DOODS2 /detect 端點,例如 http://localhost:8080/detect。請求以 JSON 格式發送,不會附加查詢參數。", + "settings.apiDetectionDetectorName": "DOODS2 偵測器名稱", + "settings.apiDetectionDetectorNameHelp": "以 detector_name 欄位隨每個請求發送。必須與伺服器 GET /detectors 所列的偵測器名稱相符;\"default\" 使用伺服器的預設偵測器。", + "settings.defaultPlaybackTransport": "預設播放傳輸方式", + "settings.defaultPlaybackTransportHelp": "套用於新建串流的播放設定檔。現有串流維持各自的選擇。", + "playbackTransport.auto": "自動(建議)", + "playbackTransport.webrtcOnly": "僅 WebRTC", + "playbackTransport.mseOnly": "僅 MSE", + "playbackTransport.hlsOnly": "僅 HLS", + "playbackTransport.webrtcThenMse": "WebRTC,接著 MSE", + "playbackTransport.mseThenHls": "MSE,接著 HLS", + "investigation.experimental": "實驗性工作區", + "investigation.title": "調查", + "investigation.description": "以共用的 UTC 游標檢視多台攝影機,不隱藏畫面中的間隙。", + "investigation.query": "調查視窗", + "investigation.queryHelp": "最多選擇 16 台攝影機。同時最多啟動四個影片播放器。", + "investigation.cameras": "攝影機", + "investigation.cameraSelection": "攝影機選擇", + "investigation.start": "開始", + "investigation.end": "結束", + "investigation.load": "載入調查", + "investigation.applyWindow": "套用時間範圍", + "investigation.loading": "載入調查中…", + "investigation.eventType": "事件類型", + "investigation.anyEventType": "所有事件類型", + "investigation.eventType.detection": "偵測", + "investigation.eventType.motion": "移動偵測", + "investigation.location": "位置", + "investigation.anyLocation": "所有位置", + "investigation.objectLabel": "物件標籤", + "investigation.anyLabel": "所有標籤", + "investigation.zone": "區域", + "investigation.anyZone": "所有區域", + "investigation.source": "偵測來源", + "investigation.anySource": "所有來源", + "investigation.captureMethod": "擷取方式", + "investigation.anyCaptureMethod": "所有擷取方式", + "investigation.recordingTag": "記錄標籤", + "investigation.anyRecordingTag": "任何記錄標籤", + "investigation.protection": "保護", + "investigation.anyProtection": "任何保護狀態", + "investigation.protected": "已保護", + "investigation.unprotected": "未保護", + "investigation.minimumConfidence": "最低信心度", + "investigation.confidenceError": "最低信心度必須介於 0 到 1 之間。", + "investigation.metadataRegionSearch": "中繼資料區域搜尋", + "investigation.regionSearchHelp": "選擇一個有影像的主要攝影機,然後在其畫面上繪製區域。", + "investigation.regionActive": "正在搜尋 {camera} 的已儲存框。未找到結果不代表沒有目標經過該區域。", + "investigation.regionMatch": "框匹配", + "investigation.regionMatch.center": "中心在內", + "investigation.regionMatch.intersects": "任何交集", + "investigation.regionMatch.minimumIntersection": "最小重疊", + "investigation.regionMinimumOverlap": "最小重疊 (%)", + "investigation.regionLeft": "左側 (%)", + "investigation.regionTop": "上方 (%)", + "investigation.regionWidth": "寬度 (%)", + "investigation.regionHeight": "高度 (%)", + "investigation.drawRegion": "繪製搜尋區域", + "investigation.drawingRegion": "正在繪製搜尋區域…", + "investigation.clearRegion": "清除區域", + "investigation.useFullFrame": "使用完整畫面", + "investigation.drawRegionPrompt": "在影片上拖曳以定義搜尋區域", + "investigation.applyFilters": "套用篩選", + "investigation.searching": "正在搜尋事件…", + "investigation.searchResults": "事件結果", + "investigation.searchHelp": "載入調查以搜尋其已儲存的事件中繼資料。", + "investigation.resultCount": "{count} 個符合的事件", + "investigation.results": "筆結果", + "investigation.resultHistogram": "事件直方圖", + "investigation.histogramHelp": "選擇一個長條以移動共用游標。", + "investigation.previousResult": "上一個事件", + "investigation.nextResult": "下一個事件", + "investigation.previousResultShortcut": "上一個事件 ([)", + "investigation.nextResultShortcut": "下一個事件 (])", + "investigation.noResults": "沒有符合此攝影機、時間及篩選條件的已儲存事件。", + "investigation.noThumbnail": "無縮圖", + "investigation.exploreThumbnails": "探索縮圖", + "investigation.exploreSelectedThumbnails": "探索事件周邊", + "investigation.thumbnailDrilldown": "縮圖深入檢視", + "investigation.thumbnailDrilldownHelp": "選擇任何時刻(包含間隔),以移動共用游標並重新生成更精確的樣本集。", + "investigation.selectThumbnailSample": "檢視 {time} 周邊", + "investigation.loadingThumbnail": "載入縮圖…", + "investigation.thumbnailUnavailable": "縮圖不可用", + "investigation.loadingSamples": "載入縮圖樣本…", + "investigation.thumbnailCoverageTruncated": "此時間區間包含的錄影數量超出取樣器可檢視的範圍。請縮小時間範圍以獲得完整覆蓋。", + "investigation.bookmarks.save": "儲存書籤", + "investigation.bookmarks.open": "書籤", + "investigation.bookmarks.saveTitle": "儲存調查書籤", + "investigation.bookmarks.listTitle": "調查書籤", + "investigation.bookmarks.notHold": "書籤可還原此檢視,但不會保護錄影免受正常保留或刪除。", + "investigation.bookmarks.title": "書籤名稱", + "investigation.bookmarks.note": "私人備註(選填)", + "investigation.bookmarks.titleRequired": "請輸入書籤名稱。", + "investigation.bookmarks.empty": "您沒有已儲存的調查書籤。", + "investigation.bookmarks.cameraCount": "{count} 台攝影機", + "investigation.bookmarks.restore": "開啟", + "investigation.bookmarks.confirmDelete": "刪除書籤?", + "investigation.actions.open": "保護 / 下載", + "investigation.actions.title": "調查錄影", + "investigation.actions.notEvidenceExport": "保護可防止正常保留刪除。ZIP 下載僅為便利匯出,非經認證的證據包。", + "investigation.actions.scope": "錄影範圍", + "investigation.actions.selectedResult": "選定的事件與攝影機", + "investigation.actions.fullWindow": "調查視窗中的所有攝影機", + "investigation.actions.preview": "預覽錄影", + "investigation.actions.previewing": "正在尋找重疊的錄影…", + "investigation.actions.invalidRange": "請選擇有效的時間範圍,結束時間需晚於開始時間。", + "investigation.actions.recordingCount": "{count} 筆重疊錄影", + "investigation.actions.protectedCount": "{count} 筆已受保護", + "investigation.actions.noRecordings": "沒有已完成的錄影與此攝影機及時間選取重疊。", + "investigation.actions.protectDenied": "{count} 筆未受保護的錄影不在您的保護範圍內,已從此次操作中排除。", + "investigation.actions.exportDenied": "{count} 筆錄影缺少匯出權限。下載為全部或無,因此無法匯出此選取。", + "investigation.actions.camera": "攝影機", + "investigation.actions.recording": "錄影", + "investigation.actions.size": "大小", + "investigation.actions.notPermitted": "無權限", + "investigation.actions.protectButton": "保護 {count}", + "investigation.actions.protecting": "保護中…", + "investigation.actions.protectUnavailable": "沒有您可以保護的未受保護錄影。", + "investigation.actions.protectResult": "保護完成:{success} 筆成功,{failed} 筆失敗。", + "investigation.actions.downloadButton": "下載 {count}", + "investigation.actions.downloadUnavailable": "建立 ZIP 前,每筆錄影都需要匯出權限。", + "investigation.actions.buildingArchive": "正在建立 ZIP…", + "investigation.actions.downloadFailed": "伺服器上 ZIP 建立失敗。", + "investigation.actions.downloadTimedOut": "ZIP 建立未在五分鐘內完成。請嘗試較窄的時間間隔。", + "investigation.actions.downloadStarted": "ZIP 下載已開始。", + "investigation.backOneLevel": "返回上一層", + "investigation.thumbnailMinimumWindow": "這已是最窄的一秒間隔。共用游標仍已移動至所選時刻。", + "investigation.localSource": "本機", + "investigation.mediaAvailable": "媒體可用", + "investigation.durationSeconds": "時長 {count} 秒", + "investigation.pageNumber": "第 {count} 頁", + "investigation.incompleteCoverage": "{count} 筆舊版事件列無法歸屬至不可變更的攝影機身分。", + "investigation.spatialCoverageGap": "{count} 筆範圍內的事件列沒有邊界框,未進行空間搜尋。", + "investigation.noSpatialMetadata": "此元資料搜尋的範圍內事件均無邊界框。", + "investigation.selectCameraError": "請至少選擇一台攝影機。", + "investigation.selectRecordingError": "請至少選擇一筆錄音。", + "investigation.investigateSelectedCount": "調查 {count} 筆選取的錄音", + "investigation.missingCameraIdentity": "無法調查:{count} 筆選取的錄音沒有攝影機身分。", + "investigation.recordingTimeError": "選取的錄音沒有有效的時間範圍。", + "investigation.windowLimit": "選取的錄音超過 31 天的調查限制。", + "investigation.timeRangeError": "結束時間必須晚於開始時間。", + "investigation.cameraLimit": "一次調查最多可包含 {count} 台攝影機。", + "investigation.decoderLimit": "同時只能有 {count} 個攝影機播放器處於作用中。", + "investigation.playbackControls": "同步播放控制", + "investigation.play": "播放", + "investigation.pause": "暫停", + "investigation.mode": "播放模式", + "investigation.wallClock": "時鐘時間", + "investigation.skipCommonGaps": "跳過共同間隔", + "investigation.speed": "速度", + "investigation.sharedCursor": "共用 UTC 游標", + "investigation.activePlayers": "作用中播放器", + "investigation.timeline": "共用時間軸", + "investigation.segments": "片段", + "investigation.truncated": "已截斷", + "investigation.gap": "無影像", + "investigation.players": "同步攝影機播放器", + "investigation.activateCamera": "請啟用至少一個時間軸列以載入影片。", + "investigation.noFootage": "無影像", + "investigation.noFootageAtTime": "共用時間無影像", + "investigation.primaryAudio": "主要音訊", + "investigation.makePrimary": "設為主要", + "investigation.status.loading": "載入媒體中", + "investigation.status.synchronizing": "同步中", + "investigation.status.ready": "已同步", + "investigation.status.late": "延遲 — 正在恢復", + "investigation.status.error": "媒體無法使用", + "investigation.status.paused-by-browser": "選擇播放以允許媒體", + "streamsConfig.eptzTitle": "魚眼 ePTZ", + "streamsConfig.eptzEnable": "啟用瀏覽器端魚眼 ePTZ", + "streamsConfig.eptzHelp": "在即時取景、時間軸播放與調查中對原始魚眼串流進行去畸變。這不會改變記錄或攝影機輸出。", + "streamsConfig.eptzModelHelp": "投影:等距圓形魚眼 · 安裝:天花板。中心與半徑使用正規化的來源影像座標。", + "streamsConfig.eptzCenterX": "光學中心 X", + "streamsConfig.eptzCenterY": "光學中心 Y", + "streamsConfig.eptzRadius": "像場半徑", + "streamsConfig.eptzLensFov": "鏡頭視場角(度)", + "streamsConfig.eptzRotation": "鏡頭旋轉(度)", + "streamsConfig.eptzDefaultYaw": "預設水平(度)", + "streamsConfig.eptzDefaultTilt": "預設垂直(度)", + "streamsConfig.eptzViewFov": "預設視圖視場角", + "streamsConfig.eptzCalibrationHelp": "拖曳以環視,使用滾輪或捏合以縮放,按 Home 重置虛擬攝影機。若像場邊緣未對齊,請微調中心與半徑。", + "settings.archive.targetType": "儲存類型", + "settings.archive.filesystem": "本機或已掛載的檔案系統(NFS/SAN)", + "settings.archive.s3": "S3 相容封存儲存區", + "settings.archive.endpoint": "HTTPS 端點", + "settings.archive.region": "區域", + "settings.archive.bucket": "專用儲存區", + "settings.archive.credential_ref": "憑證參照", + "settings.archive.budget": "封存預算(GiB,0 = 無限制)", + "settings.archive.connectionHelp": "使用私人、未版本化的儲存區,且不設定生命週期到期規則。憑證參照會選取掛載於伺服器上的密鑰檔案。請以 s3://bucket/instance-prefix 格式輸入受管位置。", + "settings.archive.policy": "外部封存策略", + "settings.archive.archive_after_seconds": "擷取後封存(秒,-1 = 停用)", + "settings.archive.hot_residency_seconds": "保留熱副本(秒,-1 = 封存後移動)", + "settings.archive.archive_protected": "優先封存受保護的記錄", + "settings.archive.archive_on_pressure": "熱儲存空間不足時提前封存", + "settings.archive.policyHelp": "封存時機依據擷取時間且需要已完成的記錄。-1 停用依時間封存或移除熱儲存最短保留時間;0 表示立即封存。編輯僅套用於新記錄。請檢視現有記錄以套用新修訂。", + "settings.archive.deletion_pending": "待刪除", + "settings.archive.archived": "已封存", + "settings.archive.hot": "熱資料", + "settings.archive.hot_and_archive": "熱資料 + 歸檔", + "settings.archive.archiving": "歸檔中", + "settings.archive.preparing": "準備回放中", + "settings.archive.unavailable": "不可用", + "settings.archive.operations": "歸檔操作", + "settings.archive.readOnly": "復原模式:記錄遷移與刪除已暫停。", + "settings.archive.disabledBuild": "此版本未啟用 S3 支援。已掛載的檔案系統目標仍可使用。", + "settings.archive.stored": "存放於儲存區", + "settings.archive.backlog": "傳輸佇列", + "settings.archive.cache": "取回快取", + "settings.archive.objectsRemaining": "個物件剩餘", + "settings.archive.waitingForReaders": "已排隊,或等待使用中讀取者。", + "settings.archive.applied": "套用於現有記錄的修訂版本", + "settings.archive.reviewExisting": "檢視現有記錄", + "settings.archive.applySummary": "{count} 筆記錄({bytes})將使用此修訂版本。{expired} 筆已超過其保留期限。", + "settings.archive.applyHelp": "保護與記錄覆寫仍然有效。串流與系統保留規則同樣適用。新的歸檔時間與目的地將於下次生命週期掃描時生效。", + "settings.archive.applyBlocked": "請先完成或處理相關傳輸,再套用此修訂版本。", + "settings.archive.apply": "套用於現有記錄", + "common.fullscreenUnsupported": "此瀏覽器不支援全螢幕模式。", + "recordings.viewInTimelineTitle": "在時間軸檢視中查看此時間點的串流", + "recordings.clickToRetry": "點擊重試", + "timeline.previousDay": "前一天", + "timeline.nextDay": "後一天", + "timeline.previousMonth": "上個月", + "timeline.nextMonth": "下個月", + "settings.searchLabel": "搜尋設定", + "settings.clearSearch": "清除搜尋", + "recordings.addTagPlaceholder": "新增標籤…", + "recordings.addNewTagPlaceholder": "新增標籤…" } diff --git a/web/public/locales/zh.json b/web/public/locales/zh.json index 9bd632c0..ba5ff7e1 100644 --- a/web/public/locales/zh.json +++ b/web/public/locales/zh.json @@ -759,9 +759,9 @@ "streamsConfig.streamNameImmutable": "流名称创建后无法更改", "streamsConfig.streamNameAllowedChars": "只允许使用字母、数字、“.”、“-”和“_”(不能有空格)。", "streamsConfig.streamUrl": "视频流 URL", - "streamsConfig.streamUrlPlaceholder": "rtsp://用户名:密码@192.168.1.100:554/stream", + "streamsConfig.streamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/stream", "streamsConfig.subStreamUrl": "子码流URL(可选)", - "streamsConfig.subStreamUrlPlaceholder": "rtsp://用户名:密码@192.168.1.100:554/substream", + "streamsConfig.subStreamUrlPlaceholder": "rtsp://username:password@192.168.1.100:554/substream", "streamsConfig.subStreamUrlHelp": "仪表板网格视图的低分辨率流URL。留空即可在任何地方使用主流。子码流仅用于网格模式下的实时预览;录制和全屏始终使用主流。", "streamsConfig.urlCredentialsHiddenTitle": "URL 凭据在演示/查看器模式下隐藏", "streamsConfig.urlCredentialsHidden": "URL 为了安全起见隐藏凭据", @@ -819,7 +819,7 @@ "streamsConfig.ensureLightObjectDetectRunning": "确保 light-object-detect 正在该端点上运行", "streamsConfig.customApiEndpointUrl": "自定义API端点URL", "streamsConfig.useDefaultEndpoint": "使用默认端点", - "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:9001/检测", + "streamsConfig.customApiEndpointPlaceholder": "http://192.168.1.100:8000/api/v1/detect", "streamsConfig.customApiEndpointHelp": "输入完整的URL到您的自定义检测API端点", "streamsConfig.overrideWithCustomEndpoint": "使用自定义端点覆盖", "streamsConfig.detectionThreshold": "检测阈值", @@ -1056,7 +1056,7 @@ "settings.detectionModelsPath": "检测模型路径", "settings.detectionModelsPathHelp": "检测模型存放目录", "settings.apiDetectionUrl": "API检测URL", - "settings.apiDetectionUrlHelp": "URL 外部物体检测 API 端点", + "settings.apiDetectionUrlHelp": "light-object-detect 端点,例如 http://localhost:8000/api/v1/detect。快照以 multipart 表单数据上传,并附加 backend 和 confidence_threshold 查询参数。", "settings.apiDetectionBackend": "API检测后端", "settings.apiDetectionBackendOnnx": "ONNX运行时", "settings.apiDetectionBackendTflite": "TensorFlow Lite", @@ -1156,5 +1156,1492 @@ "settings.discoveryIntervalSecondsRangeHelp": "扫描相机的频率(30–3600 秒)", "settings.discoveryNetwork": "探索网络", "settings.discoveryNetworkExamples": "示例:192.168.1.0/24、10.0.0.0/16、自动", - "settings.saveSettings": "保存设置" + "settings.saveSettings": "保存设置", + "nav.investigation": "排查", + "availability.label": "摄像头可用性", + "availability.live": "当前在线", + "availability.offline": "离线(曾连接过)", + "availability.neverConnected": "从未连接", + "availability.disabled": "已禁用", + "availability.all": "所有摄像头", + "live.navigator.title": "导航器", + "live.navigator.subtitle": "位置、布局与活动", + "live.navigator.cameras": "摄像头", + "live.navigator.plans": "平面图", + "live.navigator.views": "视图", + "live.navigator.events": "事件", + "live.navigator.search": "搜索摄像头…", + "live.navigator.allCameras": "全部摄像头", + "live.navigator.unassigned": "未分配", + "live.navigator.noCameras": "当前范围内没有匹配的摄像头。", + "live.navigator.saveCurrent": "保存当前布局", + "live.navigator.noLayouts": "暂无已保存的布局。", + "live.navigator.layoutNamePrompt": "命名此实时布局", + "live.navigator.shareLayoutPrompt": "将此布局共享给其他操作员?", + "live.navigator.layoutSaved": "已保存 {name}", + "live.navigator.layoutLoaded": "已加载 {name}", + "live.navigator.deleteLayoutConfirm": "删除 {name}?", + "live.navigator.shared": "已共享", + "live.navigator.loadingEvents": "正在加载近期事件…", + "live.navigator.noRecentEvents": "最近一小时内没有检测到目标。", + "live.navigator.expand": "展开导航器", + "live.navigator.collapse": "收起导航器", + "live.plan.navigatorHelp": "选择建筑或楼层。摄像头预览仅在请求时打开。", + "live.plan.noPlans": "暂无建筑平面图。请在平面图工作区中创建。", + "live.plan.emptyTitle": "构建空间摄像头视图", + "live.plan.emptyDescription": "平面图显示整个场地的状态标记,仅在操作员请求时打开视频。在此直接绘制房间和墙体,或上传扫描的平面图、场地图纸或 NVR 软件截图,然后将摄像头映射到实际房间。", + "live.plan.sketch.tools": "布局工具", + "live.plan.sketch.tool.select": "选择", + "live.plan.sketch.tool.room": "房间", + "live.plan.sketch.tool.wall": "墙体", + "live.plan.sketch.tool.area": "区域", + "live.plan.sketch.tool.label": "标签", + "live.plan.sketch.undo": "撤销绘制", + "live.plan.sketch.redo": "重做绘制", + "live.plan.sketch.snap": "对齐网格", + "live.plan.sketch.hint.select": "拖拽图形或摄像头以移动。点击图形进行编辑;按住 Alt 跳过网格。", + "live.plan.sketch.hint.room": "在平面图上拖拽以绘制房间或建筑轮廓。", + "live.plan.sketch.hint.wall": "点击添加墙体顶点。双击或按 Enter 完成,按 Escape 取消。", + "live.plan.sketch.hint.area": "点击勾勒区域轮廓。点击第一个点或按 Enter 闭合。", + "live.plan.sketch.hint.label": "点击平面图放置文本标签。", + "live.plan.sketch.type.rect": "房间", + "live.plan.sketch.type.wall": "墙体", + "live.plan.sketch.type.area": "区域", + "live.plan.sketch.type.label": "标签", + "live.plan.sketch.pointCount": "{count} 个顶点", + "live.plan.sketch.defaultLabel": "标签", + "live.plan.sketch.shapes": "布局图形", + "live.plan.sketch.noShapes": "尚未绘制任何内容。选择上方工具开始绘制。", + "live.plan.sketch.tone": "颜色", + "live.plan.sketch.tone.slate": "石板灰", + "live.plan.sketch.tone.blue": "蓝色", + "live.plan.sketch.tone.green": "绿色", + "live.plan.sketch.tone.amber": "琥珀色", + "live.plan.sketch.tone.red": "红色", + "live.plan.sketch.tone.violet": "紫色", + "live.plan.sketch.labelText": "标签", + "live.plan.sketch.text": "文本", + "live.plan.sketch.size": "大小", + "live.plan.sketch.size.sm": "小", + "live.plan.sketch.size.md": "中", + "live.plan.sketch.size.lg": "大", + "live.plan.sketch.filled": "填充房间", + "live.plan.sketch.left": "左侧 %", + "live.plan.sketch.top": "顶部 %", + "live.plan.sketch.width": "宽度 %", + "live.plan.sketch.height": "高度 %", + "live.plan.sketch.points": "顶点", + "live.plan.sketch.point": "顶点 {index}", + "live.plan.sketch.delete": "删除形状", + "live.plan.sketch.duplicate": "复制", + "live.plan.sketch.deselect": "完成", + "live.plan.sketch.emptyTitle": "此平面图暂无内容", + "live.plan.sketch.emptyBody": "在此绘制房间、墙壁和标签,或上传扫描的平面图、现场图纸或 PNG/JPEG 导出文件(最大 768 KB)。", + "live.plan.sketch.emptyBodyReadOnly": "管理员可以绘制布局或上传实际建筑的平面图。", + "live.plan.sketch.drawLayout": "绘制布局", + "live.plan.sketch.uploadImage": "上传图片", + "live.plan.sketch.limitReached": "已达到形状数量上限({max})", + "live.plan.sketch.discardDrawing": "已取消绘制", + "streams.inventory": "设备清单", + "streams.configuration": "配置", + "events.tab": "事件", + "events.eyebrow": "事件驱动集成", + "events.title": "事件与路由", + "events.description": "将摄像头和系统事件转化为持久化 MQTT 流,用于自动化、通知服务和外部处理。LightNVR 提供事件接口;邮件和短信发送由下游服务负责。", + "events.routes": "路由", + "events.destinations": "目标", + "events.catalog": "事件目录", + "events.enable": "启用", + "events.loadError": "无法加载事件路由配置", + "events.accessDenied": "访问被拒绝 - 权限不足", + "events.summary.routes": "路由", + "events.summary.enabled": "{count} 个已启用", + "events.summary.destinations": "目标", + "events.summary.managedActive": "{count} 个已管理且活跃", + "events.summary.types": "已注册类型", + "events.summary.registry": "版本化事件目录", + "events.summary.interface": "接口", + "events.summary.interfaceHelp": "持久化事件输出", + "events.route.add": "添加路由", + "events.route.addTitle": "创建事件路由", + "events.route.editTitle": "编辑事件路由", + "events.route.create": "创建路由", + "events.route.editorDescription": "选择符合条件的事件、作用范围的摄像头、目标位置,以及如何控制噪声源。", + "events.route.emptyTitle": "未配置事件路由", + "events.route.emptyDescription": "创建路由以选择事件类型、摄像头范围、计划、抑制策略和 MQTT 目标。", + "events.route.enabled": "路由已启用", + "events.route.enabledHelp": "匹配的事件将被接受并进行持久化投递", + "events.route.destination": "目标", + "events.route.destinationHelp": "每个匹配事件将为每个唯一目标持久化一次。", + "events.route.eventTypes": "事件类型", + "events.route.eventTypesHelp": "从注册表中选择一个或多个版本化事件契约。", + "events.route.detectionFilters": "过滤目标检测", + "events.route.detectionFiltersHelp": "可选地要求目标检测事件的标签、区域或最低置信度。", + "events.route.healthFilters": "过滤系统健康事件", + "events.route.healthFiltersHelp": "可选地匹配已注册的健康状况代码或严重级别。可用值来自本录像机。", + "events.route.healthConditions": "健康状况(任意)", + "events.route.healthSeverities": "严重级别(任意)", + "events.route.healthRegistryUnavailable": "健康状况注册表不可用。请在配置条件过滤器前重新加载。", + "events.route.labels": "标签(任意)", + "events.route.zones": "区域 ID(任意)", + "events.route.listHelp": "使用逗号分隔值。", + "events.route.minConfidence": "最低置信度", + "events.route.confidenceHelp": "取值范围为 0 到 1。", + "events.route.cameraScope": "摄像头范围", + "events.route.cameraScopeHelp": "复用设备组位置、标签、属性集合或指定摄像头,无需加载全部设备。", + "events.route.allCameras": "所有摄像头", + "events.route.dynamicScope": "动态摄像头选择器", + "events.route.systemScopeHelp": "系统事件不属于摄像头。当此路由包含系统级事件时,摄像头选择器不可用。", + "events.route.schedule": "计划", + "events.route.scheduleHelp": "使用 IANA 时区中的事件发生时间;支持跨午夜时间窗口。", + "events.route.restrictSchedule": "仅在配置的时间窗口内", + "events.route.suppression": "噪声与投递策略", + "events.route.suppressionHelp": "设为零可禁用某项控制。抑制仅在目标接受持久化事件后推进。", + "events.route.debounce": "防抖秒数", + "events.route.debounceHelp": "重复观测会延长此静默间隔。", + "events.route.cooldown": "冷却时间(秒)", + "events.route.cooldownHelp": "接受事件后的最小间隔。", + "events.route.grouping": "分组窗口(秒)", + "events.route.groupingHelp": "保留首个事件并合并重复项。", + "events.route.rateLimit": "每分钟事件数", + "events.route.rateLimitHelp": "每条路由和摄像头的固定窗口最大值。", + "events.route.deliveryPolicy": "投递策略", + "events.route.suppressionActive": "噪声控制已启用", + "events.route.everyMatch": "每次匹配", + "events.route.preview": "预览路由", + "events.route.previewing": "预览中…", + "events.route.previewResult": "路由预览", + "events.route.cameraMatches": "{count} 个摄像头匹配", + "events.route.previewNoPublish": "预览将验证完整规则并解析摄像头样本,不会发布事件。", + "events.route.systemPreviewHelp": "系统事件绕过摄像头选择,因此在此预览中报告零个匹配摄像头。", + "events.route.created": "事件路由已创建", + "events.route.updated": "事件路由已更新", + "events.route.deleted": "事件路由已删除", + "events.route.disabled": "事件路由已禁用", + "events.route.enabledMessage": "事件路由已启用", + "events.route.deleteConfirm": "删除事件路由\"{name}\"?", + "events.route.validation.name": "请输入路由名称。", + "events.route.validation.destination": "请选择目标。", + "events.route.validation.event_types": "请至少选择一种事件类型。", + "events.route.validation.selector": "请完善或修正摄像头选择器。", + "events.route.validation.system_scope": "摄像头选择器不能用于系统级事件。", + "events.route.validation.detection_type": "检测筛选器需要目标检测事件类型。", + "events.route.validation.detection_filter": "请至少添加一个检测标签、区域或置信度阈值。", + "events.route.validation.confidence": "最低置信度必须在 0 到 1 之间。", + "events.route.validation.predicate_mix": "检测筛选器和健康筛选器不能在同一路由中组合使用。", + "events.route.validation.health_type": "健康筛选器仅支持已注册的系统健康事件类型。", + "events.route.validation.health_filter": "请至少选择一个已注册的健康状况或严重级别。", + "events.route.validation.health_condition": "仅选择录像机健康注册表返回的条件代码。", + "events.route.validation.health_severity": "仅选择所选健康事件类型支持的严重级别。", + "events.route.validation.timezone": "输入已安装的 IANA 时区,如 UTC 或 America/New_York。", + "events.route.validation.schedule_window": "每个计划窗口至少需要一天以及不同的有效开始和结束时间。", + "events.route.validation.suppression": "抑制值必须是允许范围内的整数。", + "events.schedule.timezone": "时区", + "events.schedule.timezoneHelp": "必须存在于录像机的时区数据库中。", + "events.schedule.addWindow": "添加时间窗口", + "events.schedule.windowNumber": "窗口 {number}", + "events.schedule.start": "开始", + "events.schedule.end": "结束", + "events.schedule.sunday": "日", + "events.schedule.monday": "一", + "events.schedule.tuesday": "二", + "events.schedule.wednesday": "三", + "events.schedule.thursday": "四", + "events.schedule.friday": "五", + "events.schedule.saturday": "六", + "events.destination.add": "添加目标", + "events.destination.addTitle": "添加 MQTT 目标", + "events.destination.editTitle": "编辑 MQTT 目标", + "events.destination.create": "创建目标", + "events.destination.editorDescription": "配置持久化事件输出。凭据仅可写入,API 不会返回。", + "events.destination.default": "默认 MQTT 设置", + "events.destination.settingsManaged": "设置已托管", + "events.destination.defaultDescription": "现有 MQTT 配置仍可作为 mqtt:default 使用,当前被 {count} 条路由使用。", + "events.destination.openSettings": "打开 MQTT 设置", + "events.destination.emptyTitle": "无托管目标", + "events.destination.emptyDescription": "添加另一个 MQTT 代理,用于向云连接器、自动化系统或通知服务独立投递事件。", + "events.destination.identity": "目标标识", + "events.destination.enabled": "目标已启用", + "events.destination.enabledHelp": "连接并清空其持久化队列", + "events.destination.active": "活跃", + "events.destination.paused": "已暂停", + "events.destination.pause": "暂停", + "events.destination.broker": "Broker", + "events.destination.host": "Broker 主机", + "events.destination.hostHelp": "仅输入主机名或 IP 地址;不要包含 URL 协议前缀。", + "events.destination.port": "端口", + "events.destination.clientId": "客户端 ID", + "events.destination.clientIdHelp": "必须在此 Broker 连接中唯一。", + "events.destination.topic": "主题", + "events.destination.topicTemplate": "主题模板", + "events.destination.topicHelp": "必须包含事件类型和主体 ID 令牌;不允许使用 MQTT 通配符。", + "events.destination.keepalive": "保活间隔(秒)", + "events.destination.statusTopicTemplate": "在线状态主题", + "events.destination.statusTopicHelp": "可选。必须包含 {installation_uuid};{destination_uuid} 也可用。不允许使用 MQTT 通配符。", + "events.destination.statusTopicEnabled": "此目标已显式启用在线状态。主题不会从事件主题推断。", + "events.destination.statusTopicDisabled": "此目标已禁用在线状态。留空以保持禁用。", + "events.destination.qos": "服务质量", + "events.destination.qos0": "发送一次", + "events.destination.qos1": "至少一次", + "events.destination.qos2": "恰好一次", + "events.destination.authentication": "认证", + "events.destination.passwordPreserved": "留空以保留已存储的密码。", + "events.destination.passwordOptional": "当 Broker 允许匿名客户端时可选。", + "events.destination.clearPassword": "清除已存储的密码", + "events.destination.transportSecurity": "传输安全", + "events.destination.tlsMode": "TLS 模式", + "events.destination.tlsSystem": "系统信任存储", + "events.destination.tlsCustomCa": "自定义证书颁发机构", + "events.destination.tlsMutual": "双向 TLS", + "events.destination.tlsDisabled": "已禁用(明文)", + "events.destination.tlsHelp.system": "使用操作系统信任存储验证 Broker 证书。", + "events.destination.tlsHelp.custom_ca": "使用显式 PEM 证书颁发机构文件验证代理。", + "events.destination.tlsHelp.mutual": "使用显式 CA 验证代理,并提供客户端证书和密钥。", + "events.destination.tlsHelp.disabled": "无传输加密或代理身份验证。", + "events.destination.caFile": "CA 文件", + "events.destination.certFile": "客户端证书文件", + "events.destination.keyFile": "客户端密钥文件", + "events.destination.absolutePathHelp": "使用 LightNVR 服务可读的绝对路径。", + "events.destination.plaintextWarning": "明文 MQTT 可能暴露事件元数据和凭据。仅在受信任的隔离网络中使用。", + "events.destination.security": "安全", + "events.destination.tls.system": "系统信任", + "events.destination.tls.custom_ca": "自定义 CA", + "events.destination.tls.mutual": "双向 TLS", + "events.destination.tls.disabled": "明文", + "events.destination.routes": "路由", + "events.destination.presence": "在线状态主题", + "events.destination.deleteInUse": "删除此目标之前,请先移除或重定向路由。", + "events.destination.created": "MQTT 目标已创建", + "events.destination.updated": "MQTT 目标已更新", + "events.destination.deleted": "MQTT 目标已删除", + "events.destination.pausedMessage": "MQTT 目标已暂停;队列中的事件将持久保留直至过期。", + "events.destination.enabledMessage": "MQTT 目标已启用", + "events.destination.deleteConfirm": "删除 MQTT 目标\"{name}\"?", + "events.destination.validation.name": "请输入目标名称。", + "events.destination.validation.host": "请输入代理主机名或 IP 地址。", + "events.destination.validation.client_id": "请输入代理客户端 ID。", + "events.destination.validation.topic": "主题必须包含事件类型和主体 ID 令牌,且不能包含 MQTT 通配符。", + "events.destination.validation.status_topic": "可选的在线状态主题必须包含安装 UUID 令牌,仅使用支持的令牌,且不能包含 MQTT 通配符。", + "events.destination.validation.port": "端口必须是 1 到 65535 之间的整数。", + "events.destination.validation.keepalive": "保活时间必须是 5 到 3600 秒之间的整数。", + "events.destination.validation.qos": "请选择 MQTT QoS 0、1 或 2。", + "events.destination.validation.username": "配置密码需要提供用户名。", + "events.destination.validation.ca_file": "此 TLS 模式需要 CA 文件的绝对路径。", + "events.destination.validation.mutual_files": "Mutual TLS 需要 CA、客户端证书和客户端密钥的绝对路径。", + "fleet.eyebrow": "摄像头操作", + "fleet.title": "摄像头清单", + "fleet.description": "在大规模部署中查找、评估和组织摄像头,无需将整个清单加载到浏览器中。", + "fleet.summary": "设备组健康概览", + "fleet.totalCameras": "匹配的摄像头", + "fleet.needsAttention": "降级", + "fleet.searchLabel": "搜索摄像头", + "fleet.searchPlaceholder": "搜索名称、地址、位置、标签、厂商或型号…", + "fleet.resultCount": "{count} 个摄像头", + "fleet.filters": "筛选", + "fleet.clearFilters": "清除筛选", + "fleet.filter.health": "健康状态", + "fleet.filter.enabled": "摄像头状态", + "fleet.filter.anyState": "任意状态", + "fleet.filter.recording": "录像模式", + "fleet.filter.location": "位置子树", + "fleet.filter.allLocations": "所有位置", + "fleet.filter.tags": "标签(匹配任意)", + "fleet.filter.collection": "摄像头集合", + "fleet.health.unknown": "未知", + "fleet.health.up": "在线", + "fleet.health.degraded": "降级", + "fleet.health.down": "离线", + "fleet.health.disabled": "已禁用", + "fleet.recording.off": "关闭", + "fleet.recording.continuous": "连续", + "fleet.recording.detection": "检测", + "fleet.recordingActive": "正在录像", + "fleet.recordingInactive": "未录像", + "fleet.column.camera": "摄像头", + "fleet.column.health": "健康状态", + "fleet.column.location": "位置", + "fleet.column.tags": "标签", + "fleet.column.recording": "录像", + "fleet.viewLive": "实时", + "fleet.lastFrame": "最后帧", + "fleet.noAddress": "地址不可用", + "fleet.unassigned": "未分配", + "fleet.loading": "正在加载摄像头列表…", + "fleet.refreshing": "正在刷新…", + "fleet.loadError": "无法加载摄像头列表", + "fleet.emptyTitle": "未配置摄像头", + "fleet.emptyDescription": "添加视频流以在摄像头工作区中使用。", + "fleet.emptyFilteredTitle": "没有匹配的摄像头", + "fleet.emptyFilteredDescription": "请尝试扩大搜索范围或清除部分筛选条件。", + "fleet.paginationSummary": "显示第 {first}–{last} 条,共 {total} 条", + "fleet.perPage": "每页", + "fleet.pageOf": "第 {page} 页,共 {pages} 页", + "fleet.selectPage": "选择本页所有摄像头", + "fleet.selectCamera": "选择 {name}", + "fleet.selectedCount": "已选择 {count} 个摄像头", + "fleet.organizeSelected": "整理已选", + "fleet.clearSelection": "清除选择", + "fleet.organization.manage": "管理组织结构", + "fleet.organization.title": "摄像头组织", + "fleet.organization.description": "为摄像头列表维护可复用的位置层级和规范化标签字典。", + "fleet.organization.locations": "位置", + "fleet.organization.tags": "标签", + "fleet.organization.locationsDescription": "将站点、建筑、楼层和作业区域建模为可导航的层级结构。", + "fleet.organization.tagsDescription": "使用受管理的标签字典,避免不一致的自由标签。", + "fleet.organization.addRoot": "添加顶级位置", + "fleet.organization.addLocation": "添加位置", + "fleet.organization.editLocation": "编辑位置", + "fleet.organization.addChild": "添加子项", + "fleet.organization.type": "类型", + "fleet.organization.parent": "上级位置", + "fleet.organization.topLevel": "顶级", + "fleet.organization.sortOrder": "排序", + "fleet.organization.contents": "内容", + "fleet.organization.cameras": "摄像头", + "fleet.organization.system": "系统", + "fleet.organization.contentCounts": "{cameras} 个摄像头 · {children} 个子项", + "fleet.organization.locationNotEmpty": "请先移动摄像头并删除子位置", + "fleet.organization.noLocations": "尚未配置位置。", + "fleet.organization.locationCreated": "位置已创建", + "fleet.organization.locationUpdated": "位置已更新", + "fleet.organization.locationDeleted": "位置已删除", + "fleet.organization.deleteLocationConfirm": "删除位置\"{name}\"?", + "fleet.organization.addTag": "添加标签", + "fleet.organization.editTag": "编辑标签", + "fleet.organization.tagLabel": "标签", + "fleet.organization.color": "颜色 (#RRGGBB)", + "fleet.organization.tagDescription": "描述", + "fleet.organization.noTags": "尚未配置标准化标签。", + "fleet.organization.tagCreated": "标签已创建", + "fleet.organization.tagUpdated": "标签已更新", + "fleet.organization.tagDeleted": "标签已删除", + "fleet.organization.deleteTagConfirm": "删除\"{name}\"?当前已分配给 {count} 个摄像头。", + "fleet.organization.merge": "合并", + "fleet.organization.mergeTagNamed": "合并\"{name}\"", + "fleet.organization.mergeInto": "合并到", + "fleet.organization.chooseTag": "选择要保留的标签", + "fleet.organization.mergeWarning": "所有摄像头分配将移至保留的标签,源标签随后将被移除。", + "fleet.organization.tagsMerged": "标签已合并", + "fleet.organization.saveError": "保存失败:{message}", + "fleet.organization.deleteError": "无法删除:{message}", + "fleet.locationType.site": "站点", + "fleet.locationType.building": "建筑", + "fleet.locationType.floor": "楼层", + "fleet.locationType.area": "区域", + "fleet.locationType.zone": "分区", + "fleet.locationType.system": "系统", + "fleet.bulk.title": "整理所选摄像头", + "fleet.bulk.description": "以有限并发将位置和标签更改应用到 {count} 个摄像头。", + "fleet.bulk.location": "位置分配", + "fleet.bulk.locationHelp": "所有选中的摄像头将移动到所选位置。", + "fleet.bulk.keepLocations": "保持当前位置", + "fleet.bulk.tags": "标签分配", + "fleet.bulk.tagsHelp": "添加或移除标签而不影响其他分配,或显式替换完整标签集。", + "fleet.bulk.tagOperation.none": "保留", + "fleet.bulk.tagOperation.add": "添加", + "fleet.bulk.tagOperation.remove": "移除", + "fleet.bulk.tagOperation.replace": "全部替换", + "fleet.bulk.replaceWarning": "全部替换会先移除所有当前标签,再应用所选标签。空选择将清除所有标签。", + "fleet.bulk.apply": "应用更改", + "fleet.bulk.working": "正在应用更改…", + "fleet.bulk.success": "已更新 {count} 个摄像头", + "fleet.bulk.partial": "已更新 {succeeded} 个摄像头;{failed} 个失败", + "fleet.bulk.error": "无法整理摄像头:{message}", + "fleet.bulk.failures": "无法更新的摄像头", + "fleet.queues.degraded": "降级流", + "fleet.queues.offline": "离线摄像头", + "fleet.queues.oldest": "最早:{time}", + "fleet.queues.noneActive": "无活动条件", + "fleet.views.title": "已保存视图", + "fleet.views.choose": "选择已保存视图", + "fleet.views.none": "暂无已保存视图", + "fleet.views.shared": "共享", + "fleet.views.saveCurrent": "保存当前视图", + "fleet.views.name": "视图名称", + "fleet.views.share": "与所有操作员共享", + "fleet.views.saved": "设备组视图已保存", + "fleet.views.saveError": "无法保存视图:{message}", + "fleet.views.deleted": "设备组视图已删除", + "fleet.views.deleteConfirm": "删除已保存的视图\"{name}\"?", + "fleet.views.deleteError": "无法删除视图:{message}", + "fleet.views.unsupported": "此已保存的选择器无法用当前筛选控件表示。", + "collections.manage": "集合", + "collections.all": "所有集合", + "collections.filter": "集合", + "collections.loadMembersError": "无法加载集合摄像头:{message}", + "collections.title": "摄像头集合", + "collections.subtitle": "创建可复用的摄像头分组,用于运维、已保存视图及下游工作流。", + "collections.listDescription": "静态集合保持显式成员;智能集合持续评估设备组规则。", + "collections.create": "创建集合", + "collections.edit": "编辑集合", + "collections.editorDescription": "集合定义使用稳定的摄像头、位置和标签 UUID。", + "collections.backToList": "返回集合", + "collections.type": "集合类型", + "collections.type.static": "静态", + "collections.type.smart": "智能", + "collections.description": "描述", + "collections.shared": "共享集合", + "collections.sharedHelp": "允许其他授权用户查看此集合;摄像头访问规则仍然适用。", + "collections.typeChangeWarning": "更改集合类型将替换其成员模型。原类型的静态成员或智能规则将不再适用。", + "collections.selectorError": "选择器无效:{message}", + "collections.created": "集合已创建", + "collections.updated": "集合已更新", + "collections.saveError": "无法保存集合:{message}", + "collections.loadError": "无法加载集合:{message}", + "collections.cameras": "摄像头", + "collections.visibility.shared": "共享", + "collections.visibility.private": "私有", + "collections.selectorRedacted": "规则私有", + "collections.emptyTitle": "暂无集合", + "collections.emptyAdmin": "创建静态分组或基于智能规则的视图,以复用摄像头选择。", + "collections.emptyViewer": "当前摄像头范围内没有可用的共享集合。", + "collections.deleteConfirm": "删除集合\"{name}\"?", + "collections.deleted": "集合已删除", + "collections.deleteError": "无法删除集合:{message}", + "collections.preview.title": "规则预览", + "collections.preview.matches": "{count} 个匹配的摄像头", + "collections.preview.action": "预览", + "collections.preview.hide": "隐藏预览", + "collections.preview.loading": "评估中…", + "collections.preview.empty": "当前没有匹配的摄像头。", + "collections.preview.sample": "显示 {total} 个匹配中的 {count} 个摄像头样本。", + "collections.preview.error": "无法预览集合:{message}", + "collections.members.title": "静态成员", + "collections.members.selected": "已跨所有页面选择 {count} 个摄像头", + "collections.members.search": "搜索摄像头…", + "collections.members.selectPage": "选择本页", + "collections.members.empty": "没有匹配的摄像头。", + "collections.builder.title": "智能规则", + "collections.builder.description": "规则将根据当前摄像头的组织、配置、能力和健康状态进行评估。", + "collections.builder.match": "匹配", + "collections.builder.allRules": "所有规则", + "collections.builder.anyRule": "任意规则", + "collections.builder.addRule": "添加规则", + "collections.builder.removeRule": "移除规则", + "collections.builder.matchesAll": "没有完整规则时,此集合将匹配用户授权范围内的所有摄像头。", + "collections.builder.incompleteRule": "保存前请完成或删除所有规则。", + "collections.builder.chooseLocation": "选择位置子树", + "collections.builder.vendorPlaceholder": "厂商名称,以逗号分隔", + "collections.builder.modelPlaceholder": "型号名称,以逗号分隔", + "collections.builder.advancedMode": "高级 JSON", + "collections.builder.visualMode": "可视化构建器", + "collections.builder.cannotVisualize": "此选择器包含可视化构建器无法安全表示的嵌套或高级逻辑。", + "collections.rule.location_subtree": "位置在…内", + "collections.rule.camera_uuid": "指定摄像头", + "collections.rule.tag_any": "包含任意标签", + "collections.rule.tag_all": "包含所有标签", + "collections.rule.tag_none": "不包含任何标签", + "collections.rule.health": "健康状态为", + "collections.rule.enabled": "摄像头状态为", + "collections.rule.recording_mode": "录像模式为", + "collections.rule.capability_any": "包含任意能力", + "collections.rule.capability_all": "包含所有能力", + "collections.rule.vendor": "厂商为", + "collections.rule.model": "型号为", + "collections.capability.onvif": "ONVIF", + "collections.capability.ptz": "PTZ", + "collections.capability.backchannel": "音频回传通道", + "streamHealth.observedFps": "观测帧率", + "streamHealth.expectedFps": "预期", + "streamHealth.fpsHelp": "由 LightNVR 观测;预期值来自摄像头流元数据。", + "login.passwordChanged": "密码修改成功。请使用新密码登录。", + "passwordChangeRequired.title": "修改默认密码", + "passwordChangeRequired.description": "此安装仍在使用默认管理员密码。请在进入 LightNVR 之前更换密码。如已启用多因素认证,将在下次登录时进行验证。", + "passwordChangeRequired.currentPassword": "当前密码", + "passwordChangeRequired.newPassword": "新密码", + "passwordChangeRequired.confirmPassword": "确认新密码", + "passwordChangeRequired.passwordHelp": "至少使用 8 个字符。密码不能为 admin。", + "passwordChangeRequired.submit": "修改密码", + "passwordChangeRequired.saving": "正在修改密码…", + "passwordChangeRequired.error.currentRequired": "请输入当前密码。", + "passwordChangeRequired.error.tooShort": "新密码至少需要 8 个字符。", + "passwordChangeRequired.error.defaultPassword": "新密码不能为 admin。", + "passwordChangeRequired.error.mismatch": "两次输入的新密码不一致。", + "passwordChangeRequired.error.generic": "密码修改失败,请重试。", + "settings.tab.health": "健康状态", + "settings.tab.workspaces": "工作区", + "settings.health.title": "主机与硬件健康", + "settings.health.description": "配置受限的操作系统和硬件监控,不暴露设备路径或敏感信息。", + "settings.health.enabled": "启用健康监控", + "settings.health.enabledHelp": "收集支持的主机、服务、存储、网络和硬件信号。", + "settings.health.profile": "策略配置", + "settings.health.profileHelp": "\"均衡\"为默认选项;\"保守\"模式需要更强的证据才会触发告警。", + "settings.health.profile.balanced": "均衡", + "settings.health.profile.conservative": "保守", + "settings.health.hardwareProvider": "硬件提供者", + "settings.health.provider.auto": "自动(内核提供者)", + "settings.health.provider.smartctl": "smartctl(显式)", + "settings.health.providerHelp.auto": "仅使用受限的 sysfs、NVMe 和内核提供者;不会自动推断 smartctl。", + "settings.health.providerHelp.smartctl": "显式启用可选的受限 smartctl JSON 提供者,用于已发现的设备。", + "settings.health.providerHelp.disabled": "禁用可选的硬件提供者,同时保留可移植的健康监控功能。", + "settings.health.writeProbe": "启用存储写入探测", + "settings.health.writeProbeHelp": "定期执行受限的已配置录像目标探测。", + "settings.health.cadences": "采样频率", + "settings.health.cadencesHelp": "间隔必须从快到慢依次排列,且在服务器限制范围内。", + "settings.health.fastInterval": "快速间隔", + "settings.health.normalInterval": "常规间隔", + "settings.health.slowInterval": "慢速间隔", + "settings.health.deviceInterval": "设备间隔", + "settings.health.presenceInterval": "在线状态间隔", + "settings.health.retention": "事件保留", + "settings.health.conditions": "条件覆盖", + "settings.health.conditionsHelp": "仅覆盖有效策略注册表返回的条件代码和单位。", + "settings.health.conditionOverride": "条件覆盖", + "settings.health.overrideMode": "覆盖模式", + "settings.health.overrideModeHelp": "继承所选配置、选择另一个受限配置、禁用条件或设置已验证的阈值。", + "settings.health.profileDefault": "使用所选配置", + "settings.health.custom": "自定义阈值", + "settings.health.warning": "警告阈值", + "settings.health.critical": "严重阈值", + "settings.health.recovery": "恢复阈值", + "settings.health.warning_for_seconds": "警告持续秒数", + "settings.health.critical_for_seconds": "严重持续秒数", + "settings.health.recovery_for_seconds": "恢复持续秒数", + "settings.health.clearOverrides": "清除覆盖", + "settings.health.registryUnavailable": "服务器未返回条件注册表。编辑覆盖前请重新加载。", + "settings.health.resetDefaults": "重置健康默认值", + "settings.health.reloadGuidance": "保存操作具有原子性。保存成功后请重新加载以确认有效策略;仅在服务器明确要求时才重启。", + "settings.health.validation.profile": "选择支持的健康配置。", + "settings.health.validation.provider": "选择支持的硬件提供方。", + "settings.health.validation.healthFastIntervalSeconds": "快速间隔必须为 5 到 60 秒之间的整数。", + "settings.health.validation.healthNormalIntervalSeconds": "正常间隔必须为 15 到 600 秒之间的整数。", + "settings.health.validation.healthSlowIntervalSeconds": "慢速间隔必须为 60 到 3600 秒之间的整数。", + "settings.health.validation.healthDeviceIntervalSeconds": "设备间隔必须为 300 到 86400 秒之间的整数。", + "settings.health.validation.healthPresenceIntervalSeconds": "在线检测间隔必须为 15 到 3600 秒之间的整数。", + "settings.health.validation.healthIncidentRetentionDays": "事件保留必须为 7 到 3650 天之间的整数。", + "settings.health.validation.ordered": "采样间隔必须按快速、正常、慢速、设备的顺序排列。", + "settings.health.validation.overrides": "条件覆盖必须使用服务器注册表中唯一的代码和支持的配置。", + "settings.health.validation.thresholds": "自定义阈值必须为条件单位范围内的有限值。", + "settings.health.validation.thresholdOrder": "警告、严重和恢复阈值必须保持条件的告警方向和迟滞。", + "settings.health.validation.dwell": "持续时间必须为七天内的整秒数;警告和恢复持续时间不能为零。", + "workspaces.title": "操作员工作区", + "workspaces.description": "选择哪些专用工作区显示在导航和页面框架中。", + "workspaces.saved": "工作区偏好已保存", + "workspaces.saveError": "无法保存工作区偏好:{message}", + "workspaces.loadError": "无法加载工作区偏好。", + "workspaces.showWorkspace": "显示 {name}", + "workspaces.authorizationNote": "此设置仅控制界面显示。直接 URL 和 API 访问仍遵循您的授权策略。", + "workspaces.liveNavigator": "增强型实时导航器", + "workspaces.liveNavigatorDescription": "位置树、可用性筛选、已保存布局和最近事件。", + "workspaces.investigation": "调查", + "workspaces.investigationDescription": "搜索、关联、保护和导出录像证据。", + "settings.reduceMotion": "减少动效", + "settings.reduceMotionHelp": "禁用非必要动画和过渡效果。\"自动\"将跟随您的操作系统偏好。", + "settings.reduceMotionPreference": "减少动效偏好", + "settings.reduceMotionAuto": "自动", + "settings.reduceMotionOn": "开启", + "settings.reduceMotionOff": "关闭", + "settings.audioCompliance": "音频合规", + "settings.disableAudioGlobally": "在此实例中禁用音频", + "settings.audioDisabled": "音频已全局禁用", + "settings.audioComplianceHelp": "在此实例中禁止实时监听、双向对讲和新录像中的音频。保存后将重启活跃的 go2rtc 媒体会话。现有录像不受影响。", + "tokens.manage": "管理 API 访问", + "tokens.title": "API 访问 — {username}", + "tokens.description": "为集成创建最小权限凭证,并可独立撤销每一个。", + "tokens.recommendedTitle": "推荐使用作用域令牌", + "tokens.recommendedDescription": "每个令牌都有过期时间、明确的操作和摄像头范围,且永远不会超出用户当前的访问策略。", + "tokens.coverageNotice": "可用权限反映此服务器所执行的范围。令牌只能使用其用户已拥有的权限。", + "tokens.createTitle": "创建作用域令牌", + "tokens.createDescription": "每个集成使用一个令牌,以便在不影响其他集成的情况下进行识别、轮换和撤销。", + "tokens.name": "集成名称", + "tokens.namePlaceholder": "例如:北车库 PTZ 桥接", + "tokens.expiry": "有效期", + "tokens.expiryDays": "{days} 天", + "tokens.actions": "允许的操作", + "tokens.actionsHelp": "仅选择此集成所需的操作。破坏性操作应使用单独的令牌。", + "tokens.destructive": "破坏性", + "tokens.noEnforcedActions": "当前服务器版本不支持令牌授权操作。", + "tokens.scope.label": "摄像头范围", + "tokens.scope.all": "全部摄像头", + "tokens.scope.collection": "共享集合", + "tokens.scope.selector": "自定义选择器", + "tokens.scope.chooseCollection": "共享摄像头集合", + "tokens.scope.allValue": "全部设备", + "tokens.scope.collectionValue": "集合:{name}", + "tokens.scope.selectorValue": "自定义动态选择器", + "tokens.create": "创建令牌", + "tokens.creating": "正在创建令牌…", + "tokens.createdSuccess": "已创建作用域 API 令牌", + "tokens.createError": "无法创建 API 令牌:{message}", + "tokens.invalidResponse": "服务器返回了不完整的凭据响应。", + "tokens.existingTitle": "现有令牌", + "tokens.existingDescription": "创建后仅保留前缀和元数据。", + "tokens.emptyTitle": "无活动令牌", + "tokens.emptyDescription": "为需要 API 访问的首个集成创建作用域令牌。", + "tokens.showInactive": "显示 {count} 个已停用", + "tokens.status.active": "活动", + "tokens.status.expired": "已过期", + "tokens.status.revoked": "已撤销", + "tokens.expires": "过期时间", + "tokens.expiresValue": "过期于 {date}", + "tokens.created": "创建时间", + "tokens.lastUsed": "最后使用", + "tokens.revoke": "撤销", + "tokens.revoking": "正在撤销…", + "tokens.revokeConfirm": "撤销\"{description}\"?使用该令牌的请求将立即停止工作。", + "tokens.revokedSuccess": "API 令牌已撤销", + "tokens.revokeError": "无法撤销 API 令牌:{message}", + "tokens.validation.missing_description": "为使用此令牌的集成命名。", + "tokens.validation.description_too_long": "集成名称不得超过 128 个字符。", + "tokens.validation.invalid_expiry": "请选择 1 到 365 天的令牌有效期。", + "tokens.validation.missing_actions": "请至少选择一个允许的操作。", + "tokens.validation.invalid_action": "所选的一个或多个操作在此服务器上未启用令牌访问。", + "tokens.validation.invalid_scope": "请选择有效的摄像头范围。", + "tokens.validation.requires_all_scope": "非摄像头权限需要\"全部摄像头\"范围。请选择该范围或移除这些权限。", + "tokens.validation.missing_collection": "请选择一个可用的共享集合。", + "tokens.validation.invalid_selector": "请完成或修正自定义摄像头选择器。", + "tokens.secret.oneTime": "仅显示一次", + "tokens.secret.scopedTitle": "立即保存此作用域令牌", + "tokens.secret.legacyTitle": "立即保存此旧版 API 密钥", + "tokens.secret.scopedDescription": "lightNVR 仅存储此令牌的哈希值。如果丢失,请撤销并重新创建。", + "tokens.secret.legacyDescription": "此兼容密钥仅在此处显示一次。生成新密钥将使其失效。", + "tokens.secret.value": "API 凭据", + "tokens.secret.copied": "已复制", + "tokens.secret.copySuccess": "API 凭据已复制", + "tokens.secret.copyError": "无法自动复制;请手动选择并复制凭据。", + "tokens.secret.savedConfirm": "我已安全保存此凭据", + "tokens.secret.savedHelp": "确认后此对话框将关闭。完整值将无法再次显示。", + "tokens.legacy.title": "旧版兼容密钥", + "tokens.legacy.description": "旧版密钥拥有此用户的完整有效访问权限,不会过期,且无法按摄像头或操作进行范围限制。", + "tokens.legacy.warning": "仅当现有集成的端点尚未迁移至作用域令牌强制模式时才生成。生成后立即使之前的旧版密钥失效。", + "tokens.legacy.generate": "生成旧版密钥", + "tokens.legacy.confirm": "生成新的旧版密钥?这将立即使该用户当前的旧版密钥失效。", + "tokens.legacy.createdSuccess": "旧版 API 密钥已生成", + "tokens.legacy.createError": "无法生成旧版 API 密钥:{message}", + "audit.manage": "审计历史", + "audit.title": "安全与访问审计", + "audit.description": "追踪登录结果、访问决策和敏感策略变更,且不暴露凭据。", + "audit.retention": "保留策略", + "audit.retentionDescription": "事件当前保留 {days} 天。降低此值将立即清除较早的历史记录。", + "audit.retentionDays": "天", + "audit.retentionInvalid": "请选择 1 到 3650 天之间的保留期限。", + "audit.retentionSaved": "审计保留设置已保存;已清除 {count} 条过期事件", + "audit.retentionError": "无法保存审计保留设置:{message}", + "audit.filters": "筛选条件", + "audit.clearFilters": "清除筛选", + "audit.applyFilters": "应用筛选", + "audit.actor": "操作者", + "audit.unauthenticated": "未认证", + "audit.outcome": "结果", + "audit.action": "精确操作", + "audit.filterToAction": "筛选此操作", + "audit.since": "起始", + "audit.until": "结束", + "audit.invalidDateRange": "起始日期必须早于结束日期。", + "audit.source": "源地址", + "audit.target": "目标", + "audit.targetUuid": "目标 UUID", + "audit.noTarget": "全局", + "audit.requestId": "请求 ID", + "audit.apiToken": "作用域令牌 ID", + "audit.showDetails": "显示详情", + "audit.hideDetails": "隐藏详情", + "audit.pageSize": "每页", + "audit.resultRange": "显示第 {start}–{end} 条,共 {total} 条", + "audit.empty": "无匹配的审计事件", + "audit.emptyDescription": "请尝试清除一个或多个筛选条件,或等待新的安全活动。", + "audit.exportPage": "导出当前页", + "audit.exporting": "导出中…", + "audit.exported": "审计页面已导出", + "audit.exportError": "无法导出审计事件:{message}", + "audit.pagination": "审计历史页面", + "audit.page": "第 {page} 页", + "audit.modesTitle": "允许的决策", + "audit.modesDescription": "选择如何记录每个操作的允许只读访问。更改操作、拒绝、错误和登录始终会被记录。摘要模式每 {minutes} 分钟按用户、摄像头和客户端保留一条记录并附带计数。", + "audit.mode.record": "逐条记录", + "audit.mode.summarize": "摘要", + "audit.mode.off": "关闭", + "audit.modeOffWarning": "此操作的允许访问将不再显示在审计历史中。", + "audit.modesSaved": "审计决策模式已保存", + "audit.modesError": "无法保存审计决策模式:{message}", + "audit.summaryRange": "{from} – {to}", + "audit.eventType": "事件类型", + "audit.eventTypeSummary": "摘要", + "audit.eventTypeDecision": "逐条决策", + "access.cameraSearch": "搜索摄像头", + "access.cameraSearchPlaceholder": "输入至少两个字符进行搜索…", + "access.cameraSearchHint": "按摄像头名称、UUID、地址、位置、标签、厂商或型号搜索。", + "access.cameraSelected": "已选择", + "access.cameraAdd": "添加", + "access.cameraLimit": "选择器最多可包含 64 个显式摄像头。更大范围请使用位置或标签规则。", + "access.roles.manage": "管理角色", + "access.roles.title": "授权角色", + "access.roles.description": "将操作打包为可复用的角色,然后将其授予摄像头范围。", + "access.roles.create": "创建角色", + "access.roles.newRole": "新建角色", + "access.roles.copyName": "{name} 副本", + "access.roles.clone": "克隆", + "access.roles.builtin": "内置", + "access.roles.builtinHelp": "内置角色是固定的升级安全模板。克隆一个以进行自定义。", + "access.roles.actionCount": "{count} 个操作", + "access.roles.destructive": "敏感操作", + "access.roles.notEnforced": "尚未被任何端点强制执行", + "access.roles.destructiveWarning": "此角色可更改配置或证据。仅在需要该权限的范围内授予。", + "access.roles.created": "角色已创建", + "access.roles.updated": "角色已更新", + "access.roles.deleted": "角色已删除", + "access.roles.saveError": "无法保存角色:{message}", + "access.roles.deleteError": "无法删除角色:{message}", + "access.roles.deleteConfirm": "删除角色\"{name}\"?被授权引用的角色无法删除。", + "access.policy.manage": "管理访问权限", + "access.policy.column": "访问权限", + "access.policy.scopedShort": "范围限定", + "access.policy.title": "访问策略 — {username}", + "access.policy.description": "管理默认拒绝的角色授权并预览其摄像头范围。", + "access.policy.tab.grants": "授权", + "access.policy.tab.test": "测试访问", + "access.policy.scopedWarning": "仅匹配授权和摄像头范围允许的操作才会生效。", + "access.policy.grants": "角色授权", + "access.policy.grantsDescription": "授权将角色与整个设备组、共享集合或自定义摄像头选择器组合。", + "access.policy.addGrant": "添加授权", + "access.policy.noGrants": "未配置授权", + "access.policy.noGrantsHelp": "激活范围策略前请至少添加一个授权,除非该用户不应拥有任何访问权限。", + "access.policy.role": "角色", + "access.policy.chooseRole": "选择角色", + "access.policy.scope": "摄像头范围", + "access.policy.allCameras": "全部摄像头", + "access.policy.collectionScope": "共享集合", + "access.policy.collection": "摄像头集合", + "access.policy.chooseCollection": "选择共享集合", + "access.policy.collectionHelp": "当摄像头被添加、移除或匹配规则时,访问权限将跟随集合变化。", + "access.policy.dynamicScope": "动态选择器", + "access.policy.activateConfirm": "为 {username} 激活默认拒绝的范围策略?没有匹配授权的操作将被拒绝。", + "access.policy.emptyConfirm": "为 {username} 激活无授权的范围策略?这将有意移除所有策略控制的访问权限。", + "access.policy.saved": "访问策略已保存", + "access.policy.saveError": "无法保存访问策略:{message}", + "access.policy.version": "策略版本 {version}", + "access.policy.unsaved": "未保存的更改", + "access.policy.validation.invalid_mode": "请选择有效的评估模式。", + "access.policy.validation.missing_role": "每个授权必须引用一个可用角色。", + "access.policy.validation.invalid_scope": "每个授权必须使用全部设备、共享集合或选择器范围。", + "access.policy.validation.invalid_selector": "保存前请完成或修正所有摄像头选择器。", + "access.policy.validation.missing_collection": "为每个集合授权选择一个可用的共享集合。", + "access.policy.validation.duplicate_grant": "保存前请移除重复的角色和范围授权。", + "access.test.title": "测试有效访问", + "access.test.description": "以 {username} 身份评估已保存的操作和摄像头,但不执行。", + "access.test.saveFirst": "测试前请保存或放弃授权更改,以确保结果反映此处显示的策略。", + "access.test.action": "操作", + "access.test.camera": "摄像头", + "access.test.run": "测试访问", + "access.test.running": "测试中…", + "access.test.allowed": "允许", + "access.test.denied": "拒绝", + "access.test.version": "版本 {version}", + "access.test.source": "来源:{source} · 角色:{role}", + "recordings.pullToRefresh": "下拉刷新录像", + "recordings.releaseToRefresh": "松开刷新录像", + "recordings.refreshing": "正在刷新录像…", + "recordings.refreshed": "录像已刷新", + "recordings.refreshFailed": "无法刷新录像:{message}", + "recordings.download": "下载", + "recordings.tags": "标签", + "recordings.selectRecording": "选择录像", + "timeline.legend.recording": "录像", + "timeline.legend.detection": "检测事件", + "timeline.detectionEvent": "检测事件", + "streams.showCredentials": "显示凭据", + "streams.hideCredentials": "隐藏凭据", + "streams.streamSuccessfullyEnabled": "流已成功启用。", + "streams.errorEnablingStream": "启用流出错:{message}", + "live.favorites": "收藏", + "live.favoritesOnly": "仅显示收藏的摄像头", + "live.addFavorite": "将 {stream} 添加到收藏", + "live.removeFavorite": "从收藏中移除 {stream}", + "live.noFavorites": "暂无收藏的摄像头。点击摄像头卡片上的星标即可添加。", + "live.favoriteUpdateError": "无法更新收藏:{message}", + "system.health.tab": "健康状态", + "system.health.operatorView": "运行健康状态", + "system.health.title": "系统健康状态", + "system.health.loading": "正在加载系统健康状态…", + "system.health.loadError": "无法加载系统健康状态。", + "system.health.refreshing": "正在刷新…", + "system.health.activeIncidentCount": "{count} 个活跃事件", + "system.health.coverage": "覆盖范围", + "system.health.monitoringDisabled": "健康监控已禁用", + "system.health.lastRecordedValue": "最近记录值", + "system.health.monitoringDisabledHelp": "当前健康指标未采集。请在\"设置 → 健康状态\"中启用健康监控;保存后如提示重启,请重启。事件历史仅显示过往事件,不反映当前资源使用情况。", + "system.health.monitoringRestartRequired": "已保存的配置中健康监控已启用,但运行中的采样器仍处于禁用状态。请重启 LightNVR 以应用更改。事件历史仅显示过往事件。", + "system.health.containerCoverage": "主机覆盖范围有限", + "system.health.hostHardwareUnavailable": "此安装可查看容器及挂载资源的健康状态,但主机硬件信息不可用。缺失的主机值表示未知,而非健康。", + "system.health.coverageUnknown": "尚无已完成的健康快照。在采集完成前,值将保持未知状态。", + "system.health.coverageComplete": "此安装可见的所有健康指标均已成功采集。", + "system.health.coveragePartial": "覆盖范围不完整。{count} 项观测或采集检查不可用、已过期或不完整。", + "system.health.effectiveScope": "有效范围", + "system.health.activeIncidents": "活跃事件", + "system.health.noActiveIncidents": "可见覆盖范围内未报告活跃事件。", + "system.health.duration": "持续时间", + "system.health.currentValue": "当前值", + "system.health.thresholds": "阈值与驻留时间", + "system.health.thresholdSummary": "警告 {warning},严重 {critical},恢复 {recovery} {unit};警告驻留 {seconds} 秒", + "system.health.remediation": "建议响应", + "system.health.facts": "健康指标", + "system.health.group.resources": "资源", + "system.health.group.storage": "存储", + "system.health.group.hardware": "硬件", + "system.health.group.network": "网络", + "system.health.group.clock": "时钟", + "system.health.group.components": "组件", + "system.health.noFacts": "此组中没有可见的信息。", + "system.health.observationState": "能力与时效性", + "system.health.valueUnavailable": "一个或多个值未知", + "system.health.componentStatus": "监控组件", + "system.health.collectors": "采集器", + "system.health.collectorSummary": "已注册 {total} 个 · {attention} 个需要关注", + "system.health.collectorsNeedingAttention": "需要关注的采集器", + "system.health.collectionFailures": "{count} 个失败或超时", + "system.health.stale": "过期", + "system.health.eventDelivery": "事件投递", + "system.health.degraded": "降级", + "system.health.circularDelivery": "这是唯一配置的告警通道,因此无法独立报告自身故障。", + "system.health.incidentPersistence": "事件持久化", + "system.health.persistenceSummary": "{pending} 个待处理 · {failures} 个失败 · {retries} 个重试", + "system.health.recentSamples": "近期采集活动", + "system.health.recentSamplesHelp": "最多显示 {count} 条服务端生成摘要;这是覆盖活动,不是数值图表。", + "system.health.sampleSequence": "第 {sequence} 次生成", + "system.health.sampleCoverage": "{observations} 条观测 · {dropped} 条丢弃", + "system.health.noSamples": "没有已完成的采集生成记录。", + "system.health.incidentHistory": "事件历史", + "system.health.incidentHistoryHelp": "最新事件优先。历史按有限分页加载。", + "system.health.loadingHistory": "正在加载事件历史…", + "system.health.historyError": "无法加载事件历史。", + "system.health.emptyHistory": "没有记录到任何事件。", + "system.health.firstSeen": "首次出现", + "system.health.lastSeen": "最近出现", + "system.health.deliveryState": "投递状态", + "system.health.historyPagination": "事件历史分页", + "system.health.pageCount": "本页 {count} 条事件", + "system.health.remediation.memory": "降低内存压力,检查进程和 cgroup 限制,并查看近期 OOM 活动。", + "system.health.remediation.cpu": "识别持续占用 CPU 的进程,并在调整限制前验证服务吞吐量。", + "system.health.remediation.io": "检查存储延迟和活跃写入;在破坏性维护前保留录像。", + "system.health.remediation.filesystem": "检查指定逻辑文件系统的可用空间或 inode,并确认其仍可写入。", + "system.health.remediation.thermal": "改善散热并降低负载;在温度达到关机限制前检查风扇和通风口。", + "system.health.remediation.network": "通过独立网络路径检查可见接口、链路、交换机和错误计数器。", + "system.health.remediation.clock": "恢复时间同步,并在依赖事件时间戳前验证主机时钟源。", + "system.health.remediation.process": "检查 LightNVR 资源限制和日志,然后降低负载或提高已验证的限制。", + "system.health.remediation.storage": "备份重要录像,并在更换或维修前检查映射的存储设备。", + "system.health.remediation.hardware": "检查受影响的硬件和平台日志;如果问题持续存在,请安排维护。", + "system.health.remediation.health": "恢复采集器的访问权限,以便评估缺失的健康证据。", + "system.health.remediation.system": "查看上次运行和主机日志,以区分进程重启和主机重启。", + "system.health.remediation.event": "使用本地 API 或指标视图,清除持久队列压力,并恢复独立的告警目标。", + "system.health.remediation.default": "查看受影响的组件和近期日志,然后在新的健康周期中验证恢复。", + "system.capacityTarget": "容量目标", + "system.capacityTargetValue": "保留 {pct}% 可用空间", + "system.fillRate": "填充速率", + "system.fillRateValue": "{value} / 天", + "system.projectedToTarget": "预计达到目标时间", + "system.projectedNow": "当前已达/超过目标", + "system.projectedDays": "~{count} 天", + "system.projectedHours": "~{count} 小时", + "system.projectedUnknown": "—", + "common.description": "描述", + "common.remove": "移除", + "live.resetZoom": "重置缩放", + "live.audioPlaybackBlocked": "浏览器已阻止摄像头音频。再次点击扬声器按钮重试。", + "live.fullscreenSubStreamFallback": "{stream}:全屏时带宽不足以播放全分辨率流——已切换至子码流。", + "live.tileActions": "摄像头操作", + "live.takeSnapshot": "抓拍", + "live.openStreamRecordings": "打开此流的录像", + "live.enterReorderMode": "重新排列摄像头", + "live.pullToRefresh": "下拉刷新流", + "live.releaseToRefresh": "释放以刷新流", + "live.refreshingStreams": "正在刷新流…", + "live.streamsRefreshed": "流已刷新", + "live.refreshStreamsFailed": "无法刷新流:{message}", + "live.tipDoubleTapFullscreen": "提示:双击画面可全屏显示。", + "live.dayNightControl": "日夜模式", + "live.dayNightLoading": "加载中…", + "live.dayNightApplying": "应用中…", + "live.dayNightMode_auto": "自动", + "live.dayNightMode_day": "日间", + "live.dayNightMode_night": "夜间", + "live.dayNightMode_unknown": "未知", + "live.dayNightApplied": "日夜模式已设为{mode}", + "live.dayNightApplyFailed": "设置日夜模式失败", + "live.dayNightLoadFailed": "读取日夜模式失败", + "live.playbackFallbackUsed": "回退:{transport}", + "live.playbackTransportUnavailable": "服务器已为此码流禁用 {transport}。", + "live.recordingMode.constant": "持续录像", + "live.recordingMode.detection": "侦测录像", + "live.recordingMode.schedule": "计划录像", + "live.recordingMode.none": "未录像", + "live.health.healthy": "码流正常", + "live.health.degraded": "码流缓冲或恢复中", + "live.health.offline": "码流不可用", + "live.enterPictureInPicture": "开启画中画", + "live.exitPictureInPicture": "关闭画中画", + "live.pictureInPictureError": "画中画失败:{message}", + "live.alwaysFullscreenOnTapEnable": "单击画面即全屏", + "live.alwaysFullscreenOnTapDisable": "单击画面时禁用全屏", + "live.displayMode": "显示模式", + "live.displayModeFit": "适应", + "live.displayModeFill": "填充", + "live.displayModeFitDescription": "适应:显示完整画面,上下留黑边", + "live.displayModeFillDescription": "填充:填满画面,裁切边缘", + "live.slideshowStartCameras": "开始轮播:切换摄像头", + "live.slideshowStartPages": "开始轮播:切换网格页", + "live.slideshowStop": "停止轮播", + "live.slideshowInterval": "轮播间隔", + "live.slideshowSeconds": "{seconds}秒", + "streams.selectStream": "选择 {name}", + "streams.search": "搜索流", + "streams.searchPlaceholder": "搜索摄像头、位置或标签", + "streams.noStreamsMatchFilters": "没有符合当前筛选条件的流。", + "streamHealth.sourceConnected": "源已连接", + "streamHealth.videoAdvancing": "视频推进中", + "streamHealth.recorderWriting": "录像器写入中", + "streamHealth.detectorOperating": "检测器运行中", + "streamHealth.lastSegment": "最近完成的片段", + "streams.disablingStreamsProgress": "正在禁用流…", + "streams.onvifInvalidAddress": "ONVIF 设备 IP 地址缺失或无效。", + "streams.warningFallingBackToHttp": "HTTPS 连接失败,正在通过 HTTP 重试。凭据可能以明文发送。", + "streamsConfig.playbackTransport": "回放传输方式", + "streamsConfig.playbackTransportHelp": "选择此摄像头的浏览器回放方式,以及所选方式的回退顺序。", + "streamsConfig.playbackTransportUnavailable": "服务器不可用:{transports}。请全局启用该传输方式或选择其他配置。", + "streamsConfig.audioDisabledByPolicy": "实例策略已禁用音频", + "streamsConfig.audioDisabledByPolicyHelp": "启用全局音频合规策略时,录像、实时监听和双向对讲不可用。", + "streamsConfig.audioVoiceEnhancement": "语音增强(录像)", + "streamsConfig.customApiModel": "自定义 API 检测", + "streamsConfig.modelNotSupportedByBuild": "当前版本不支持", + "streamsConfig.tierCriticalMultiplier": "关键层级 ×", + "streamsConfig.tierImportantMultiplier": "重要层级 ×", + "streamsConfig.tierEphemeralMultiplier": "临时层级 ×", + "streamsConfig.tierMultipliersHelp": "各层级对基础保留时长的倍率。层级越高的录像保留越久,磁盘空间不足时最后被清除。", + "streamsConfig.storagePriority": "存储优先级(1-10)", + "streamsConfig.storagePriorityHelp": "回收空间时此流录像的相对重要性;优先级越高保留越久。", + "streamsConfig.restream": "转发 / 推流(RTMP)", + "streamsConfig.publishUrl": "推流地址(RTMP/RTMPS)", + "streamsConfig.publishUrlHelp": "通过 go2rtc 将此摄像头转发至 YouTube Live 等服务。粘贴包含流密钥的完整 RTMP 推流地址(例如 rtmp://a.rtmp.youtube.com/live2/xxxx-xxxx)。如需同时转发至多个服务,请用逗号分隔各地址。YouTube 要求 H264 视频和 AAC 音频;LightNVR 现已自动转码(非 H264 摄像头转 H264,非 AAC 音频转 AAC),大多数摄像头可直接使用。注意:YouTube 还要求必须有音频轨道——完全没有音频的摄像头仍会被拒绝。留空则禁用。", + "streams.lastSeen": "最后在线 {time}", + "streams.claimed": "已认领", + "streams.duplicateSuspected": "可能重复", + "streams.duplicateSuspectedHelp": "稳定标识或端点证据与另一条发现记录冲突。", + "streams.onvifClaimWarning": "流已添加,但无法将其发现记录标记为已认领:{message}", + "common.online": "在线", + "common.offline": "离线", + "settings.storageTargets.title": "录像存储目标", + "settings.storageTargets.description": "将本地磁盘及管理员挂载的 NFS 或 SMB 文件系统注册为独立监控的录像存储目标。", + "settings.storageTargets.foundationNotice": "采集使用文件系统目标。S3 存储桶和已挂载的 NFS/SAN 目标可保存已验证的归档副本。热存储压力会保留归档录像,直到其逻辑保留期到期。", + "settings.storageTargets.add": "添加存储目标", + "settings.storageTargets.edit": "编辑存储目标", + "settings.storageTargets.editorHelp": "已启用的目标必须已存在并通过写入、fsync 和清理测试。将不可用的未来挂载保存为禁用状态,挂载后再启用。", + "settings.storageTargets.name": "目标名称", + "settings.storageTargets.root": "挂载根路径", + "settings.storageTargets.rootLocked": "默认或非空目标保持不可变的根路径,以防止现有录像成为孤立文件。", + "settings.storageTargets.class": "性能等级", + "settings.storageTargets.hot": "热 — 活跃录制", + "settings.storageTargets.warm": "温 — 已挂载归档", + "settings.storageTargets.cold": "冷 — 低频访问", + "settings.storageTargets.reserveGb": "预留空间 (GB)", + "settings.storageTargets.lowWatermark": "低水位线 (% 已用)", + "settings.storageTargets.highWatermark": "高水位线 (% 已用)", + "settings.storageTargets.migrationBandwidth": "生命周期带宽 (Mbit/s)", + "settings.storageTargets.migrationBandwidthHelp": "0 表示不限制。创建移动或复制任务时会快照当前限制值。", + "settings.storageTargets.archiveStart": "归档窗口开始", + "settings.storageTargets.archiveEnd": "归档窗口结束", + "settings.storageTargets.archiveWindowHelp": "本地时间。开始和结束时间相同表示全天允许生命周期任务;跨夜窗口可跨越午夜。", + "settings.storageTargets.enabled": "已启用(放置策略可选择此目标)", + "settings.storageTargets.notRouted": "没有已启用的放置策略将摄像头路由到此目标。新录像将继续写入默认目标,直到某个策略将此目标指定为主目标、池成员或归档目标。", + "settings.storageTargets.degradedNotice": "已超过高水位线或处于预留空间内。放置策略将跳过此目标,直到释放空间。", + "settings.storageTargets.probePassedIneligible": "写入测试通过,但目标状态为 {status}:放置策略不会选择此目标。", + "settings.storageTargets.mountRequired": "要求已挂载的文件系统", + "settings.storageTargets.mountRequiredHelp": "将此目标固定到当前非根挂载点。如果该 NFS、SMB、bind 或 PVC 挂载消失,录制将暂停,而不是写入底层主机目录。", + "settings.storageTargets.mountGuard": "必需挂载", + "settings.storageTargets.mountPending": "启用目标时将自动检测", + "settings.storageTargets.default": "默认", + "settings.storageTargets.capacity": "容量", + "settings.storageTargets.available": "可用", + "settings.storageTargets.recordings": "已索引录像", + "settings.storageTargets.replicas": "{count} 个已验证副本 · {bytes}", + "settings.storageTargets.reserve": "已预留", + "settings.storageTargets.pressure.normal": "压力正常", + "settings.storageTargets.pressure.high": "高水位线", + "settings.storageTargets.pressure.reserve": "预留空间不足", + "settings.storageTargets.pressure.unavailable": "压力不可用", + "settings.storageTargets.cleanupActive": "目标范围清理已启用,将在不删除分配给其他目标的录像的情况下,使 {target} 可用。", + "settings.storageTargets.test": "测试目标", + "settings.storageTargets.probing": "测试中…", + "settings.storageTargets.probePassed": "存储目标写入测试通过", + "settings.storageTargets.duplicateFilesystem": "此根目录与另一个目标共享同一底层文件系统。启用放置时,容量不得重复计算。", + "settings.storageTargets.deleteLocked": "默认目标和非空目标不可删除。", + "settings.storageTargets.deleteConfirm": "删除空存储目标\"{name}\"?不会移除任何文件。", + "settings.storageTargets.created": "存储目标已创建", + "settings.storageTargets.updated": "存储目标已更新", + "settings.storageTargets.deleted": "存储目标已删除", + "settings.storageTargets.invalidThresholds": "检查水位线、预留空间、生命周期带宽和归档窗口时间。", + "settings.storageTargets.loadError": "无法加载存储目标", + "settings.storagePools.title": "存储池", + "settings.storagePools.description": "将健康目标分组,用于自动溢出和独立目标复制。", + "settings.storagePools.add": "添加池", + "settings.storagePools.strategy": "分配策略", + "settings.storagePools.mostFree": "最大可用空间", + "settings.storagePools.roundRobin": "轮询", + "settings.storagePools.priority": "显式优先级", + "settings.storagePools.members": "目标(显示顺序即分配优先级)", + "settings.storagePools.enabled": "池已启用", + "settings.storagePools.active": "活跃", + "settings.storagePools.inactive": "已禁用", + "settings.storagePools.strategyValue.most_free": "最大可用", + "settings.storagePools.strategyValue.round_robin": "轮询", + "settings.storagePools.strategyValue.priority": "优先级顺序", + "settings.storagePools.created": "存储池已创建", + "settings.storagePools.updated": "存储池已更新", + "settings.storagePools.deleted": "存储池已删除", + "settings.storagePools.deleteConfirm": "删除存储池\"{name}\"?", + "settings.storagePools.empty": "暂无存储池。", + "settings.storageMigrations.title": "录像迁移任务", + "settings.storageMigrations.description": "持久移动和保留副本会遵循每个目标的归档窗口和带宽限制,验证 SHA-256,并在重启后安全恢复。", + "settings.storageMigrations.empty": "暂无录像迁移任务。", + "settings.storageMigrations.loadError": "无法加载录像迁移任务", + "settings.storageMigrations.recording": "录像 #{id}", + "settings.storageMigrations.attempt": "第 {current}/{max} 次尝试", + "settings.storageMigrations.operation.move": "移动", + "settings.storageMigrations.operation.copy": "保留副本", + "settings.storageMigrations.cancelled": "已接受迁移取消请求", + "settings.storageMigrations.cancelling": "正在取消…", + "settings.storageMigrations.retried": "迁移已加入重试队列", + "settings.storageMigrations.state.queued": "已排队", + "settings.storageMigrations.state.copying": "复制中", + "settings.storageMigrations.state.verifying": "验证中", + "settings.storageMigrations.state.committing": "提交中", + "settings.storageMigrations.state.cleanup_pending": "清理源中", + "settings.storageMigrations.state.retry_wait": "等待重试", + "settings.storageMigrations.state.completed": "已完成", + "settings.storageMigrations.state.failed": "失败", + "settings.storageMigrations.state.cancelled": "已取消", + "settings.storagePolicies.title": "摄像头放置策略", + "settings.storagePolicies.description": "按优先级顺序将匹配的摄像头路由到主录像目标。摄像头使用第一个匹配的已启用策略。", + "settings.storagePolicies.add": "添加放置策略", + "settings.storagePolicies.edit": "编辑放置策略", + "settings.storagePolicies.editorHelp": "新片段将重新评估策略。更改不会移动已存在的录像。", + "settings.storagePolicies.priority": "优先级(高者优先)", + "settings.storagePolicies.priorityValue": "优先级 {priority}", + "settings.storagePolicies.primary": "主目标", + "settings.storagePolicies.primaryPool": "放置池(可选)", + "settings.storagePolicies.exactTarget": "使用精确主目标", + "settings.storagePolicies.fallback": "主目标不可用时", + "settings.storagePolicies.fallbackDefault": "使用默认目标", + "settings.storagePolicies.fallbackTarget": "使用指定备用目标", + "settings.storagePolicies.fallbackPause": "暂停录制", + "settings.storagePolicies.fallbackFail": "录制启动失败", + "settings.storagePolicies.namedFallback": "备用目标", + "settings.storagePolicies.chooseTarget": "选择目标", + "settings.storagePolicies.choosePool": "选择池", + "settings.storagePolicies.minimumDays": "最短保留天数", + "settings.storagePolicies.desiredDays": "期望保留天数", + "settings.storagePolicies.maximumDays": "最长保留天数", + "settings.storagePolicies.copyCount": "所需已验证副本数", + "settings.storagePolicies.replicationPool": "复制池", + "settings.storagePolicies.migrateAfter": "超过天数后迁移", + "settings.storagePolicies.migrationTarget": "归档目标", + "settings.storagePolicies.pressurePriority": "压力删除优先级(数值越小越优先)", + "settings.storagePolicies.disabledTarget": "已禁用", + "settings.storagePolicies.enabled": "策略已启用", + "settings.storagePolicies.selector": "匹配摄像头", + "settings.storagePolicies.preview": "预览优先级", + "settings.storagePolicies.previewing": "评估中…", + "settings.storagePolicies.previewRequired": "保存前预览当前草稿,查看摄像头重叠情况和生效的优先策略。", + "settings.storagePolicies.previewSummary": "匹配 {matched} 个摄像头;此草稿对 {effective} 个生效。", + "settings.storagePolicies.previewShadowed": "有更高优先级的策略在 {count} 个匹配摄像头上生效。", + "settings.storagePolicies.previewWins": "在 {count} 个摄像头上优先于\"{policy}\"(优先级 {priority})。", + "settings.storagePolicies.previewLoses": "在 {count} 个摄像头上低于\"{policy}\"(优先级 {priority})。", + "settings.storagePolicies.previewNoMatches": "当前选择器未匹配到任何摄像头。", + "settings.storagePolicies.invalidPriority": "优先级必须是 -1,000,000 到 1,000,000 之间的整数。", + "settings.storagePolicies.invalidLifecycle": "请检查保留顺序、副本数与复制池、迁移天数与目标。", + "settings.storagePolicies.created": "放置策略已创建", + "settings.storagePolicies.updated": "放置策略已更新", + "settings.storagePolicies.deleted": "放置策略已删除", + "settings.storagePolicies.deleteConfirm": "删除放置策略\"{name}\"?现有录像不受影响。", + "settings.storagePolicies.active": "已启用", + "settings.storagePolicies.inactive": "已禁用", + "settings.storagePolicies.routesTo": "主目标:{target}", + "settings.storagePolicies.lifecycleSummary": "保留期 最小/期望/最大:{minimum}/{desired}/{maximum} 天 · {copies} 个已验证副本", + "settings.storagePolicies.fallsBackTo": "回退目标:{target}", + "settings.storagePolicies.mode.default": "回退:默认目标", + "settings.storagePolicies.mode.pause": "回退:暂停录制", + "settings.storagePolicies.mode.fail": "回退:录制启动失败", + "settings.storagePolicies.empty": "暂无放置策略。摄像头继续使用默认目标;在策略将摄像头路由到其他目标之前,其他目标不会接收任何数据。", + "settings.storagePolicies.archiveNoTrigger": "已设置归档目标,但没有触发移动的条件。请设置\"移动前天数\"、归档前天数或归档选项;否则不会移动任何录像。", + "settings.storageCompliance.title": "容量与策略合规", + "settings.storageCompliance.description": "基于30天观测速率预测目标压力和实际保留情况;活跃的生命周期违规项将持续显示直至解决。", + "settings.storageCompliance.loadError": "无法加载存储合规信息", + "settings.storageCompliance.unknown": "未知", + "settings.storageCompliance.days": "{days} 天", + "settings.storageCompliance.day": "天", + "settings.storageCompliance.targetForecasts": "目标预测", + "settings.storageCompliance.target": "目标", + "settings.storageCompliance.dailyRate": "观测速率", + "settings.storageCompliance.toHigh": "距高水位线", + "settings.storageCompliance.expected": "预期保留期", + "settings.storageCompliance.confidence": "置信度", + "settings.storageCompliance.policyCompliance": "策略合规", + "settings.storageCompliance.compliant": "无活跃违规", + "settings.storageCompliance.violationCount": "{count} 个违规", + "settings.storageCompliance.policyForecast": "实际 {achieved};预测 {expected};期望 {desired} 天。", + "settings.storageCompliance.copyDeficits": "{count} 个录像需要额外的已验证副本。", + "settings.storageCompliance.activeViolations": "活跃违规", + "settings.storageCompliance.type.copy_count": "副本数量", + "settings.storageCompliance.type.minimum_retention": "最小保留容量", + "settings.storageCompliance.type.target_unavailable": "目标不可用", + "settings.storageCompliance.type.migration_failed": "生命周期任务失败", + "settings.recordingDirectoryFormat": "录像文件夹布局", + "settings.recordingDirectoryFormatHelp": "将新的 MP4 录像按摄像头文件夹分区存放。现有录像不会被移动。", + "settings.recordingDirectoryFlat": "平铺(仅摄像头文件夹)", + "settings.recordingDirectoryMonth": "按月(YYYY/MM)", + "settings.recordingDirectoryDay": "按天(YYYY/MM/DD)", + "settings.minFreePct": "最小可用空间(%)", + "settings.minFreePctHelp": "通过自动删除最旧的录像,保持至少此百分比的卷可用空间,不受保留天数限制。这将使用量限制在磁盘大小内——设置后磁盘将不会写满。设为 0 则禁用容量上限。", + "settings.pressureThresholds": "磁盘压力阈值(%)", + "settings.pressureThresholdsHelp": "触发自动清理升级的可用空间区间。必须满足:紧急 < 严重 < 警告。", + "settings.pressureWarningPct": "警告低于(可用 %)", + "settings.pressureCriticalPct": "严重低于(可用 %)", + "settings.pressureEmergencyPct": "紧急低于(可用 %)", + "settings.databaseBackupVerify": "备份验证", + "settings.databaseBackupVerifyFull": "完整(integrity_check,交叉校验每个索引)", + "settings.databaseBackupVerifyQuick": "快速(quick_check,仅检查页结构)", + "settings.databaseBackupVerifyOff": "关闭(不执行复制后扫描)", + "settings.databaseBackupVerifyHelp": "在备份发布前对每个副本执行扫描。在机械磁盘上的大型数据库中,完整校验可能比复制本身耗时更长,并可能触发 30 分钟安全阀而丢弃该备份;快速校验仍能以更少的磁盘寻道捕获损坏或截断的页。", + "settings.viewMethodAuto": "自动 — 按摄像头偏好设置,带回退", + "settings.resetWizardPending": "正在启动向导…", + "settings.apiDetectionFormat": "API 请求格式", + "settings.apiDetectionFormatLightObjectDetect": "light-object-detect(multipart 图片上传)", + "settings.apiDetectionFormatDoods2": "DOODS2(JSON 请求体,base64 图片)", + "settings.apiDetectionFormatHelp": "LightNVR 向检测 API 发送快照时使用的传输格式。light-object-detect 或实现其协议的服务器请保持此选项;DOODS2 服务器请选择 DOODS2。", + "settings.apiDetectionUrlHelpDoods2": "DOODS2 /detect 端点,例如 http://localhost:8080/detect。请求以 JSON 格式发送,不添加查询参数。", + "settings.apiDetectionDetectorName": "DOODS2 检测器名称", + "settings.apiDetectionDetectorNameHelp": "以 detector_name 字段随每个请求发送。必须与服务器 GET /detectors 列出的检测器名称匹配;\"default\" 使用服务器默认检测器。", + "settings.defaultPlaybackTransport": "默认回放传输方式", + "settings.defaultPlaybackTransportHelp": "应用于新建流的回放配置。现有流保持各自的选择。", + "playbackTransport.auto": "自动(推荐)", + "playbackTransport.webrtcOnly": "仅 WebRTC", + "playbackTransport.mseOnly": "仅 MSE", + "playbackTransport.hlsOnly": "仅 HLS", + "playbackTransport.webrtcThenMse": "WebRTC,然后 MSE", + "playbackTransport.mseThenHls": "MSE,然后 HLS", + "investigation.experimental": "实验性工作区", + "investigation.title": "调查", + "investigation.description": "使用共享的 UTC 时间游标同时查看多个摄像头,不隐藏画面中的空白时段。", + "investigation.query": "调查窗口", + "investigation.queryHelp": "最多选择 16 个摄像头,同时最多激活四个视频播放器。", + "investigation.cameras": "摄像头", + "investigation.cameraSelection": "摄像头选择", + "investigation.start": "开始", + "investigation.end": "结束", + "investigation.load": "加载调查", + "investigation.applyWindow": "应用时间窗口", + "investigation.loading": "正在加载调查…", + "investigation.eventType": "事件类型", + "investigation.anyEventType": "任意事件类型", + "investigation.eventType.detection": "检测", + "investigation.eventType.motion": "移动侦测", + "investigation.location": "位置", + "investigation.anyLocation": "任意位置", + "investigation.objectLabel": "目标标签", + "investigation.anyLabel": "任意标签", + "investigation.zone": "区域", + "investigation.anyZone": "任意区域", + "investigation.source": "检测来源", + "investigation.anySource": "任意来源", + "investigation.captureMethod": "捕获方式", + "investigation.anyCaptureMethod": "任意捕获方式", + "investigation.recordingTag": "录像标签", + "investigation.anyRecordingTag": "任意录像标签", + "investigation.protection": "保护", + "investigation.anyProtection": "任意保护状态", + "investigation.protected": "已保护", + "investigation.unprotected": "未保护", + "investigation.minimumConfidence": "最低置信度", + "investigation.confidenceError": "最低置信度必须在 0 到 1 之间。", + "investigation.metadataRegionSearch": "元数据区域搜索", + "investigation.regionSearchHelp": "选择一台有录像的主摄像头,然后在其视频上绘制区域。", + "investigation.regionActive": "正在搜索 {camera} 的已存储检测框。未找到结果不代表没有目标经过该区域。", + "investigation.regionMatch": "检测框匹配", + "investigation.regionMatch.center": "中心点在内部", + "investigation.regionMatch.intersects": "任意相交", + "investigation.regionMatch.minimumIntersection": "最小重叠", + "investigation.regionMinimumOverlap": "最小重叠 (%)", + "investigation.regionLeft": "左 (%)", + "investigation.regionTop": "上 (%)", + "investigation.regionWidth": "宽 (%)", + "investigation.regionHeight": "高 (%)", + "investigation.drawRegion": "绘制搜索区域", + "investigation.drawingRegion": "正在绘制搜索区域…", + "investigation.clearRegion": "清除区域", + "investigation.useFullFrame": "使用全画面", + "investigation.drawRegionPrompt": "在视频上拖动以定义搜索区域", + "investigation.applyFilters": "应用筛选", + "investigation.searching": "正在搜索事件…", + "investigation.searchResults": "事件结果", + "investigation.searchHelp": "加载一个调查以搜索其持久化的事件元数据。", + "investigation.resultCount": "{count} 个匹配事件", + "investigation.results": "条结果", + "investigation.resultHistogram": "事件直方图", + "investigation.histogramHelp": "选择一个柱状条以移动共享光标。", + "investigation.previousResult": "上一个事件", + "investigation.nextResult": "下一个事件", + "investigation.previousResultShortcut": "上一个事件 ([)", + "investigation.nextResultShortcut": "下一个事件 (])", + "investigation.noResults": "没有与当前摄像头、时间和筛选条件匹配的已保存事件。", + "investigation.noThumbnail": "无缩略图", + "investigation.exploreThumbnails": "浏览缩略图", + "investigation.exploreSelectedThumbnails": "浏览事件附近", + "investigation.thumbnailDrilldown": "缩略图下钻", + "investigation.thumbnailDrilldownHelp": "选择任意时刻(包括间隔),移动共享光标并重新生成更精确的样本集。", + "investigation.selectThumbnailSample": "查看 {time} 附近", + "investigation.loadingThumbnail": "加载缩略图…", + "investigation.thumbnailUnavailable": "缩略图不可用", + "investigation.loadingSamples": "加载缩略图样本…", + "investigation.thumbnailCoverageTruncated": "此时间段内的录像数量超出采样器可检查的范围。请缩小时间窗口以获取完整覆盖。", + "investigation.bookmarks.save": "保存书签", + "investigation.bookmarks.open": "书签", + "investigation.bookmarks.saveTitle": "保存调查书签", + "investigation.bookmarks.listTitle": "调查书签", + "investigation.bookmarks.notHold": "书签可恢复此视图,但不会保护录像免受正常保留策略或删除的影响。", + "investigation.bookmarks.title": "书签名称", + "investigation.bookmarks.note": "私有备注(可选)", + "investigation.bookmarks.titleRequired": "请输入书签名称。", + "investigation.bookmarks.empty": "您没有已保存的调查书签。", + "investigation.bookmarks.cameraCount": "{count} 个摄像头", + "investigation.bookmarks.restore": "打开", + "investigation.bookmarks.confirmDelete": "删除书签?", + "investigation.actions.open": "保护 / 下载", + "investigation.actions.title": "调查录像", + "investigation.actions.notEvidenceExport": "保护可防止正常保留策略删除。ZIP 下载仅为便捷导出,并非经过验证的证据包。", + "investigation.actions.scope": "录像范围", + "investigation.actions.selectedResult": "选中的事件和摄像头", + "investigation.actions.fullWindow": "调查窗口中的所有摄像头", + "investigation.actions.preview": "预览录像", + "investigation.actions.previewing": "正在查找重叠录像…", + "investigation.actions.invalidRange": "请选择有效的时间范围,结束时间需晚于开始时间。", + "investigation.actions.recordingCount": "{count} 条重叠录像", + "investigation.actions.protectedCount": "{count} 条已保护", + "investigation.actions.noRecordings": "没有已完成的录像与该摄像头和时间选择重叠。", + "investigation.actions.protectDenied": "{count} 条未保护录像超出您的保护范围,已从本次操作中排除。", + "investigation.actions.exportDenied": "{count} 条录像缺少导出权限。下载为全有或全无操作,因此无法导出此选择。", + "investigation.actions.camera": "摄像头", + "investigation.actions.recording": "录像", + "investigation.actions.size": "大小", + "investigation.actions.notPermitted": "无权限", + "investigation.actions.protectButton": "保护 {count}", + "investigation.actions.protecting": "正在保护…", + "investigation.actions.protectUnavailable": "没有您有权保护的未保护录像。", + "investigation.actions.protectResult": "保护完成:成功 {success},失败 {failed}。", + "investigation.actions.downloadButton": "下载 {count}", + "investigation.actions.downloadUnavailable": "创建 ZIP 前,每条录像都需要导出权限。", + "investigation.actions.buildingArchive": "正在生成 ZIP…", + "investigation.actions.downloadFailed": "服务器端 ZIP 创建失败。", + "investigation.actions.downloadTimedOut": "ZIP 创建未在五分钟内完成。请尝试缩小时间范围。", + "investigation.actions.downloadStarted": "ZIP 下载已开始。", + "investigation.backOneLevel": "返回上一级", + "investigation.thumbnailMinimumWindow": "这是可用的最窄一秒间隔。共享游标已移动到所选时刻。", + "investigation.localSource": "本地", + "investigation.mediaAvailable": "媒体可用", + "investigation.durationSeconds": "时长 {count} 秒", + "investigation.pageNumber": "第 {count} 页", + "investigation.incompleteCoverage": "{count} 条旧版事件记录无法归属到不可变的摄像头标识。", + "investigation.spatialCoverageGap": "{count} 条范围内的事件记录没有边界框,未进行空间搜索。", + "investigation.noSpatialMetadata": "此元数据搜索范围内没有带边界框的事件。", + "investigation.selectCameraError": "请至少选择一个摄像头。", + "investigation.selectRecordingError": "请至少选择一个录像。", + "investigation.investigateSelectedCount": "调查 {count} 个已选录像", + "investigation.missingCameraIdentity": "无法调查:{count} 个已选录像缺少摄像头标识。", + "investigation.recordingTimeError": "所选录像没有有效的时间范围。", + "investigation.windowLimit": "所选录像超出 31 天的调查时间限制。", + "investigation.timeRangeError": "结束时间必须晚于开始时间。", + "investigation.cameraLimit": "每次调查最多可包含 {count} 个摄像头。", + "investigation.decoderLimit": "同时最多只能激活 {count} 个摄像头播放器。", + "investigation.playbackControls": "同步播放控制", + "investigation.play": "播放", + "investigation.pause": "暂停", + "investigation.mode": "回放模式", + "investigation.wallClock": "实时时钟", + "investigation.skipCommonGaps": "跳过公共间隙", + "investigation.speed": "速度", + "investigation.sharedCursor": "共享 UTC 游标", + "investigation.activePlayers": "活跃播放器", + "investigation.timeline": "共享时间线", + "investigation.segments": "片段", + "investigation.truncated": "已截断", + "investigation.gap": "无录像", + "investigation.players": "同步摄像头播放器", + "investigation.activateCamera": "请至少激活一个时间线行以加载视频。", + "investigation.noFootage": "无录像", + "investigation.noFootageAtTime": "共享时间点无录像", + "investigation.primaryAudio": "主音频", + "investigation.makePrimary": "设为主音频", + "investigation.status.loading": "加载媒体中", + "investigation.status.synchronizing": "同步中", + "investigation.status.ready": "已同步", + "investigation.status.late": "延迟 — 恢复中", + "investigation.status.error": "媒体不可用", + "investigation.status.paused-by-browser": "选择播放以允许媒体", + "streamsConfig.eptzTitle": "鱼眼 ePTZ", + "streamsConfig.eptzEnable": "在浏览器端启用鱼眼 ePTZ", + "streamsConfig.eptzHelp": "在实时视图、时间线回放和调查中展开原始鱼眼流。这不会改变录像或摄像头输出。", + "streamsConfig.eptzModelHelp": "投影:等距圆形鱼眼 · 安装:吸顶。中心和半径使用归一化源图像坐标。", + "streamsConfig.eptzCenterX": "光心 X", + "streamsConfig.eptzCenterY": "光心 Y", + "streamsConfig.eptzRadius": "像圈半径", + "streamsConfig.eptzLensFov": "镜头视场角(度)", + "streamsConfig.eptzRotation": "镜头旋转(度)", + "streamsConfig.eptzDefaultYaw": "默认水平角(度)", + "streamsConfig.eptzDefaultTilt": "默认俯仰角(度)", + "streamsConfig.eptzViewFov": "默认视图视场角", + "streamsConfig.eptzCalibrationHelp": "拖动环视,使用滚轮或双指缩放,按 Home 键重置虚拟摄像头。如果像圈边缘未对齐,请微调中心和半径。", + "settings.archive.targetType": "存储类型", + "settings.archive.filesystem": "本地或挂载的文件系统(NFS/SAN)", + "settings.archive.s3": "S3 兼容归档存储桶", + "settings.archive.endpoint": "HTTPS 端点", + "settings.archive.region": "区域", + "settings.archive.bucket": "专用存储桶", + "settings.archive.credential_ref": "凭据引用", + "settings.archive.budget": "归档预算(GiB,0 = 无限制)", + "settings.archive.connectionHelp": "使用私有、无版本控制且无生命周期过期规则的存储桶。凭据引用选择挂载在服务器上的密钥文件。以 s3://bucket/instance-prefix 格式输入托管位置。", + "settings.archive.policy": "外部归档策略", + "settings.archive.archive_after_seconds": "采集后归档(秒,-1 = 禁用)", + "settings.archive.hot_residency_seconds": "保留热副本(秒,-1 = 归档后移动)", + "settings.archive.archive_protected": "优先归档受保护录像", + "settings.archive.archive_on_pressure": "热存储空间紧张时提前归档", + "settings.archive.policyHelp": "归档时机基于采集时间且要求录像已完成。-1 禁用基于时间的归档或移除热存储最短驻留时间;0 表示立即归档。编辑仅对新录像生效。请检查现有录像以应用新修订。", + "settings.archive.deletion_pending": "待删除", + "settings.archive.archived": "已归档", + "settings.archive.hot": "热存储", + "settings.archive.hot_and_archive": "热存储 + 归档", + "settings.archive.archiving": "归档中", + "settings.archive.preparing": "准备回放", + "settings.archive.unavailable": "不可用", + "settings.archive.operations": "归档操作", + "settings.archive.readOnly": "恢复模式:录像迁移和删除已暂停。", + "settings.archive.disabledBuild": "此版本未启用 S3 支持。已挂载的文件系统目标仍可使用。", + "settings.archive.stored": "存储于存储桶", + "settings.archive.backlog": "传输积压", + "settings.archive.cache": "检索缓存", + "settings.archive.objectsRemaining": "个对象剩余", + "settings.archive.waitingForReaders": "已排队,或等待活跃读取者。", + "settings.archive.applied": "策略修订已应用于现有录像", + "settings.archive.reviewExisting": "查看现有录像", + "settings.archive.applySummary": "{count} 个录像({bytes})将使用此修订。{expired} 个已超过其保留期限。", + "settings.archive.applyHelp": "保护和录像覆盖规则仍然有效。流和系统保留策略同样适用。新的归档时间和目标将在下次生命周期扫描时生效。", + "settings.archive.applyBlocked": "请先完成或处理相关传输,再应用此修订。", + "settings.archive.apply": "应用于现有录像", + "live.plan.previewUnavailable": "摄像头预览不可用", + "live.plan.previewAlt": "{name} 当前视图", + "live.plan.degreesValue": "{value}°", + "live.plan.inDegrees": "{label}(度)", + "live.plan.imageDimensionsError": "无法读取图片尺寸", + "live.plan.loading": "正在加载平面图…", + "live.plan.created": "已创建 {name}", + "live.plan.renamed": "已重命名为 {name}", + "live.plan.deleted": "已删除 {name}", + "live.plan.backgroundType": "背景必须为 PNG 或 JPEG 图片", + "live.plan.backgroundTooLarge": "背景图片过大,最大支持 768 KB", + "live.plan.backgroundAspect": "已上传,但图片宽高比不匹配任何有效画布尺寸", + "live.plan.backgroundUpdatedSave": "已更新 {name} 的背景;保存布局以应用画布尺寸", + "live.plan.backgroundNotResized": "背景已上传,但画布未调整大小:{error}", + "live.plan.backgroundUpdated": "{name} 的背景已更新", + "live.plan.backgroundRemoved": "背景已移除", + "live.plan.saved": "已保存 {name}", + "live.plan.createTitle": "创建建筑平面图", + "live.plan.createDescription": "为建筑或楼层命名,绘制布局或上传平面图,然后放置摄像头。", + "live.plan.nameLabel": "平面图名称", + "live.plan.namePlaceholder": "主楼 · 一层", + "live.plan.createConfirm": "创建平面图", + "live.plan.eyebrow": "建筑平面图", + "live.plan.placedSummary": "已放置 {placed} · 当前在线 {live}", + "live.plan.zoomAndPan": "平面图缩放与平移", + "live.plan.panLeft": "向左平移", + "live.plan.panUp": "向上平移", + "live.plan.panDown": "向下平移", + "live.plan.panRight": "向右平移", + "live.plan.zoomOut": "缩小", + "live.plan.zoomIn": "放大", + "live.plan.fitTitle": "适应平面图", + "live.plan.fit": "适应", + "live.plan.backgroundMenu": "背景…", + "live.plan.save": "保存平面图", + "live.plan.uploadBackgroundTitle": "上传 PNG 或 JPEG 图片作为平面图背景", + "live.plan.replaceBackground": "替换背景", + "live.plan.uploadBackground": "上传背景", + "live.plan.removeBackground": "移除背景", + "live.plan.rename": "重命名", + "live.plan.newPlan": "新建方案", + "live.plan.editLayout": "编辑布局", + "live.plan.placementHint": "点击方案以放置 {name}", + "live.plan.clusterLabel": "{count} 个摄像头;放大查看", + "live.plan.markerLabel": "{name};{availability};朝向 {rotation}°,视场角 {fov}°", + "live.plan.cameraFallback": "摄像头", + "live.plan.legendLive": "实时", + "live.plan.canvas": "方案画布", + "live.plan.width": "宽度", + "live.plan.height": "高度", + "live.plan.canvasHint": "上传背景图片后,画布将自动调整为图片尺寸。", + "live.plan.canvasInvalid": "宽度须为 400–4000,高度须为 300–4000。", + "live.plan.openLive": "打开实时画面", + "live.plan.direction": "摄像头朝向", + "live.plan.fov": "视场角", + "live.plan.coverageNote": "扇形仅显示方向和角度;方案中的距离未经校准。", + "live.plan.removeCamera": "从方案中移除", + "live.plan.selectCamera": "选择摄像头", + "live.plan.selectHintEditing": "拖动已放置的标记以微调。可查看状态并按需打开实时画面。", + "live.plan.selectHint": "可查看状态并按需打开实时画面。", + "live.plan.cameras": "方案摄像头", + "live.plan.findPlaceholder": "在此方案中查找…", + "live.plan.findLabel": "在此方案中查找摄像机", + "live.plan.unplaced": "未放置的摄像机", + "live.plan.unplacedHint": "选择一台摄像机,然后点击其在方案上的位置。", + "live.plan.renameTitle": "重命名方案", + "live.plan.renameDescription": "方案将与本站点的所有操作员共享。", + "live.plan.deleteTitle": "删除方案", + "live.plan.deleteMessage": "删除「{name}」及其上传的背景图?此方案上的摄像机布局将被移除;摄像机本身不受影响。", + "setupWizard.welcomeTitle": "欢迎使用 LightNVR", + "setupWizard.welcomeIntro": "让我们通过几个简单步骤完成 NVR 配置。您随时可以在设置页面中重新修改这些设置。", + "setupWizard.welcomeStorage": "存储路径与容量限制", + "setupWizard.welcomePerformance": "针对摄像机数量的性能限制", + "setupWizard.welcomeSecurity": "安全的管理员登录", + "setupWizard.storageTitle": "存储与数据库", + "setupWizard.storageIntro": "录像和数据库应存储在什么位置?", + "setupWizard.storagePath": "录像存储路径", + "setupWizard.storagePathHint": "视频文件写入的绝对路径。", + "setupWizard.maxStorage": "最大存储容量 (GB)", + "setupWizard.maxStorageHint": "0 = 无限制。", + "setupWizard.dbPath": "数据库路径", + "setupWizard.dbPathHint": "SQLite 数据库文件位置。", + "setupWizard.performanceTitle": "性能", + "setupWizard.performanceIntro": "这些设置控制的是容量,而非视频质量。大多数用户可保持默认值。", + "setupWizard.threadPool": "工作线程池大小", + "setupWizard.threadPoolInfo": "影响后台 Web/服务器工作。通常使用推荐默认值即可,除非您正在调优性能。", + "setupWizard.maxStreams": "最大并发流数", + "setupWizard.maxStreamsInfo": "是当前运行实例的摄像头容量上限。请将其设置为至少等于您计划添加的摄像头数量,并预留一些余量。", + "setupWizard.important": "重要:", + "setupWizard.restartWarning": "如果您更改了任一设置,新值将立即保存,但需重启 LightNVR 后才会生效。例如,如果当前流上限为 1,您将其提高到 32,则必须重启后才能添加超出旧上限的摄像头。", + "setupWizard.threadPoolHintCores": "推荐:{recommended}(您的 {cores} 核 CPU 的 2 倍)。此项控制 libuv 后台工作线程数。范围:2–128。", + "setupWizard.threadPoolHint": "推荐:{recommended}(您的 CPU 核心数的 2 倍)。此项控制 libuv 后台工作线程数。范围:2–128。", + "setupWizard.maxStreamsHint": "LightNVR 可同时保持活跃的摄像头数量。默认 32,最大 {max}。如果您预计使用 8 个摄像头,请至少选择 8。需重启后生效。", + "setupWizard.completeTitle": "设置完成!", + "setupWizard.saved": "您的设置已成功保存。", + "setupWizard.notSaved": "未更改任何设置——将使用默认值。", + "setupWizard.restartRequired": "需要重启", + "setupWizard.restartRequiredInfo": "线程池大小和/或最大流数的更改已保存,但需重启服务后才会生效。请在添加更多摄像头或期望新容量上限生效之前重启。", + "setupWizard.saveFailed": "保存设置失败:{error}", + "setupWizard.back": "上一步", + "setupWizard.saving": "保存中…", + "setupWizard.saveContinue": "保存并继续", + "setupWizard.next": "下一步 →", + "setupWizard.finish": "前往仪表盘", + "setupWizard.skip": "跳过设置向导", + "common.fullscreenUnsupported": "此浏览器不支持全屏模式。", + "recordings.viewInTimelineTitle": "在时间线视图中查看此时间点的流", + "recordings.clickToRetry": "点击重试", + "timeline.previousDay": "前一天", + "timeline.nextDay": "后一天", + "timeline.previousMonth": "上个月", + "timeline.nextMonth": "下个月", + "settings.searchLabel": "搜索设置", + "settings.clearSearch": "清除搜索", + "recordings.addTagPlaceholder": "添加标签…", + "recordings.addNewTagPlaceholder": "添加新标签…", + "live.eptzCanvasLabel": "鱼眼电子云台变焦视图", + "live.eptzCanvasHint": "拖拽平移和倾斜;滚轮或捏合缩放;Home 键重置", + "live.eptzReset": "重置 ePTZ 视图", + "live.autoShort": "自动", + "live.webrtcShort": "WebRTC" } diff --git a/web/tests/locale-coverage.spec.js b/web/tests/locale-coverage.spec.js new file mode 100644 index 00000000..3ce1f926 --- /dev/null +++ b/web/tests/locale-coverage.spec.js @@ -0,0 +1,52 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +const localeDir = path.resolve(__dirname, '../public/locales'); +const readCatalog = (code) => JSON.parse(fs.readFileSync(path.join(localeDir, `${code}.json`), 'utf8')); +const manifest = JSON.parse(fs.readFileSync(path.join(localeDir, 'manifest.json'), 'utf8')); +const english = readCatalog('en'); +const englishKeys = Object.keys(english); +const englishKeySet = new Set(englishKeys); +const placeholders = (value) => [...value.matchAll(/\{[^{}]+\}/g)].map(([token]) => token).sort(); +const markup = (value) => [...value.matchAll(/<[^>]+>/g)].map(([token]) => token).sort(); +const exampleUrls = (value) => [...value.matchAll(/(?:https?|rtsps?|rtmps?|s3):\/\/[A-Za-z0-9_@.:/…-]+/g)].map(([url]) => url.replace(/\.$/, '')); +const protocolNames = ['LightNVR', 'lightNVR', 'go2rtc', 'ONVIF', 'RTSP', 'WebRTC', 'HLS', 'MSE', 'MQTT', 'S3', 'PTZ', 'ePTZ', 'TOTP']; +const shortcutNames = ['Alt', 'Ctrl/Cmd', 'Shift', 'Enter', 'Escape']; +const shortcutKeys = new Set([ + 'live.plan.sketch.hint.select', + 'live.plan.sketch.hint.wall', + 'live.plan.sketch.hint.area', + 'timeline.help.zoomControls', + 'timeline.help.panControls', + 'timeline.inlineHint', +]); + +describe('locale catalog coverage', () => { + for (const { code } of manifest.locales) { + if (code === 'en') continue; + + test(`${code} has valid keys and preserved literals`, () => { + const catalog = readCatalog(code); + const missing = englishKeys.filter((key) => !(key in catalog)); + const orphans = Object.keys(catalog).filter((key) => !englishKeySet.has(key)); + const invalid = Object.entries(catalog).flatMap(([key, value]) => { + if (typeof value !== 'string' || !value.trim()) return [key]; + if (/__\s*P\d+\s*__/i.test(value)) return [key]; + if (!englishKeySet.has(key)) return []; + if (JSON.stringify(placeholders(value)) !== JSON.stringify(placeholders(english[key]))) return [key]; + if (JSON.stringify(markup(value)) !== JSON.stringify(markup(english[key]))) return [key]; + if (exampleUrls(english[key]).some((url) => !value.includes(url))) return [key]; + if (shortcutKeys.has(key) && shortcutNames.some((name) => english[key].includes(name) && !value.includes(name))) return [key]; + return protocolNames.some((name) => english[key].includes(name) + && !value.includes(name) + && !(name === 'lightNVR' && value.includes('LightNVR'))) ? [key] : []; + }); + + const coverage = ((englishKeys.length - missing.length) / englishKeys.length * 100).toFixed(1); + console.info(`${code}: ${coverage}% coverage (${missing.length} missing keys)`); + if (missing.length) console.warn(`${code} missing ${missing.length} English keys`); + expect(orphans).toEqual([]); + expect(invalid).toEqual([]); + }); + } +});