diff --git a/docs/docs/configuration/genai/review_summaries.md b/docs/docs/configuration/genai/review_summaries.md index 4e8107441..fd6762df9 100644 --- a/docs/docs/configuration/genai/review_summaries.md +++ b/docs/docs/configuration/genai/review_summaries.md @@ -68,6 +68,36 @@ The mere presence of an unidentified person in private areas during late night h +### Camera Spatial Context + +In addition to defining activity patterns, you can provide spatial context for specific cameras to help the LLM generate more accurate and descriptive titles and scene descriptions. The `camera_context` field allows you to describe physical features and locations that are outside the camera's field of view but are relevant for understanding the scene. + +**Important Guidelines:** + +- This context is used **only for descriptive purposes** to help the LLM write better titles and scene descriptions +- It should describe **physical features and spatial relationships** (e.g., "front door is to the right", "driveway on the left") +- It should **NOT** include subjective assessments or threat evaluations (e.g., "high-crime area") +- Threat level determination remains based solely on observable actions defined in the activity patterns + +Example configuration: + +```yaml +cameras: + front_door: + review: + genai: + enabled: true + camera_context: | + - Front door entrance is to the right of the frame + - Driveway and street are to the left + - Steps in the center lead from the sidewalk to the front door + - Garage is located beyond the left edge of the frame +``` + +This helps the LLM generate more natural descriptions like "Person approaching front door" instead of "Person walking toward right side of frame". + +The `camera_context` can be defined globally under `genai.review` and overridden per camera for specific spatial details. + ### Image Source By default, review summaries use preview images (cached preview frames) which have a lower resolution but use fewer tokens per image. For better image quality and more detailed analysis, you can configure Frigate to extract frames directly from recordings at a higher resolution: diff --git a/frigate/api/event.py b/frigate/api/event.py index 544e58fd2..61c1d86c4 100644 --- a/frigate/api/event.py +++ b/frigate/api/event.py @@ -912,7 +912,7 @@ def events_summary( "count": int(g.count or 0), } - return JSONResponse(content=list(grouped.values())) + return JSONResponse(content=sorted(grouped.values(), key=lambda x: x["day"])) @router.get( diff --git a/frigate/api/media.py b/frigate/api/media.py index 8d310fec8..2bad3658f 100644 --- a/frigate/api/media.py +++ b/frigate/api/media.py @@ -496,7 +496,7 @@ def all_recordings_summary( for g in period_query: days[g.day] = True - return JSONResponse(content=days) + return JSONResponse(content=dict(sorted(days.items()))) @router.get( diff --git a/frigate/config/camera/review.py b/frigate/config/camera/review.py index 67ba3b60c..3ed3ffa76 100644 --- a/frigate/config/camera/review.py +++ b/frigate/config/camera/review.py @@ -140,6 +140,10 @@ Evaluate in this order: The mere presence of an unidentified person in private areas during late night hours is inherently suspicious and warrants human review, regardless of what activity they appear to be doing or how brief the sequence is.""", title="Custom activity context prompt defining normal and suspicious activity patterns for this property.", ) + camera_context: str = Field( + default="", + title="Spatial context about the camera's field of view to help with descriptive accuracy. Should describe physical features and locations outside the frame.", + ) class ReviewConfig(FrigateBaseModel): diff --git a/frigate/data_processing/post/review_descriptions.py b/frigate/data_processing/post/review_descriptions.py index 94250dd37..501168da6 100644 --- a/frigate/data_processing/post/review_descriptions.py +++ b/frigate/data_processing/post/review_descriptions.py @@ -458,6 +458,7 @@ def run_analysis( genai_config.preferred_language, genai_config.debug_save_thumbnails, genai_config.activity_context_prompt, + genai_config.camera_context, ) review_inference_speed.update(datetime.datetime.now().timestamp() - start) diff --git a/frigate/detectors/detection_runners.py b/frigate/detectors/detection_runners.py index 9dadb16fa..5b45238be 100644 --- a/frigate/detectors/detection_runners.py +++ b/frigate/detectors/detection_runners.py @@ -234,7 +234,10 @@ class OpenVINOModelRunner(BaseModelRunner): # Import here to avoid circular imports from frigate.embeddings.types import EnrichmentModelTypeEnum - return model_type in [EnrichmentModelTypeEnum.paddleocr.value] + return model_type in [ + EnrichmentModelTypeEnum.paddleocr.value, + EnrichmentModelTypeEnum.jina_v2.value, + ] def __init__(self, model_path: str, device: str, model_type: str, **kwargs): self.model_path = model_path @@ -345,6 +348,16 @@ class OpenVINOModelRunner(BaseModelRunner): # Create tensor with the correct element type input_element_type = input_port.get_element_type() + + # Ensure input data matches the expected dtype to prevent type mismatches + # that can occur with models like Jina-CLIP v2 running on OpenVINO + expected_dtype = input_element_type.to_dtype() + if input_data.dtype != expected_dtype: + logger.debug( + f"Converting input '{input_name}' from {input_data.dtype} to {expected_dtype}" + ) + input_data = input_data.astype(expected_dtype) + input_tensor = ov.Tensor(input_element_type, input_data.shape) np.copyto(input_tensor.data, input_data) diff --git a/frigate/genai/__init__.py b/frigate/genai/__init__.py index 4d789d77e..13d57046c 100644 --- a/frigate/genai/__init__.py +++ b/frigate/genai/__init__.py @@ -45,6 +45,7 @@ class GenAIClient: preferred_language: str | None, debug_save: bool, activity_context_prompt: str, + camera_context: str = "", ) -> ReviewMetadata | None: """Generate a description for the review item activity.""" @@ -69,6 +70,16 @@ class GenAIClient: else: return "\n- (No objects detected)" + def get_camera_context_section() -> str: + if camera_context: + return f"""## Camera Spatial Context + +Use this spatial information when writing the title and scene description to provide more accurate context about where activity is occurring or where people/objects are moving to/from. + +{camera_context}""" + return "" + + camera_context_section = get_camera_context_section() context_prompt = f""" Your task is to analyze the sequence of images ({len(thumbnails)} total) taken in chronological order from the perspective of the {review_data["camera"].replace("_", " ")} security camera. @@ -76,6 +87,8 @@ Your task is to analyze the sequence of images ({len(thumbnails)} total) taken i {activity_context_prompt} +{camera_context_section} + ## Task Instructions Your task is to provide a clear, accurate description of the scene that: @@ -100,7 +113,7 @@ When forming your description: ## Response Format Your response MUST be a flat JSON object with: -- `title` (string): A concise, direct title that describes the purpose or overall action, not just what you literally see. Use names from "Objects in Scene" based on what you visually observe. If you see both a name and an unidentified object of the same type but visually observe only one person/object, use ONLY the name. Examples: "Joe walking dog", "Person taking out trash", "Joe accessing vehicle", "Joe and person on front porch". +- `title` (string): A concise, direct title that describes the purpose or overall action, not just what you literally see. {"Use spatial context when available to make titles more meaningful." if camera_context_section else ""} Use names from "Objects in Scene" based on what you visually observe. If you see both a name and an unidentified object of the same type but visually observe only one person/object, use ONLY the name. Examples: "Joe walking dog", "Person taking out trash", "Joe accessing vehicle", "Person leaving porch for driveway", "Joe and person on front porch". - `scene` (string): A narrative description of what happens across the sequence from start to finish. **Only describe actions you can actually observe happening in the frames provided.** Do not infer or assume actions that aren't visible (e.g., if you see someone walking but never see them sit, don't say they sat down). Include setting, detected objects, and their observable actions. Avoid speculation or filling in assumed behaviors. Your description should align with and support the threat level you assign. - `confidence` (float): 0-1 confidence in your analysis. Higher confidence when objects/actions are clearly visible and context is unambiguous. Lower confidence when the sequence is unclear, objects are partially obscured, or context is ambiguous. - `potential_threat_level` (integer): 0, 1, or 2 as defined in "Normal Activity Patterns for This Property" above. Your threat level must be consistent with your scene description and the guidance above. diff --git a/frigate/test/http_api/test_http_media.py b/frigate/test/http_api/test_http_media.py new file mode 100644 index 000000000..970a331e7 --- /dev/null +++ b/frigate/test/http_api/test_http_media.py @@ -0,0 +1,379 @@ +"""Unit tests for recordings/media API endpoints.""" + +from datetime import datetime, timezone +from typing import Any + +import pytz +from fastapi.testclient import TestClient + +from frigate.api.auth import get_allowed_cameras_for_filter, get_current_user +from frigate.models import Recordings +from frigate.test.http_api.base_http_test import BaseTestHttp + + +class TestHttpMedia(BaseTestHttp): + """Test media API endpoints, particularly recordings with DST handling.""" + + def setUp(self): + """Set up test fixtures.""" + super().setUp([Recordings]) + self.app = super().create_app() + + # Mock auth to bypass camera access for tests + async def mock_get_current_user(request: Any): + return {"username": "test_user", "role": "admin"} + + self.app.dependency_overrides[get_current_user] = mock_get_current_user + self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [ + "front_door", + "back_door", + ] + + def tearDown(self): + """Clean up after tests.""" + self.app.dependency_overrides.clear() + super().tearDown() + + def test_recordings_summary_across_dst_spring_forward(self): + """ + Test recordings summary across spring DST transition (spring forward). + + In 2024, DST in America/New_York transitions on March 10, 2024 at 2:00 AM + Clocks spring forward from 2:00 AM to 3:00 AM (EST to EDT) + """ + tz = pytz.timezone("America/New_York") + + # March 9, 2024 at 12:00 PM EST (before DST) + march_9_noon = tz.localize(datetime(2024, 3, 9, 12, 0, 0)).timestamp() + + # March 10, 2024 at 12:00 PM EDT (after DST transition) + march_10_noon = tz.localize(datetime(2024, 3, 10, 12, 0, 0)).timestamp() + + # March 11, 2024 at 12:00 PM EDT (after DST) + march_11_noon = tz.localize(datetime(2024, 3, 11, 12, 0, 0)).timestamp() + + with TestClient(self.app) as client: + # Insert recordings for each day + Recordings.insert( + id="recording_march_9", + path="/media/recordings/march_9.mp4", + camera="front_door", + start_time=march_9_noon, + end_time=march_9_noon + 3600, # 1 hour recording + duration=3600, + motion=100, + objects=5, + ).execute() + + Recordings.insert( + id="recording_march_10", + path="/media/recordings/march_10.mp4", + camera="front_door", + start_time=march_10_noon, + end_time=march_10_noon + 3600, + duration=3600, + motion=150, + objects=8, + ).execute() + + Recordings.insert( + id="recording_march_11", + path="/media/recordings/march_11.mp4", + camera="front_door", + start_time=march_11_noon, + end_time=march_11_noon + 3600, + duration=3600, + motion=200, + objects=10, + ).execute() + + # Test recordings summary with America/New_York timezone + response = client.get( + "/recordings/summary", + params={"timezone": "America/New_York", "cameras": "all"}, + ) + + assert response.status_code == 200 + summary = response.json() + + # Verify we get exactly 3 days + assert len(summary) == 3, f"Expected 3 days, got {len(summary)}" + + # Verify the correct dates are returned (API returns dict with True values) + assert "2024-03-09" in summary, f"Expected 2024-03-09 in {summary}" + assert "2024-03-10" in summary, f"Expected 2024-03-10 in {summary}" + assert "2024-03-11" in summary, f"Expected 2024-03-11 in {summary}" + assert summary["2024-03-09"] is True + assert summary["2024-03-10"] is True + assert summary["2024-03-11"] is True + + def test_recordings_summary_across_dst_fall_back(self): + """ + Test recordings summary across fall DST transition (fall back). + + In 2024, DST in America/New_York transitions on November 3, 2024 at 2:00 AM + Clocks fall back from 2:00 AM to 1:00 AM (EDT to EST) + """ + tz = pytz.timezone("America/New_York") + + # November 2, 2024 at 12:00 PM EDT (before DST transition) + nov_2_noon = tz.localize(datetime(2024, 11, 2, 12, 0, 0)).timestamp() + + # November 3, 2024 at 12:00 PM EST (after DST transition) + # Need to specify is_dst=False to get the time after fall back + nov_3_noon = tz.localize( + datetime(2024, 11, 3, 12, 0, 0), is_dst=False + ).timestamp() + + # November 4, 2024 at 12:00 PM EST (after DST) + nov_4_noon = tz.localize(datetime(2024, 11, 4, 12, 0, 0)).timestamp() + + with TestClient(self.app) as client: + # Insert recordings for each day + Recordings.insert( + id="recording_nov_2", + path="/media/recordings/nov_2.mp4", + camera="front_door", + start_time=nov_2_noon, + end_time=nov_2_noon + 3600, + duration=3600, + motion=100, + objects=5, + ).execute() + + Recordings.insert( + id="recording_nov_3", + path="/media/recordings/nov_3.mp4", + camera="front_door", + start_time=nov_3_noon, + end_time=nov_3_noon + 3600, + duration=3600, + motion=150, + objects=8, + ).execute() + + Recordings.insert( + id="recording_nov_4", + path="/media/recordings/nov_4.mp4", + camera="front_door", + start_time=nov_4_noon, + end_time=nov_4_noon + 3600, + duration=3600, + motion=200, + objects=10, + ).execute() + + # Test recordings summary with America/New_York timezone + response = client.get( + "/recordings/summary", + params={"timezone": "America/New_York", "cameras": "all"}, + ) + + assert response.status_code == 200 + summary = response.json() + + # Verify we get exactly 3 days + assert len(summary) == 3, f"Expected 3 days, got {len(summary)}" + + # Verify the correct dates are returned (API returns dict with True values) + assert "2024-11-02" in summary, f"Expected 2024-11-02 in {summary}" + assert "2024-11-03" in summary, f"Expected 2024-11-03 in {summary}" + assert "2024-11-04" in summary, f"Expected 2024-11-04 in {summary}" + assert summary["2024-11-02"] is True + assert summary["2024-11-03"] is True + assert summary["2024-11-04"] is True + + def test_recordings_summary_multiple_cameras_across_dst(self): + """ + Test recordings summary with multiple cameras across DST boundary. + """ + tz = pytz.timezone("America/New_York") + + # March 9, 2024 at 10:00 AM EST (before DST) + march_9_morning = tz.localize(datetime(2024, 3, 9, 10, 0, 0)).timestamp() + + # March 10, 2024 at 3:00 PM EDT (after DST transition) + march_10_afternoon = tz.localize(datetime(2024, 3, 10, 15, 0, 0)).timestamp() + + with TestClient(self.app) as client: + # Insert recordings for front_door on March 9 + Recordings.insert( + id="front_march_9", + path="/media/recordings/front_march_9.mp4", + camera="front_door", + start_time=march_9_morning, + end_time=march_9_morning + 3600, + duration=3600, + motion=100, + objects=5, + ).execute() + + # Insert recordings for back_door on March 10 + Recordings.insert( + id="back_march_10", + path="/media/recordings/back_march_10.mp4", + camera="back_door", + start_time=march_10_afternoon, + end_time=march_10_afternoon + 3600, + duration=3600, + motion=150, + objects=8, + ).execute() + + # Test with all cameras + response = client.get( + "/recordings/summary", + params={"timezone": "America/New_York", "cameras": "all"}, + ) + + assert response.status_code == 200 + summary = response.json() + + # Verify we get both days + assert len(summary) == 2, f"Expected 2 days, got {len(summary)}" + assert "2024-03-09" in summary + assert "2024-03-10" in summary + assert summary["2024-03-09"] is True + assert summary["2024-03-10"] is True + + def test_recordings_summary_at_dst_transition_time(self): + """ + Test recordings that span the exact DST transition time. + """ + tz = pytz.timezone("America/New_York") + + # March 10, 2024 at 1:00 AM EST (1 hour before DST transition) + # At 2:00 AM, clocks jump to 3:00 AM + before_transition = tz.localize(datetime(2024, 3, 10, 1, 0, 0)).timestamp() + + # Recording that spans the transition (1:00 AM to 3:30 AM EDT) + # This is 1.5 hours of actual time but spans the "missing" hour + after_transition = tz.localize(datetime(2024, 3, 10, 3, 30, 0)).timestamp() + + with TestClient(self.app) as client: + Recordings.insert( + id="recording_during_transition", + path="/media/recordings/transition.mp4", + camera="front_door", + start_time=before_transition, + end_time=after_transition, + duration=after_transition - before_transition, + motion=100, + objects=5, + ).execute() + + response = client.get( + "/recordings/summary", + params={"timezone": "America/New_York", "cameras": "all"}, + ) + + assert response.status_code == 200 + summary = response.json() + + # The recording should appear on March 10 + assert len(summary) == 1 + assert "2024-03-10" in summary + assert summary["2024-03-10"] is True + + def test_recordings_summary_utc_timezone(self): + """ + Test recordings summary with UTC timezone (no DST). + """ + # Use UTC timestamps directly + march_9_utc = datetime(2024, 3, 9, 17, 0, 0, tzinfo=timezone.utc).timestamp() + march_10_utc = datetime(2024, 3, 10, 17, 0, 0, tzinfo=timezone.utc).timestamp() + + with TestClient(self.app) as client: + Recordings.insert( + id="recording_march_9_utc", + path="/media/recordings/march_9_utc.mp4", + camera="front_door", + start_time=march_9_utc, + end_time=march_9_utc + 3600, + duration=3600, + motion=100, + objects=5, + ).execute() + + Recordings.insert( + id="recording_march_10_utc", + path="/media/recordings/march_10_utc.mp4", + camera="front_door", + start_time=march_10_utc, + end_time=march_10_utc + 3600, + duration=3600, + motion=150, + objects=8, + ).execute() + + # Test with UTC timezone + response = client.get( + "/recordings/summary", params={"timezone": "utc", "cameras": "all"} + ) + + assert response.status_code == 200 + summary = response.json() + + # Verify we get both days + assert len(summary) == 2 + assert "2024-03-09" in summary + assert "2024-03-10" in summary + assert summary["2024-03-09"] is True + assert summary["2024-03-10"] is True + + def test_recordings_summary_no_recordings(self): + """ + Test recordings summary when no recordings exist. + """ + with TestClient(self.app) as client: + response = client.get( + "/recordings/summary", + params={"timezone": "America/New_York", "cameras": "all"}, + ) + + assert response.status_code == 200 + summary = response.json() + assert len(summary) == 0 + + def test_recordings_summary_single_camera_filter(self): + """ + Test recordings summary filtered to a single camera. + """ + tz = pytz.timezone("America/New_York") + march_10_noon = tz.localize(datetime(2024, 3, 10, 12, 0, 0)).timestamp() + + with TestClient(self.app) as client: + # Insert recordings for both cameras + Recordings.insert( + id="front_recording", + path="/media/recordings/front.mp4", + camera="front_door", + start_time=march_10_noon, + end_time=march_10_noon + 3600, + duration=3600, + motion=100, + objects=5, + ).execute() + + Recordings.insert( + id="back_recording", + path="/media/recordings/back.mp4", + camera="back_door", + start_time=march_10_noon, + end_time=march_10_noon + 3600, + duration=3600, + motion=150, + objects=8, + ).execute() + + # Test with only front_door camera + response = client.get( + "/recordings/summary", + params={"timezone": "America/New_York", "cameras": "front_door"}, + ) + + assert response.status_code == 200 + summary = response.json() + assert len(summary) == 1 + assert "2024-03-10" in summary + assert summary["2024-03-10"] is True diff --git a/frigate/video.py b/frigate/video.py index e2de5fe49..739fb5c03 100755 --- a/frigate/video.py +++ b/frigate/video.py @@ -196,7 +196,9 @@ class CameraWatchdog(threading.Thread): self.sleeptime = self.config.ffmpeg.retry_interval self.config_subscriber = CameraConfigUpdateSubscriber( - None, {config.name: config}, [CameraConfigUpdateEnum.enabled] + None, + {config.name: config}, + [CameraConfigUpdateEnum.enabled, CameraConfigUpdateEnum.record], ) self.requestor = InterProcessRequestor() self.was_enabled = self.config.enabled diff --git a/web/public/locales/ca/common.json b/web/public/locales/ca/common.json index b3a5344d6..fa5ce3b62 100644 --- a/web/public/locales/ca/common.json +++ b/web/public/locales/ca/common.json @@ -218,7 +218,10 @@ } }, "label": { - "back": "Torna enrere" + "back": "Torna enrere", + "hide": "Oculta {{item}}", + "show": "Mostra {{item}}", + "ID": "ID" }, "button": { "apply": "Aplicar", @@ -281,5 +284,14 @@ "readTheDocumentation": "Llegir la documentació", "information": { "pixels": "{{area}}px" + }, + "list": { + "two": "{{0}} i {{1}}", + "many": "{{items}}, i {{last}}", + "separatorWithSpace": ",· " + }, + "field": { + "optional": "Opcional", + "internalID": "L'ID intern que Frigate s'utilitza a la configuració i a la base de dades" } } diff --git a/web/public/locales/ca/components/dialog.json b/web/public/locales/ca/components/dialog.json index 6f38c7c13..0fa89afbe 100644 --- a/web/public/locales/ca/components/dialog.json +++ b/web/public/locales/ca/components/dialog.json @@ -117,6 +117,7 @@ "search": { "placeholder": "Cerca per etiqueta o subetiqueta..." }, - "noImages": "No s'han trobat miniatures per a aquesta càmera" + "noImages": "No s'han trobat miniatures per a aquesta càmera", + "unknownLabel": "Imatge activadora desada" } } diff --git a/web/public/locales/ca/views/classificationModel.json b/web/public/locales/ca/views/classificationModel.json index 78897acb4..b64214a89 100644 --- a/web/public/locales/ca/views/classificationModel.json +++ b/web/public/locales/ca/views/classificationModel.json @@ -5,7 +5,10 @@ "renameCategory": "Reanomena la classe", "deleteCategory": "Suprimeix la classe", "deleteImages": "Suprimeix les imatges", - "trainModel": "Model de tren" + "trainModel": "Model de tren", + "addClassification": "Afegeix una classificació", + "deleteModels": "Suprimeix els models", + "editModel": "Edita el model" }, "toast": { "success": { @@ -13,13 +16,19 @@ "deletedImage": "Imatges suprimides", "categorizedImage": "Imatge classificada amb èxit", "trainedModel": "Model entrenat amb èxit.", - "trainingModel": "S'ha iniciat amb èxit la formació de models." + "trainingModel": "S'ha iniciat amb èxit la formació de models.", + "deletedModel_one": "S'ha suprimit correctament el model {{count}}", + "deletedModel_many": "S'han suprimit correctament {{count}} models", + "deletedModel_other": "", + "updatedModel": "S'ha actualitzat correctament la configuració del model" }, "error": { "deleteImageFailed": "No s'ha pogut suprimir: {{errorMessage}}", "deleteCategoryFailed": "No s'ha pogut suprimir la classe: {{errorMessage}}", "categorizeFailed": "No s'ha pogut categoritzar la imatge: {{errorMessage}}", - "trainingFailed": "No s'ha pogut iniciar l'entrenament del model: {{errorMessage}}" + "trainingFailed": "No s'ha pogut iniciar l'entrenament del model: {{errorMessage}}", + "deleteModelFailed": "No s'ha pogut suprimir el model: {{errorMessage}}", + "updateModelFailed": "No s'ha pogut actualitzar el model: {{errorMessage}}" } }, "deleteCategory": { @@ -43,7 +52,8 @@ }, "train": { "title": "Classificacions recents", - "aria": "Selecciona les classificacions recents" + "aria": "Selecciona les classificacions recents", + "titleShort": "Recent" }, "categories": "Classes", "createCategory": { @@ -98,7 +108,8 @@ "stateRequiresTwoClasses": "Els models d'estat requereixen almenys 2 classes", "objectLabelRequired": "Seleccioneu una etiqueta d'objecte", "objectTypeRequired": "Seleccioneu un tipus de classificació" - } + }, + "states": "Estats" }, "step2": { "description": "Seleccioneu les càmeres i definiu l'àrea a monitoritzar per a cada càmera. El model classificarà l'estat d'aquestes àrees.", @@ -131,5 +142,23 @@ }, "generateSuccess": "Imatges de mostra generades amb èxit" } + }, + "deleteModel": { + "title": "Suprimeix el model de classificació", + "single": "Esteu segur que voleu suprimir {{name}}? Això suprimirà permanentment totes les dades associades, incloses les imatges i les dades d'entrenament. Aquesta acció no es pot desfer.", + "desc": "Esteu segur que voleu suprimir {{count}} model(s)? Això suprimirà permanentment totes les dades associades, incloses les imatges i les dades d'entrenament. Aquesta acció no es pot desfer." + }, + "menu": { + "objects": "Objectes", + "states": "Estats" + }, + "details": { + "scoreInfo": "La puntuació representa la confiança mitjana de la classificació en totes les deteccions d'aquest objecte." + }, + "edit": { + "title": "Edita el model de classificació", + "descriptionState": "Edita les classes per a aquest model de classificació d'estats. Els canvis requeriran tornar a entrenar el model.", + "descriptionObject": "Edita el tipus d'objecte i el tipus de classificació per a aquest model de classificació d'objectes.", + "stateClassesInfo": "Nota: Canviar les classes d'estat requereix tornar a entrenar el model amb les classes actualitzades." } } diff --git a/web/public/locales/ca/views/events.json b/web/public/locales/ca/views/events.json index 412955efa..2bb9bc0e1 100644 --- a/web/public/locales/ca/views/events.json +++ b/web/public/locales/ca/views/events.json @@ -43,10 +43,17 @@ "aria": "Canvia la vista de detall", "trackedObject_other": "objectes", "noObjectDetailData": "No hi ha dades de detall d'objecte disponibles.", - "label": "Detall" + "label": "Detall", + "settings": "Configuració de la vista detallada", + "alwaysExpandActive": { + "title": "Expandeix sempre actiu", + "desc": "Expandeix sempre els detalls de l'objecte de la revisió activa quan estigui disponible." + } }, "objectTrack": { "clickToSeek": "Feu clic per cercar aquesta hora", "trackedPoint": "Punt de seguiment" - } + }, + "zoomIn": "Amplia", + "zoomOut": "Redueix" } diff --git a/web/public/locales/ca/views/explore.json b/web/public/locales/ca/views/explore.json index 08bd84758..d45f92665 100644 --- a/web/public/locales/ca/views/explore.json +++ b/web/public/locales/ca/views/explore.json @@ -84,7 +84,8 @@ "details": "detalls", "snapshot": "instantània", "video": "vídeo", - "object_lifecycle": "cicle de vida de l'objecte" + "object_lifecycle": "cicle de vida de l'objecte", + "thumbnail": "miniatura" }, "details": { "timestamp": "Marca temporal", @@ -240,7 +241,7 @@ "noImageFound": "No s'ha trobat cap imatge amb aquesta hora.", "createObjectMask": "Crear màscara d'objecte", "adjustAnnotationSettings": "Ajustar configuració d'anotacions", - "scrollViewTips": "Desplaça per veure els moments significants del cicle de vida d'aquest objecte.", + "scrollViewTips": "Feu clic per veure els moments significatius del cicle de vida d'aquest objecte.", "autoTrackingTips": "Limitar les posicións de la caixa serà inacurat per càmeras de seguiment automàtic.", "count": "{{first}} de {{second}}", "trackedPoint": "Punt Seguit", @@ -270,7 +271,7 @@ }, "offset": { "label": "Òfset d'Anotació", - "desc": "Aquestes dades provenen del flux de detecció de la càmera, però se superposen a les imatges del flux de gravació. És poc probable que els dos fluxos estiguin perfectament sincronitzats. Com a resultat, el quadre delimitador i el metratge no s'alinearan perfectament. Tanmateix, es pot utilitzar el camp annotation_offset per ajustar-ho.", + "desc": "Aquestes dades provenen del flux de detecció de la càmera, però se superposen a les imatges del flux de gravació. És poc probable que els dos fluxos estiguin perfectament sincronitzats. Com a resultat, el quadre delimitador i les imatges no s'alinearan perfectament. Tanmateix, es pot utilitzar el camp annotation_offset per ajustar-ho.", "millisecondsToOffset": "Millisegons per l'òfset de detecció d'anotacions per. Per defecte: 0", "tips": "CONSELL: Imagineu-vos que hi ha un clip d'esdeveniment amb una persona caminant d'esquerra a dreta. Si el quadre delimitador de la cronologia de l'esdeveniment està constantment a l'esquerra de la persona, aleshores s'hauria de disminuir el valor. De la mateixa manera, si una persona camina d'esquerra a dreta i el quadre delimitador està constantment per davant de la persona, aleshores s'hauria d'augmentar el valor.", "toast": { diff --git a/web/public/locales/ca/views/exports.json b/web/public/locales/ca/views/exports.json index dfe5de963..dec2726ff 100644 --- a/web/public/locales/ca/views/exports.json +++ b/web/public/locales/ca/views/exports.json @@ -13,5 +13,11 @@ "error": { "renameExportFailed": "Error al canviar el nom de l’exportació: {{errorMessage}}" } + }, + "tooltip": { + "shareExport": "Comparteix l'exportació", + "downloadVideo": "Baixa el vídeo", + "editName": "Edita el nom", + "deleteExport": "Suprimeix l'exportació" } } diff --git a/web/public/locales/ca/views/search.json b/web/public/locales/ca/views/search.json index 3f5940348..dec453728 100644 --- a/web/public/locales/ca/views/search.json +++ b/web/public/locales/ca/views/search.json @@ -55,12 +55,12 @@ "searchFor": "Buscar {{inputValue}}", "button": { "clear": "Netejar cerca", - "save": "Desar la cerca", - "delete": "Suprimeix la recerca desada", - "filterInformation": "Informació de filtre", + "save": "Desa la cerca", + "delete": "Elimina la recerca desada", + "filterInformation": "Informació del filtre", "filterActive": "Filtres actius" }, - "trackedObjectId": "ID d'objecte rastrejat", + "trackedObjectId": "ID de l'objecte rastrejat", "placeholder": { "search": "Cercar…" }, diff --git a/web/public/locales/ca/views/settings.json b/web/public/locales/ca/views/settings.json index 794b6d759..36a041510 100644 --- a/web/public/locales/ca/views/settings.json +++ b/web/public/locales/ca/views/settings.json @@ -49,6 +49,10 @@ "playAlertVideos": { "label": "Reproduir vídeos d’alerta", "desc": "Per defecte, les alertes recents al tauler en directe es reprodueixen com a vídeos petits en bucle. Desactiva aquesta opció per mostrar només una imatge estàtica de les alertes recents en aquest dispositiu/navegador." + }, + "displayCameraNames": { + "label": "Mostra sempre els noms de la càmera", + "desc": "Mostra sempre els noms de les càmeres en un xip al tauler de visualització en directe multicàmera." } }, "storedLayouts": { @@ -695,7 +699,9 @@ }, "actions": { "alert": "Marcar com Alerta", - "notification": "Enviar Notificació" + "notification": "Enviar Notificació", + "sub_label": "Afegeix una subetiqueta", + "attribute": "Afegeix un atribut" }, "dialog": { "createTrigger": { @@ -713,25 +719,28 @@ "form": { "name": { "title": "Nom", - "placeholder": "Entrar el nom del disparador", + "placeholder": "Anomena aquest activador", "error": { - "minLength": "El nom ha de tenir almenys 2 caràcters de llargada.", - "invalidCharacters": "El nom només pot contenir lletres, números, guions i guinons baixos.", + "minLength": "El camp ha de tenir almenys 2 caràcters.", + "invalidCharacters": "El camp només pot contenir lletres, números, guions baixos i guions.", "alreadyExists": "El disparador amb aquest nom ja existeix per aquesta càmera." - } + }, + "description": "Introduïu un nom o una descripció únics per a identificar aquest activador" }, "enabled": { "description": "Activar o desactivar aquest disparador" }, "type": { "title": "Tipus", - "placeholder": "Selecciona un tipus de disparador" + "placeholder": "Selecciona un tipus de disparador", + "description": "Activa quan es detecta una descripció similar d'un objecte rastrejat", + "thumbnail": "Activa quan es detecti una miniatura d'objecte rastrejada similar" }, "content": { "title": "Contingut", - "imagePlaceholder": "Selecciona una imatge", + "imagePlaceholder": "Selecciona una miniatura", "textPlaceholder": "Entra el contingut de text", - "imageDesc": "Selecciona una imatge per disparar aquesta acció quan una imatge similar sigui detectada.", + "imageDesc": "Només es mostren les 100 miniatures més recents. Si no podeu trobar la miniatura desitjada, reviseu els objectes anteriors a Explora i configureu un activador des del menú.", "textDesc": "Entra el text per disparar aquesta acció quan es detecti una descripció d'objecte a rastrejar similar.", "error": { "required": "Contigunt requerit." @@ -742,11 +751,12 @@ "error": { "min": "El llindar ha de ser mínim 0", "max": "El llindar ha de ser máxim 1" - } + }, + "desc": "Estableix el llindar de similitud per a aquest activador. Un llindar més alt significa que es requereix una coincidència més propera per disparar el disparador." }, "actions": { "title": "Accions", - "desc": "Per defecte, Frigate dispara un missatge MQTT per tots els disparadors. Tria una acció adicional per realitzar quan aquest disparador dispari.", + "desc": "Per defecte, Frigate dispara un missatge MQTT per a tots els activadors. Subetiquetes afegeix el nom de l'activador a l'etiqueta de l'objecte. Els atributs són metadades cercables emmagatzemades per separat a les metadades de l'objecte rastrejat.", "error": { "min": "S'ha de seleccionar una acció com a mínim." } @@ -772,13 +782,30 @@ }, "documentTitle": "Disparadors", "management": { - "title": "Gestió de disparadors", + "title": "Activadors", "desc": "Gestionar els disparadors de {{camera}}. Usa les tipus de miniatures per disparar miniatures similars a l'objecte a seguir seleccionat, i el tipus de descripció per disparar en cas de descripcions similars a l'especificada." }, "addTrigger": "Afegir disaprador", "semanticSearch": { "desc": "La cerca semàntica ha d'estar activada per a utilitzar els activadors.", "title": "La cerca semàntica està desactivada" + }, + "wizard": { + "title": "Crea un activador", + "step1": { + "description": "Configura la configuració bàsica per al vostre activador." + }, + "step2": { + "description": "Configura el contingut que activarà aquesta acció." + }, + "step3": { + "description": "Configura el llindar i les accions d'aquest activador." + }, + "steps": { + "nameAndType": "Nom i tipus", + "configureData": "Configura les dades", + "thresholdAndActions": "Llindar i accions" + } } }, "roles": { @@ -831,7 +858,9 @@ "createRole": "Rol {{role}} creat exitosament", "updateCameras": "Càmeres actualitzades per al rol {{role}}", "deleteRole": "Rol {{role}} eliminat exitosament", - "userRolesUpdated": "{{count}} usuari(s) asignats a aquest rol s'han actualitzat a 'visor', i tenen accés a totes les càmeres." + "userRolesUpdated_one": "{{count}} usuari(s) asignats a aquest rol s'han actualitzat a 'visor', i tenen accés a totes les càmeres.", + "userRolesUpdated_many": "", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Error al crear el rol: {{errorMessage}}", @@ -985,7 +1014,9 @@ "estimatedBandwidth": "Amplada de banda estimad", "roles": "Rols", "streamValidated": "El flux {{number}} s'ha validat correctament", - "streamValidationFailed": "Ha fallat la validació del flux {{number}}" + "streamValidationFailed": "Ha fallat la validació del flux {{number}}", + "ffmpegModule": "Usa el mode de compatibilitat del flux", + "ffmpegModuleDescription": "Si el flux no es carrega després de diversos intents, proveu d'activar-ho. Quan està activat, Frigate utilitzarà el mòdul ffmpeg amb go2rtc. Això pot proporcionar una millor compatibilitat amb alguns fluxos de càmera." } }, "cameraManagement": { diff --git a/web/public/locales/cs/components/auth.json b/web/public/locales/cs/components/auth.json index a3dd01b32..00b0160cb 100644 --- a/web/public/locales/cs/components/auth.json +++ b/web/public/locales/cs/components/auth.json @@ -10,6 +10,7 @@ "unknownError": "Neznámá chyba. Zkontrolujte logy.", "webUnknownError": "Neznámá chuba. Zkontrolujte logy konzoly.", "rateLimit": "Limit požadavků překročen. Zkuste to znovu později." - } + }, + "firstTimeLogin": "Přihlašujete se poprvé? Přihlašovací údaje jsou vypsány v logu Frigate." } } diff --git a/web/public/locales/cs/views/classificationModel.json b/web/public/locales/cs/views/classificationModel.json index 0967ef424..a8d060290 100644 --- a/web/public/locales/cs/views/classificationModel.json +++ b/web/public/locales/cs/views/classificationModel.json @@ -1 +1,7 @@ -{} +{ + "documentTitle": "Klasifikační modely", + "button": { + "deleteClassificationAttempts": "Odstranit Klasifikační obrazy", + "renameCategory": "Přejmenovat třídu" + } +} diff --git a/web/public/locales/cs/views/faceLibrary.json b/web/public/locales/cs/views/faceLibrary.json index 8db564c37..58751f810 100644 --- a/web/public/locales/cs/views/faceLibrary.json +++ b/web/public/locales/cs/views/faceLibrary.json @@ -41,7 +41,7 @@ "aria": "Vybrat trénink" }, "description": { - "addFace": "Prúvodce přidání nové kolekce do Knižnice obličejů.", + "addFace": "Přidejte novou kolekci do Knihovny obličejů nahráním prvního obrázku.", "placeholder": "Zadejte název pro tuto kolekci", "invalidName": "Neplatný název. Názvy mohou obsahovat pouze písmena, čísla, mezery, apostrofy, podtržítka a pomlčky." }, diff --git a/web/public/locales/cs/views/settings.json b/web/public/locales/cs/views/settings.json index 17b54fc7f..c0ff72f5f 100644 --- a/web/public/locales/cs/views/settings.json +++ b/web/public/locales/cs/views/settings.json @@ -11,7 +11,8 @@ "general": "Obecné nastavení - Frigate", "frigatePlus": "Frigate+ nastavení - Frigate", "enrichments": "Nastavení obohacení - Frigate", - "cameraManagement": "Správa kamer - Frigate" + "cameraManagement": "Správa kamer - Frigate", + "cameraReview": "Nastavení kontroly kamery - Frigate" }, "frigatePlus": { "toast": { @@ -846,7 +847,9 @@ "createRole": "Role {{role}} byla úspěšně vytvořena", "updateCameras": "Kamery byly aktualizovány pro roli {{role}}", "deleteRole": "Role {{role}} byla úspěšně smazána", - "userRolesUpdated": "{{count}} uživatel(ů) přiřazených k této roli bylo aktualizováno na „Divák“, který má přístup ke všem kamerám." + "userRolesUpdated_one": "{{count}} uživatel(ů) přiřazených k této roli bylo aktualizováno na „Divák“, který má přístup ke všem kamerám.", + "userRolesUpdated_few": "", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Nepodařilo se vytvořit roli: {{errorMessage}}", diff --git a/web/public/locales/de/views/settings.json b/web/public/locales/de/views/settings.json index 33a44bfa2..be4ec3259 100644 --- a/web/public/locales/de/views/settings.json +++ b/web/public/locales/de/views/settings.json @@ -892,7 +892,8 @@ "createRole": "Rolle {{role}} erfolgreich erstellt", "updateCameras": "Kameras für Rolle {{role}} aktualisiert", "deleteRole": "Rolle {{role}} erfolgreich gelöscht", - "userRolesUpdated": "{{count}} Benutzer, denen diese Rolle zugewiesen wurde, wurden auf „Zuschauer“ aktualisiert, der Zugriff auf alle Kameras hat." + "userRolesUpdated_one": "{{count}} Benutzer, denen diese Rolle zugewiesen wurde, wurden auf „Zuschauer“ aktualisiert, der Zugriff auf alle Kameras hat.", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Fehler beim Erstellen der Rolle: {{errorMessage}}", diff --git a/web/public/locales/en/config/review.json b/web/public/locales/en/config/review.json index a44c2cfa9..f5b6cbeae 100644 --- a/web/public/locales/en/config/review.json +++ b/web/public/locales/en/config/review.json @@ -67,8 +67,11 @@ }, "activity_context_prompt": { "label": "Custom activity context prompt defining normal activity patterns for this property." + }, + "camera_context": { + "label": "Spatial context about the camera's field of view to help with descriptive accuracy. Should describe physical features and locations outside the frame. This is for spatial reference only and should NOT include subjective assessments." } } } } -} \ No newline at end of file +} diff --git a/web/public/locales/en/views/explore.json b/web/public/locales/en/views/explore.json index 787581bf7..afc81eaa6 100644 --- a/web/public/locales/en/views/explore.json +++ b/web/public/locales/en/views/explore.json @@ -74,7 +74,7 @@ "label": "Annotation Offset", "desc": "This data comes from your camera's detect feed but is overlayed on images from the the record feed. It is unlikely that the two streams are perfectly in sync. As a result, the bounding box and the footage will not line up perfectly. You can use this setting to offset the annotations forward or backward in time to better align them with the recorded footage.", "millisecondsToOffset": "Milliseconds to offset detect annotations by. Default: 0", - "tips": "TIP: Imagine there is an event clip with a person walking from left to right. If the event timeline bounding box is consistently to the left of the person then the value should be decreased. Similarly, if a person is walking from left to right and the bounding box is consistently ahead of the person then the value should be increased.", + "tips": "Lower the value if the video playback is ahead of the boxes and path points, and increase the value if the video playback is behind them. This value can be negative.", "toast": { "success": "Annotation offset for {{camera}} has been saved to the config file. Restart Frigate to apply your changes." } @@ -215,6 +215,8 @@ "trackedObjectsCount_other": "{{count}} tracked objects ", "searchResult": { "tooltip": "Matched {{type}} at {{confidence}}%", + "previousTrackedObject": "Previous tracked object", + "nextTrackedObject": "Next tracked object", "deleteTrackedObject": { "toast": { "success": "Tracked object deleted successfully.", diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json index fe837663c..626e5385a 100644 --- a/web/public/locales/en/views/settings.json +++ b/web/public/locales/en/views/settings.json @@ -745,7 +745,8 @@ "createRole": "Role {{role}} created successfully", "updateCameras": "Cameras updated for role {{role}}", "deleteRole": "Role {{role}} deleted successfully", - "userRolesUpdated": "{{count}} user(s) assigned to this role have been updated to 'viewer', which has access to all cameras." + "userRolesUpdated_one": "{{count}} user assigned to this role has been updated to 'viewer', which has access to all cameras.", + "userRolesUpdated_other": "{{count}} users assigned to this role have been updated to 'viewer', which has access to all cameras." }, "error": { "createRoleFailed": "Failed to create role: {{errorMessage}}", diff --git a/web/public/locales/es/components/dialog.json b/web/public/locales/es/components/dialog.json index dcf8119da..e200c388d 100644 --- a/web/public/locales/es/components/dialog.json +++ b/web/public/locales/es/components/dialog.json @@ -69,7 +69,7 @@ "noVaildTimeSelected": "No se seleccionó un rango de tiempo válido.", "endTimeMustAfterStartTime": "La hora de finalización debe ser posterior a la hora de inicio." }, - "success": "Exportación iniciada con éxito. Ver el archivo en la carpeta /exports." + "success": "Exportación iniciada con éxito. Ver el archivo en la página exportaciones." }, "fromTimeline": { "saveExport": "Guardar exportación", diff --git a/web/public/locales/es/views/classificationModel.json b/web/public/locales/es/views/classificationModel.json index 0967ef424..b2446ea01 100644 --- a/web/public/locales/es/views/classificationModel.json +++ b/web/public/locales/es/views/classificationModel.json @@ -1 +1,40 @@ -{} +{ + "documentTitle": "Modelos de Clasificación", + "button": { + "deleteClassificationAttempts": "Borrar Imágenes de Clasificación.", + "renameCategory": "Renombrar Clase", + "deleteCategory": "Borrar Clase", + "deleteImages": "Borrar Imágenes", + "trainModel": "Entrenar Modelo", + "addClassification": "Añadir Clasificación", + "deleteModels": "Borrar Modelos", + "editModel": "Editar Modelo" + }, + "toast": { + "success": { + "deletedCategory": "Clase Borrada", + "deletedImage": "Imágenes Borradas", + "deletedModel_one": "Borrado con éxito {{count}} modelo", + "deletedModel_many": "Borrados con éxito {{count}} modelos", + "deletedModel_other": "Borrados con éxito {{count}} modelos", + "categorizedImage": "Imagen Clasificada Correctamente", + "trainedModel": "Modelo entrenado correctamente." + }, + "error": { + "deleteImageFailed": "Fallo al borrar: {{errorMessage}}", + "deleteCategoryFailed": "Fallo al borrar clase: {{errorMessage}}", + "deleteModelFailed": "Fallo al borrar modelo: {{errorMessage}}", + "categorizeFailed": "Fallo al categorizar imagen: {{errorMessage}}", + "trainingFailed": "Fallo al iniciar el entrenamiento del modelo: {{errorMessage}}", + "updateModelFailed": "Fallo al actualizar modelo: {{errorMessage}}" + } + }, + "deleteCategory": { + "title": "Borrar Clase", + "desc": "¿Esta seguro de que quiere borrar la clase {{name}}? Esto borrará permanentemente todas las imágenes asociadas y requerirá reentrenar el modelo." + }, + "deleteModel": { + "title": "Borrar Modelo de Clasificación", + "single": "¿Está seguro de que quiere eliminar {{name}}? Esto borrar permanentemente todos los datos asociados incluidas las imágenes y los datos de entrenamiento. Esta acción no se puede deshacer." + } +} diff --git a/web/public/locales/es/views/events.json b/web/public/locales/es/views/events.json index a428169a4..097b08b64 100644 --- a/web/public/locales/es/views/events.json +++ b/web/public/locales/es/views/events.json @@ -37,5 +37,17 @@ "selected_other": "{{count}} seleccionados", "detected": "detectado", "suspiciousActivity": "Actividad Sospechosa", - "threateningActivity": "Actividad Amenzadora" + "threateningActivity": "Actividad Amenzadora", + "zoomIn": "Agrandar", + "zoomOut": "Alejar", + "detail": { + "label": "Detalle", + "trackedObject_one": "objeto", + "trackedObject_other": "objetos", + "noObjectDetailData": "No hay datos detallados del objeto.", + "settings": "Configuración de la Vista Detalle" + }, + "objectTrack": { + "clickToSeek": "Clic para ir a este momento" + } } diff --git a/web/public/locales/es/views/explore.json b/web/public/locales/es/views/explore.json index 4816a78ed..064bdf0d8 100644 --- a/web/public/locales/es/views/explore.json +++ b/web/public/locales/es/views/explore.json @@ -110,7 +110,8 @@ "snapshot": "captura instantánea", "video": "vídeo", "object_lifecycle": "ciclo de vida del objeto", - "details": "detalles" + "details": "detalles", + "thumbnail": "miniatura" }, "objectLifecycle": { "title": "Ciclo de vida del objeto", @@ -224,5 +225,11 @@ }, "concerns": { "label": "Preocupaciones" + }, + "trackingDetails": { + "title": "Detalles del Seguimiento", + "noImageFound": "No se ha encontrado imagen en este momento.", + "createObjectMask": "Crear Máscara de Objeto", + "adjustAnnotationSettings": "Ajustar configuración de anotaciones" } } diff --git a/web/public/locales/es/views/exports.json b/web/public/locales/es/views/exports.json index b3b686cae..9de2fa330 100644 --- a/web/public/locales/es/views/exports.json +++ b/web/public/locales/es/views/exports.json @@ -13,5 +13,11 @@ "renameExportFailed": "No se pudo renombrar la exportación: {{errorMessage}}" } }, - "deleteExport.desc": "¿Estás seguro de que quieres eliminar {{exportName}}?" + "deleteExport.desc": "¿Estás seguro de que quieres eliminar {{exportName}}?", + "tooltip": { + "shareExport": "Compartir exportación", + "downloadVideo": "Descargar video", + "editName": "Editar nombre", + "deleteExport": "Eliminar exportación" + } } diff --git a/web/public/locales/es/views/faceLibrary.json b/web/public/locales/es/views/faceLibrary.json index 036f6bc07..25fa983e7 100644 --- a/web/public/locales/es/views/faceLibrary.json +++ b/web/public/locales/es/views/faceLibrary.json @@ -1,6 +1,6 @@ { "description": { - "addFace": "Guía para agregar una nueva colección a la Biblioteca de Rostros.", + "addFace": "Agregar una nueva colección a la Biblioteca de Rostros subiendo tu primera imagen.", "placeholder": "Introduce un nombre para esta colección", "invalidName": "Nombre inválido. Los nombres solo pueden incluir letras, números, espacios, apóstrofes, guiones bajos y guiones." }, @@ -23,11 +23,11 @@ "title": "Crear colección", "desc": "Crear una nueva colección", "new": "Crear nuevo rostro", - "nextSteps": "Para construir una base sólida:
  • Usa la pestaña Entrenar para seleccionar y entrenar con imágenes de cada persona detectada.
  • Enfócate en imágenes frontales para obtener los mejores resultados; evita entrenar con imágenes que capturen rostros en ángulo.
  • " + "nextSteps": "Para construir una base sólida:
  • Usa la pestaña Reconocimientos Recientes para seleccionar y entrenar con imágenes de cada persona detectada.
  • Céntrate en imágenes frontales para obtener los mejores resultados; evita entrenar con imágenes que capturen rostros de perfil.
  • " }, "train": { - "title": "Entrenar", - "aria": "Seleccionar entrenamiento", + "title": "Reconocimientos Recientes", + "aria": "Seleccionar reconocimientos recientes", "empty": "No hay intentos recientes de reconocimiento facial" }, "selectItem": "Seleccionar {{item}}", diff --git a/web/public/locales/es/views/settings.json b/web/public/locales/es/views/settings.json index 9308af481..42bead0be 100644 --- a/web/public/locales/es/views/settings.json +++ b/web/public/locales/es/views/settings.json @@ -27,7 +27,8 @@ "enrichments": "Análisis avanzado", "triggers": "Disparadores", "roles": "Rols", - "cameraManagement": "Administración" + "cameraManagement": "Administración", + "cameraReview": "Revisar" }, "dialog": { "unsavedChanges": { @@ -864,7 +865,9 @@ "createRole": "Rol {{role}} creado exitosamente", "updateCameras": "Cámara actualizada para el rol {{role}}", "deleteRole": "Rol {{role}} eliminado exitosamente", - "userRolesUpdated": "{{count}} usuarios asignados a este rol han sido actualizados a 'visor', que tiene acceso a todas las cámaras." + "userRolesUpdated_one": "{{count}} usuarios asignados a este rol han sido actualizados a 'visor', que tiene acceso a todas las cámaras.", + "userRolesUpdated_many": "", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Creación de rol fallida: {{errorMessage}}", diff --git a/web/public/locales/fr/common.json b/web/public/locales/fr/common.json index a9fe31ada..3cf25e977 100644 --- a/web/public/locales/fr/common.json +++ b/web/public/locales/fr/common.json @@ -301,6 +301,7 @@ }, "list": { "two": "{{0}} et {{1}}", - "many": "{{items}}, et {{last}}" + "many": "{{items}}, et {{last}}", + "separatorWithSpace": ", " } } diff --git a/web/public/locales/fr/views/classificationModel.json b/web/public/locales/fr/views/classificationModel.json index 53f0464a7..7d7d93ba3 100644 --- a/web/public/locales/fr/views/classificationModel.json +++ b/web/public/locales/fr/views/classificationModel.json @@ -5,7 +5,10 @@ "renameCategory": "Renommer la classe", "deleteCategory": "Supprimer la classe", "deleteImages": "Supprimer les images", - "trainModel": "Entraîner le modèle" + "trainModel": "Entraîner le modèle", + "addClassification": "Ajouter une classification", + "deleteModels": "Supprimer les modèles", + "editModel": "Modifier le modèle" }, "toast": { "success": { @@ -13,13 +16,19 @@ "deletedImage": "Images supprimées", "categorizedImage": "Image classifiée avec succès", "trainedModel": "Modèle entraîné avec succès.", - "trainingModel": "L'entraînement du modèle a démarré avec succès." + "trainingModel": "L'entraînement du modèle a démarré avec succès.", + "deletedModel_one": "{{count}} modèle supprimé avec succès", + "deletedModel_many": "{{count}} modèles supprimés avec succès", + "deletedModel_other": "{{count}} modèles supprimés avec succès", + "updatedModel": "Configuration du modèle mise à jour avec succès" }, "error": { "deleteImageFailed": "Échec de la suppression : {{errorMessage}}", "deleteCategoryFailed": "Échec de la suppression de la classe : {{errorMessage}}", "categorizeFailed": "Échec de la catégorisation de l'image : {{errorMessage}}", - "trainingFailed": "Échec du démarrage de l'entraînement du modèle : {{errorMessage}}" + "trainingFailed": "Échec du démarrage de l'entraînement du modèle : {{errorMessage}}", + "deleteModelFailed": "Impossible de supprimer le modèle : {{errorMessage}}", + "updateModelFailed": "Impossible de mettre à jour le modèle : {{errorMessage}}" } }, "deleteCategory": { @@ -43,7 +52,8 @@ }, "train": { "title": "Classifications récentes", - "aria": "Sélectionner des classifications récentes" + "aria": "Sélectionner des classifications récentes", + "titleShort": "Récent" }, "categories": "Classes", "createCategory": { @@ -98,7 +108,8 @@ "stateRequiresTwoClasses": "Les modèles d'état nécessitent au moins deux classes.", "objectLabelRequired": "Veuillez sélectionner une étiquette d'objet.", "objectTypeRequired": "Veuillez sélectionner un type de classification." - } + }, + "states": "États" }, "step2": { "description": "Sélectionnez les caméras et définissez la zone à surveiller pour chaque caméra. Le modèle classifiera l'état de ces zones.", @@ -131,5 +142,23 @@ }, "generateSuccess": "Génération des images d'exemple réussie" } + }, + "deleteModel": { + "title": "Supprimer le modèle de classification", + "single": "Voulez-vous vraiment supprimer {{name}} ? Cela supprimera définitivement toutes les données associées, y compris les images et les données d'entraînement. Cette action est irréversible.", + "desc": "Voulez-vous vraiment supprimer {{count}} modèle(s) ? Cela supprimera définitivement toutes les données associées, y compris les images et les données d'entraînement. Cette action est irréversible." + }, + "menu": { + "objects": "Objets", + "states": "États" + }, + "details": { + "scoreInfo": "Le score représente la moyenne de la confiance de classification pour toutes les détections de cet objet." + }, + "edit": { + "title": "Modifier le modèle de classification", + "descriptionState": "Modifier les classes pour ce modèle de classification d'état. Les modifications nécessiteront un réentraînement du modèle.", + "descriptionObject": "Modifier le type d'objet et le type de classification pour ce modèle de classification d'objet", + "stateClassesInfo": "Note : La modification des classes d'état nécessite un réentraînement du modèle avec les classes mises à jour." } } diff --git a/web/public/locales/fr/views/events.json b/web/public/locales/fr/views/events.json index eb6be7bc0..c32ffec3c 100644 --- a/web/public/locales/fr/views/events.json +++ b/web/public/locales/fr/views/events.json @@ -44,10 +44,17 @@ "trackedObject_one": "objet", "trackedObject_other": "objets", "noObjectDetailData": "Aucun détail d'objet disponible", - "label": "Détail" + "label": "Détail", + "settings": "Paramètres de la vue Détail", + "alwaysExpandActive": { + "title": "Toujours développer l'élément actif", + "desc": "Toujours développer les détails de l'objet de l'événement actif si disponibles" + } }, "objectTrack": { "trackedPoint": "Point suivi", "clickToSeek": "Cliquez pour atteindre ce moment." - } + }, + "zoomIn": "Zoom avant", + "zoomOut": "Zoom arrière" } diff --git a/web/public/locales/fr/views/explore.json b/web/public/locales/fr/views/explore.json index 267f3d622..015d7560b 100644 --- a/web/public/locales/fr/views/explore.json +++ b/web/public/locales/fr/views/explore.json @@ -109,7 +109,8 @@ "details": "détails", "video": "vidéo", "object_lifecycle": "cycle de vie de l'objet", - "snapshot": "instantané" + "snapshot": "instantané", + "thumbnail": "Miniature" }, "objectLifecycle": { "title": "Cycle de vie de l'objet", @@ -240,7 +241,7 @@ "noImageFound": "Aucune image trouvée pour cet horodatage", "createObjectMask": "Créer un masque d'objet", "adjustAnnotationSettings": "Ajuster les paramètres d'annotation", - "scrollViewTips": "Défilez pour voir les moments significatifs du cycle de vie de cet objet.", + "scrollViewTips": "Cliquez pour voir les moments significatifs du cycle de vie de cet objet.", "autoTrackingTips": "Les positions des cadres de détection seront imprécises pour les caméras à suivi automatique.", "count": "{{first}} sur {{second}}", "trackedPoint": "Point suivi", @@ -264,7 +265,7 @@ }, "annotationSettings": { "offset": { - "desc": "Ces données proviennent du flux de détection de votre caméra mais sont superposées aux images du flux d'enregistrement. Il est peu probable que les deux flux soient parfaitement synchronisés. Par conséquent, le cadre de détection et l'enregistrement ne seront pas parfaitement alignés. Cependant, le champ annotation_offset peut être utilisé pour corriger cela.", + "desc": "Ces données proviennent du flux de détection de votre caméra, mais elles sont superposées aux images du flux d'enregistrement. Il est peu probable que les deux flux soient parfaitement synchronisés. Par conséquent, le cadre de délimitation et la vidéo ne s'aligneront pas parfaitement. Vous pouvez utiliser ce paramètre pour décaler les annotations vers l'avant ou vers l'arrière dans le temps afin de mieux les aligner avec la vidéo enregistrée.", "millisecondsToOffset": "Millisecondes de décalage pour les annotations de détection. Par défaut : 0", "tips": "ASTUCE : Imaginez une séquence d'événement avec une personne marchant de gauche à droite. Si le cadre de détection sur la chronologie de l'événement est constamment à gauche de la personne, la valeur doit être diminuée. De même, si une personne marche de gauche à droite et que le cadre de détection est constamment devant la personne, la valeur doit être augmentée.", "toast": { diff --git a/web/public/locales/fr/views/settings.json b/web/public/locales/fr/views/settings.json index a0e5fe98c..61202dc6f 100644 --- a/web/public/locales/fr/views/settings.json +++ b/web/public/locales/fr/views/settings.json @@ -51,6 +51,10 @@ "playAlertVideos": { "label": "Lire les vidéos d'alerte", "desc": "Par défaut, les alertes récentes du tableau de bord en direct sont diffusées sous forme de petites vidéos en boucle. Désactivez cette option pour afficher uniquement une image statique des alertes récentes sur cet appareil/navigateur." + }, + "displayCameraNames": { + "label": "Toujours afficher les noms des caméras", + "desc": "Toujours afficher les noms des caméras dans une puce sur le tableau de bord de la vue en direct multi-caméras" } }, "storedLayouts": { @@ -767,7 +771,9 @@ }, "actions": { "alert": "Marquer comme alerte", - "notification": "Envoyer une notification" + "notification": "Envoyer une notification", + "sub_label": "Ajouter une sous-étiquette", + "attribute": "Ajouter un attribut" }, "dialog": { "createTrigger": { @@ -822,7 +828,7 @@ }, "actions": { "title": "Actions", - "desc": "Par défaut, Frigate publie un message MQTT à chaque déclenchement. Sélectionnez une action complémentaire à exécuter lors de ce déclenchement.", + "desc": "Par défaut, Frigate envoie un message MQTT pour tous les déclencheurs. Les sous-étiquettes ajoutent le nom du déclencheur à l'étiquette de l'objet. Les attributs sont des métadonnées recherchables stockées séparément dans les métadonnées de l'objet suivi.", "error": { "min": "Au moins une action doit être sélectionnée." } @@ -887,7 +893,9 @@ "createRole": "Rôle {{role}} créé avec succès", "updateCameras": "Caméras mis à jour pour le rôle {{role}}", "deleteRole": "Rôle {{role}} supprimé avec succès", - "userRolesUpdated": "{{count}} utilisateurs affectés à ce rôle ont été mis à jour avec des droits \"Observateur\", et ont accès à toutes les caméras." + "userRolesUpdated_one": "{{count}} utilisateurs affectés à ce rôle ont été mis à jour avec des droits \"Observateur\", et ont accès à toutes les caméras.", + "userRolesUpdated_many": "", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Échec dans la création du rôle : {{errorMessage}}", @@ -1072,7 +1080,9 @@ "resolutionHigh": "La résolution {{resolution}} risque d'augmenter l'utilisation des ressources.", "resolutionLow": "La résolution {{resolution}} risque d'être trop faible pour détecter les petits objets de manière fiable." }, - "valid": "Valide" + "valid": "Valide", + "ffmpegModule": "Utiliser le mode de compatibilité du flux", + "ffmpegModuleDescription": "Si le flux ne se charge pas après plusieurs tentatives, essayez d'activer cette option. Lorsqu'elle est activée, Frigate utilisera le module ffmpeg avec go2rtc. Cela peut offrir une meilleure compatibilité avec certains flux de caméra." } }, "cameraManagement": { diff --git a/web/public/locales/hu/components/auth.json b/web/public/locales/hu/components/auth.json index 37dc3a2e4..43b8e9e17 100644 --- a/web/public/locales/hu/components/auth.json +++ b/web/public/locales/hu/components/auth.json @@ -10,6 +10,7 @@ "unknownError": "Ismeretlen hiba. Ellenőrizze a naplókat.", "webUnknownError": "Ismeretlen hiba. Ellenőrizze a konzol naplókat.", "rateLimit": "Túl sokszor próbálkozott. Próbálja meg később." - } + }, + "firstTimeLogin": "Először próbálsz bejelentkezni? A hitelesítési adatok a Frigate naplóiban vannak feltüntetve." } } diff --git a/web/public/locales/hu/views/classificationModel.json b/web/public/locales/hu/views/classificationModel.json index 0967ef424..8ce7864e9 100644 --- a/web/public/locales/hu/views/classificationModel.json +++ b/web/public/locales/hu/views/classificationModel.json @@ -1 +1,17 @@ -{} +{ + "documentTitle": "Osztályozási modellek", + "button": { + "deleteClassificationAttempts": "Osztályozási képek törlése", + "deleteImages": "Képek törlése", + "trainModel": "Modell betanítása", + "deleteModels": "Modellek törlése" + }, + "toast": { + "success": { + "deletedImage": "Törölt képek", + "deletedModel_one": "Sikeresen törölt {{count}} modellt", + "deletedModel_other": "", + "categorizedImage": "A kép sikeresen osztályozva" + } + } +} diff --git a/web/public/locales/hu/views/events.json b/web/public/locales/hu/views/events.json index d470abbd5..abea6b464 100644 --- a/web/public/locales/hu/views/events.json +++ b/web/public/locales/hu/views/events.json @@ -36,5 +36,6 @@ "selected_one": "{{count}} kiválasztva", "selected_other": "{{count}} kiválasztva", "suspiciousActivity": "Gyanús Tevékenység", - "threateningActivity": "Fenyegető Tevékenység" + "threateningActivity": "Fenyegető Tevékenység", + "zoomIn": "Nagyítás" } diff --git a/web/public/locales/hu/views/exports.json b/web/public/locales/hu/views/exports.json index f54c70923..ab07aba94 100644 --- a/web/public/locales/hu/views/exports.json +++ b/web/public/locales/hu/views/exports.json @@ -13,5 +13,11 @@ "error": { "renameExportFailed": "Sikertelen export átnevezés: {{errorMessage}}" } + }, + "tooltip": { + "downloadVideo": "Videó letöltése", + "editName": "Név szerkesztése", + "deleteExport": "Export törlése", + "shareExport": "Export megosztása" } } diff --git a/web/public/locales/hu/views/faceLibrary.json b/web/public/locales/hu/views/faceLibrary.json index 7b12521d5..4f9331f87 100644 --- a/web/public/locales/hu/views/faceLibrary.json +++ b/web/public/locales/hu/views/faceLibrary.json @@ -42,12 +42,12 @@ "title": "Gyűjtemény létrehozása", "desc": "Új gyűjtemény létrehozása", "new": "Új arc létrhozása", - "nextSteps": "A jó alap készítéséhez:
  • Használja a Tanítás fület az egyes észlelt személyekhez tartozó képek kiválasztására és betanítására.
  • A legjobb eredmény érdekében válassza az egyenesen előre néző arcokat ábrázoló képeket és kerülje a ferde szögből készült arcképeket a tanításhoz." + "nextSteps": "A jó alap készítéséhez:
  • Használja a Legutóbbi felismerések fület az egyes észlelt személyekhez tartozó képek kiválasztásához és betanításához.
  • A legjobb eredmény érdekében válassza az egyenesen előre néző arcokat ábrázoló képeket és kerülje a ferde szögből készült arcképeket a tanításhoz." }, "description": { "placeholder": "Adj nevet ennek a gyűjteménynek", "invalidName": "Nem megfelelő név. A nevek csak betűket, számokat, szóközöket, aposztrófokat, alulhúzásokat és kötőjeleket tartalmazhatnak.", - "addFace": "Segédlet új gyűjtemény hozzáadásához az arckép könyvtárban." + "addFace": "Adj hozzá egy új gyűjteményt az Arcképtárhoz az első képed feltöltésével." }, "selectFace": "Arc kiválasztása", "deleteFaceLibrary": { diff --git a/web/public/locales/hu/views/settings.json b/web/public/locales/hu/views/settings.json index 1754ceb52..c36e9a53f 100644 --- a/web/public/locales/hu/views/settings.json +++ b/web/public/locales/hu/views/settings.json @@ -799,7 +799,8 @@ "createRole": "Szerepkör létrehozva: {{role}}", "updateCameras": "Kamerák frissítve a szerepkörhöz: {{role}}", "deleteRole": "Szerepkör sikeresen törölve: {{role}}", - "userRolesUpdated": "{{count}} felhasználó, akit ehhez a szerepkörhöz rendeltünk, frissült „néző”-re, amely hozzáféréssel rendelkezik az összes kamerához." + "userRolesUpdated_one": "{{count}} felhasználó, akit ehhez a szerepkörhöz rendeltünk, frissült „néző”-re, amely hozzáféréssel rendelkezik az összes kamerához.", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Nem sikerült létrehozni a szerepkört: {{errorMessage}}", diff --git a/web/public/locales/id/audio.json b/web/public/locales/id/audio.json index 3b4d05aaf..0f759c193 100644 --- a/web/public/locales/id/audio.json +++ b/web/public/locales/id/audio.json @@ -84,5 +84,6 @@ "banjo": "Banjo", "snoring": "Ngorok", "cough": "Batuk", - "clapping": "Tepukan" + "clapping": "Tepukan", + "camera": "Kamera" } diff --git a/web/public/locales/id/components/auth.json b/web/public/locales/id/components/auth.json index 0bc931d99..742e3111a 100644 --- a/web/public/locales/id/components/auth.json +++ b/web/public/locales/id/components/auth.json @@ -4,12 +4,13 @@ "password": "Kata sandi", "login": "Masuk", "errors": { - "usernameRequired": "Wajib Menggunakan Username", - "passwordRequired": "Wajib memakai Password", + "usernameRequired": "Username diperlukan", + "passwordRequired": "Password diperlukan", "rateLimit": "Melewati batas permintaan. Coba lagi nanti.", "loginFailed": "Gagal Masuk", "unknownError": "Eror tidak diketahui. Mohon lihat log.", "webUnknownError": "Eror tidak diketahui. Mohon lihat log konsol." - } + }, + "firstTimeLogin": "Mencoba masuk untuk pertama kali? Kredensial sudah dicetak di dalam riwayat Frigate." } } diff --git a/web/public/locales/id/views/configEditor.json b/web/public/locales/id/views/configEditor.json index 3577999ab..a4d7baeaa 100644 --- a/web/public/locales/id/views/configEditor.json +++ b/web/public/locales/id/views/configEditor.json @@ -13,5 +13,6 @@ } }, "confirm": "Keluar tanpa menyimpan?", - "safeModeDescription": "Frigate sedang dalam mode aman karena kesalahan validasi konfigurasi." + "safeModeDescription": "Frigate sedang dalam mode aman karena kesalahan validasi konfigurasi.", + "safeConfigEditor": "Editor Konfigurasi(Mode Aman)" } diff --git a/web/public/locales/id/views/events.json b/web/public/locales/id/views/events.json index f320bae8f..94ee3d47d 100644 --- a/web/public/locales/id/views/events.json +++ b/web/public/locales/id/views/events.json @@ -12,5 +12,48 @@ "motion": "Data gerakan tidak ditemukan" }, "timeline.aria": "Pilih timeline", - "timeline": "Linimasa" + "timeline": "Linimasa", + "zoomIn": "Perbesar", + "zoomOut": "Perkecil", + "events": { + "label": "Peristiwa-Peristiwa", + "aria": "Pilih peristiwa", + "noFoundForTimePeriod": "Tidak ada peristiwa dalam periode waktu berikut." + }, + "detail": { + "label": "Detil", + "noDataFound": "Tidak ada detil data untuk di review", + "aria": "Beralih tampilan detil", + "trackedObject_one": "objek", + "trackedObject_other": "objek-objek", + "noObjectDetailData": "Tidak ada data objek detil tersedia.", + "settings": "Pengaturan Tampilan Detil", + "alwaysExpandActive": { + "title": "Selalu lebarkan yang aktif", + "desc": "Selalu perluas detil objek item tinjauan aktif jika tersedia." + } + }, + "objectTrack": { + "trackedPoint": "Titik terlacak", + "clickToSeek": "Klik untuk mencari waktu ini" + }, + "documentTitle": "Tinjauan - Frigate", + "recordings": { + "documentTitle": "Rekaman - Frigate" + }, + "calendarFilter": { + "last24Hours": "24 Jam Terakhir" + }, + "markAsReviewed": "Tandai sebagai sudah ditinjau", + "markTheseItemsAsReviewed": "Tandai item-item berikut sebagai sudah ditinjau", + "newReviewItems": { + "button": "Item Batu Untuk Ditinjau", + "label": "Lihat item ulasan baru" + }, + "selected_one": "{{count}} terpilih", + "selected_other": "{{count}} terpilih", + "camera": "Kamera", + "detected": "terdeteksi", + "suspiciousActivity": "Aktivitas Mencurigakan", + "threateningActivity": "Aktivitas yang Mengancam" } diff --git a/web/public/locales/id/views/exports.json b/web/public/locales/id/views/exports.json index ebb88a9f7..043c313de 100644 --- a/web/public/locales/id/views/exports.json +++ b/web/public/locales/id/views/exports.json @@ -1,17 +1,23 @@ { "documentTitle": "Expor - Frigate", "search": "Cari", - "noExports": "Tidak bisa mengekspor", + "noExports": "Ekspor tidak ditemukan", "deleteExport": "Hapus Ekspor", "deleteExport.desc": "Apakah Anda yakin ingin menghapus {{exportName}}?", "editExport": { - "title": "Ganti Nama saat Ekspor", - "desc": "Masukkan nama baru untuk mengekspor.", + "title": "Ganti Nama Ekspor", + "desc": "Masukkan nama baru untuk ekspor ini.", "saveExport": "Simpan Ekspor" }, "toast": { "error": { - "renameExportFailed": "Gagal mengganti nama export: {{errorMessage}}" + "renameExportFailed": "Gagal mengganti nama ekspor: {{errorMessage}}" } + }, + "tooltip": { + "shareExport": "Bagikan Ekspor", + "downloadVideo": "Unduh Video", + "editName": "Ubah nama", + "deleteExport": "Hapus ekspor" } } diff --git a/web/public/locales/id/views/faceLibrary.json b/web/public/locales/id/views/faceLibrary.json index ff1fd4b61..bde637fa0 100644 --- a/web/public/locales/id/views/faceLibrary.json +++ b/web/public/locales/id/views/faceLibrary.json @@ -1,6 +1,6 @@ { "description": { - "addFace": "Tambah ke koleksi Pustaka Wajah.", + "addFace": "Tambah ke koleksi Pustaka Wajah dengan men-upload gambar pertama anda.", "placeholder": "Masukkan Nama untuk koleksi ini", "invalidName": "Nama tidak valid. Nama hanya dapat berisi huruf, angka, spasi, apostrof, garis bawah, dan tanda hubung." }, @@ -18,13 +18,75 @@ "createFaceLibrary": { "desc": "Buat koleksi baru", "title": "Buat Koleksi", - "nextSteps": "Untuk membangun fondasi yang kuat:
  • Gunakan tab Latih untuk memilih dan melatih gambar untuk setiap orang yang terdeteksi.
  • Fokus pada gambar lurus untuk hasil terbaik; hindari melatih gambar yang menangkap wajah pada sudut tertentu.
  • " + "nextSteps": "Untuk membangun fondasi yang kuat:
  • Gunakan tab Pengenalan Terbaru untuk memilih dan melatih gambar untuk setiap orang yang terdeteksi.
  • Fokus pada gambar langsung untuk hasil terbaik; hindari melatih gambar yang menangkap wajah pada sudut tertentu.
  • ", + "new": "Buat Wajah Baru" }, "uploadFaceImage": { "desc": "Unggah gambar untuk dipindai wajah dan sertakan untuk {{pageToggle}}", "title": "Unggah Gambar Wajah" }, "steps": { - "faceName": "Masukkan Nama Wajah" + "faceName": "Masukkan Nama Wajah", + "uploadFace": "Unggah Gambar Wajah", + "nextSteps": "Langkah Berikutnya", + "description": { + "uploadFace": "Upload sebuah gambar dari {{name}} yang menunjukkan wajah mereka dari sisi depan. Gambar tidak perlu dipotong ke wajah mereka." + } + }, + "train": { + "title": "Pengenalan Terkini", + "aria": "Pilih pengenalan terkini", + "empty": "Tidak ada percobaan pengenalan wajah baru-baru ini" + }, + "deleteFaceLibrary": { + "title": "Hapus Nama", + "desc": "Apakah anda yakin ingin menghapus koleksi {{name}}? Ini akan menghapus semua wajah terkait secara permanen." + }, + "deleteFaceAttempts": { + "title": "Hapus Wajah-Wajah", + "desc_other": "Apakah anda yakin ingin menghapis {{count}} wajah? Aksi ini tidak dapat diurungkan." + }, + "renameFace": { + "title": "Ganti Nama Wajah", + "desc": "Masukkan nama baru untuk {{name}}" + }, + "button": { + "deleteFaceAttempts": "Hapus Wajah", + "addFace": "Tambah Wajah", + "renameFace": "Ganti Nama Wajah", + "deleteFace": "Hapus Wajah", + "uploadImage": "Unggah Gambar", + "reprocessFace": "Proses Ulang Wajah" + }, + "imageEntry": { + "validation": { + "selectImage": "Silahkan pilih sebuah file gambar." + }, + "dropActive": "Letakkan gambar di sini…", + "dropInstructions": "Seret dan lepaskan atau tempel gambar di sini, atau klik untuk memilih", + "maxSize": "Ukuran maksimum: {{size}}MB" + }, + "nofaces": "Tidak ada wajah tersedia", + "trainFaceAs": "Latih Gambar sebagai:", + "trainFace": "Latih Wajah", + "toast": { + "success": { + "uploadedImage": "Berhasil men unggah gambar.", + "addFaceLibrary": "{{name}} telah berhasil ditambahkan ke Pustaka Wajah!", + "deletedFace_other": "Berhasil menghapus {{count}} wajah.", + "deletedName_other": "{{count}} wajah telah berhasil dihapus.", + "renamedFace": "Berhasil mengganti nama wajah ke {{name}}", + "trainedFace": "Berhasil melatih wajah.", + "updatedFaceScore": "Berhasil memperbaharui nilai wajah." + }, + "error": { + "uploadingImageFailed": "Gagal menunggah gambar: {{errorMessage}}", + "addFaceLibraryFailed": "Gagal mengatur nama wajah: {{errorMessage}}", + "deleteFaceFailed": "Gagal untuk menghapus: {{errorMessage}}", + "deleteNameFailed": "Gagal menghapus nama: {{errorMessage}}", + "renameFaceFailed": "Gagal mengganti nama wajah: {{errorMessage}}", + "trainFailed": "Gagal untuk melatih: {{errorMessage}}", + "updateFaceScoreFailed": "Gagal untuk memperbaharui nilai wajah: {{errorMessage}}" + } } } diff --git a/web/public/locales/it/common.json b/web/public/locales/it/common.json index 35a41f22b..48c37740c 100644 --- a/web/public/locales/it/common.json +++ b/web/public/locales/it/common.json @@ -145,7 +145,10 @@ } }, "label": { - "back": "Vai indietro" + "back": "Vai indietro", + "hide": "Nascondi {{item}}", + "show": "Mostra {{item}}", + "ID": "ID" }, "menu": { "configuration": "Configurazione", @@ -265,7 +268,7 @@ "title": "Ruolo", "admin": "Amministratore", "viewer": "Spettatore", - "desc": "Gli Amministratori hanno accesso completo a tutte le funzionalità dell'interfaccia di Frigate. Gli Spettatori sono limitati alla sola visualizzazione delle telecamere, rivedono gli oggetti e le registrazioni storiche nell'interfaccia utente." + "desc": "Gli amministratori hanno accesso completo a tutte le funzionalità dell'interfaccia utente di Frigate. Gli spettatori possono visualizzare solo le telecamere, gli elementi di revisione e i filmati storici nell'interfaccia utente." }, "accessDenied": { "desc": "Non hai i permessi per visualizzare questa pagina.", @@ -291,5 +294,14 @@ "readTheDocumentation": "Leggi la documentazione", "information": { "pixels": "{{area}}px" + }, + "list": { + "two": "{{0}} e {{1}}", + "many": "{{items}}, e {{last}}", + "separatorWithSpace": ", " + }, + "field": { + "optional": "Opzionale", + "internalID": "L'ID interno che Frigate utilizza nella configurazione e nel database" } } diff --git a/web/public/locales/it/components/dialog.json b/web/public/locales/it/components/dialog.json index 8c3b07f65..0f69e7213 100644 --- a/web/public/locales/it/components/dialog.json +++ b/web/public/locales/it/components/dialog.json @@ -61,7 +61,7 @@ "export": "Esporta", "selectOrExport": "Seleziona o esporta", "toast": { - "success": "Esportazione avviata correttamente. Visualizza il file nella cartella /exports.", + "success": "Esportazione avviata correttamente. Visualizza il file nella pagina delle esportazioni.", "error": { "failed": "Impossibile avviare l'esportazione: {{error}}", "endTimeMustAfterStartTime": "L'ora di fine deve essere successiva all'ora di inizio", @@ -129,6 +129,7 @@ "search": { "placeholder": "Cerca per etichetta o sottoetichetta..." }, - "noImages": "Nessuna miniatura trovata per questa fotocamera" + "noImages": "Nessuna miniatura trovata per questa fotocamera", + "unknownLabel": "Immagine di attivazione salvata" } } diff --git a/web/public/locales/it/components/filter.json b/web/public/locales/it/components/filter.json index 85dabf7e7..22fc52093 100644 --- a/web/public/locales/it/components/filter.json +++ b/web/public/locales/it/components/filter.json @@ -63,7 +63,7 @@ "label": "Cerca la fonte", "desc": "Scegli se cercare nelle miniature o nelle descrizioni degli oggetti tracciati.", "options": { - "thumbnailImage": "Immagine anteprima", + "thumbnailImage": "Immagine in miniatura", "description": "Descrizione" } } diff --git a/web/public/locales/it/views/classificationModel.json b/web/public/locales/it/views/classificationModel.json index 0967ef424..343cc3602 100644 --- a/web/public/locales/it/views/classificationModel.json +++ b/web/public/locales/it/views/classificationModel.json @@ -1 +1,164 @@ -{} +{ + "documentTitle": "Modelli di classificazione", + "button": { + "deleteClassificationAttempts": "Elimina immagini di classificazione", + "renameCategory": "Rinomina classe", + "deleteCategory": "Elimina classe", + "deleteImages": "Elimina immagini", + "trainModel": "Modello di addestramento", + "addClassification": "Aggiungi classificazione", + "deleteModels": "Elimina modelli", + "editModel": "Modifica modello" + }, + "toast": { + "success": { + "deletedCategory": "Classe eliminata", + "deletedImage": "Immagini eliminate", + "categorizedImage": "Immagine classificata con successo", + "trainedModel": "Modello addestrato con successo.", + "trainingModel": "Avviato con successo l'addestramento del modello.", + "deletedModel_one": "Eliminato con successo {{count}} modello", + "deletedModel_many": "Eliminati con successo {{count}} modelli", + "deletedModel_other": "Eliminati con successo {{count}} modelli", + "updatedModel": "Configurazione del modello aggiornata correttamente" + }, + "error": { + "deleteImageFailed": "Impossibile eliminare: {{errorMessage}}", + "deleteCategoryFailed": "Impossibile eliminare la classe: {{errorMessage}}", + "categorizeFailed": "Impossibile categorizzare l'immagine: {{errorMessage}}", + "trainingFailed": "Impossibile avviare l'addestramento del modello: {{errorMessage}}", + "deleteModelFailed": "Impossibile eliminare il modello: {{errorMessage}}", + "updateModelFailed": "Impossibile aggiornare il modello: {{errorMessage}}" + } + }, + "deleteCategory": { + "title": "Elimina classe", + "desc": "Vuoi davvero eliminare la classe {{name}}? Questa operazione eliminerà definitivamente tutte le immagini associate e richiederà un nuovo addestramento del modello." + }, + "deleteDatasetImages": { + "title": "Elimina immagini della base dati", + "desc": "Vuoi davvero eliminare {{count}} immagini da {{dataset}}? Questa azione non può essere annullata e richiederà un nuovo addestramento del modello." + }, + "deleteTrainImages": { + "title": "Elimina le immagini di addestramento", + "desc": "Vuoi davvero eliminare {{count}} immagini? Questa azione non può essere annullata." + }, + "renameCategory": { + "title": "Rinomina classe", + "desc": "Inserisci un nuovo nome per {{name}}. Sarà necessario riaddestrare il modello affinché la modifica del nome abbia effetto." + }, + "description": { + "invalidName": "Nome non valido. I nomi possono contenere solo lettere, numeri, spazi, apostrofi, caratteri di sottolineatura e trattini." + }, + "train": { + "title": "Classificazioni recenti", + "titleShort": "Recente", + "aria": "Seleziona classificazioni recenti" + }, + "categories": "Classi", + "createCategory": { + "new": "Crea nuova classe" + }, + "categorizeImageAs": "Classifica immagine come:", + "categorizeImage": "Classifica immagine", + "noModels": { + "object": { + "title": "Nessun modello di classificazione degli oggetti", + "description": "Crea un modello personalizzato per classificare gli oggetti rilevati.", + "buttonText": "Crea modello oggetto" + }, + "state": { + "title": "Nessun modello di classificazione dello stato", + "description": "Crea un modello personalizzato per monitorare e classificare i cambiamenti di stato in aree specifiche della telecamera.", + "buttonText": "Crea modello di stato" + } + }, + "wizard": { + "title": "Crea nuova classificazione", + "steps": { + "nameAndDefine": "Nome e definizione", + "stateArea": "Area di stato", + "chooseExamples": "Scegli esempi" + }, + "step1": { + "description": "I modelli di stato monitorano le aree fisse delle telecamere per rilevare eventuali cambiamenti (ad esempio, porta aperta/chiusa). I modelli di oggetti aggiungono classificazioni agli oggetti rilevati (ad esempio, animali noti, addetti alle consegne, ecc.).", + "name": "Nome", + "namePlaceholder": "Inserisci il nome del modello...", + "type": "Tipo", + "typeState": "Stato", + "typeObject": "Oggetto", + "objectLabel": "Etichetta oggetto", + "objectLabelPlaceholder": "Seleziona il tipo di oggetto...", + "classificationType": "Tipo di classificazione", + "classificationTypeTip": "Scopri i tipi di classificazione", + "classificationTypeDesc": "Le sottoetichette aggiungono testo aggiuntivo all'etichetta dell'oggetto (ad esempio, \"Persona: UPS\"). Gli attributi sono metadati ricercabili, archiviati separatamente nei metadati dell'oggetto.", + "classificationSubLabel": "Etichetta secondaria", + "classificationAttribute": "Attributo", + "classes": "Classi", + "classesTip": "Scopri di più sulle classi", + "classesStateDesc": "Definisci i diversi stati in cui può trovarsi l'area della tua telecamera. Ad esempio: \"aperto\" e \"chiuso\" per una porta del garage.", + "classesObjectDesc": "Definisci le diverse categorie in cui classificare gli oggetti rilevati. Ad esempio: \"corriere\", \"residente\", \"straniero\" per la classificazione delle persone.", + "classPlaceholder": "Inserisci il nome della classe...", + "errors": { + "nameRequired": "Il nome del modello è obbligatorio", + "nameLength": "Il nome del modello deve contenere al massimo 64 caratteri", + "nameOnlyNumbers": "Il nome del modello non può contenere solo numeri", + "classRequired": "È richiesta almeno 1 classe", + "classesUnique": "I nomi delle classi devono essere univoci", + "stateRequiresTwoClasses": "I modelli di stato richiedono almeno 2 classi", + "objectLabelRequired": "Seleziona un'etichetta per l'oggetto", + "objectTypeRequired": "Seleziona un tipo di classificazione" + }, + "states": "Stati" + }, + "step2": { + "description": "Seleziona le telecamere e definisci l'area da monitorare per ciascuna telecamera. Il modello classificherà lo stato di queste aree.", + "cameras": "Telecamere", + "selectCamera": "Seleziona telecamera", + "noCameras": "Fai clic su + per aggiungere telecamere", + "selectCameraPrompt": "Selezionare una telecamera dall'elenco per definire la sua area di monitoraggio" + }, + "step3": { + "selectImagesPrompt": "Seleziona tutte le immagini con: {{className}}", + "selectImagesDescription": "Clicca sulle immagini per selezionarle. Clicca su Continua quando hai finito con questa classe.", + "generating": { + "title": "Generazione di immagini campione", + "description": "Frigate sta estraendo immagini rappresentative dalle registrazioni. L'operazione potrebbe richiedere qualche istante..." + }, + "training": { + "title": "Modello di addestramento", + "description": "Il tuo modello è in fase di addestramento in sottofondo. Chiudi questa finestra di dialogo e il tuo modello inizierà a funzionare non appena l'addestramento sarà completato." + }, + "retryGenerate": "Riprova generazione", + "noImages": "Nessuna immagine campione generata", + "classifying": "Classificazione e addestramento...", + "trainingStarted": "Addestramento iniziato con successo", + "errors": { + "noCameras": "Nessuna telecamera configurata", + "noObjectLabel": "Nessuna etichetta oggetto selezionata", + "generateFailed": "Impossibile generare esempi: {{error}}", + "generationFailed": "Generazione fallita. Per favore riprova.", + "classifyFailed": "Impossibile classificare le immagini: {{error}}" + }, + "generateSuccess": "Immagini campione generate correttamente" + } + }, + "deleteModel": { + "title": "Elimina modello di classificazione", + "single": "Vuoi davvero eliminare {{name}}? Questa operazione eliminerà definitivamente tutti i dati associati, comprese le immagini e i dati di allenamento. Questa azione non può essere annullata.", + "desc": "Vuoi davvero eliminare {{count}} modello/i? Questa operazione eliminerà definitivamente tutti i dati associati, comprese le immagini e i dati di addestramento. Questa azione non può essere annullata." + }, + "menu": { + "objects": "Oggetti", + "states": "Stati" + }, + "details": { + "scoreInfo": "Il punteggio rappresenta la confidenza media della classificazione in tutti i rilevamenti di questo oggetto." + }, + "edit": { + "title": "Modifica modello di classificazione", + "descriptionState": "Modifica le classi per questo modello di classificazione dello stato. Le modifiche richiederanno un nuovo addestramento del modello.", + "descriptionObject": "Modifica il tipo di oggetto e il tipo di classificazione per questo modello di classificazione degli oggetti.", + "stateClassesInfo": "Nota: la modifica delle classi di stato richiede il riaddestramento del modello con le classi aggiornate." + } +} diff --git a/web/public/locales/it/views/events.json b/web/public/locales/it/views/events.json index 938ab60d2..c5c90509f 100644 --- a/web/public/locales/it/views/events.json +++ b/web/public/locales/it/views/events.json @@ -44,10 +44,17 @@ "trackedObject_one": "oggetto", "trackedObject_other": "oggetti", "noObjectDetailData": "Non sono disponibili dati dettagliati sull'oggetto.", - "label": "Dettaglio" + "label": "Dettaglio", + "settings": "Impostazioni di visualizzazione dettagliata", + "alwaysExpandActive": { + "title": "Espandi sempre attivo", + "desc": "Espandere sempre i dettagli dell'oggetto dell'elemento di revisione attivo quando disponibili." + } }, "objectTrack": { "trackedPoint": "Punto tracciato", "clickToSeek": "Premi per cercare in questo momento" - } + }, + "zoomIn": "Ingrandisci", + "zoomOut": "Rimpicciolisci" } diff --git a/web/public/locales/it/views/explore.json b/web/public/locales/it/views/explore.json index 3fb2e39e0..cbe20ab4f 100644 --- a/web/public/locales/it/views/explore.json +++ b/web/public/locales/it/views/explore.json @@ -158,7 +158,8 @@ "snapshot": "istantanea", "object_lifecycle": "ciclo di vita dell'oggetto", "details": "dettagli", - "video": "video" + "video": "video", + "thumbnail": "miniatura" }, "itemMenu": { "downloadSnapshot": { @@ -201,11 +202,15 @@ }, "hideObjectDetails": { "label": "Nascondi il percorso dell'oggetto" + }, + "viewTrackingDetails": { + "label": "Visualizza i dettagli di tracciamento", + "aria": "Mostra i dettagli di tracciamento" } }, "dialog": { "confirmDelete": { - "desc": "L'eliminazione di questo oggetto tracciato rimuove l'istantanea, eventuali incorporamenti salvati e tutte le voci associate al ciclo di vita dell'oggetto. Il filmato registrato di questo oggetto tracciato nella vista Storico NON verrà eliminato.

    Vuoi davvero procedere?", + "desc": "L'eliminazione di questo oggetto tracciato rimuove l'istantanea, eventuali incorporamenti salvati e tutte le voci associate ai dettagli di tracciamento. Il filmato registrato di questo oggetto tracciato nella vista Storico NON verrà eliminato.

    Vuoi davvero procedere?", "title": "Conferma eliminazione" } }, @@ -230,5 +235,53 @@ }, "concerns": { "label": "Preoccupazioni" + }, + "trackingDetails": { + "title": "Dettagli di tracciamento", + "noImageFound": "Nessuna immagine trovata per questo orario.", + "createObjectMask": "Crea maschera oggetto", + "adjustAnnotationSettings": "Regola le impostazioni di annotazione", + "scrollViewTips": "Clicca per visualizzare i momenti più significativi del ciclo di vita di questo oggetto.", + "autoTrackingTips": "Le posizioni dei riquadri di delimitazione saranno imprecise per le telecamere con tracciamento automatico.", + "count": "{{first}} di {{second}}", + "trackedPoint": "Punto tracciato", + "lifecycleItemDesc": { + "visible": "{{label}} rilevato", + "entered_zone": "{{label}} è entrato in {{zones}}", + "active": "{{label}} è diventato attivo", + "stationary": "{{label}} è diventato stazionario", + "attribute": { + "faceOrLicense_plate": "{{attribute}} rilevato per {{label}}", + "other": "{{label}} riconosciuto come {{attribute}}" + }, + "gone": "{{label}} lasciato", + "heard": "{{label}} sentito", + "external": "{{label}} rilevato", + "header": { + "zones": "Zone", + "ratio": "Rapporto", + "area": "Area" + } + }, + "annotationSettings": { + "title": "Impostazioni di annotazione", + "showAllZones": { + "title": "Mostra tutte le zone", + "desc": "Mostra sempre le zone nei fotogrammi in cui gli oggetti sono entrati in una zona." + }, + "offset": { + "label": "Differenza annotazione", + "desc": "Questi dati provengono dal flusso di rilevamento della telecamera, ma vengono sovrapposti alle immagini del flusso di registrazione. È improbabile che i due flussi siano perfettamente sincronizzati. Di conseguenza, il riquadro di delimitazione e il filmato non saranno perfettamente allineati. È possibile utilizzare questa impostazione per spostare le annotazioni in avanti o indietro nel tempo per allinearle meglio al filmato registrato.", + "millisecondsToOffset": "Millisecondi per compensare il rilevamento delle annotazioni. Predefinito: 0", + "tips": "SUGGERIMENTO: Immagina un video evento con una persona che cammina da sinistra a destra. Se il riquadro di delimitazione della cronologia dell'evento si trova costantemente a sinistra della persona, il valore dovrebbe essere diminuito. Allo stesso modo, se una persona cammina da sinistra a destra e il riquadro di delimitazione si trova costantemente davanti alla persona, il valore dovrebbe essere aumentato.", + "toast": { + "success": "La differenza dell'annotazione per {{camera}} è stato salvato nel file di configurazione. Riavvia Frigate per applicare le modifiche." + } + } + }, + "carousel": { + "previous": "Diapositiva precedente", + "next": "Diapositiva successiva" + } } } diff --git a/web/public/locales/it/views/exports.json b/web/public/locales/it/views/exports.json index 0c42816ef..186647521 100644 --- a/web/public/locales/it/views/exports.json +++ b/web/public/locales/it/views/exports.json @@ -13,5 +13,11 @@ "error": { "renameExportFailed": "Impossibile rinominare l'esportazione: {{errorMessage}}" } + }, + "tooltip": { + "shareExport": "Condividi esportazione", + "downloadVideo": "Scarica video", + "editName": "Modifica nome", + "deleteExport": "Elimina esportazione" } } diff --git a/web/public/locales/it/views/faceLibrary.json b/web/public/locales/it/views/faceLibrary.json index 8d2a48899..040d28680 100644 --- a/web/public/locales/it/views/faceLibrary.json +++ b/web/public/locales/it/views/faceLibrary.json @@ -1,7 +1,7 @@ { "selectItem": "Seleziona {{item}}", "description": { - "addFace": "Procedura per aggiungere una nuova raccolta alla Libreria dei Volti.", + "addFace": "Aggiungi una nuova raccolta alla Libreria dei Volti caricando la tua prima immagine.", "placeholder": "Inserisci un nome per questa raccolta", "invalidName": "Nome non valido. I nomi possono contenere solo lettere, numeri, spazi, apostrofi, caratteri di sottolineatura e trattini." }, diff --git a/web/public/locales/it/views/settings.json b/web/public/locales/it/views/settings.json index f3b102adc..5f20486ff 100644 --- a/web/public/locales/it/views/settings.json +++ b/web/public/locales/it/views/settings.json @@ -494,7 +494,11 @@ "label": "Riproduci video di avvisi", "desc": "Per impostazione predefinita, gli avvisi recenti nella schermata dal vivo vengono riprodotti come brevi video in ciclo. Disattiva questa opzione per visualizzare solo un'immagine statica degli avvisi recenti su questo dispositivo/browser." }, - "title": "Schermata dal vivo" + "title": "Schermata dal vivo", + "displayCameraNames": { + "label": "Mostra sempre i nomi delle telecamere", + "desc": "Mostra sempre i nomi delle telecamere in una scheda nel cruscotto della visualizzazione dal vivo multi telecamera." + } }, "title": "Impostazioni generali", "storedLayouts": { @@ -745,7 +749,7 @@ "triggers": { "documentTitle": "Inneschi", "management": { - "title": "Gestione inneschi", + "title": "Inneschi", "desc": "Gestisci gli inneschi per {{camera}}. Utilizza il tipo miniatura per attivare miniature simili all'oggetto tracciato selezionato e il tipo descrizione per attivare descrizioni simili al testo specificato." }, "addTrigger": "Aggiungi innesco", @@ -766,7 +770,9 @@ }, "actions": { "alert": "Contrassegna come avviso", - "notification": "Invia notifica" + "notification": "Invia notifica", + "sub_label": "Aggiungi sottoetichetta", + "attribute": "Aggiungi attributo" }, "dialog": { "createTrigger": { @@ -784,25 +790,28 @@ "form": { "name": { "title": "Nome", - "placeholder": "Inserisci il nome dell'innesco", + "placeholder": "Assegna un nome a questo innesco", "error": { - "minLength": "Il nome deve essere lungo almeno 2 caratteri.", - "invalidCharacters": "Il nome può contenere solo lettere, numeri, caratteri di sottolineatura e trattini.", + "minLength": "Il campo deve contenere almeno 2 caratteri.", + "invalidCharacters": "Il campo può contenere solo lettere, numeri, caratteri di sottolineatura e trattini.", "alreadyExists": "Per questa telecamera esiste già un innesco con questo nome." - } + }, + "description": "Inserisci un nome o una descrizione univoca per identificare questo innesco" }, "enabled": { "description": "Abilita o disabilita questo innesco" }, "type": { "title": "Tipo", - "placeholder": "Seleziona il tipo di innesco" + "placeholder": "Seleziona il tipo di innesco", + "description": "Si attiva quando viene rilevata una descrizione di un oggetto simile tracciato", + "thumbnail": "Attiva quando viene rilevata una miniatura di un oggetto simile tracciato" }, "content": { "title": "Contenuto", - "imagePlaceholder": "Seleziona un'immagine", + "imagePlaceholder": "Seleziona una miniatura", "textPlaceholder": "Inserisci il contenuto del testo", - "imageDesc": "Seleziona un'immagine per attivare questa azione quando viene rilevata un'immagine simile.", + "imageDesc": "Vengono visualizzate solo le 100 miniature più recenti. Se non riesci a trovare la miniatura desiderata, controlla gli oggetti precedenti in Esplora e imposta un innesco dal menu.", "textDesc": "Inserisci il testo per attivare questa azione quando viene rilevata una descrizione simile dell'oggetto tracciato.", "error": { "required": "Il contenuto è obbligatorio." @@ -813,11 +822,12 @@ "error": { "min": "La soglia deve essere almeno 0", "max": "La soglia deve essere al massimo 1" - } + }, + "desc": "Imposta la soglia di similarità per questo innesco. Una soglia più alta indica che è necessaria una corrispondenza più vicina per attivare l'innesco." }, "actions": { "title": "Azioni", - "desc": "Per impostazione predefinita, Frigate invia un messaggio MQTT per tutti gli inneschi. Scegli un'azione aggiuntiva da eseguire quando questo innesco si attiva.", + "desc": "Per impostazione predefinita, Frigate invia un messaggio MQTT per tutti gli inneschi. Le sottoetichette aggiungono il nome dell'innesco all'etichetta dell'oggetto. Gli attributi sono metadati ricercabili, memorizzati separatamente nei metadati dell'oggetto tracciato.", "error": { "min": "È necessario selezionare almeno un'azione." } @@ -844,6 +854,23 @@ "semanticSearch": { "title": "La ricerca semantica è disabilitata", "desc": "Per utilizzare gli inneschi, è necessario abilitare la ricerca semantica." + }, + "wizard": { + "title": "Crea innesco", + "step1": { + "description": "Configura le impostazioni di base per il tuo innesco." + }, + "step2": { + "description": "Imposta il contenuto che attiverà questa azione." + }, + "step3": { + "description": "Configura la soglia e le azioni per questo innesco." + }, + "steps": { + "nameAndType": "Nome e tipo", + "configureData": "Configurare i dati", + "thresholdAndActions": "Soglia e azioni" + } } }, "roles": { @@ -865,7 +892,9 @@ "createRole": "Ruolo {{role}} creato con successo", "updateCameras": "Telecamere aggiornate per il ruolo {{role}}", "deleteRole": "Ruolo {{role}} eliminato con successo", - "userRolesUpdated": "{{count}} utenti assegnati a questo ruolo sono stati aggiornati a \"spettatore\", che ha accesso a tutte le telecamere." + "userRolesUpdated_one": "{{count}} utenti assegnati a questo ruolo sono stati aggiornati a \"spettatore\", che ha accesso a tutte le telecamere.", + "userRolesUpdated_many": "", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Impossibile creare il ruolo: {{errorMessage}}", @@ -984,7 +1013,9 @@ }, "resolutionHigh": "Una risoluzione di {{resolution}} potrebbe causare un aumento dell'utilizzo delle risorse.", "resolutionLow": "Una risoluzione di {{resolution}} potrebbe essere troppo bassa per un rilevamento affidabile di oggetti di piccole dimensioni." - } + }, + "ffmpegModule": "Utilizza la modalità di compatibilità della trasmissione", + "ffmpegModuleDescription": "Se il flusso non si carica dopo diversi tentativi, prova ad abilitare questa opzione. Se abilitata, Frigate utilizzerà il modulo ffmpeg con go2rtc. Questo potrebbe garantire una migliore compatibilità con alcuni flussi di telecamere." }, "title": "Aggiungi telecamera", "description": "Per aggiungere una nuova telecamera alla tua installazione Frigate, segui i passaggi indicati di seguito.", diff --git a/web/public/locales/ja/views/settings.json b/web/public/locales/ja/views/settings.json index 9b38c854d..000aac898 100644 --- a/web/public/locales/ja/views/settings.json +++ b/web/public/locales/ja/views/settings.json @@ -582,7 +582,7 @@ "createRole": "ロール {{role}} を作成しました", "updateCameras": "ロール {{role}} のカメラを更新しました", "deleteRole": "ロール {{role}} を削除しました", - "userRolesUpdated": "このロールに割り当てられていた {{count}} ユーザーは「viewer」に更新され、すべてのカメラへの閲覧アクセスが付与されました。" + "userRolesUpdated_other": "このロールに割り当てられていた {{count}} ユーザーは「viewer」に更新され、すべてのカメラへの閲覧アクセスが付与されました。" }, "error": { "createRoleFailed": "ロールの作成に失敗しました: {{errorMessage}}", diff --git a/web/public/locales/lt/views/settings.json b/web/public/locales/lt/views/settings.json index 199f818ea..4fcd9cb8f 100644 --- a/web/public/locales/lt/views/settings.json +++ b/web/public/locales/lt/views/settings.json @@ -782,7 +782,9 @@ "toast": { "success": { "deleteRole": "Rolė {{role}} sėkmingai pašalinta", - "userRolesUpdated": "{{count}} šios rolės vartotojai buvo priskirti rolei 'žiūrovas', kuri turi prieigą prie visų kamerų.", + "userRolesUpdated_one": "{{count}} šios rolės vartotojai buvo priskirti rolei 'žiūrovas', kuri turi prieigą prie visų kamerų.", + "userRolesUpdated_few": "", + "userRolesUpdated_other": "", "createRole": "Rolė {{role}} sėkmingai sukurta", "updateCameras": "Atnaujintos kameros rolei {{role}}" }, diff --git a/web/public/locales/nb-NO/common.json b/web/public/locales/nb-NO/common.json index cfb36753a..52058ab6e 100644 --- a/web/public/locales/nb-NO/common.json +++ b/web/public/locales/nb-NO/common.json @@ -294,6 +294,7 @@ }, "list": { "two": "{{0}} og {{1}}", - "many": "{{items}}, og {{last}}" + "many": "{{items}}, og {{last}}", + "separatorWithSpace": ", " } } diff --git a/web/public/locales/nb-NO/components/dialog.json b/web/public/locales/nb-NO/components/dialog.json index d144c5f5c..bebf2368c 100644 --- a/web/public/locales/nb-NO/components/dialog.json +++ b/web/public/locales/nb-NO/components/dialog.json @@ -29,7 +29,7 @@ "false_other": "Dette er ikke en {{label}}" }, "question": { - "label": "Bekreft denne merkelappen for Frigate Plus", + "label": "Bekreft denne etiketten for Frigate Plus", "ask_an": "Er dette objekt en {{label}}?", "ask_a": "Er dette objektet en {{label}}?", "ask_full": "Er dette objekt en {{untranslatedLabel}} ({{translatedLabel}})?" @@ -56,7 +56,7 @@ } }, "toast": { - "success": "Eksport startet. Se filen på eksport­siden.", + "success": "Eksport startet. Se filen på eksportsiden.", "error": { "failed": "Klarte ikke å starte eksport: {{error}}", "noVaildTimeSelected": "Ingen gyldig tidsperiode valgt", @@ -124,7 +124,7 @@ "imagePicker": { "selectImage": "Velg et sporet objekts miniatyrbilde", "search": { - "placeholder": "Søk etter (under-)merkelapp..." + "placeholder": "Søk etter (under-)etikett..." }, "noImages": "Ingen miniatyrbilder funnet for dette kameraet", "unknownLabel": "Lagret utløserbilde" diff --git a/web/public/locales/nb-NO/components/filter.json b/web/public/locales/nb-NO/components/filter.json index b7b81da9b..241102e08 100644 --- a/web/public/locales/nb-NO/components/filter.json +++ b/web/public/locales/nb-NO/components/filter.json @@ -1,14 +1,14 @@ { "filter": "Filter", "labels": { - "label": "Merkelapper", + "label": "Etiketter", "all": { "title": "Alle masker / soner", - "short": "Merkelapper" + "short": "Etiketter" }, "count": "{{count}} merkelapper", - "count_other": "{{count}} Merkelapper", - "count_one": "{{count}} Merkelapp" + "count_other": "{{count}} Etiketter", + "count_one": "{{count}} Etikett" }, "features": { "hasVideoClip": "Har et videoklipp", @@ -39,7 +39,7 @@ "title": "Innstillinger", "defaultView": { "title": "Standard visning", - "desc": "Når ingen filtre er valgt, vis et sammendrag av de nyeste sporede objektene per merkelapp, eller vis et ufiltrert rutenett.", + "desc": "Når ingen filtre er valgt, vis et sammendrag av de nyeste sporede objektene per etikett, eller vis et ufiltrert rutenett.", "summary": "Sammendrag", "unfilteredGrid": "Ufiltrert rutenett" }, @@ -101,8 +101,8 @@ }, "timeRange": "Tidsrom", "subLabels": { - "label": "Under-Merkelapper", - "all": "Alle under-Merkelapper" + "label": "Underetiketter", + "all": "Alle underetiketter" }, "score": "Poengsum", "estimatedSpeed": "Estimert hastighet ({{unit}})", diff --git a/web/public/locales/nb_NO/views/classificationModel.json b/web/public/locales/nb-NO/views/classificationModel.json similarity index 84% rename from web/public/locales/nb_NO/views/classificationModel.json rename to web/public/locales/nb-NO/views/classificationModel.json index 73026a6e4..0dc06ea32 100644 --- a/web/public/locales/nb_NO/views/classificationModel.json +++ b/web/public/locales/nb-NO/views/classificationModel.json @@ -5,7 +5,9 @@ "renameCategory": "Gi nytt navn til kategori", "deleteCategory": "Slett kategori", "deleteImages": "Slett bilder", - "trainModel": "Tren modell" + "trainModel": "Tren modell", + "addClassification": "Legg til klassifisering", + "deleteModels": "Slett modeller" }, "toast": { "success": { @@ -13,13 +15,16 @@ "deletedImage": "Bilder slettet", "categorizedImage": "Bildet ble klassifisert", "trainedModel": "Modellen ble trent.", - "trainingModel": "Modelltrening startet." + "trainingModel": "Modelltrening startet.", + "deletedModel_one": "{{count}} modell(er) ble slettet", + "deletedModel_other": "" }, "error": { "deleteImageFailed": "Kunne ikke slette: {{errorMessage}}", "deleteCategoryFailed": "Kunne ikke slette kategori: {{errorMessage}}", "categorizeFailed": "Kunne ikke klassifisere bilde: {{errorMessage}}", - "trainingFailed": "Kunne ikke starte modelltrening: {{errorMessage}}" + "trainingFailed": "Kunne ikke starte modelltrening: {{errorMessage}}", + "deleteModelFailed": "Kunne ikke slette modell: {{errorMessage}}" } }, "deleteCategory": { @@ -43,7 +48,8 @@ }, "train": { "title": "Nylige klassifiseringer", - "aria": "Velg nylige klassifiseringer" + "aria": "Velg nylige klassifiseringer", + "titleShort": "Nylig" }, "categories": "Kategorier", "createCategory": { @@ -98,7 +104,8 @@ "stateRequiresTwoClasses": "Tilstandsmodeller krever minst to kategorier", "objectLabelRequired": "Velg en objektetikett", "objectTypeRequired": "Velg en klassifiseringstype" - } + }, + "states": "Tilstander" }, "step2": { "description": "Velg kameraer og definer området som skal overvåkes for hvert kamera. Modellen vil klassifisere tilstanden til disse områdene.", @@ -131,5 +138,17 @@ }, "generateSuccess": "Eksempelbilder ble generert" } + }, + "deleteModel": { + "title": "Slett klassifiseringsmodell", + "single": "Er du sikker på at du vil slette {{name}}? Dette vil permanent slette alle tilknyttede data, inkludert bilder og treningsdata. Denne handlingen kan ikke angres.", + "desc": "Er du sikker på at du vil slette {{count}} modell(er)? Dette vil permanent slette alle tilknyttede data, inkludert bilder og treningsdata. Denne handlingen kan ikke angres." + }, + "menu": { + "objects": "Objekter", + "states": "Tilstander" + }, + "details": { + "scoreInfo": "Poengsummen representerer gjennomsnittlig klassifiseringskonfidens på tvers av alle deteksjoner av dette objektet." } } diff --git a/web/public/locales/nb-NO/views/events.json b/web/public/locales/nb-NO/views/events.json index e97431b06..f28a06a0c 100644 --- a/web/public/locales/nb-NO/views/events.json +++ b/web/public/locales/nb-NO/views/events.json @@ -43,10 +43,17 @@ "trackedObject_one": "objekt", "trackedObject_other": "objekter", "noObjectDetailData": "Ingen detaljdata for objektet tilgjengelig.", - "label": "Detalj" + "label": "Detalj", + "settings": "Detaljvisning – innstillinger", + "alwaysExpandActive": { + "desc": "Utvid alltid objektdetaljene for det aktive gjennomgangselementet når tilgjengelig.", + "title": "Utvid alltid for aktive" + } }, "objectTrack": { "trackedPoint": "Sporingspunkt", "clickToSeek": "Klikk for å gå til dette tidspunktet" - } + }, + "zoomIn": "Zoom inn", + "zoomOut": "Zoom ut" } diff --git a/web/public/locales/nb-NO/views/explore.json b/web/public/locales/nb-NO/views/explore.json index 2a37c5478..bfa70cde3 100644 --- a/web/public/locales/nb-NO/views/explore.json +++ b/web/public/locales/nb-NO/views/explore.json @@ -87,7 +87,7 @@ }, "toast": { "success": { - "updatedSublabel": "Under-merkelapp oppdatert med suksess.", + "updatedSublabel": "Underetikett ble oppdatert.", "updatedLPR": "Vellykket oppdatering av kjennemerke.", "regenerate": "En ny beskrivelse har blitt anmodet fra {{provider}}. Avhengig av hastigheten til leverandøren din, kan den nye beskrivelsen ta litt tid å regenerere.", "audioTranscription": "Lydtranskripsjon ble forespurt." @@ -95,7 +95,7 @@ "error": { "regenerate": "Feil ved anrop til {{provider}} for en ny beskrivelse: {{errorMessage}}", "updatedLPRFailed": "Oppdatering av kjennemerke feilet: {{errorMessage}}", - "updatedSublabelFailed": "Feil ved oppdatering av under-merkelapp: {{errorMessage}}", + "updatedSublabelFailed": "Feil ved oppdatering av underetikett: {{errorMessage}}", "audioTranscription": "Forespørsel om lydtranskripsjon feilet: {{errorMessage}}" } }, @@ -103,7 +103,7 @@ "tips": { "mismatch_one": "{{count}} utilgjengelig objekt ble oppdaget og inkludert i dette inspeksjonselementet. Disse objektene kvalifiserte ikke som et varsel eller deteksjon, eller har allerede blitt ryddet opp/slettet.", "mismatch_other": "{{count}} utilgjengelige objekter ble oppdaget og inkludert i dette inspeksjonselementet. Disse objektene kvalifiserte ikke som et varsel eller deteksjon, eller har allerede blitt ryddet opp/slettet.", - "hasMissingObjects": "Juster konfigurasjonen hvis du vil at Frigate skal lagre sporede objekter for følgende merkelapper: {{objects}}" + "hasMissingObjects": "Juster konfigurasjonen hvis du vil at Frigate skal lagre sporede objekter for følgende etiketter: {{objects}}" } }, "topScore": { @@ -126,10 +126,10 @@ }, "regenerateFromThumbnails": "Regenerer fra miniatyrbilder", "tips": { - "descriptionSaved": "Beskrivelse lagret med suksess", + "descriptionSaved": "Beskrivelsen ble lagret", "saveDescriptionFailed": "Feil ved lagring av beskrivelse: {{errorMessage}}" }, - "label": "Merkelapp", + "label": "Etikett", "editLPR": { "title": "Rediger kjennemerke", "descNoLabel": "Skriv inn et nytt kjennemerke for dette sporede objekt", @@ -142,9 +142,9 @@ "expandRegenerationMenu": "Utvid regenereringsmenyen", "regenerateFromSnapshot": "Regenerer fra øyeblikksbilde", "editSubLabel": { - "title": "Rediger under-merkelapp", - "desc": "Angi en ny under-merkelapp for denne {{label}}", - "descNoLabel": "Angi en ny under-merkelapp for dette sporede objektet" + "title": "Rediger underetikett", + "desc": "Angi en ny underetikett for \"{{label}}\"", + "descNoLabel": "Angi en ny underetikett for dette sporede objektet" }, "snapshotScore": { "label": "Øyeblikksbilde poengsum" @@ -204,7 +204,7 @@ "deleteTrackedObject": { "toast": { "error": "Feil ved sletting av sporet objekt: {{errorMessage}}", - "success": "Sporet objekt ble slettet med suksess." + "success": "Sporet objekt ble slettet." } }, "tooltip": "Samsvarer {{type}} til {{confidence}}%" @@ -214,7 +214,8 @@ "details": "detaljer", "snapshot": "øyeblikksbilde", "video": "video", - "object_lifecycle": "objektets livssyklus" + "object_lifecycle": "objektets livssyklus", + "thumbnail": "miniatyrbilde" }, "dialog": { "confirmDelete": { @@ -238,7 +239,7 @@ "noImageFound": "Ingen bilder funnet for dette tidsstempelet.", "createObjectMask": "Opprett objektmaske", "adjustAnnotationSettings": "Juster annoteringsinnstillinger", - "scrollViewTips": "Rull for å se de viktige øyeblikkene i dette objektets livssyklus.", + "scrollViewTips": "Klikk for å se de viktige øyeblikkene i dette objektets livssyklus.", "autoTrackingTips": "Posisjonene til avgrensningsboksene vil være unøyaktige for kameraer med automatisk sporing.", "count": "{{first}} av {{second}}", "trackedPoint": "Sporet punkt", @@ -268,11 +269,11 @@ }, "offset": { "label": "Annoteringsforskyvning", - "desc": "Disse dataene kommer fra kameraets deteksjonsstrøm, men legges over bilder fra opptaksstrømmen. Det er usannsynlig at de to strømmene er perfekt synkronisert. Som et resultat vil avgrensningsboksen og opptaket ikke stemme perfekt overens. Feltet annotation_offset kan imidlertid brukes til å justere dette.", + "desc": "Disse dataene kommer fra kameraets deteksjonsstrøm, men legges over bilder fra opptaksstrømmen. Det er lite sannsynlig at de to strømmene er perfekt synkronisert. Som et resultat vil avgrensningsboksen og opptaket ikke stemme perfekt overens. Du kan bruke denne innstillingen til å forskyve annoteringene fremover eller bakover i tid for å tilpasse dem bedre til det innspilte opptaket.", "millisecondsToOffset": "Antall millisekunder deteksjonsannoteringene skal forskyves med. Standard: 0", "tips": "TIPS: Se for deg et hendelsesklipp med en person som går fra venstre mot høyre. Hvis avgrensningsboksen på tidslinjen for hendelsen konsekvent er til venstre for personen, bør verdien reduseres. På samme måte, hvis en person går fra venstre mot høyre og avgrensningsboksen konsekvent er foran personen, bør verdien økes.", "toast": { - "success": "Annoteringsforskyvning for {{camera}} er lagret i konfigurasjonsfilen. Start Frigate på nytt for å ta i bruk endringene." + "success": "Annoteringsforskyvning for {{camera}} er lagret i konfigurasjonsfilen. Start Frigate på nytt for å aktivere endringene." } } }, diff --git a/web/public/locales/nb-NO/views/live.json b/web/public/locales/nb-NO/views/live.json index 0e390d771..78270c0ce 100644 --- a/web/public/locales/nb-NO/views/live.json +++ b/web/public/locales/nb-NO/views/live.json @@ -71,15 +71,15 @@ "label": "Vis statistikk", "desc": "Aktiver dette alternativet for å vise strømmestatistikk som et overlegg på kamerastrømmen." }, - "started": "Startet manuelt opptak på forespørsel.", - "end": "Avslutt opptak på forespørsel", - "title": "På forespørsel", + "started": "Startet manuelt opptak.", + "end": "Avslutt manuelt opptak", + "title": "Manuelt opptak", "debugView": "Feilsøkingsvisning", - "start": "Start opptak på forespørsel", - "failedToStart": "Kunne ikke starte manuelt opptak på forespørsel.", + "start": "Start manuelt opptak", + "failedToStart": "Kunne ikke starte manuelt opptak.", "recordDisabledTips": "Siden opptak er deaktivert eller begrenset i konfigurasjonen for dette kameraet, vil kun et øyeblikksbilde bli lagret.", - "ended": "Avsluttet manuelt opptak på forespørsel.", - "failedToEnd": "Kunne ikke avslutte manuelt opptak på forespørsel." + "ended": "Avsluttet manuelt opptak.", + "failedToEnd": "Kunne ikke avslutte manuelt opptak." }, "audio": "Lyd", "suspend": { diff --git a/web/public/locales/nb-NO/views/search.json b/web/public/locales/nb-NO/views/search.json index baf25a900..4d81b38b0 100644 --- a/web/public/locales/nb-NO/views/search.json +++ b/web/public/locales/nb-NO/views/search.json @@ -12,14 +12,14 @@ "filter": { "label": { "cameras": "Kameraer", - "labels": "Merkelapper", + "labels": "Etiketter", "search_type": "Søketype", "after": "Etter", "min_score": "Min. poengsum", "max_score": "Maks. poengsum", "min_speed": "Min. hastighet", "zones": "Soner", - "sub_labels": "Under-merkelapper", + "sub_labels": "Underetiketter", "time_range": "Tidsintervall", "before": "Før", "max_speed": "Maks. hastighet", diff --git a/web/public/locales/nb-NO/views/settings.json b/web/public/locales/nb-NO/views/settings.json index 7b1aaf88c..e37e546f1 100644 --- a/web/public/locales/nb-NO/views/settings.json +++ b/web/public/locales/nb-NO/views/settings.json @@ -50,6 +50,10 @@ "automaticLiveView": { "label": "Automatisk direktevisning", "desc": "Bytt automatisk til et kameras direktevisning når aktivitet oppdages. Deaktivering av dette valget gjør at statiske kamerabilder i Direkte-dashbord kun oppdateres én gang i minuttet." + }, + "displayCameraNames": { + "label": "Vis alltid kameranavn", + "desc": "Vis alltid kameranavnene i en merkelapp i dashbordet for direktevisning med flere kameraer." } }, "storedLayouts": { @@ -337,7 +341,7 @@ } }, "toast": { - "success": "Sone ({{zoneName}}) er lagret. Start Frigate på nytt for å bruke endringer." + "success": "Sone ({{zoneName}}) er lagret. Start Frigate på nytt for å aktivere endringer." } }, "motionMasks": { @@ -681,12 +685,12 @@ "enrichments": { "title": "Innstillinger for utvidelser", "licensePlateRecognition": { - "desc": "Frigate kan gjenkjenne kjennemerker på kjøretøy og automatisk legge til de oppdagede tegnene i feltet \"recognized_license_plate\", eller et kjent navn som en under-merkelapp på objekter av typen bil. Et vanlig brukstilfelle kan være å lese kjennemerker på biler som kjører inn i en innkjørsel eller biler som passerer på en gate.", + "desc": "Frigate kan gjenkjenne kjennemerker på kjøretøy og automatisk legge til de oppdagede tegnene i feltet \"recognized_license_plate\", eller et kjent navn som en underetikett på objekter av typen bil. Et vanlig brukstilfelle kan være å lese kjennemerker på biler som kjører inn i en innkjørsel eller biler som passerer på en gate.", "title": "Kjennemerke gjenkjenning", "readTheDocumentation": "Se dokumentasjonen" }, "birdClassification": { - "desc": "Fugleklassifisering identifiserer kjente fugler ved hjelp av en kvantisert TensorFlow-modell. Når en fugl gjenkjennes, vil det vanlige navnet legges til som en under-merkelapp. Denne informasjonen vises i brukergrensesnittet, filtre, samt i meldingsvarsler.", + "desc": "Fugleklassifisering identifiserer kjente fugler ved hjelp av en kvantisert TensorFlow-modell. Når en fugl gjenkjennes, vil det vanlige navnet legges til som en underetikett. Denne informasjonen vises i brukergrensesnittet, filtre, samt i meldingsvarsler.", "title": "Klassifisering av fugler" }, "semanticSearch": { @@ -730,7 +734,7 @@ } }, "title": "Ansiktsgjenkjenning", - "desc": "Ansiktsgjenkjenning gjør det mulig å tildele navn til personer, og når ansiktet deres gjenkjennes, vil Frigate tildele personens navn som en under-merkelapp. Denne informasjonen vises i brukergrensesnittet, filtre, samt i meldingsvarsler.", + "desc": "Ansiktsgjenkjenning gjør det mulig å tildele navn til personer, og når ansiktet deres gjenkjennes, vil Frigate tildele personens navn som en underetikett. Denne informasjonen vises i brukergrensesnittet, filtre, samt i meldingsvarsler.", "readTheDocumentation": "Se dokumentasjonen" }, "unsavedChanges": "Ulagrede endringer i innstillinger for utvidelser", @@ -764,7 +768,9 @@ }, "actions": { "alert": "Marker som varsel", - "notification": "Send meldingsvarsel" + "notification": "Send meldingsvarsel", + "sub_label": "Legg til underetikett", + "attribute": "Legg til attributt" }, "dialog": { "createTrigger": { @@ -819,7 +825,7 @@ }, "actions": { "title": "Handlinger", - "desc": "Som standard sender Frigate en MQTT-melding for alle utløsere. Velg en ekstra handling som skal utføres når denne utløseren aktiveres.", + "desc": "Som standard sender Frigate en MQTT-melding for alle utløsere. Underetiketter legger til navnet på utløseren i objektetiketten. Attributter er søkbare metadata som lagres separat i objektets sporingsmetadata.", "error": { "min": "Minst én handling må velges." } @@ -884,7 +890,8 @@ "createRole": "Rollen {{role}} ble opprettet", "updateCameras": "Kameraer oppdatert for rollen {{role}}", "deleteRole": "Rollen {{role}} ble slettet", - "userRolesUpdated": "{{count}} bruker(e) som var tildelt denne rollen er oppdatert til \"visningsbruker\", som har tilgang til alle kameraer." + "userRolesUpdated_one": "{{count}} bruker(e) som var tildelt denne rollen er oppdatert til \"visningsbruker\", som har tilgang til alle kameraer.", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Kunne ikke opprette rolle: {{errorMessage}}", @@ -1069,7 +1076,9 @@ }, "resolutionHigh": "En oppløsning på {{resolution}} kan føre til økt ressursbruk.", "resolutionLow": "En oppløsning på {{resolution}} kan være for lav for pålitelig deteksjon av små objekter." - } + }, + "ffmpegModuleDescription": "Hvis strømmen ikke lastes inn etter flere forsøk, kan du prøve å aktivere dette. Når det er aktivert, vil Frigate bruke ffmpeg-modulen sammen med go2rtc. Dette kan gi bedre kompatibilitet med enkelte kamerastrømmer.", + "ffmpegModule": "Bruk kompatibilitetsmodus for strøm" } }, "cameraManagement": { @@ -1145,7 +1154,7 @@ "selectDetectionsZones": "Velg soner for deteksjoner", "limitDetections": "Avgrens deteksjoner til bestemte soner", "toast": { - "success": "Konfigurasjonen for inspeksjonsklassifisering er lagret. Start Frigate på nytt for å bruke endringer." + "success": "Konfigurasjonen for inspeksjonsklassifisering er lagret. Start Frigate på nytt for å aktivere endringer." } } } diff --git a/web/public/locales/nl/common.json b/web/public/locales/nl/common.json index 7e5f507ff..5ff9ca549 100644 --- a/web/public/locales/nl/common.json +++ b/web/public/locales/nl/common.json @@ -290,7 +290,8 @@ }, "list": { "two": "{{0}} en {{1}}", - "many": "{{items}}, en {{last}}" + "many": "{{items}}, en {{last}}", + "separatorWithSpace": ", " }, "field": { "optional": "Optioneel", diff --git a/web/public/locales/nl/views/classificationModel.json b/web/public/locales/nl/views/classificationModel.json index eeac5b0f3..79956bf3d 100644 --- a/web/public/locales/nl/views/classificationModel.json +++ b/web/public/locales/nl/views/classificationModel.json @@ -5,7 +5,10 @@ "renameCategory": "Klasse hernoemen", "deleteCategory": "Klasse verwijderen", "deleteImages": "Afbeeldingen verwijderen", - "trainModel": "Model trainen" + "trainModel": "Model trainen", + "addClassification": "Classificatie toevoegen", + "deleteModels": "Modellen verwijderen", + "editModel": "Model bewerken" }, "toast": { "success": { @@ -13,13 +16,18 @@ "deletedImage": "Verwijderde afbeeldingen", "categorizedImage": "Succesvol geclassificeerde afbeelding", "trainedModel": "Succesvol getraind model.", - "trainingModel": "Modeltraining succesvol gestart." + "trainingModel": "Modeltraining succesvol gestart.", + "deletedModel_one": "{{count}} model succesvol verwijderd", + "deletedModel_other": "{{count}} modellen succesvol verwijderd", + "updatedModel": "Modelconfiguratie succesvol bijgewerkt" }, "error": { "deleteImageFailed": "Verwijderen mislukt: {{errorMessage}}", "deleteCategoryFailed": "Het verwijderen van de klasse is mislukt: {{errorMessage}}", "categorizeFailed": "Afbeelding categoriseren mislukt: {{errorMessage}}", - "trainingFailed": "Het starten van de modeltraining is mislukt: {{errorMessage}}" + "trainingFailed": "Het starten van de modeltraining is mislukt: {{errorMessage}}", + "deleteModelFailed": "Model verwijderen mislukt: {{errorMessage}}", + "updateModelFailed": "Bijwerken van model mislukt: {{errorMessage}}" } }, "deleteCategory": { @@ -43,7 +51,8 @@ }, "train": { "title": "Recente classificaties", - "aria": "Selecteer recente classificaties" + "aria": "Selecteer recente classificaties", + "titleShort": "Recent" }, "categories": "Klassen", "createCategory": { @@ -98,7 +107,8 @@ "stateRequiresTwoClasses": "Toestandsmodellen vereisen minimaal 2 klassen", "objectLabelRequired": "Selecteer een objectlabel", "objectTypeRequired": "Selecteer een classificatietype" - } + }, + "states": "Staten" }, "step2": { "description": "Selecteer camera’s en definieer voor elke camera het te monitoren gebied. Het model zal de toestand van deze gebieden classificeren.", @@ -131,5 +141,23 @@ }, "generateSuccess": "Met succes gegenereerde voorbeeldafbeeldingen" } + }, + "deleteModel": { + "title": "Classificatiemodel verwijderen", + "single": "Weet u zeker dat u {{name}} wilt verwijderen? Hiermee worden alle bijbehorende gegevens, inclusief afbeeldingen en trainingsgegevens, definitief verwijderd. Deze actie kan niet ongedaan worden gemaakt.", + "desc": "Weet u zeker dat u {{count}} model(len) wilt verwijderen? Hiermee worden alle bijbehorende gegevens, inclusief afbeeldingen en trainingsgegevens, permanent verwijderd. Deze actie kan niet ongedaan worden gemaakt." + }, + "menu": { + "objects": "Objecten", + "states": "Staten" + }, + "details": { + "scoreInfo": "Score geeft het gemiddelde classificatievertrouwen weer over alle detecties van dit object." + }, + "edit": { + "title": "Classificatiemodel bewerken", + "descriptionState": "Bewerk de klassen voor dit statusclassificatiemodel. Wijzigingen vereisen dat het model opnieuw wordt getraind.", + "descriptionObject": "Bewerk het objecttype en het classificatietype voor dit objectclassificatiemodel.", + "stateClassesInfo": "Let op: het wijzigen van statusklassen vereist dat het model opnieuw wordt getraind met de bijgewerkte klassen." } } diff --git a/web/public/locales/nl/views/events.json b/web/public/locales/nl/views/events.json index 2f39f5815..643fef8b0 100644 --- a/web/public/locales/nl/views/events.json +++ b/web/public/locales/nl/views/events.json @@ -43,10 +43,17 @@ "trackedObject_one": "object", "trackedObject_other": "objecten", "noObjectDetailData": "Geen objectdetails beschikbaar.", - "label": "Detail" + "label": "Detail", + "settings": "Instellingen voor detailweergave", + "alwaysExpandActive": { + "desc": "Altijd de objectdetails van het actieve beoordelingsitem uitklappen wanneer deze beschikbaar zijn.", + "title": "Het huidige item altijd uitvouwen" + } }, "objectTrack": { "trackedPoint": "Gevolgd punt", "clickToSeek": "Klik om naar deze tijd te zoeken" - } + }, + "zoomIn": "Zoom in", + "zoomOut": "Zoom uit" } diff --git a/web/public/locales/nl/views/explore.json b/web/public/locales/nl/views/explore.json index 96f495b98..10fa78697 100644 --- a/web/public/locales/nl/views/explore.json +++ b/web/public/locales/nl/views/explore.json @@ -33,7 +33,8 @@ "details": "Details", "video": "video", "snapshot": "snapshot", - "object_lifecycle": "objectlevenscyclus" + "object_lifecycle": "objectlevenscyclus", + "thumbnail": "thumbnail" }, "objectLifecycle": { "createObjectMask": "Objectmasker maken", @@ -238,7 +239,7 @@ "noImageFound": "Er is geen afbeelding beschikbaar voor dit tijdstip.", "createObjectMask": "Objectmasker maken", "adjustAnnotationSettings": "Annotatie-instellingen aanpassen", - "scrollViewTips": "Scroll om de belangrijke momenten uit de levenscyclus van dit object te bekijken.", + "scrollViewTips": "Klik om de belangrijke momenten uit de levenscyclus van dit object te bekijken.", "autoTrackingTips": "Als u een automatische objectvolgende camera gebruikt, zal het objectkader onnauwkeurig zijn.", "count": "{{first}} van {{second}}", "trackedPoint": "Volgpunt", @@ -251,7 +252,7 @@ "faceOrLicense_plate": "{{attribute}} Gedetecteerd voor {{label}}", "other": "{{label}} Herkend als {{attribute}}" }, - "gone": "{{label}} Links", + "gone": "{{label}} vertrok", "heard": "{{label}} gehoord", "external": "{{label}} gedetecteerd", "header": { @@ -268,7 +269,7 @@ }, "offset": { "label": "Annotatie-afwijking", - "desc": "Deze gegevens zijn afkomstig van de detectiestream van je camera, maar worden weergegeven op beelden uit de opnamestream. Het is onwaarschijnlijk dat deze twee streams perfect gesynchroniseerd zijn. Hierdoor zullen het objectkader en het beeld niet exact op elkaar aansluiten. Het veld annotation_offset kan echter worden gebruikt om deze annotatie-afwijking te corrigeren.", + "desc": "Deze gegevens zijn afkomstig van de detectiestream van je camera, maar worden weergegeven op beelden uit de opnamestream. Het is onwaarschijnlijk dat deze twee streams perfect gesynchroniseerd zijn. Hierdoor zullen het objectkader en het beeld niet exact op elkaar aansluiten. Met deze instelling kun je de annotaties vooruit of achteruit in de tijd verschuiven om ze beter uit te lijnen met het opgenomen beeldmateriaal.", "millisecondsToOffset": "Aantal milliseconden om objectkader mee te verschuiven. Standaard: 0", "tips": "TIP: Stel je voor dat er een clip is waarin een persoon van links naar rechts loopt. Als het objectkader in de tijdlijn van de activiteit steeds links van de persoon ligt, dan moet de waarde verlaagd worden. Op dezelfde manier als het objectkader consequent vóór de persoon ligt dus vooruitloopt, moet de waarde verhoogd worden.", "toast": { diff --git a/web/public/locales/nl/views/live.json b/web/public/locales/nl/views/live.json index 66f14f678..798d24368 100644 --- a/web/public/locales/nl/views/live.json +++ b/web/public/locales/nl/views/live.json @@ -128,7 +128,7 @@ "documentation": "Lees de documentatie ", "title": "Audio moet via je camera komen en in go2rtc geconfigureerd zijn voor deze stream." }, - "unavailable": "Audio is niet beschikbaar voor deze stroom", + "unavailable": "Audio is niet beschikbaar voor deze stream", "available": "Audio is beschikbaar voor deze stream" }, "playInBackground": { diff --git a/web/public/locales/nl/views/settings.json b/web/public/locales/nl/views/settings.json index de3b211f1..d62df1215 100644 --- a/web/public/locales/nl/views/settings.json +++ b/web/public/locales/nl/views/settings.json @@ -50,6 +50,10 @@ "playAlertVideos": { "label": "Meldingen afspelen", "desc": "Standaard worden recente meldingen op het Live dashboard afgespeeld als kleine lusvideo's. Schakel deze optie uit om alleen een statische afbeelding van recente meldingen weer te geven op dit apparaat/browser." + }, + "displayCameraNames": { + "label": "Altijd cameranamen weergeven", + "desc": "Toon altijd de cameranamen in een label op het live-cameradashboard." } }, "title": "Algemene instellingen", @@ -764,7 +768,9 @@ }, "actions": { "alert": "Markeren als waarschuwing", - "notification": "Melding verzenden" + "notification": "Melding verzenden", + "sub_label": "Sublabel toevoegen", + "attribute": "Attribuut toevoegen" }, "dialog": { "createTrigger": { @@ -819,7 +825,7 @@ }, "actions": { "title": "Acties", - "desc": "Standaard verstuurt Frigate een MQTT-bericht voor alle triggers. Kies een extra actie die moet worden uitgevoerd wanneer deze trigger wordt geactiveerd.", + "desc": "Standaard stuurt Frigate een MQTT-bericht voor alle triggers. Sublabels voegen de triggernaam toe aan het objectlabel. Attributen zijn doorzoekbare metadata die afzonderlijk worden opgeslagen in de metadata van het gevolgde object.", "error": { "min": "Er moet ten minste één actie worden geselecteerd." } @@ -884,7 +890,8 @@ "createRole": "Rol {{role}} succesvol aangemaakt", "updateCameras": "Camera's bijgewerkt voor rol {{role}}", "deleteRole": "Rol {{role}} succesvol verwijderd", - "userRolesUpdated": "{{count}} gebruiker(s) die aan deze rol waren toegewezen, zijn bijgewerkt naar ‘kijker’, die toegang heeft tot alle camera’s." + "userRolesUpdated_one": "{{count}} gebruiker(s) die aan deze rol waren toegewezen, zijn bijgewerkt naar ‘kijker’, die toegang heeft tot alle camera’s.", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Kan rol niet aanmaken: {{errorMessage}}", @@ -1069,7 +1076,9 @@ }, "resolutionHigh": "Een resolutie van {{resolution}} kan leiden tot een verhoogd gebruik van systeembronnen.", "resolutionLow": "Een resolutie van {{resolution}} kan te laag zijn voor betrouwbare detectie van kleine objecten." - } + }, + "ffmpegModule": "Gebruik stream-compatibiliteitsmodus", + "ffmpegModuleDescription": "Als de stream na meerdere pogingen niet wordt geladen, probeer dit dan in te schakelen. Wanneer deze optie is ingeschakeld, gebruikt Frigate de ffmpeg-module samen met go2rtc. Dit kan zorgen voor een betere compatibiliteit met sommige camerastreams." } }, "cameraManagement": { diff --git a/web/public/locales/pl/views/settings.json b/web/public/locales/pl/views/settings.json index 406bfb04a..0291f39c5 100644 --- a/web/public/locales/pl/views/settings.json +++ b/web/public/locales/pl/views/settings.json @@ -757,7 +757,9 @@ "createRole": "Utworzono rolę {{role}}", "updateCameras": "Zaktualizowano kamery dla roli {{role}}", "deleteRole": "Rola {{role}} została usunięta", - "userRolesUpdated": "{{count}} użytkowników przypisanych do tej roli zostało zaktualizowanych do roli 'viewer', która ma dostęp do wszystkich kamer." + "userRolesUpdated_one": "{{count}} użytkowników przypisanych do tej roli zostało zaktualizowanych do roli 'viewer', która ma dostęp do wszystkich kamer.", + "userRolesUpdated_few": "", + "userRolesUpdated_many": "" }, "error": { "createRoleFailed": "Nie udało się utworzyć roli: {{errorMessage}}", diff --git a/web/public/locales/pt-BR/views/classificationModel.json b/web/public/locales/pt-BR/views/classificationModel.json new file mode 100644 index 000000000..5cfed4b10 --- /dev/null +++ b/web/public/locales/pt-BR/views/classificationModel.json @@ -0,0 +1,39 @@ +{ + "documentTitle": "Modelos de Classificação", + "button": { + "deleteClassificationAttempts": "Apagar Imagens de Classificação", + "renameCategory": "Renomear Classe", + "deleteCategory": "Apagar Classe", + "deleteImages": "Apagar Imagens", + "trainModel": "Treinar Modelo", + "addClassification": "Adicionar classificação", + "deleteModels": "Excluir modelos" + }, + "toast": { + "success": { + "deletedCategory": "Classe Apagada", + "deletedImage": "Imagens Apagadas", + "categorizedImage": "Imagem Classificada com Sucesso", + "trainedModel": "Modelo treinado com sucesso.", + "trainingModel": "Treinamento do modelo iniciado com sucesso.", + "deletedModel_one": "Modelo(s) {{count}} excluído(s) com sucesso", + "deletedModel_many": "", + "deletedModel_other": "" + }, + "error": { + "deleteImageFailed": "Falha ao deletar:{{errorMessage}}", + "deleteCategoryFailed": "Falha ao deletar classe:{{errorMessage}}", + "categorizeFailed": "Falha ao categorizar imagem:{{errorMessage}}", + "deleteModelFailed": "Falha ao excluir o modelo: {{errorMessage}}", + "trainingFailed": "Falha ao iniciar o treinamento do modelo: {{errorMessage}}" + } + }, + "deleteCategory": { + "title": "Excluir Classe", + "desc": "Tem certeza de que deseja excluir a classe {{name}}? Isso excluirá permanentemente todas as imagens associadas e exigirá o treinamento do modelo novamente." + }, + "deleteModel": { + "title": "Deletar modelo de classificação", + "single": "Tem certeza de que deseja excluir {{name}}? Isso excluirá permanentemente todos os dados associados, incluindo imagens e dados de treinamento. Esta ação não pode ser desfeita." + } +} diff --git a/web/public/locales/pt-BR/views/events.json b/web/public/locales/pt-BR/views/events.json index 5425aa6c7..8edaa67ca 100644 --- a/web/public/locales/pt-BR/views/events.json +++ b/web/public/locales/pt-BR/views/events.json @@ -40,13 +40,19 @@ "detail": { "noDataFound": "Nenhum dado de detalhe para revisar", "aria": "Alternar visualização de detalhe", - "trackedObject_one": "objeto rastreado", - "trackedObject_other": "objetos rastreados", + "trackedObject_one": "objeto", + "trackedObject_other": "objetos", "noObjectDetailData": "Nenhum dado de detalhe de objeto disponível.", - "label": "Detalhe" + "label": "Detalhe", + "settings": "Configurações de visualização detalhada", + "alwaysExpandActive": { + "title": "Expandir sempre o modo ativo" + } }, "objectTrack": { "trackedPoint": "Ponto rastreado", "clickToSeek": "Clique para ir para esse horário" - } + }, + "zoomIn": "Ampliar", + "zoomOut": "Diminuir o zoom" } diff --git a/web/public/locales/pt-BR/views/explore.json b/web/public/locales/pt-BR/views/explore.json index 9de511f9d..bb3e6fdab 100644 --- a/web/public/locales/pt-BR/views/explore.json +++ b/web/public/locales/pt-BR/views/explore.json @@ -111,7 +111,8 @@ "details": "detalhes", "snapshot": "captura de imagem", "video": "vídeo", - "object_lifecycle": "ciclo de vida do objeto" + "object_lifecycle": "ciclo de vida do objeto", + "thumbnail": "thumbnail" }, "objectLifecycle": { "title": "Ciclo de Vida do Objeto", diff --git a/web/public/locales/pt-BR/views/settings.json b/web/public/locales/pt-BR/views/settings.json index 291538097..dbf8cf433 100644 --- a/web/public/locales/pt-BR/views/settings.json +++ b/web/public/locales/pt-BR/views/settings.json @@ -800,7 +800,9 @@ "createRole": "Papel {{role}} criado com sucesso", "updateCameras": "Câmeras atualizados para o papel {{role}}", "deleteRole": "Papel {{role}} apagado com sucesso", - "userRolesUpdated": "{{count}} usuário(os) atribuídos a esse papel foram atualizados para 'visualizador', que possui acesso a todas as câmeras." + "userRolesUpdated_one": "{{count}} usuário(os) atribuídos a esse papel foram atualizados para 'visualizador', que possui acesso a todas as câmeras.", + "userRolesUpdated_many": "", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Falha ao criar papel: {{errorMessage}}", diff --git a/web/public/locales/pt/views/settings.json b/web/public/locales/pt/views/settings.json index d30d093f0..1bab92d78 100644 --- a/web/public/locales/pt/views/settings.json +++ b/web/public/locales/pt/views/settings.json @@ -864,7 +864,9 @@ "createRole": "Papel {{role}} criado com sucesso", "updateCameras": "Câmaras atualizados para o papel {{role}}", "deleteRole": "Papel {{role}} apagado com sucesso", - "userRolesUpdated": "{{count}} utilizador(os) atribuídos a este papel foram atualizados para 'visualizador', que possui acesso a todas as câmaras." + "userRolesUpdated_one": "{{count}} utilizador(os) atribuídos a este papel foram atualizados para 'visualizador', que possui acesso a todas as câmaras.", + "userRolesUpdated_many": "", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Falha ao criar papel: {{errorMessage}}", diff --git a/web/public/locales/pt_BR/views/classificationModel.json b/web/public/locales/pt_BR/views/classificationModel.json deleted file mode 100644 index bdac4a0ff..000000000 --- a/web/public/locales/pt_BR/views/classificationModel.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "documentTitle": "Modelos de Classificação", - "button": { - "deleteClassificationAttempts": "Apagar Imagens de Classificação", - "renameCategory": "Renomear Classe", - "deleteCategory": "Apagar Classe", - "deleteImages": "Apagar Imagens", - "trainModel": "Treinar Modelo" - }, - "toast": { - "success": { - "deletedCategory": "Classe Apagada", - "deletedImage": "Imagens Apagadas", - "categorizedImage": "Imagem Classificada com Sucesso", - "trainedModel": "Modelo treinado com sucesso.", - "trainingModel": "Treinamento do modelo iniciado com sucesso." - }, - "error": { - "deleteImageFailed": "Falha ao deletar:{{errorMessage}}", - "deleteCategoryFailed": "Falha ao deletar classe:{{errorMessage}}", - "categorizeFailed": "Falha ao categorizar imagem:{{errorMessage}}" - } - } -} diff --git a/web/public/locales/ro/common.json b/web/public/locales/ro/common.json index cad2932b2..d232a8047 100644 --- a/web/public/locales/ro/common.json +++ b/web/public/locales/ro/common.json @@ -237,7 +237,10 @@ } }, "label": { - "back": "Mergi înapoi" + "back": "Mergi înapoi", + "hide": "Ascunde {{item}}", + "show": "Afișează {{item}}", + "ID": "ID" }, "selectItem": "Selectează {{item}}", "pagination": { @@ -281,5 +284,14 @@ "readTheDocumentation": "Citește documentația", "information": { "pixels": "{{area}}px" + }, + "list": { + "two": "{{0}} și {{1}}", + "many": "{{items}}, și {{last}}", + "separatorWithSpace": ", " + }, + "field": { + "optional": "Opțional", + "internalID": "ID-ul Intern pe care Frigate îl folosește în configurație și în baza de date" } } diff --git a/web/public/locales/ro/components/dialog.json b/web/public/locales/ro/components/dialog.json index 44a984bc9..c3a451368 100644 --- a/web/public/locales/ro/components/dialog.json +++ b/web/public/locales/ro/components/dialog.json @@ -83,7 +83,7 @@ "export": "Exportă", "selectOrExport": "Selectează sau exportă", "toast": { - "success": "Exportul a început cu succes. Vizualizați fișierul în dosarul /exports.", + "success": "Exportul a început cu succes. Vizualizați fișierul pe pagina de exporturi.", "error": { "failed": "Eroare la pornirea exportului: {{error}}", "endTimeMustAfterStartTime": "Ora de sfârșit trebuie să fie după ora de început", @@ -129,6 +129,7 @@ "search": { "placeholder": "Caută după etichetă sau subetichetă..." }, - "noImages": "Nu s-au găsit miniaturi pentru această cameră" + "noImages": "Nu s-au găsit miniaturi pentru această cameră", + "unknownLabel": "Imaginea declanșator salvată" } } diff --git a/web/public/locales/ro/views/classificationModel.json b/web/public/locales/ro/views/classificationModel.json index 0967ef424..1e48893ba 100644 --- a/web/public/locales/ro/views/classificationModel.json +++ b/web/public/locales/ro/views/classificationModel.json @@ -1 +1,164 @@ -{} +{ + "documentTitle": "Modele de clasificare", + "button": { + "deleteClassificationAttempts": "Șterge imaginile de clasificare", + "renameCategory": "Redenumește clasa", + "deleteCategory": "Șterge clasa", + "deleteImages": "Șterge imaginile", + "trainModel": "Antrenează modelul", + "addClassification": "Adaugă clasificare", + "deleteModels": "Șterge modelele", + "editModel": "Editează modelul" + }, + "toast": { + "success": { + "deletedCategory": "Clasă ștearsă", + "deletedImage": "Imagini șterse", + "categorizedImage": "Imagine clasificată cu succes", + "trainedModel": "Model antrenat cu succes.", + "trainingModel": "Antrenamentul modelului a fost pornit cu succes.", + "deletedModel_one": "{{count}} model șters cu succes", + "deletedModel_few": "{{count}} modele șterse cu succes", + "deletedModel_other": "{{count}} modele șterse cu succes", + "updatedModel": "Configurația modelului a fost actualizată cu succes" + }, + "error": { + "deleteImageFailed": "Ștergerea a eșuat: {{errorMessage}}", + "deleteCategoryFailed": "Ștergerea clasei a eșuat: {{errorMessage}}", + "categorizeFailed": "Categorisirea imaginii a eșuat: {{errorMessage}}", + "trainingFailed": "Pornirea antrenamentului modelului a eșuat: {{errorMessage}}", + "deleteModelFailed": "Ștergerea modelului a eșuat: {{errorMessage}}", + "updateModelFailed": "Actualizarea modelului a eșuat: {{errorMessage}}" + } + }, + "deleteCategory": { + "title": "Șterge clasa", + "desc": "Sigur doriți să ștergeți clasa {{name}}? Aceasta va șterge permanent toate imaginile asociate și va necesita reantrenarea modelului." + }, + "deleteDatasetImages": { + "title": "Șterge imaginile setului de date", + "desc": "Sigur doriți să ștergeți {{count}} imagini din {{dataset}}? Această acțiune nu poate fi anulată și va necesita reantrenarea modelului." + }, + "deleteTrainImages": { + "title": "Șterge imaginile de antrenament", + "desc": "Sigur doriți să ștergeți {{count}} imagini? Această acțiune nu poate fi anulată." + }, + "renameCategory": { + "title": "Redenumește clasa", + "desc": "Introduceți un nume nou pentru {{name}}. Va trebui să reantrenați modelul pentru ca modificarea numelui să aibă efect." + }, + "description": { + "invalidName": "Nume invalid. Numele pot include doar litere, cifre, spații, apostrofuri, underscore-uri și liniuțe." + }, + "train": { + "title": "Clasificări recente", + "titleShort": "Recente", + "aria": "Selectează clasificările recente" + }, + "categories": "Clase", + "createCategory": { + "new": "Creează clasă nouă" + }, + "categorizeImageAs": "Clasifică imaginea ca:", + "categorizeImage": "Clasifică imaginea", + "noModels": { + "object": { + "title": "Nu există modele de clasificare a obiectelor", + "description": "Creează un model personalizat pentru a clasifica obiectele detectate.", + "buttonText": "Creează model de obiect" + }, + "state": { + "title": "Nu există modele de clasificare a stării", + "description": "Creează un model personalizat pentru a monitoriza și clasifica schimbările de stare în anumite zone ale camerei.", + "buttonText": "Creează model de stare" + } + }, + "wizard": { + "title": "Creează clasificare nouă", + "steps": { + "nameAndDefine": "Numire și definire", + "stateArea": "Zona de stare", + "chooseExamples": "Alege exemple" + }, + "step1": { + "description": "Modelele de stare monitorizează zone fixe ale camerei pentru schimbări (de exemplu, ușă deschisă/închisă). Modelele de obiect adaugă clasificări obiectelor detectate (de exemplu, animale cunoscute, curieri etc.).", + "name": "Nume", + "namePlaceholder": "Introduceți numele modelului...", + "type": "Tip", + "typeState": "Stare", + "typeObject": "Obiect", + "objectLabel": "Etichetă obiect", + "objectLabelPlaceholder": "Selectează tipul obiectului...", + "classificationType": "Tip de clasificare", + "classificationTypeTip": "Află despre tipurile de clasificare", + "classificationTypeDesc": "Subetichetele adaugă text suplimentar la eticheta obiectului (de exemplu, 'Persoană: UPS'). Atributele sunt metadate căutabile, stocate separat în metadatele obiectului.", + "classificationSubLabel": "Subeticheta", + "classificationAttribute": "Atribut", + "classes": "Clase", + "classesTip": "Află despre clase", + "classesStateDesc": "Definește diferitele stări în care poate fi zona camerei tale. De exemplu: 'deschis' și 'închis' pentru o ușă de garaj.", + "classesObjectDesc": "Definește diferitele categorii în care să fie clasificate obiectele detectate. De exemplu: 'curier', 'rezident', 'necunoscut' pentru clasificarea persoanelor.", + "classPlaceholder": "Introduceți numele clasei...", + "errors": { + "nameRequired": "Numele modelului este obligatoriu", + "nameLength": "Numele modelului trebuie să aibă 64 de caractere sau mai puțin", + "nameOnlyNumbers": "Numele modelului nu poate conține doar cifre", + "classRequired": "Este necesară cel puțin 1 clasă", + "classesUnique": "Numele claselor trebuie să fie unice", + "stateRequiresTwoClasses": "Modelele de stare necesită cel puțin 2 clase", + "objectLabelRequired": "Vă rugăm să selectați o etichetă de obiect", + "objectTypeRequired": "Vă rugăm să selectați un tip de clasificare" + }, + "states": "Stări" + }, + "step2": { + "description": "Selectați camerele și definiți zona de monitorizat pentru fiecare cameră. Modelul va clasifica starea acestor zone.", + "cameras": "Camere", + "selectCamera": "Selectează camera", + "noCameras": "Apasă pe + pentru a adăuga camere", + "selectCameraPrompt": "Selectați o cameră din listă pentru a defini aria sa de monitorizare" + }, + "step3": { + "selectImagesPrompt": "Selectați toate imaginile cu: {{className}}", + "selectImagesDescription": "Apăsați pe imagini pentru a le selecta. Apăsați pe Continuare când ați terminat cu această clasă.", + "generating": { + "title": "Generare imagini de exemplu", + "description": "Frigate preia imagini reprezentative din înregistrările tale. Aceasta poate dura câteva momente..." + }, + "training": { + "title": "Antrenare model", + "description": "Modelul tău este antrenat în fundal. Închide această fereastră și modelul va începe să ruleze imediat ce antrenamentul este finalizat." + }, + "retryGenerate": "Reîncearcă generarea", + "noImages": "Nu s-au generat imagini de exemplu", + "classifying": "Clasificare și antrenare...", + "trainingStarted": "Antrenamentul a început cu succes", + "errors": { + "noCameras": "Nu există camere configurate", + "noObjectLabel": "Nu a fost selectată nicio etichetă de obiect", + "generateFailed": "Generarea exemplelor a eșuat: {{error}}", + "generationFailed": "Generarea a eșuat. Vă rugăm să încercați din nou.", + "classifyFailed": "Clasificarea imaginilor a eșuat: {{error}}" + }, + "generateSuccess": "Imaginile de exemplu au fost generate cu succes" + } + }, + "deleteModel": { + "title": "Șterge modelul de clasificare", + "single": "Sigur doriți să ștergeți {{name}}? Aceasta va șterge permanent toate datele asociate, inclusiv imaginile și datele de antrenament. Această acțiune nu poate fi anulată.", + "desc": "Sigur doriți să ștergeți {{count}} model(e)? Aceasta va șterge permanent toate datele asociate, inclusiv imaginile și datele de antrenament. Această acțiune nu poate fi anulată." + }, + "menu": { + "objects": "Obiecte", + "states": "Stări" + }, + "details": { + "scoreInfo": "Scorul reprezintă încrederea medie a clasificării pentru toate detecțiile acestui obiect." + }, + "edit": { + "title": "Editează modelul de clasificare", + "descriptionState": "Editează clasele pentru acest model de clasificare a stării. Modificările vor necesita reantrenarea modelului.", + "descriptionObject": "Editează tipul de obiect și tipul de clasificare pentru acest model de clasificare a obiectelor.", + "stateClassesInfo": "Notă: Modificarea claselor de stare necesită reantrenarea modelului cu clasele actualizate." + } +} diff --git a/web/public/locales/ro/views/events.json b/web/public/locales/ro/views/events.json index da11d1f1b..c0210ce36 100644 --- a/web/public/locales/ro/views/events.json +++ b/web/public/locales/ro/views/events.json @@ -40,12 +40,20 @@ "detail": { "noDataFound": "Nicio dată detaliată de revizuit", "aria": "Comută vizualizarea detaliată", - "trackedObject_one": "obiect urmărit", - "trackedObject_other": "obiecte urmărite", - "noObjectDetailData": "Nicio dată de detaliu obiect disponibilă." + "trackedObject_one": "obiect", + "trackedObject_other": "obiecte", + "noObjectDetailData": "Nicio dată de detaliu obiect disponibilă.", + "label": "Detaliu", + "settings": "Setări vizualizare detaliată", + "alwaysExpandActive": { + "title": "Extinde întotdeauna activul", + "desc": "Extinde întotdeauna detaliile obiectului elementului activ de revizuire, atunci când sunt disponibile." + } }, "objectTrack": { "trackedPoint": "Punct urmărit", - "clickToSeek": "Fă clic pentru a naviga la acest moment" - } + "clickToSeek": "Apasă pentru a naviga la acest moment" + }, + "zoomIn": "Mărește", + "zoomOut": "Micșorează" } diff --git a/web/public/locales/ro/views/explore.json b/web/public/locales/ro/views/explore.json index 9cc496377..2c9e1c072 100644 --- a/web/public/locales/ro/views/explore.json +++ b/web/public/locales/ro/views/explore.json @@ -33,7 +33,8 @@ "details": "detalii", "snapshot": "snapshot", "video": "video", - "object_lifecycle": "ciclul de viață al obiectului" + "object_lifecycle": "ciclul de viață al obiectului", + "thumbnail": "miniatură" }, "objectLifecycle": { "lifecycleItemDesc": { @@ -200,12 +201,22 @@ "audioTranscription": { "label": "Transcrie", "aria": "Solicită transcrierea audio" + }, + "viewTrackingDetails": { + "label": "Vizualizați detaliile de urmărire", + "aria": "Vizualizați detaliile de urmărire" + }, + "showObjectDetails": { + "label": "Afișează traseul obiectului" + }, + "hideObjectDetails": { + "label": "Ascunde traseul obiectului" } }, "dialog": { "confirmDelete": { "title": "Confirmă ștergerea", - "desc": "Ștergerea acestui obiect urmărit elimină instantaneul, orice încorporări salvate și orice intrări asociate ciclului de viață al obiectului. Materialul video înregistrat al acestui obiect urmărit în vizualizarea Istoric NU va fi șters.

    Ești sigur că vrei să continui?" + "desc": "Ștergerea acestui obiect urmărit elimină snapshot-ul, orice încorporări salvate și orice intrări asociate detaliilor de urmărire. Materialul video înregistrat al acestui obiect urmărit în vizualizarea Istoric NU va fi șters.

    Ești sigur că vrei să continui?" } }, "noTrackedObjects": "Nu au fost găsite obiecte urmărite", @@ -224,5 +235,53 @@ }, "concerns": { "label": "Îngrijorări" + }, + "trackingDetails": { + "title": "Detalii de Urmărire", + "noImageFound": "Nu s-a găsit nicio imagine pentru acest marcaj de timp.", + "createObjectMask": "Creează Masca Obiectului", + "adjustAnnotationSettings": "Ajustează Setările de anotare", + "scrollViewTips": "Apasă pentru a vizualiza momentele semnificative din ciclul de viață al acestui obiect.", + "autoTrackingTips": "Pozițiile casetelor de delimitare vor fi inexacte pentru camerele cu urmărire automată.", + "count": "{{first}} din {{second}}", + "trackedPoint": "Punct Urmărit", + "lifecycleItemDesc": { + "visible": "detectat {{label}}", + "entered_zone": "{{label}} a intrat în {{zones}}", + "active": "{{label}} a devenit activ", + "stationary": "{{label}} a devenit staționar", + "attribute": { + "faceOrLicense_plate": "{{attribute}} detectat pentru {{label}}", + "other": "{{label}} recunoscut ca {{attribute}}" + }, + "gone": "{{label}} a plecat", + "heard": "{{label}} auzit", + "external": "{{label}} detectat", + "header": { + "zones": "Zone", + "ratio": "Raport", + "area": "Aria" + } + }, + "annotationSettings": { + "title": "Setări de adnotare", + "showAllZones": { + "title": "Afișează toate", + "desc": "Afișează întotdeauna zonele pe cadrele în care obiectele au intrat într-o zonă." + }, + "offset": { + "label": "Compensare adnotare", + "desc": "Aceste date provin din fluxul de detectare al camerei tale, dar sunt suprapuse pe imaginile din fluxul de înregistrare. Este puțin probabil ca cele două fluxuri să fie perfect sincronizate. Drept urmare, caseta delimitatoare și materialul video nu se vor alinia perfect. Poți folosi această setare pentru a decală adnotările înainte sau înapoi în timp, pentru a le alinia mai bine cu materialul înregistrat.", + "millisecondsToOffset": "Millisecunde pentru a decalca adnotările de detectare. Implicit: 0", + "tips": "SFAT: Imaginează-ți că există un clip al unui eveniment cu o persoană care merge de la stânga la dreapta. Dacă caseta delimitatoare a cronologiei evenimentului este constant în stânga persoanei, atunci valoarea ar trebui să fie scăzută. În mod similar, dacă o persoană merge de la stânga la dreapta și caseta delimitatoare este constant în fața persoanei, atunci valoarea ar trebui să fie crescută.", + "toast": { + "success": "Decalajul de adnotare pentru {{camera}} a fost salvat în fișierul de configurare. Repornește Frigate pentru a aplica modificările." + } + } + }, + "carousel": { + "previous": "Slide-ul anterior", + "next": "Slide-ul următor" + } } } diff --git a/web/public/locales/ro/views/exports.json b/web/public/locales/ro/views/exports.json index 786b07150..fa9077459 100644 --- a/web/public/locales/ro/views/exports.json +++ b/web/public/locales/ro/views/exports.json @@ -13,5 +13,11 @@ "error": { "renameExportFailed": "Eroare redenumire export: {{errorMessage}}" } + }, + "tooltip": { + "shareExport": "Partajează exportul", + "downloadVideo": "Descarcă videoclipul", + "editName": "Editează numele", + "deleteExport": "Șterge exportul" } } diff --git a/web/public/locales/ro/views/faceLibrary.json b/web/public/locales/ro/views/faceLibrary.json index b530c3077..a1e03f734 100644 --- a/web/public/locales/ro/views/faceLibrary.json +++ b/web/public/locales/ro/views/faceLibrary.json @@ -1,8 +1,8 @@ { "description": { - "addFace": "Parcurge adăugarea unei colecții noi la biblioteca de fețe.", + "addFace": "Adaugă o colecție nouă în Biblioteca de fețe încărcând prima ta imagine.", "placeholder": "Introduceti un nume pentru aceasta colectie", - "invalidName": "Nume invalid. Numele poate conține doar litere, cifre, spații, apostrofuri, liniuțe de subliniere și cratime." + "invalidName": "Nume invalid. Numele pot include doar litere, cifre, spații, apostrofuri, underscore-uri și liniuțe." }, "details": { "person": "Persoană", diff --git a/web/public/locales/ro/views/live.json b/web/public/locales/ro/views/live.json index f93404448..ed57d49f7 100644 --- a/web/public/locales/ro/views/live.json +++ b/web/public/locales/ro/views/live.json @@ -17,9 +17,9 @@ }, "move": { "clickMove": { - "label": "Fă click în cadrul imaginii pentru a centra camera", - "enable": "Activează clic pentru a muta", - "disable": "Dezactivează clic pentru a muta" + "label": "Apasă în cadrul imaginii pentru a centra camera", + "enable": "Activează mutarea prin clic", + "disable": "Dezactivează mutarea prin clic" }, "left": { "label": "Mișcă camera PTZ spre stânga" @@ -36,7 +36,7 @@ }, "frame": { "center": { - "label": "Fă clic în cadru pentru a centra camera PTZ" + "label": "Apasă în cadru pentru a centra camera PTZ" } }, "presets": "Presetări cameră PTZ", @@ -100,7 +100,7 @@ "start": "Pornește înregistrarea la cerere", "started": "Înregistrare la cerere pornită manual.", "failedToStart": "Nu s-a putut porni înregistrarea manuală la cerere.", - "recordDisabledTips": "Deoarece înregistrarea este dezactivată sau restricționată în configurația pentru această cameră, va fi salvată doar o captură de ecran.", + "recordDisabledTips": "Deoarece înregistrarea este dezactivată sau restricționată în configurația pentru această cameră, doar un snapshot va fi salvat.", "end": "Oprește înregistrarea la cerere", "ended": "Înregistrarea manuală la cerere s-a încheiat.", "failedToEnd": "Nu s-a reușit încheierea înregistrării manuale la cerere." diff --git a/web/public/locales/ro/views/search.json b/web/public/locales/ro/views/search.json index 9e80fdc3b..94d035a5e 100644 --- a/web/public/locales/ro/views/search.json +++ b/web/public/locales/ro/views/search.json @@ -33,7 +33,7 @@ "step1": "Tastează un nume de filtru urmat de două puncte (ex. „camere:” ).", "step3": "Folosește mai multe filtre adăugându-le unul după altul, separate prin spațiu.", "step4": "Filtrele de dată (înainte: și după:) folosesc formatul {{DateFormat}}.", - "step6": "Elimină filtrele făcând clic pe „X”-ul de lângă ele.", + "step6": "Elimină filtrele apăsând pe „X”-ul de lângă ele.", "exampleLabel": "Exemplu:", "step5": "Filtrul pentru intervalul de timp folosește formatul {{exampleTime}}.", "step2": "Selectează o valoare din sugestii sau tastează propria valoare.", diff --git a/web/public/locales/ro/views/settings.json b/web/public/locales/ro/views/settings.json index 84e12d348..262d50547 100644 --- a/web/public/locales/ro/views/settings.json +++ b/web/public/locales/ro/views/settings.json @@ -50,6 +50,10 @@ "playAlertVideos": { "label": "Redă videoclipurile de alertă", "desc": "În mod implicit, alertele recente din panoul Live se redau ca videoclipuri mici, ce ruleaza repetat. Dezactivează această opțiune pentru a afișa doar o imagine statică a alertelor recente pe acest dispozitiv/browser." + }, + "displayCameraNames": { + "label": "Afișează întotdeauna numele camerelor", + "desc": "Afișează întotdeauna numele camerelor într-un indicator în tabloul de bord cu vizualizare live pe mai multe camere." } }, "storedLayouts": { @@ -267,7 +271,7 @@ "desc": "Specifică o viteză minimă pe care trebuie să o aibă obiectele pentru a fi considerate în această zonă." }, "documentTitle": "Editează zone - Frigate", - "clickDrawPolygon": "Click pentru a desena un poligon pe imagine.", + "clickDrawPolygon": "Apasă pentru a desena un poligon pe imagine.", "toast": { "success": "Zona ({{zoneName}}) a fost salvată. Repornește Frigate pentru a aplica modificările." }, @@ -282,7 +286,7 @@ "point_one": "{{count}} punct", "point_few": "{{count}} puncte", "point_other": "{{count}} de puncte", - "clickDrawPolygon": "Fă click pentru a desena un poligon pe imagine.", + "clickDrawPolygon": "Fă clic pentru a desena un poligon pe imagine.", "label": "Măști de mișcare", "documentTitle": "Editează masca de mișcare - Frigate", "desc": { @@ -330,7 +334,7 @@ "title": "{{polygonName}} a fost salvat. Repornește Frigate pentru a aplica modificările." } }, - "clickDrawPolygon": "Fă click pentru a desena un poligon pe imagine.", + "clickDrawPolygon": "Fă clic pentru a desena un poligon pe imagine.", "context": "Măștile de filtrare a obiectelor sunt folosite pentru a elimina falsele pozitive pentru un anumit tip de obiect, în funcție de locația acestuia." }, "restart_required": "Repornire necesară (măști/zone modificate)", @@ -682,7 +686,7 @@ "triggers": { "documentTitle": "Declanșatoare", "management": { - "title": "Gestionarea declanșatoarelor", + "title": "Declanșatoare", "desc": "Gestionează declanșatoarele pentru {{camera}}. Folosește tipul miniatură pentru a declanșa pe miniaturi similare cu obiectul urmărit selectat și tipul descriere pentru a declanșa pe descrieri similare textului pe care îl specifici." }, "addTrigger": "Adaugă declanșator", @@ -703,7 +707,9 @@ }, "actions": { "alert": "Marchează ca alertă", - "notification": "Trimite notificare" + "notification": "Trimite notificare", + "sub_label": "Adaugă subeticheta", + "attribute": "Adaugă atribut" }, "dialog": { "createTrigger": { @@ -721,25 +727,28 @@ "form": { "name": { "title": "Nume", - "placeholder": "Introdu numele declanșatorului", + "placeholder": "Denumește acest declanșator", "error": { - "minLength": "Numele trebuie să aibă cel puțin 2 caractere.", - "invalidCharacters": "Numele poate conține doar litere, cifre, underscore-uri și cratime.", + "minLength": "Câmpul trebuie să aibă cel puțin 2 caractere.", + "invalidCharacters": "Câmpul poate conține doar litere, cifre, underscore-uri și cratime.", "alreadyExists": "Un declanșator cu acest nume există deja pentru această cameră." - } + }, + "description": "Introduceți un nume sau o descriere unică pentru a identifica acest declanșator" }, "enabled": { "description": "Activează sau dezactivează acest declanșator" }, "type": { "title": "Tip", - "placeholder": "Selectează tipul de declanșator" + "placeholder": "Selectează tipul de declanșator", + "description": "Declanșează atunci când este detectată o descriere de obiect urmărit similară", + "thumbnail": "Declanșează atunci când este detectată o miniatură de obiect urmărit similară" }, "content": { "title": "Conținut", - "imagePlaceholder": "Selectează o imagine", + "imagePlaceholder": "Selectează o miniatură", "textPlaceholder": "Introdu conținutul textului", - "imageDesc": "Selectează o imagine pentru a declanșa această acțiune atunci când o imagine similară este detectată.", + "imageDesc": "Sunt afișate doar ultimele 100 de miniaturi. Dacă nu găsiți miniatura dorită, vă rugăm să verificați obiectele anterioare în Explorator și să configurați un declanșator din meniul de acolo.", "textDesc": "Introduceți textul pentru a declanșa această acțiune atunci când este detectată o descriere de obiect urmărit similară.", "error": { "required": "Conținutul este obligatoriu." @@ -750,11 +759,12 @@ "error": { "min": "Pragul trebuie să fie cel puțin 0", "max": "Pragul trebuie să fie cel mult 1" - } + }, + "desc": "Setați pragul de similitudine pentru acest declanșator. Un prag mai mare înseamnă că este necesară o potrivire mai apropiată pentru declanșarea acestuia." }, "actions": { "title": "Acțiuni", - "desc": "Implicit, Frigate trimite un mesaj MQTT pentru toate declanșatoarele. Alegeți o acțiune suplimentară de efectuat atunci când acest declanșator se activează.", + "desc": "În mod implicit, Frigate trimite un mesaj MQTT pentru toate declanșatoarele. Subetichetele adaugă numele declanșatorului la eticheta obiectului. Atributele sunt metadate căutabile, stocate separat în metadatele obiectului urmărit.", "error": { "min": "Trebuie selectată cel puțin o acțiune." } @@ -781,6 +791,23 @@ "semanticSearch": { "title": "Căutarea semantică este dezactivată", "desc": "Căutarea semantică trebuie să fie activată pentru a utiliza declanșatoarele." + }, + "wizard": { + "title": "Creează declanșator", + "step1": { + "description": "Configurează setările de bază pentru declanșatorul tău." + }, + "step2": { + "description": "Configurează conținutul care va declanșa această acțiune." + }, + "step3": { + "description": "Configurează pragul și acțiunile pentru acest declanșator." + }, + "steps": { + "nameAndType": "Nume și Tip", + "configureData": "Configurează datele", + "thresholdAndActions": "Prag și Acțiuni" + } } }, "roles": { @@ -802,7 +829,9 @@ "createRole": "Rolul {{role}} a fost creat cu succes", "updateCameras": "Camerele au fost actualizate pentru rolul {{role}}", "deleteRole": "Rolul {{role}} a fost șters cu succes", - "userRolesUpdated": "{{count}} utilizator(i) atribuiți acestui rol au fost actualizați la „vizualizator”, care are acces la toate camerele." + "userRolesUpdated_one": "{{count}} utilizator(i) atribuiți acestui rol au fost actualizați la „vizualizator”, care are acces la toate camerele.", + "userRolesUpdated_few": "", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Crearea rolului a eșuat: {{errorMessage}}", @@ -896,11 +925,16 @@ "invalidCharacters": "Numele camerei conține caractere nevalide", "nameExists": "Numele camerei există deja", "brands": { - "reolink-rtsp": "RTSP Reolink nu este recomandat. Se recomandă să activezi HTTP în setările camerei și să repornești asistentul de cameră." - } + "reolink-rtsp": "RTSP Reolink nu este recomandat. Activează HTTP în setările firmware ale camerei și repornește asistentul." + }, + "customUrlRtspRequired": "URL-urile personalizate trebuie să înceapă cu \"rtsp://\". Este necesară configurare manuală pentru stream-urile de cameră non-RTSP." }, "docs": { "reolink": "https://docs.frigate.video/configuration/camera_specific.html#reolink-cameras" + }, + "testing": { + "probingMetadata": "Sondare metadate cameră...", + "fetchingSnapshot": "Preluare snapshot cameră..." } }, "step2": { @@ -982,7 +1016,9 @@ }, "resolutionHigh": "O rezoluție de {{resolution}} poate cauza o utilizare crescută a resurselor.", "resolutionLow": "O rezoluție de {{resolution}} poate fi prea mică pentru detectarea fiabilă a obiectelor mici." - } + }, + "ffmpegModule": "Folosește modul de compatibilitate pentru stream-uri", + "ffmpegModuleDescription": "Dacă fluxul nu se încarcă după mai multe încercări, activați această opțiune. Când este activată, Frigate va folosi modulul ffmpeg împreună cu go2rtc. Aceasta poate oferi o compatibilitate mai bună cu unele fluxuri de camere." } }, "cameraManagement": { diff --git a/web/public/locales/ru/views/classificationModel.json b/web/public/locales/ru/views/classificationModel.json index 0967ef424..cabb7793e 100644 --- a/web/public/locales/ru/views/classificationModel.json +++ b/web/public/locales/ru/views/classificationModel.json @@ -1 +1,40 @@ -{} +{ + "documentTitle": "Модели классификации", + "details": { + "scoreInfo": "Оценка представляет собой среднюю степень достоверности классификации по всем обнаружениям данного объекта." + }, + "button": { + "deleteClassificationAttempts": "Удалить изображения классификации", + "renameCategory": "Переименовать класс", + "deleteCategory": "Удалить класс", + "deleteImages": "Удалить изображения", + "trainModel": "Тренировать модель", + "addClassification": "Добавить классификацию", + "deleteModels": "Удалить модели", + "editModel": "Редактировать модель" + }, + "toast": { + "success": { + "deletedCategory": "Удаленный класс", + "deletedImage": "Удалённые изображения", + "deletedModel_one": "Успешно удалена {{count}} модель", + "deletedModel_few": "Успешно удалены {{count}} модели", + "deletedModel_many": "Успешно удалены {{count}} моделей", + "categorizedImage": "Изображение успешно классифицировано", + "trainedModel": "Успешно обученная модель.", + "trainingModel": "Успешно начато обучение моделей.", + "updatedModel": "Успешно обновлена конфигурация модели" + }, + "error": { + "deleteImageFailed": "Не удалось удалить: {{errorMessage}}", + "deleteCategoryFailed": "Не удалось удалить класс: {{errorMessage}}", + "deleteModelFailed": "Не удалось удалить модель: {{errorMessage}}", + "categorizeFailed": "Не удалось классифицировать изображение: {{errorMessage}}", + "trainingFailed": "Не удалось начать обучение модели: {{errorMessage}}" + } + }, + "deleteCategory": { + "title": "Удалить класс", + "desc": "Вы уверены, что хотите удалить класс {{name}}? Это приведёт к безвозвратному удалению всех связанных с ним изображений и потребует повторного обучения модели." + } +} diff --git a/web/public/locales/ru/views/events.json b/web/public/locales/ru/views/events.json index c3e095eb0..85f8bed39 100644 --- a/web/public/locales/ru/views/events.json +++ b/web/public/locales/ru/views/events.json @@ -41,12 +41,16 @@ "detail": { "noDataFound": "Нет данных для просмотра", "aria": "Переключить подробный режим просмотра", - "trackedObject_one": "отслеживаемый объект", - "trackedObject_other": "отслеживаемые объекты", - "noObjectDetailData": "Данные о деталях объекта недоступны." + "trackedObject_one": "объект", + "trackedObject_other": "объекты", + "noObjectDetailData": "Данные о деталях объекта недоступны.", + "label": "Деталь", + "settings": "Настройки подробного просмотра" }, "objectTrack": { "trackedPoint": "Отслеживаемая точка", "clickToSeek": "Перейти к этому моменту" - } + }, + "zoomIn": "Увеличить", + "zoomOut": "Отдалить" } diff --git a/web/public/locales/ru/views/explore.json b/web/public/locales/ru/views/explore.json index 833dc3095..778ffd7d1 100644 --- a/web/public/locales/ru/views/explore.json +++ b/web/public/locales/ru/views/explore.json @@ -110,7 +110,8 @@ "details": "детали", "snapshot": "снимок", "video": "видео", - "object_lifecycle": "жизненный цикл объекта" + "object_lifecycle": "жизненный цикл объекта", + "thumbnail": "миниатюра" }, "objectLifecycle": { "title": "Жизненный цикл объекта", diff --git a/web/public/locales/ru/views/exports.json b/web/public/locales/ru/views/exports.json index f48fb3e71..c14a578ca 100644 --- a/web/public/locales/ru/views/exports.json +++ b/web/public/locales/ru/views/exports.json @@ -13,5 +13,11 @@ "error": { "renameExportFailed": "Не удалось переименовать экспорт: {{errorMessage}}" } + }, + "tooltip": { + "shareExport": "Поделиться экспортом", + "downloadVideo": "Скачать видео", + "editName": "Изменить название", + "deleteExport": "Удалить экспорт" } } diff --git a/web/public/locales/ru/views/faceLibrary.json b/web/public/locales/ru/views/faceLibrary.json index 802f0cebe..3dcfd7cd5 100644 --- a/web/public/locales/ru/views/faceLibrary.json +++ b/web/public/locales/ru/views/faceLibrary.json @@ -12,7 +12,7 @@ "documentTitle": "Библиотека лиц - Frigate", "description": { "placeholder": "Введите название коллекции", - "addFace": "Пошаговое добавление новой коллекции в Библиотеку лиц.", + "addFace": "Добавьте новую коллекцию в библиотеку лиц, загрузив свое первое изображение.", "invalidName": "Недопустимое имя. Имена могут содержать только буквы, цифры, пробелы, апострофы, подчеркивания и дефисы." }, "createFaceLibrary": { @@ -28,8 +28,8 @@ }, "selectItem": "Выбор {{item}}", "train": { - "aria": "Выбор обучения", - "title": "Обучение", + "aria": "Выберите последние распознавания", + "title": "Последние распознавания", "empty": "Нет недавних попыток распознавания лиц" }, "toast": { diff --git a/web/public/locales/sk/audio.json b/web/public/locales/sk/audio.json index b12849747..4ea31df06 100644 --- a/web/public/locales/sk/audio.json +++ b/web/public/locales/sk/audio.json @@ -432,5 +432,72 @@ "shofar": "Šofar", "liquid": "Kvapalina", "splash": "Šplechnutie", - "slosh": "Slosh" + "slosh": "Slosh", + "squish": "Vytlačiť", + "drip": "Kvapkať", + "pour": "Nalej", + "trickle": "Pokvapkať", + "gush": "Striekať", + "fill": "Vyplňte", + "spray": "Striekajte", + "pump": "Pumpa", + "stir": "Miešajte", + "boiling": "Varenie", + "sonar": "Sonar", + "arrow": "Šípka", + "whoosh": "Whoosh", + "thump": "Palec", + "thunk": "Thunk", + "electronic_tuner": "Elektronický tuner", + "effects_unit": "Efektuje jednotky", + "chorus_effect": "Zborový efekt", + "basketball_bounce": "Odrážanie basketbalovej lopty", + "bang": "Bang", + "slap": "Buchnutie", + "whack": "Odpáliť", + "smash": "Rozbiť", + "breaking": "Prelomenie", + "bouncing": "Odskakovanie", + "whip": "Bič", + "flap": "Klapka", + "scratch": "Poškriabanie", + "scrape": "Škrabať", + "rub": "Potrieť", + "roll": "Rolovať", + "crushing": "Rozdrvovanie", + "crumpling": "Mačkanie", + "tearing": "Trhanie", + "beep": "Pípnutie", + "ping": "Ping", + "ding": "Ding", + "clang": "Zvonenie", + "squeal": "Kňučať", + "creak": "Vŕzganie", + "rustle": "Šuchot", + "whir": "Vrčanie", + "clatter": "Cvakať", + "sizzle": "Syčať", + "clicking": "Klikanie", + "clickety_clack": "Klikanie kľak", + "rumble": "Rachot", + "plop": "Prasknutie", + "hum": "Hmkanie", + "zing": "Zing", + "boing": "Boing", + "crunch": "Chrumnutie", + "sine_wave": "Sínusoida", + "harmonic": "Harmonický", + "chirp_tone": "Cvrlikací tón", + "pulse": "Pulz", + "inside": "Vnútri", + "outside": "Vonku", + "reverberation": "Dozvuk", + "echo": "Ozvena", + "noise": "Zvuk", + "mains_hum": "Hlavné Hum", + "distortion": "Skreslenie", + "sidetone": "Vedľajší tón", + "cacophony": "Kakofónia", + "throbbing": "Pulzujúci", + "vibration": "Vibrácia" } diff --git a/web/public/locales/sk/common.json b/web/public/locales/sk/common.json index 8411f5379..a1a13eed1 100644 --- a/web/public/locales/sk/common.json +++ b/web/public/locales/sk/common.json @@ -101,7 +101,10 @@ }, "readTheDocumentation": "Prečítajte si dokumentáciu", "label": { - "back": "Choď späť" + "back": "Choď späť", + "hide": "Skryť {{item}}", + "show": "Zobraziť {{item}}", + "ID": "ID" }, "button": { "apply": "Použiť", @@ -281,5 +284,14 @@ }, "information": { "pixels": "{{area}}px" + }, + "list": { + "two": "{{0}} a {{1}}", + "many": "{{items}}, a {{last}}", + "separatorWithSpace": ", " + }, + "field": { + "optional": "Voliteľné", + "internalID": "Interné ID Frigate používa v konfigurácii a databáze" } } diff --git a/web/public/locales/sk/components/dialog.json b/web/public/locales/sk/components/dialog.json index 148de2812..fe4ca101b 100644 --- a/web/public/locales/sk/components/dialog.json +++ b/web/public/locales/sk/components/dialog.json @@ -53,7 +53,7 @@ "export": "Exportovať", "selectOrExport": "Vybrať pre Export", "toast": { - "success": "Export úspešne spustený. Súbor nájdete v adresári /exports.", + "success": "Export bol úspešne spustený. Súbor si pozrite na stránke exportov.", "error": { "failed": "Chyba spustenia exportu: {{error}}", "endTimeMustAfterStartTime": "Čas konca musí byť po čase začiatku", @@ -117,6 +117,7 @@ "search": { "placeholder": "Hľadať podľa štítku alebo podštítku..." }, - "noImages": "Pre tuto kameru sa nenašli žiadne miniatúry" + "noImages": "Pre tuto kameru sa nenašli žiadne miniatúry", + "unknownLabel": "Uložený obrázok spúšťača" } } diff --git a/web/public/locales/sk/views/classificationModel.json b/web/public/locales/sk/views/classificationModel.json index 900c1a1ae..0442406fc 100644 --- a/web/public/locales/sk/views/classificationModel.json +++ b/web/public/locales/sk/views/classificationModel.json @@ -5,7 +5,9 @@ "renameCategory": "Premenovať triedu", "deleteCategory": "Odstrániť triedu", "deleteImages": "Odstrániť obrázky", - "trainModel": "Model vlaku" + "trainModel": "Model vlaku", + "addClassification": "Pridať klasifikáciu", + "deleteModels": "Odstrániť modely" }, "toast": { "success": { @@ -13,13 +15,17 @@ "deletedImage": "Vymazané obrázky", "categorizedImage": "Obrázok bol úspešne klasifikovaný", "trainedModel": "Úspešne vyškolený model.", - "trainingModel": "Úspešne spustený modelový tréning." + "trainingModel": "Úspešne spustený modelový tréning.", + "deletedModel_one": "Úspešne zmazané {{count}} model (y)", + "deletedModel_few": "", + "deletedModel_other": "" }, "error": { "deleteImageFailed": "Nepodarilo sa odstrániť: {{errorMessage}}", "deleteCategoryFailed": "Nepodarilo sa odstrániť triedu: {{errorMessage}}", "categorizeFailed": "Nepodarilo sa kategorizovať obrázok: {{errorMessage}}", - "trainingFailed": "Nepodarilo sa spustiť trénovanie modelu: {{errorMessage}}" + "trainingFailed": "Nepodarilo sa spustiť trénovanie modelu: {{errorMessage}}", + "deleteModelFailed": "Nepodarilo sa odstrániť model: {{errorMessage}}" } }, "deleteCategory": { @@ -43,7 +49,8 @@ }, "train": { "title": "Posledné klasifikácie", - "aria": "Vyberte Nedávne Klasifikácie" + "aria": "Vyberte Nedávne Klasifikácie", + "titleShort": "Nedávne" }, "categories": "Triedy", "createCategory": { @@ -98,7 +105,8 @@ "stateRequiresTwoClasses": "Modely štátov vyžadujú aspoň 2 triedy", "objectLabelRequired": "Vyberte označenie objektu", "objectTypeRequired": "Vyberte typ klasifikácie" - } + }, + "states": "Štátov" }, "step2": { "description": "Vyberte kamery a definujte oblasť, ktorú chcete pre každú kameru monitorovať. Model klasifikuje stav týchto oblastí.", @@ -131,5 +139,14 @@ }, "generateSuccess": "Vzorové obrázky boli úspešne vygenerované" } + }, + "deleteModel": { + "title": "Odstrániť klasifikačný model", + "single": "Ste si istí, že chcete odstrániť {{name}}? To bude trvalo odstrániť všetky súvisiace údaje vrátane obrázkov a vzdelávacích údajov. Táto akcia nemôže byť neporušená.", + "desc": "Ste si istí, že chcete odstrániť {{count}} model (y)? To bude trvalo odstrániť všetky súvisiace údaje vrátane obrázkov a vzdelávacích údajov. Táto akcia nemôže byť neporušená." + }, + "menu": { + "objects": "Objekty", + "states": "Štátov" } } diff --git a/web/public/locales/sk/views/events.json b/web/public/locales/sk/views/events.json index 72d25d0b2..59ab1eaf1 100644 --- a/web/public/locales/sk/views/events.json +++ b/web/public/locales/sk/views/events.json @@ -43,10 +43,17 @@ "trackedObject_one": "objekt", "trackedObject_other": "objekty", "noObjectDetailData": "Nie sú k dispozícii žiadne podrobné údaje o objekte.", - "label": "Detail" + "label": "Detail", + "settings": "Nastavenia podrobného zobrazenia", + "alwaysExpandActive": { + "title": "Rozbaľte vždy aktívne", + "desc": "Vždy rozbaľte podrobnosti objektu aktívnej položky recenzie, ak sú k dispozícii." + } }, "objectTrack": { "trackedPoint": "Sledovaný bod", "clickToSeek": "Kliknutím prejdete na tento čas" - } + }, + "zoomIn": "Priblížiť", + "zoomOut": "Oddialiť" } diff --git a/web/public/locales/sk/views/explore.json b/web/public/locales/sk/views/explore.json index b597c3868..e406dfa89 100644 --- a/web/public/locales/sk/views/explore.json +++ b/web/public/locales/sk/views/explore.json @@ -111,7 +111,8 @@ "details": "detaily", "snapshot": "snímka", "video": "video", - "object_lifecycle": "životný cyklus objektu" + "object_lifecycle": "životný cyklus objektu", + "thumbnail": "Náhľad" }, "objectLifecycle": { "title": "Životný cyklus Objektu", @@ -203,12 +204,16 @@ }, "hideObjectDetails": { "label": "Skryť cestu objektu" + }, + "viewTrackingDetails": { + "label": "Zobraziť podrobnosti sledovania", + "aria": "Zobraziť podrobnosti o sledovaní" } }, "dialog": { "confirmDelete": { "title": "Potvrdiť zmazanie", - "desc": "Odstránením tohto sledovaného objektu sa odstráni snímka, všetky uložené vloženia a všetky súvisiace položky životného cyklu objektu. Zaznamenaný záznam tohto sledovaného objektu v zobrazení História NEBUDE zmazaný.

    Naozaj chcete pokračovať?" + "desc": "Odstránením tohto sledovaného objektu sa odstráni snímka, všetky uložené vložené prvky a všetky súvisiace položky s podrobnosťami o sledovaní. Zaznamenané zábery tohto sledovaného objektu v zobrazení História NEBUDÚ odstránené.

    Naozaj chcete pokračovať?" } }, "noTrackedObjects": "Žiadne sledované objekty neboli nájdené", @@ -230,5 +235,53 @@ }, "concerns": { "label": "Obavy" + }, + "trackingDetails": { + "title": "Podrobnosti sledovania", + "noImageFound": "Pre túto časovú pečiatku sa nenašiel žiadny obrázok.", + "createObjectMask": "Vytvoriť masku objektu", + "adjustAnnotationSettings": "Upravte nastavenia anotácií", + "scrollViewTips": "Kliknite pre zobrazenie významných momentov životného cyklu tohto objektu.", + "autoTrackingTips": "Pozície ohraničujúcich rámčekov budú pre kamery s automatickým sledovaním nepresné.", + "count": "{{first}} z {{second}}", + "trackedPoint": "Sledovaný bod", + "lifecycleItemDesc": { + "visible": "Zistený {{label}}", + "entered_zone": "{{label}} vstúpil do {{zones}}", + "active": "{{label}} sa stal aktívnym", + "stationary": "{{label}} sa zastavil", + "attribute": { + "faceOrLicense_plate": "Pre {{label}} bol zistený {{attribute}}", + "other": "{{label}} rozpoznané ako {{attribute}}" + }, + "gone": "{{label}} zostalo", + "heard": "{{label}} počul", + "external": "Zistený {{label}}", + "header": { + "zones": "Zóny", + "ratio": "Pomer", + "area": "Oblasť" + } + }, + "annotationSettings": { + "title": "Nastavenia anotácií", + "showAllZones": { + "title": "Zobraziť všetky zóny", + "desc": "Vždy zobrazovať zóny na rámoch, do ktorých objekty vstúpili." + }, + "offset": { + "label": "Odsadenie anotácie", + "desc": "Tieto údaje pochádzajú z detektoru kamery, ale sú prepustené na obrázky z rekordného krmiva. Je nepravdepodobné, že dva prúdy sú perfektne synchronizované. V dôsledku toho, skreslenie box a zábery nebudú dokonale zaradiť. Toto nastavenie môžete použiť na ofsetovanie annotácií dopredu alebo dozadu, aby ste ich lepšie zladili s zaznamenanými zábermi.", + "millisecondsToOffset": "Milisekundy na posunutie detekcie anotácií. Predvolené: 0", + "tips": "TIP: Predstavte si klip udalosti, v ktorom osoba kráča zľava doprava. Ak je ohraničujúci rámček časovej osi udalosti stále naľavo od osoby, hodnota by sa mala znížiť. Podobne, ak osoba kráča zľava doprava a ohraničujúci rámček je stále pred ňou, hodnota by sa mala zvýšiť.", + "toast": { + "success": "Odsadenie anotácie pre {{camera}} bolo uložené do konfiguračného súboru. Reštartujte Frigate, aby sa zmeny prejavili." + } + } + }, + "carousel": { + "previous": "Predchádzajúca snímka", + "next": "Ďalšia snímka" + } } } diff --git a/web/public/locales/sk/views/exports.json b/web/public/locales/sk/views/exports.json index 53c83f090..d9df68500 100644 --- a/web/public/locales/sk/views/exports.json +++ b/web/public/locales/sk/views/exports.json @@ -13,5 +13,11 @@ "error": { "renameExportFailed": "Nepodarilo sa premenovať export: {{errorMessage}}" } + }, + "tooltip": { + "shareExport": "Zdieľať export", + "downloadVideo": "Stiahnite si video", + "editName": "Upraviť meno", + "deleteExport": "Odstrániť export" } } diff --git a/web/public/locales/sk/views/faceLibrary.json b/web/public/locales/sk/views/faceLibrary.json index 7604d0024..a390aab8d 100644 --- a/web/public/locales/sk/views/faceLibrary.json +++ b/web/public/locales/sk/views/faceLibrary.json @@ -1,6 +1,6 @@ { "description": { - "addFace": "Sprievodca pridáním novej kolekcie do Knižnice tvárí.", + "addFace": "Sprievodca pridaním novej kolekcie do Knižnice tvárí.", "invalidName": "Neplatné meno. Mená môžu obsahovať iba písmená, čísla, medzery, apostrofy, podčiarkovníky a spojovníky.", "placeholder": "Zadajte názov pre túto kolekciu" }, @@ -23,7 +23,7 @@ "title": "Vytvoriť Zbierku", "desc": "Vytvoriť novú zbierku", "new": "Vytvoriť novú tvár", - "nextSteps": "Vybudovanie pevných základov:
  • Pomocou záložky Tréning vyberte a trénujte obrázky pre každú detekovanú osobu.
  • Pre dosiahnutie najlepších výsledkov sa zamerajte na snímky s priamym pohľadom; vyhnite sa snímkam, ktoré zachytávajú tváre pod uhlom.
  • " + "nextSteps": "Vybudovanie silného základu:
  • Použite kartu Nedávne rozpoznania na výber a trénovanie obrázkov pre každú rozpoznanú osobu.
  • Pre dosiahnutie najlepších výsledkov sa zamerajte na priame obrázky; vyhnite sa trénovaniu obrázkov, ktoré zachytávajú tváre pod uhlom.
  • " }, "steps": { "faceName": "Zadajte Meno tváre", diff --git a/web/public/locales/sk/views/settings.json b/web/public/locales/sk/views/settings.json index 95e20cac4..424ce5f0c 100644 --- a/web/public/locales/sk/views/settings.json +++ b/web/public/locales/sk/views/settings.json @@ -49,6 +49,10 @@ "playAlertVideos": { "label": "Prehrať videá s upozornením", "desc": "Predvolene sa nedávne upozornenia na paneli Živé vysielanie prehrávajú ako krátke cyklické videá. Túto možnosť vypnite, ak chcete zobrazovať iba statický obrázok nedávnych upozornení na tomto zariadení/prehliadači." + }, + "displayCameraNames": { + "label": "Vždy Zobraziť názvy kamier", + "desc": "Vždy zobrazujte názvy kamier v čipe na ovládacom paneli živého náhľadu z viacerých kamier." } }, "storedLayouts": { @@ -292,7 +296,7 @@ "name": { "title": "Meno", "inputPlaceHolder": "Zadajte meno…", - "tips": "Názov musí mať aspoň 2 znaky a nesmie byť zhodný s názvom kamery alebo inej zóny." + "tips": "Názov musí mať aspoň 2 znaky, musí mať aspoň jedno písmeno a nesmie byť názvom kamery alebo inej zóny." }, "inertia": { "title": "Zotrvačnosť", @@ -793,5 +797,284 @@ } } } + }, + "roles": { + "management": { + "title": "Správa roly diváka", + "desc": "Spravujte vlastné roly divákov a ich povolenia na prístup ku kamere pre túto inštanciu Frigate." + }, + "addRole": "Pridať rolu", + "table": { + "role": "Rola", + "cameras": "Kamery", + "actions": "Akcie", + "noRoles": "Neboli nájdené žiadne vlastné role.", + "editCameras": "Editovať kamery", + "deleteRole": "Odstrániť rolu" + }, + "toast": { + "success": { + "createRole": "Rola {{role}} bola úspešne vytvorená", + "updateCameras": "Kamery aktualizované pre rolu {{role}}", + "deleteRole": "Rola {{role}} bola úspešne odstránená", + "userRolesUpdated_one": "{{count}} užívateľ (y) priradené tejto úlohe boli aktualizované pre \"viewer\", ktorý má prístup ku všetkým kamerám.", + "userRolesUpdated_few": "", + "userRolesUpdated_other": "" + }, + "error": { + "createRoleFailed": "Nepodarilo sa vytvoriť rolu: {{errorMessage}}", + "updateCamerasFailed": "Nepodarilo sa aktualizovať kamery: {{errorMessage}}", + "deleteRoleFailed": "Nepodarilo sa odstrániť rolu: {{errorMessage}}", + "userUpdateFailed": "Nepodarilo sa aktualizovať používateľské role: {{errorMessage}}" + } + }, + "dialog": { + "createRole": { + "title": "Vytvoriť novú rolu", + "desc": "Pridajte novú úlohu a zadajte prístup k kamerám." + }, + "editCameras": { + "title": "Editovať Rolu Kamery", + "desc": "Aktualizujte prístup k kamere pre rolu {{role}}." + }, + "deleteRole": { + "title": "Odstrániť rolu", + "desc": "Túto akciu nie je možné vrátiť späť. Týmto sa rola natrvalo odstráni a všetci používatelia s touto rolou budú priradení k role „pozerač“, ktorá umožní divákovi prístup ku všetkým kamerám.", + "warn": "Ste si istí, že chcete odstrániť {{role}}?", + "deleting": "Odstraňuje sa..." + }, + "form": { + "role": { + "title": "Názov role", + "placeholder": "Zadajte názov roly", + "desc": "Povolené sú iba písmená, čísla, bodky a podčiarkovníky.", + "roleIsRequired": "Vyžaduje sa názov roly", + "roleOnlyInclude": "Názov role môže obsahovať iba písmená, čísla, . alebo _", + "roleExists": "Úloha s týmto menom už existuje." + }, + "cameras": { + "title": "Kamery", + "desc": "Vyberte kamery, ku ktorým má táto rola prístup. Vyžaduje sa aspoň jedna kamera.", + "required": "Aspoň jedna kamera musí byť vybraná." + } + } + } + }, + "notification": { + "title": "Notifikacie", + "notificationSettings": { + "title": "Nastavenia notifikácií", + "desc": "Frigate dokáže natívne odosielať push notifikácie do vášho zariadenia, keď je spustený v prehliadači alebo nainštalovaný ako PWA." + }, + "notificationUnavailable": { + "title": "Notifikacie su nedostupné", + "desc": "Webové push notifikácie vyžadujú zabezpečený kontext (https://…). Ide o obmedzenie prehliadača. Ak chcete používať notifikácie, pristupujte k Frigate bezpečne." + }, + "globalSettings": { + "title": "Globálne nastavenia", + "desc": "Dočasne pozastaviť upozornenia pre konkrétne kamery na všetkých registrovaných zariadeniach." + }, + "email": { + "title": "E-mail", + "placeholder": "e.g. príklad@email.com", + "desc": "Vyžaduje sa platný e-mail, ktorý bude použitý na upozornenie v prípade akýchkoľvek problémov so službou push." + }, + "cameras": { + "title": "Kamery", + "noCameras": "K dispozícii nie sú žiadne kamery", + "desc": "Vyberte, na ktoré kamery umožňujú notifikácie." + }, + "deviceSpecific": "Špecifické nastavenia zariadenia", + "registerDevice": "Registrovať toto zariadenie", + "unregisterDevice": "Zrušte registráciu tohto zariadenia", + "sendTestNotification": "Odoslať testovacie oznámenie", + "unsavedRegistrations": "Neuložené registrácie oznámení", + "unsavedChanges": "Neuložené zmeny upozornení", + "active": "Upozornenia sú aktívne", + "suspended": "Oznámenie pozastavuju {{time}}", + "suspendTime": { + "suspend": "Pozastaviť", + "5minutes": "Pozastaviť na 5 minút", + "10minutes": "Pozastaviť na 10 minút", + "30minutes": "Pozastaviť na 30 minút", + "1hour": "Pozastaviť na 1 hodinu", + "12hours": "Pozastaviť na 12 hodín", + "24hours": "Pozastaviť na 24 hodín", + "untilRestart": "Pozastaviť do reštartovania" + }, + "cancelSuspension": "Zrušiť pozastavenie", + "toast": { + "success": { + "registered": "Úspešne zaregistrované pre upozornenia. Pred odoslaním akýchkoľvek upozornení (vrátane testovacieho upozornenia) je potrebné reštartovať Frigate.", + "settingSaved": "Nastavenie oznámenia boli uložené." + }, + "error": { + "registerFailed": "Uloženie registrácie upozornenia zlyhalo." + } + } + }, + "frigatePlus": { + "title": "Nastavenie Frigate+", + "apiKey": { + "title": "Frigate + API kľúč", + "validated": "Frigate + API kľúč je detekovaný a overený", + "notValidated": "Frigate + API kľúč nie je detekovaný alebo nie je overený", + "desc": "Frigate+ API kľúč umožňuje integráciu s Frigate+ služby.", + "plusLink": "Prečítajte si viac o Frigate+" + }, + "snapshotConfig": { + "title": "Konfigurácia snímky", + "desc": "Odosielanie do Frigate+ vyžaduje, aby boli v konfigurácii povolené snímky aj snímky clean_copy.", + "cleanCopyWarning": "Niektoré kamery majú povolené snímky, ale voľba clean_copy je zakázaná. Pre možnosť odosielania snímok z týchto kamier do služby Frigate+ je nutné túto voľbu povoliť v konfigurácii snímok.", + "table": { + "camera": "Kamera", + "snapshots": "Snímky", + "cleanCopySnapshots": "clean_copy Snímky" + } + }, + "modelInfo": { + "title": "Informácie o Modele", + "modelType": "Typ Modelu", + "trainDate": "Dátum Tréningu", + "baseModel": "Základný Model", + "plusModelType": { + "baseModel": "Základný Model", + "userModel": "Doladené" + }, + "supportedDetectors": "Podporované Detektory", + "cameras": "Kamery", + "loading": "Načítavam informácie o modeli…", + "error": "Chyba načítania informácií o modeli", + "availableModels": "Dostupné Moduly", + "loadingAvailableModels": "Načítavam dostupné modely…", + "modelSelect": "Tu môžete vybrať dostupné modely zo služby Frigate+. Upozorňujeme, že je možné zvoliť iba modely kompatibilné s aktuálnou konfiguráciou detektora." + }, + "unsavedChanges": "Neuložené zmeny nastavenia Frigate+", + "restart_required": "Vyžadovaný reštart (model Frigate+ zmenený)", + "toast": { + "success": "Nastavenia Frigate+ boli uložené. Reštartujte Frigate+ pre aplikovanie zmien.", + "error": "Chyba pri ukladaní zmien konfigurácie: {{errorMessage}}" + } + }, + "triggers": { + "documentTitle": "Spúšťače", + "semanticSearch": { + "title": "Sémantické vyhľadávanie je vypnuté", + "desc": "Na používanie spúšťačov musí byť povolené sémantické vyhľadávanie." + }, + "management": { + "title": "Spúšťače", + "desc": "Správa spúšťa {{camera}}. Použite typ miniatúry, aby ste spustili na podobných miniatúr na vybraných tracked objekt, a typ popisu, aby ste spustili podobné popisy na text, ktorý určíte." + }, + "addTrigger": "Pridať Spúšťač", + "table": { + "name": "Meno", + "type": "Typ", + "content": "Obsah", + "threshold": "Prah", + "actions": "Akcie", + "noTriggers": "Pre túto kameru nie sú nakonfigurované žiadne spúšťače.", + "edit": "Upraviť", + "deleteTrigger": "Odstrániť spúšťač", + "lastTriggered": "Naposledy spustené" + }, + "type": { + "thumbnail": "Náhľad", + "description": "Popis" + }, + "actions": { + "notification": "Poslať upozornenie", + "sub_label": "Pridať vedľajší štítok", + "attribute": "Pridať atribút" + }, + "dialog": { + "createTrigger": { + "title": "Vytvoriť spúšťač", + "desc": "Vytvorte spúšť pre kameru {{camera}}" + }, + "editTrigger": { + "title": "Upraviť spúšťač", + "desc": "Upraviť nastavenia spúšťača na kamere {{camera}}" + }, + "deleteTrigger": { + "title": "Odstrániť spúšťač", + "desc": "Naozaj chcete odstrániť spúšťač {{triggerName}}? Túto akciu nie je možné vrátiť späť." + }, + "form": { + "name": { + "title": "Meno", + "placeholder": "Zadajte meno pre spúšťača", + "description": "Zadajte jedinečné meno alebo popis na identifikáciu tohto spúšťania", + "error": { + "minLength": "Názov musí mať aspoň 2 znaky.", + "invalidCharacters": "Meno môže obsahovať iba písmená, číslice, podčiarkovníky a pomlčky.", + "alreadyExists": "Spúšťač s týmto názvom už pre túto kameru existuje." + } + }, + "enabled": { + "description": "Povoliť alebo zakázať tento spúšťač" + }, + "type": { + "title": "Typ", + "placeholder": "Vybrať typ spúšťača", + "description": "Spustiť, keď sa zistí podobný popis sledovaného objektu", + "thumbnail": "Spustiť, keď sa zistí podobná miniatúra sledovaného objektu" + }, + "content": { + "title": "Obsah", + "imagePlaceholder": "Vyberte miniatúru", + "textPlaceholder": "Zadajte obsah textu", + "imageDesc": "Zobrazujú sa iba posledné 100 miniatúr. Ak nemôžete nájsť požadovanú miniatúru, prečítajte si skôr objekty v preskúmať a nastaviť spúšťací z ponuky tam.", + "textDesc": "Zadajte text, aby ste spustili túto akciu, keď je detekovaný podobný popis objektu.", + "error": { + "required": "Obsah je potrebný." + } + }, + "threshold": { + "title": "Prah", + "desc": "Nastavte prah podobnosti pre tento spúšťač. Vyšší prah znamená, že na spustenie spúšťača je potrebná bližšia zhoda.", + "error": { + "min": "Threshold musí byť aspoň 0", + "max": "Threshold musí byť na väčšine 1" + } + }, + "actions": { + "title": "Akcie", + "desc": "V predvolenom nastavení Frigate odosiela MQTT správu pre všetky spúšťače. Zvoľte dodatočnú akciu, ktorá sa má vykonať, keď sa tento spúšťač aktivuje.", + "error": { + "min": "Musí byť vybraná aspoň jedna akcia." + } + } + } + }, + "wizard": { + "title": "Vytvoriť spúšťač", + "step1": { + "description": "Konfigurujte základné nastavenia pre vašu spúšť." + }, + "step2": { + "description": "Nastavte obsah, ktorý spustí túto akciu." + }, + "step3": { + "description": "Konfigurovať prah a akcie pre tento spúšťač." + }, + "steps": { + "nameAndType": "Meno a typ", + "configureData": "Konfigurovať údaje", + "thresholdAndActions": "Prah a akcie" + } + }, + "toast": { + "success": { + "createTrigger": "Spúšťač {{name}} bol úspešne vytvorený.", + "updateTrigger": "Spúšťač {{name}} bol úspešne aktualizovaný.", + "deleteTrigger": "Spúšťač {{name}} bol úspešne zmazaný." + }, + "error": { + "createTriggerFailed": "Nepodarilo sa vytvoriť spúšťač: {{errorMessage}}", + "updateTriggerFailed": "Nepodarilo sa aktualizovať spúšťač: {{errorMessage}}", + "deleteTriggerFailed": "Nepodarilo sa zmazať spúšťač: {{errorMessage}}" + } + } } } diff --git a/web/public/locales/sv/common.json b/web/public/locales/sv/common.json index 908f87cc7..2e9e1a627 100644 --- a/web/public/locales/sv/common.json +++ b/web/public/locales/sv/common.json @@ -250,7 +250,10 @@ "copyUrlToClipboard": "Webbadressen har kopierats till urklipp." }, "label": { - "back": "Gå tillbaka" + "back": "Gå tillbaka", + "hide": "Dölj {{item}}", + "show": "Visa {{item}}", + "ID": "ID" }, "unit": { "speed": { @@ -274,5 +277,14 @@ "readTheDocumentation": "Läs dokumentationen", "information": { "pixels": "{{area}}px" + }, + "list": { + "two": "{{0}} och {{1}}", + "many": "{{items}} och {{last}}", + "separatorWithSpace": ", " + }, + "field": { + "optional": "Valfritt", + "internalID": "Det interna ID som Frigate använder i konfigurationen och databasen" } } diff --git a/web/public/locales/sv/views/classificationModel.json b/web/public/locales/sv/views/classificationModel.json index 0c4ad8624..d7ee2ddfc 100644 --- a/web/public/locales/sv/views/classificationModel.json +++ b/web/public/locales/sv/views/classificationModel.json @@ -5,7 +5,10 @@ "renameCategory": "Byt namn på klass", "deleteCategory": "Ta bort klass", "deleteImages": "Ta bort bilder", - "trainModel": "Träna modellen" + "trainModel": "Träna modellen", + "addClassification": "Lägg till klassificering", + "deleteModels": "Ta bort modeller", + "editModel": "Redigera modell" }, "toast": { "success": { @@ -13,13 +16,18 @@ "deletedImage": "Raderade bilder", "categorizedImage": "Lyckades klassificera bilden", "trainedModel": "Modellen har tränats.", - "trainingModel": "Modellträning har startat." + "trainingModel": "Modellträning har startat.", + "deletedModel_one": "{{count}} modell har raderats", + "deletedModel_other": "{{count}} modeller har raderats", + "updatedModel": "Uppdaterade modellkonfiguration" }, "error": { "deleteImageFailed": "Misslyckades med att ta bort: {{errorMessage}}", "deleteCategoryFailed": "Misslyckades med att ta bort klassen: {{errorMessage}}", "categorizeFailed": "Misslyckades med att kategorisera bilden: {{errorMessage}}", - "trainingFailed": "Misslyckades med att starta modellträning: {{errorMessage}}" + "trainingFailed": "Misslyckades med att starta modellträning: {{errorMessage}}", + "deleteModelFailed": "Misslyckades med att ta bort modellen: {{errorMessage}}", + "updateModelFailed": "Misslyckades med att uppdatera modell: {{errorMessage}}" } }, "deleteCategory": { @@ -43,7 +51,8 @@ }, "train": { "title": "Nyligen tillagd klassificeringar", - "aria": "Välj senaste klassificeringar" + "aria": "Välj senaste klassificeringar", + "titleShort": "Nyligen" }, "categories": "Klasser", "createCategory": { @@ -82,7 +91,73 @@ "classificationType": "Klassificeringstyp", "classificationTypeTip": "Lär dig mer om klassificeringstyper", "classificationTypeDesc": "Underetiketter lägger till ytterligare text till objektetiketten (t.ex. 'Person: UPS'). Attribut är sökbara metadata som lagras separat i objektmetadata.", - "classificationSubLabel": "Underetikett" + "classificationSubLabel": "Underetikett", + "classificationAttribute": "Attribut", + "classes": "Klasser", + "states": "Tillstånd", + "classesTip": "Lär dig mer om klasser", + "classesStateDesc": "Definiera de olika tillstånd som ditt kameraområde kan vara i. Till exempel: \"öppen\" och \"stängd\" för en garageport.", + "classesObjectDesc": "Definiera de olika kategorierna som detekterade objekt ska klassificeras i. Till exempel: 'leveransperson', 'boende', 'främling' för personklassificering.", + "classPlaceholder": "Ange klassnamn...", + "errors": { + "nameRequired": "Modellnamn krävs", + "nameLength": "Modellnamnet måste vara högst 64 tecken långt", + "nameOnlyNumbers": "Modellnamnet får inte bara innehålla siffror", + "classRequired": "Minst 1 klass krävs", + "classesUnique": "Klassnamn måste vara unika", + "stateRequiresTwoClasses": "Tillståndsmodeller kräver minst två klasser", + "objectLabelRequired": "Välj en objektetikett", + "objectTypeRequired": "Vänligen välj en klassificeringstyp" + } + }, + "step2": { + "description": "Välj kameror och definiera området som ska övervakas för varje kamera. Modellen kommer att klassificera tillståndet för dessa områden.", + "cameras": "Kameror", + "selectCamera": "Välj kamera", + "noCameras": "Klicka på + för att lägga till kameror", + "selectCameraPrompt": "Välj en kamera från listan för att definiera dess övervakningsområde" + }, + "step3": { + "selectImagesPrompt": "Markera alla bilder med: {{className}}", + "selectImagesDescription": "Klicka på bilderna för att välja dem. Klicka på Fortsätt när du är klar med den här klass.", + "generating": { + "title": "Generera exempelbilder", + "description": "Frigate hämtar representativa bilder från dina inspelningar. Det kan ta en stund..." + }, + "training": { + "title": "Träningsmodell", + "description": "Din modell tränas i bakgrunden. Stäng den här dialogrutan så börjar modellen köras så snart träningen är klar." + }, + "retryGenerate": "Försök att generera igen", + "noImages": "Inga exempelbilder genererade", + "classifying": "Klassificering & Träning...", + "trainingStarted": "Träningen har börjat", + "errors": { + "noCameras": "Inga kameror konfigurerade", + "noObjectLabel": "Ingen objektetikett vald", + "generateFailed": "Misslyckades med att generera exempel: {{error}}", + "generationFailed": "Genereringen misslyckades. Försök igen.", + "classifyFailed": "Misslyckades med att klassificera bilder: {{error}}" + }, + "generateSuccess": "Exempelbilder har genererats" } + }, + "deleteModel": { + "title": "Ta bort klassificeringsmodell", + "single": "Är du säker på att du vill ta bort {{name}}? Detta kommer att permanent ta bort all tillhörande data, inklusive bilder och träningsdata. Åtgärden kan inte ångras.", + "desc": "Är du säker på att du vill ta bort {{count}} modell(er)? Detta kommer att permanent ta bort all tillhörande data, inklusive bilder och träningsdata. Åtgärden kan inte ångras." + }, + "menu": { + "objects": "Objekt", + "states": "Tillstånd" + }, + "details": { + "scoreInfo": "Poängen representerar den genomsnittliga klassificeringssäkerheten för alla upptäckter av detta objekt." + }, + "edit": { + "title": "Redigera klassificeringsmodell", + "descriptionState": "Redigera klasserna för denna tillståndsklassificeringsmodell. Ändringar kräver omträning av modellen.", + "descriptionObject": "Redigera objekttyp och klassificeringstyp för denna objektklassificeringsmodell.", + "stateClassesInfo": "Observera: För att ändra tillståndsklasser måste modellen omtränas med de uppdaterade klasserna." } } diff --git a/web/public/locales/sv/views/events.json b/web/public/locales/sv/views/events.json index 6ba446f38..aed86c7ea 100644 --- a/web/public/locales/sv/views/events.json +++ b/web/public/locales/sv/views/events.json @@ -43,10 +43,17 @@ "trackedObject_one": "objekt", "trackedObject_other": "objekt", "noObjectDetailData": "Inga objektdetaljdata tillgängliga.", - "label": "Detalj" + "label": "Detalj", + "settings": "Detaljvy inställningar", + "alwaysExpandActive": { + "title": "Expandera alltid aktivt", + "desc": "Expandera alltid objektinformationen för det aktiva granskningsobjektet när den är tillgänglig." + } }, "objectTrack": { "trackedPoint": "Spårad punkt", "clickToSeek": "Klicka för att söka till den här tiden" - } + }, + "zoomIn": "Zooma in", + "zoomOut": "Zooma ut" } diff --git a/web/public/locales/sv/views/explore.json b/web/public/locales/sv/views/explore.json index 66e30bce3..b66acead6 100644 --- a/web/public/locales/sv/views/explore.json +++ b/web/public/locales/sv/views/explore.json @@ -109,7 +109,8 @@ "details": "detaljer", "video": "video", "snapshot": "ögonblicksbild", - "object_lifecycle": "objektets livscykel" + "object_lifecycle": "objektets livscykel", + "thumbnail": "miniatyrbild" }, "trackedObjectDetails": "Detaljer om spårade objekt", "objectLifecycle": { @@ -199,6 +200,13 @@ }, "showObjectDetails": { "label": "Visa objektets plats" + }, + "viewTrackingDetails": { + "label": "Visa spårningsinformation", + "aria": "Visa spårningsdetaljerna" + }, + "hideObjectDetails": { + "label": "Dölj objektsökväg" } }, "dialog": { @@ -231,7 +239,7 @@ "noImageFound": "Ingen bild hittades för denna tidsstämpel.", "createObjectMask": "Skapa objektmask", "adjustAnnotationSettings": "Justera annoteringsinställningar", - "scrollViewTips": "Scrolla för att se de viktiga ögonblicken i detta objekts livscykel.", + "scrollViewTips": "Klicka för att se de viktiga ögonblicken i detta objekts livscykel.", "autoTrackingTips": "Begränsningsrutornas positioner kommer att vara felaktiga för autospårningskameror.", "count": "{{first}} av {{second}}", "trackedPoint": "Spårad punkt", @@ -261,7 +269,7 @@ }, "offset": { "label": "Annoteringsförskjutning", - "desc": "Denna data kommer från din kameras detekteringsflöde men läggs ovanpå bilder från inspelningsflödet. Det är osannolikt att de två strömmarna är helt synkroniserade. Som ett resultat kommer avgränsningsramen och filmmaterialet inte att radas upp perfekt. Fältet annotation_offset kan dock användas för att justera detta.", + "desc": "Denna data kommer från din kameras detekteringsflöde men läggs ovanpå bilder från inspelningsflödet. Det är osannolikt att de två strömmarna är helt synkroniserade. Som ett resultat kommer avgränsningsramen och filmmaterialet inte att radas upp perfekt. Du kan använda den här inställningen för att förskjuta anteckningarna framåt eller bakåt i tiden för att bättre anpassa dem till det inspelade materialet.", "millisecondsToOffset": "Millisekunder för att förskjuta detektera annoteringar med. Standard: 0", "tips": "TIPS: Föreställ dig ett händelseklipp med en person som går från vänster till höger. Om tidslinjens avgränsningsram konsekvent är till vänster om personen bör värdet minskas. På samma sätt, om en person går från vänster till höger och avgränsningsramen konsekvent är framför personen bör värdet ökas.", "toast": { @@ -270,7 +278,8 @@ } }, "carousel": { - "previous": "Föregående bild" + "previous": "Föregående bild", + "next": "Nästa bild" } } } diff --git a/web/public/locales/sv/views/settings.json b/web/public/locales/sv/views/settings.json index 1598ddf76..0045d30bb 100644 --- a/web/public/locales/sv/views/settings.json +++ b/web/public/locales/sv/views/settings.json @@ -25,7 +25,11 @@ "desc": "Som standard visas varningar på Live panelen som små loopande klipp. Inaktivera denna inställning för att bara visa en statisk bild av nya varningar på denna enhet/webbläsare.", "label": "Spela upp Varnings videor" }, - "title": "Live Panel" + "title": "Live Panel", + "displayCameraNames": { + "label": "Visa alltid kameranamn", + "desc": "Visa alltid kameranamnen i ett chip i instrumentpanelen för livevisning med flera kameror." + } }, "storedLayouts": { "title": "Sparade Layouter", @@ -640,7 +644,8 @@ "createRole": "Roll {{role}} skapad", "updateCameras": "Kameror uppdaterade för roll {{role}}", "deleteRole": "Roll {{role}} raderad", - "userRolesUpdated": "{{count}} användare som tilldelats den här rollen har uppdaterats till 'tittare', vilket har åtkomst till alla kameror." + "userRolesUpdated_one": "{{count}} användare som tilldelats den här rollen har uppdaterats till 'tittare', vilket har åtkomst till alla kameror.", + "userRolesUpdated_other": "" }, "error": { "createRoleFailed": "Misslyckades att skapa roll: {{errorMessage}}", @@ -731,7 +736,7 @@ "triggers": { "documentTitle": "Utlösare", "management": { - "title": "Utlösare hantering", + "title": "Utlösare", "desc": "Hantera utlösare för {{camera}}. Använd miniatyrtypen för att utlösa liknande miniatyrer som ditt valda spårade objekt och beskrivningstypen för att utlösa liknande beskrivningar av text du anger." }, "addTrigger": "Lägg till utlösare", @@ -752,7 +757,9 @@ }, "actions": { "notification": "Skicka avisering", - "alert": "Markera som Varning" + "alert": "Markera som Varning", + "sub_label": "Lägg till underetikett", + "attribute": "Lägg till attribut" }, "dialog": { "createTrigger": { @@ -770,25 +777,28 @@ "form": { "name": { "title": "Namn", - "placeholder": "Ange utlösarens namn", + "placeholder": "Namnge denna utlösare", "error": { - "minLength": "Namnet måste vara minst 2 tecken lång.", - "invalidCharacters": "Namnet får bara innehålla bokstäver, siffror, understreck, och bindestreck.", + "minLength": "Fältet måste vara minst 2 tecken långt.", + "invalidCharacters": "Fältet får bara innehålla bokstäver, siffror, understreck och bindestreck.", "alreadyExists": "En utlösare med detta namn finns redan för den här kameran." - } + }, + "description": "Ange ett unikt namn eller en unik beskrivning för att identifiera den här utlösaren" }, "enabled": { "description": "Aktivera eller inaktivera den här utlösaren" }, "type": { "title": "Typ", - "placeholder": "Välj utlösartyp" + "placeholder": "Välj utlösartyp", + "description": "Utlöses när en liknande beskrivning av spårat objekt detekteras", + "thumbnail": "Utlöses när en liknande miniatyrbild av ett spårat objekt upptäcks" }, "content": { "title": "Innehåll", - "imagePlaceholder": "Välj en bild", + "imagePlaceholder": "Välj en miniatyrbild", "textPlaceholder": "Ange textinnehåll", - "imageDesc": "Välj en bild för att utlösa den här åtgärden när en liknande bild upptäcks.", + "imageDesc": "Endast de senaste 100 miniatyrerna visas. Om du inte hittar önskad miniatyr kan du granska tidigare objekt i Utforska och skapa en utlösare från menyn där.", "textDesc": "Ange text för att utlösa den här åtgärden när en liknande beskrivning av spårat objekt upptäcks.", "error": { "required": "Innehåll krävs." @@ -799,11 +809,12 @@ "error": { "min": "Tröskelvärdet måste vara minst 0", "max": "Tröskelvärdet får vara högst 1" - } + }, + "desc": "Ställ in likhetströskeln för denna utlösare. En högre tröskel innebär att en bättre matchning krävs för att utlösaren ska aktiveras." }, "actions": { "title": "Åtgärder", - "desc": "Som standard utlöser Frigate ett MQTT-meddelande för alla utlösare. Välj en ytterligare åtgärd att utföra när den här utlösaren utlöses.", + "desc": "Som standard utlöser Frigate ett MQTT-meddelande för alla utlösare. Underetiketter lägger till utlösarnamnet till objektetiketten. Attribut är sökbara metadata som lagras separat i de spårade objektmetadata.", "error": { "min": "Minst en åtgärd måste väljas." } @@ -830,6 +841,23 @@ "semanticSearch": { "title": "Semantisk sökning är inaktiverad", "desc": "Semantisk sökning måste vara aktiverad för att använda Utlösare." + }, + "wizard": { + "title": "Skapa utlösare", + "step1": { + "description": "Konfigurera grundinställningarna för din trigger." + }, + "step2": { + "description": "Ställ in innehållet som ska utlösa den här åtgärden." + }, + "step3": { + "description": "Konfigurera tröskelvärdet och åtgärderna för den här utlösaren." + }, + "steps": { + "nameAndType": "Namn och typ", + "configureData": "Konfigurera data", + "thresholdAndActions": "Tröskelvärde och åtgärder" + } } }, "cameraWizard": { @@ -886,10 +914,15 @@ "nameExists": "Kameranamnet finns redan", "brands": { "reolink-rtsp": "Reolink RTSP rekommenderas inte. Aktivera HTTP i kamerans firmwareinställningar och starta om guiden." - } + }, + "customUrlRtspRequired": "Anpassade webbadresser måste börja med \"rtsp://\". Manuell konfiguration krävs för kameraströmmar som inte använder RTSP." }, "docs": { "reolink": "https://docs.frigate.video/configuration/camera_specific.html#reolink-cameras" + }, + "testing": { + "probingMetadata": "Undersöker kamerans metadata...", + "fetchingSnapshot": "Hämtar kamerabild..." } }, "step2": { @@ -968,8 +1001,12 @@ }, "hikvision": { "substreamWarning": "Delström 1 är låst till en låg upplösning. Många Hikvision kameror stöder ytterligare delströmmar som måste aktiveras i kamerans inställningar. Det rekommenderas att kontrollera och använda dessa strömmar om de är tillgängliga." - } - } + }, + "resolutionHigh": "En upplösning på {{resolution}} kan orsaka ökad resursanvändning.", + "resolutionLow": "En upplösning på {{resolution}} kan vara för låg för tillförlitlig detektering av små objekt." + }, + "ffmpegModule": "Använd läge för strömkompatibilitet", + "ffmpegModuleDescription": "Om strömmen inte läses in efter flera försök, prova att aktivera detta. När det är aktiverat kommer Frigate att använda ffmpeg-modulen med go2rtc. Detta kan ge bättre kompatibilitet med vissa kameraströmmar." } }, "cameraManagement": { diff --git a/web/public/locales/tr/components/auth.json b/web/public/locales/tr/components/auth.json index dbc444b05..5d99dcd75 100644 --- a/web/public/locales/tr/components/auth.json +++ b/web/public/locales/tr/components/auth.json @@ -10,6 +10,7 @@ "rateLimit": "İstek sınırı aşıldı. Daha sonra tekrar deneyin.", "unknownError": "Bilinmeyen hata. Günlükleri kontrol edin." }, - "user": "Kullanıcı Adı" + "user": "Kullanıcı Adı", + "firstTimeLogin": "İlk kez giriş yapmayı mı deniyorsunuz? Giriş bilgileri Frigate loglarında görüntülenir." } } diff --git a/web/public/locales/tr/components/dialog.json b/web/public/locales/tr/components/dialog.json index a4d7df98c..9b2e2e3f0 100644 --- a/web/public/locales/tr/components/dialog.json +++ b/web/public/locales/tr/components/dialog.json @@ -59,7 +59,7 @@ "export": "Dışa Aktar", "selectOrExport": "Seç veya Dışa Aktar", "toast": { - "success": "Dışa aktarım başladı. Dosyaya /exports klasöründe veya Dışa Aktar sekmesinden ulaşabilirsiniz.", + "success": "Dışa aktarma başarıyla başlatıldı. Dosyayı dışa aktarmalar sayfasında görüntüleyebilirsiniz.", "error": { "failed": "Dışa aktarım başlatılamadı: {{error}}", "endTimeMustAfterStartTime": "Bitiş zamanı başlangıç zamanından sonra olmalıdır", diff --git a/web/public/locales/tr/views/classificationModel.json b/web/public/locales/tr/views/classificationModel.json index 0967ef424..82790b549 100644 --- a/web/public/locales/tr/views/classificationModel.json +++ b/web/public/locales/tr/views/classificationModel.json @@ -1 +1,78 @@ -{} +{ + "documentTitle": "Sınıflandırma Modelleri", + "details": { + "scoreInfo": "Skor, modelin nesneyi tespit ettiği tüm durumlar için ortalama güven düzeyini gösterir." + }, + "button": { + "deleteClassificationAttempts": "Sınıflandırma Fotoğraflarını Sil", + "renameCategory": "Sınıfı Yeniden Adlandır", + "deleteCategory": "Sınıfı Sil", + "deleteImages": "Fotoğrafları Sil", + "trainModel": "Modeli Eğit", + "addClassification": "Sınıflandırma Ekle", + "deleteModels": "Modelleri Sil" + }, + "toast": { + "success": { + "deletedCategory": "Silinmiş Sınıf", + "deletedImage": "Silinmiş Fotoğraflar", + "deletedModel_one": "{{tane}} model(ler) başarıyla silindi", + "deletedModel_other": "", + "categorizedImage": "Fotoğraf Başarıyla Sınıflandırıldı", + "trainedModel": "Model başarıyla eğitildi.", + "trainingModel": "Model eğitimi başarıyla başladı." + }, + "error": { + "deleteImageFailed": "Silinirken hatayla karşılaşıldı: {{errorMessage}}", + "deleteModelFailed": "Model silinirken hata oluştu: {{errorMessage}}", + "categorizeFailed": "Görsel sınıflandırılamadı: {{errorMessage}}", + "trainingFailed": "Model eğitimi başlatılamadı: {{errorMessage}}" + } + }, + "deleteCategory": { + "title": "Sınıfı Sil", + "desc": "{{name}} adlı sınıfı silmek istediğinizden emin misiniz? Bu işlem, sınıfa ait tüm görselleri kalıcı olarak silecek ve modelin yeniden eğitilmesini gerektirecektir." + }, + "deleteModel": { + "title": "Sınıflandırma Modelini Sil", + "single": "{{name}} öğesini silmek istediğinizden emin misiniz? Bu işlem, görseller ve eğitim verileri dâhil olmak üzere tüm ilişkili verileri kalıcı olarak silecektir. Bu işlem geri alınamaz.", + "desc": "{{count}} modeli silmek istediğinizden emin misiniz? Bu işlem, görseller ve eğitim verileri dâhil olmak üzere tüm ilişkili verileri kalıcı olarak silecektir. Bu işlem geri alınamaz." + }, + "deleteDatasetImages": { + "title": "Eğitim verisi görsellerini sil", + "desc": "{{dataset}} veri kümesinden {{count}} görseli silmek istediğinizden emin misiniz? Bu işlem geri alınamaz ve modelin yeniden eğitilmesini gerektirecektir." + }, + "deleteTrainImages": { + "title": "Eğitim Görsellerini Sil", + "desc": "{{count}} görseli silmek istediğinizden emin misiniz? Bu işlem geri alınamaz." + }, + "renameCategory": { + "title": "Sınıfı Yeniden Adlandır", + "desc": "{{name}} için yeni bir ad girin. Ad değişikliğinin etkili olabilmesi için modeli yeniden eğitmeniz gerekecektir." + }, + "description": { + "invalidName": "Geçersiz ad. Ad yalnızca harfler, rakamlar, boşluklar, kesme işaretleri (’), alt çizgiler (_) ve tireler (-) içerebilir." + }, + "train": { + "title": "Son Sınıflandırmalar", + "titleShort": "Son", + "aria": "Son Sınıflandırmaları Seç" + }, + "categories": "Sınıflar", + "createCategory": { + "new": "Yeni Sınıf Oluştur" + }, + "categorizeImageAs": "Görseli Şu Şekilde Sınıflandır:", + "categorizeImage": "Görseli Sınıflandır", + "menu": { + "objects": "Nesneler", + "states": "Durumlar" + }, + "noModels": { + "object": { + "title": "Nesne sınıflandırma modeli mevcut değil", + "description": "Algılanan nesneleri sınıflandırmak için özel bir model oluşturun.", + "buttonText": "Nesne Modeli Oluştur" + } + } +} diff --git a/web/public/locales/tr/views/events.json b/web/public/locales/tr/views/events.json index c1a821407..376ac03da 100644 --- a/web/public/locales/tr/views/events.json +++ b/web/public/locales/tr/views/events.json @@ -36,5 +36,23 @@ "selected_other": "{{count}} seçildi", "detected": "algılandı", "suspiciousActivity": "Şüpheli Etkinlik", - "threateningActivity": "Tehlikeli Etkinlik" + "threateningActivity": "Tehlikeli Etkinlik", + "zoomIn": "Büyüt", + "zoomOut": "Küçült", + "detail": { + "label": "Detay", + "aria": "Ayrıntı görünümünü aç/kapat", + "trackedObject_one": "Nesne", + "trackedObject_other": "nesneler", + "noObjectDetailData": "Nesneye ait ayrıntılı veri bulunmuyor.", + "settings": "Ayrıntılı Görünüm Ayarları", + "alwaysExpandActive": { + "title": "Etkin olanı her zaman genişlet", + "desc": "Varsa, etkin inceleme öğesinin nesne ayrıntılarını daima göster." + } + }, + "objectTrack": { + "trackedPoint": "Takip edilen nokta", + "clickToSeek": "Bu zamana gitmek için tıklayın" + } } diff --git a/web/public/locales/tr/views/explore.json b/web/public/locales/tr/views/explore.json index ce9466741..a12586cc4 100644 --- a/web/public/locales/tr/views/explore.json +++ b/web/public/locales/tr/views/explore.json @@ -109,7 +109,8 @@ "details": "detaylar", "object_lifecycle": "nesne yaşam döngüsü", "snapshot": "fotoğraf", - "video": "video" + "video": "video", + "thumbnail": "küçük resim" }, "objectLifecycle": { "title": "Nesne Yaşam Döngüsü", @@ -219,5 +220,32 @@ "exploreMore": "Daha fazla {{label}} nesnesini keşfet", "aiAnalysis": { "title": "Yapay Zeka Analizi" + }, + "trackingDetails": { + "title": "Takip Ayrıntıları", + "noImageFound": "Bu zaman damgasına ait bir görsel bulunamadı.", + "createObjectMask": "Nesne Maskesi Oluştur", + "adjustAnnotationSettings": "Etiketleme ayarlarını düzenle", + "scrollViewTips": "Bu nesnenin yaşam döngüsündeki önemli olayları görmek için tıklayın.", + "autoTrackingTips": "Otomatik takip yapan kameralar için sınır kutusu konumları doğru olmayabilir.", + "count": "{{second}}’den {{first}}", + "trackedPoint": "Takip edilen nokta", + "lifecycleItemDesc": { + "visible": "{{label}} tespit edildi", + "entered_zone": "{{label}} {{zones}} bölgesine girdi", + "active": "{{label}} etkin hale geldi", + "stationary": "{{label}} sabit hale geldi", + "attribute": { + "faceOrLicense_plate": "{{label}} için {{attribute}} tespit edildi", + "other": "{{label}}, {{attribute}} olarak tanındı" + }, + "gone": "{{label}} ayrıldı", + "heard": "{{label}} duyuldu", + "external": "{{label}} tespit edildi", + "header": { + "zones": "Bölgeler", + "ratio": "Oran" + } + } } } diff --git a/web/public/locales/tr/views/exports.json b/web/public/locales/tr/views/exports.json index 3a1d19512..0c8fec129 100644 --- a/web/public/locales/tr/views/exports.json +++ b/web/public/locales/tr/views/exports.json @@ -13,5 +13,11 @@ "renameExportFailed": "Dışa aktarım adlandırılamadı: {{errorMessage}}" } }, - "noExports": "Dışa aktarım bulunamadı" + "noExports": "Dışa aktarım bulunamadı", + "tooltip": { + "shareExport": "Dışa aktarmayı paylaş", + "downloadVideo": "Videoyu İndir", + "editName": "İsmi Düzenle", + "deleteExport": "Dışa Aktarmayı Sil" + } } diff --git a/web/public/locales/tr/views/faceLibrary.json b/web/public/locales/tr/views/faceLibrary.json index 428d6eaf2..f3cfed89f 100644 --- a/web/public/locales/tr/views/faceLibrary.json +++ b/web/public/locales/tr/views/faceLibrary.json @@ -2,8 +2,8 @@ "selectItem": "{{item}} seçin", "description": { "placeholder": "Bu koleksiyona bir isim verin", - "addFace": "Yüz Kütüphanesi’ne yeni bir koleksiyon ekleme adımlarını takip edin.", - "invalidName": "Geçersiz isim. İsimlerde yalnızca harf, sayı, boşluk, kesme işareti, tire veya alt çizgi kullanılabilir." + "addFace": "İlk görselinizi yükleyerek Yüz Kütüphanesi’ne yeni bir koleksiyon ekleyin.", + "invalidName": "Geçersiz ad. Ad yalnızca harfler, rakamlar, boşluklar, kesme işaretleri (’), alt çizgiler (_) ve tireler (-) içerebilir." }, "details": { "person": "İnsan", @@ -24,11 +24,11 @@ "desc": "Yeni bir yüz koleksiyonu oluşturun", "new": "Yeni Yüz Oluştur", "title": "Koleksiyon Oluştur", - "nextSteps": "Sağlam bir temel oluşturmak için:
  • Her tespit edilen kişi için 'Eğit' sekmesinden resimler seçip eğitin.
  • En iyi sonuçlar için doğrudan karşıdan çekilmiş yüz resimlerine odaklanın; açılı yüz resimlerinden kaçının.
  • " + "nextSteps": "Sağlam bir temel oluşturmak için:
  • Her tespit edilen kişi için **Recent Recognitions (Son Tanımalar)** sekmesini kullanarak görüntüleri seçin ve eğitim gerçekleştirin.
  • En iyi sonuçlar için doğrudan önden çekilmiş yüz görüntülerine odaklanın; yüzlerin açılı göründüğü fotoğrafları eğitimde kullanmaktan kaçının.
  • " }, "train": { - "title": "Eğit", - "aria": "Eğitimi seç", + "title": "Son Algılananlar", + "aria": "Son algılanan nesneleri seç", "empty": "Yakın zamanda yüz tanıma denemesi olmadı" }, "deleteFaceLibrary": { @@ -49,7 +49,7 @@ "validation": { "selectImage": "Lütfen bir resim dosyası seçin." }, - "dropInstructions": "Bir resmi buraya sürükleyip bırakın ya da tıklayarak seçin" + "dropInstructions": "Bir görseli buraya sürükleyip bırakın, yapıştırın ya da seçmek için tıklayın." }, "trainFaceAs": "Yüzü şu olarak eğit:", "toast": { diff --git a/web/public/locales/tr/views/live.json b/web/public/locales/tr/views/live.json index ae3b0cd1c..ad1704ab7 100644 --- a/web/public/locales/tr/views/live.json +++ b/web/public/locales/tr/views/live.json @@ -19,11 +19,11 @@ }, "started": "Manuel talep üzerine kayıt başlatıldı.", "failedToStart": "Manuel talep üzerine kayıt başlatılamadı.", - "title": "İsteğe Bağlı Kayıt", + "title": "İsteğe Bağlı", "end": "Talep Üzerine Kaydı Bitir", "debugView": "Hata Ayıklama Görünümü", "ended": "Manuel talep üzerine kayıt bitirildi.", - "tips": "Bu kameranın kayıt tutma ayarları kapsamında manuel olarak bir olay başlatın.", + "tips": "Bu kameranın kayıt saklama ayarlarına göre anlık bir görüntü indirin veya manuel bir olay başlatın.", "playInBackground": { "label": "Arka planda oynat", "desc": "Yayını oynatıcı arkadayken de devam ettirmek için bu seçeneği açın." @@ -167,5 +167,11 @@ "transcription": { "enable": "Canlı Ses Çözümlemeyi Aç", "disable": "Canlı Ses Çözümlemeyi Kapat" + }, + "snapshot": { + "takeSnapshot": "Anlık Ekran Görüntüsünü İndir", + "noVideoSource": "Anlık görüntü için kullanılabilir bir video kaynağı bulunamadı.", + "captureFailed": "Anlık görüntü yakalanamadı.", + "downloadStarted": "Anlık görüntü indirme işlemi başlatıldı." } } diff --git a/web/public/locales/tr/views/settings.json b/web/public/locales/tr/views/settings.json index 714f6a4fc..a9c801962 100644 --- a/web/public/locales/tr/views/settings.json +++ b/web/public/locales/tr/views/settings.json @@ -10,7 +10,9 @@ "object": "Hata Ayıklama - Frigate", "general": "Genel Ayarlar - Frigate", "notifications": "Bildirim Ayarları - Frigate", - "enrichments": "Zenginleştirme Ayarları - Frigate" + "enrichments": "Zenginleştirme Ayarları - Frigate", + "cameraManagement": "Kameraları Yönet - Frigate", + "cameraReview": "Kamera İnceleme Ayarları - Frigate" }, "menu": { "masksAndZones": "Maskeler / Alanlar", @@ -23,7 +25,10 @@ "debug": "Hata Ayıklama", "cameras": "Kamera Ayarları", "enrichments": "Zenginleştirmeler", - "triggers": "Tetikler" + "triggers": "Tetikler", + "cameraManagement": "Yönet", + "cameraReview": "İncele", + "roles": "Roller" }, "general": { "title": "Genel Ayarlar", @@ -36,7 +41,11 @@ "label": "Alarm Videolarını Oynat", "desc": "Varsayılan olarak canlı görüntü panelinde gösterilen son alarmlar ufak videolar olarak oynatılır. Bu tarayıcı/cihazda video yerine sabit resim göstermek için bu seçeneği kapatın." }, - "title": "Canlı Görüntü Paneli" + "title": "Canlı Görüntü Paneli", + "displayCameraNames": { + "label": "Kamera Adlarını Her Zaman Göster", + "desc": "Çok kameralı canlı izleme panelinde, kamera adlarını her zaman bir etiket içinde göster." + } }, "storedLayouts": { "desc": "Kamera grubundaki kameraların düzenini kameraları sürükleyerek ve büyüterek/küçülterek değiştirebilirsiniz. Düzen bilgisi tarayıcınızda depolanır.", diff --git a/web/public/locales/uk/common.json b/web/public/locales/uk/common.json index d9fd097cd..a3338a223 100644 --- a/web/public/locales/uk/common.json +++ b/web/public/locales/uk/common.json @@ -106,7 +106,7 @@ "enable": "Увімкнути", "disabled": "Вимкнено", "disable": "Вимкнути", - "save": "Зберігати", + "save": "Зберегти", "download": "Завантажити", "info": "Інфо", "suspended": "Призупинено", @@ -238,7 +238,10 @@ } }, "label": { - "back": "Повернутись" + "back": "Повернутись", + "hide": "Приховати {{item}}", + "show": "Показати {{item}}", + "ID": "ID" }, "toast": { "save": { @@ -282,5 +285,14 @@ "readTheDocumentation": "Прочитати документацію", "information": { "pixels": "{{area}}пикс" + }, + "list": { + "two": "{{0}} і {{1}}", + "many": "{{items}}, і {{last}}", + "separatorWithSpace": ", " + }, + "field": { + "optional": "Необов'язково", + "internalID": "Внутрішній ідентифікатор, який Frigate використовує в конфігурації та базі даних" } } diff --git a/web/public/locales/uk/components/dialog.json b/web/public/locales/uk/components/dialog.json index e6d8f3298..762eea9ed 100644 --- a/web/public/locales/uk/components/dialog.json +++ b/web/public/locales/uk/components/dialog.json @@ -57,7 +57,7 @@ "endTimeMustAfterStartTime": "Час закінчення повинен бути після часу початку", "noVaildTimeSelected": "Не вибрано допустимий діапазон часу" }, - "success": "Експорт успішно запущено. Файл доступний у теці /exports." + "success": "Експорт успішно розпочато. Перегляньте файл на сторінці експорту." }, "fromTimeline": { "saveExport": "Зберегти експорт", @@ -117,6 +117,7 @@ "search": { "placeholder": "Пошук за міткою або підміткою..." }, - "noImages": "Для цієї камери не знайдено мініатюр" + "noImages": "Для цієї камери не знайдено мініатюр", + "unknownLabel": "Збережене зображення тригера" } } diff --git a/web/public/locales/uk/views/classificationModel.json b/web/public/locales/uk/views/classificationModel.json index 0967ef424..943aebba3 100644 --- a/web/public/locales/uk/views/classificationModel.json +++ b/web/public/locales/uk/views/classificationModel.json @@ -1 +1,164 @@ -{} +{ + "documentTitle": "Моделі класифікації", + "button": { + "deleteClassificationAttempts": "Видалити зображення класифікації", + "renameCategory": "Перейменувати клас", + "deleteCategory": "Видалити клас", + "deleteImages": "Видалити зображення", + "trainModel": "Модель поїзда", + "addClassification": "Додати класифікацію", + "deleteModels": "Видалити моделі", + "editModel": "Редагувати модель" + }, + "toast": { + "success": { + "deletedCategory": "Видалений клас", + "deletedImage": "Видалені зображення", + "categorizedImage": "Зображення успішно класифіковано", + "trainedModel": "Успішно навчена модель.", + "trainingModel": "Успішно розпочато навчання моделі.", + "deletedModel_one": "Успішно видалено модель {{count}}", + "deletedModel_few": "Успішно видалено моделей {{count}}", + "deletedModel_many": "Успішно видалено моделі {{count}}", + "updatedModel": "Конфігурацію моделі успішно оновлено" + }, + "error": { + "deleteImageFailed": "Не вдалося видалити: {{errorMessage}}", + "deleteCategoryFailed": "Не вдалося видалити клас: {{errorMessage}}", + "categorizeFailed": "Не вдалося класифікувати зображення: {{errorMessage}}", + "trainingFailed": "Не вдалося розпочати навчання моделі: {{errorMessage}}", + "deleteModelFailed": "Не вдалося видалити модель: {{errorMessage}}", + "updateModelFailed": "Не вдалося оновити модель: {{errorMessage}}" + } + }, + "deleteCategory": { + "title": "Видалити клас", + "desc": "Ви впевнені, що хочете видалити клас {{name}}? Це назавжди видалить усі пов'язані зображення та вимагатиме повторного навчання моделі." + }, + "deleteDatasetImages": { + "title": "Видалити зображення набору даних", + "desc": "Ви впевнені, що хочете видалити {{count}} зображень з {{dataset}}? Цю дію неможливо скасувати, вона вимагатиме повторного навчання моделі." + }, + "deleteTrainImages": { + "title": "Видалити зображення поїздів", + "desc": "Ви впевнені, що хочете видалити {{count}} зображень? Цю дію не можна скасувати." + }, + "renameCategory": { + "title": "Перейменувати клас", + "desc": "Введіть нову назву для {{name}}. Вам потрібно буде перенавчити модель, щоб зміна назви набула чинності." + }, + "description": { + "invalidName": "Недійсне ім'я. Ім'я може містити лише літери, цифри, пробіли, апострофи, символи підкреслення та дефіси." + }, + "train": { + "title": "Нещодавні класифікації", + "titleShort": "Нещодавні", + "aria": "Виберіть останні класифікації" + }, + "categories": "Заняття", + "createCategory": { + "new": "Створити новий клас" + }, + "categorizeImageAs": "Класифікувати зображення як:", + "categorizeImage": "Класифікувати зображення", + "noModels": { + "object": { + "title": "Без моделей класифікації об'єктів", + "description": "Створіть власну модель для класифікації виявлених об'єктів.", + "buttonText": "Створення об'єктної моделі" + }, + "state": { + "title": "Без моделей класифікації штатів", + "description": "Створіть власну модель для моніторингу та класифікації змін стану в певних областях камери.", + "buttonText": "Створити модель стану" + } + }, + "wizard": { + "title": "Створити нову класифікацію", + "steps": { + "nameAndDefine": "Назва та визначення", + "stateArea": "Площа штату", + "chooseExamples": "Виберіть приклади" + }, + "step1": { + "description": "Моделі станів відстежують зміни в зонах дії фіксованих камер (наприклад, відкриття/закриття дверей). Моделі об'єктів додають класифікації до виявлених об'єктів (наприклад, відомі тварини, кур'єри тощо).", + "name": "Ім'я", + "namePlaceholder": "Введіть назву моделі...", + "type": "Тип", + "typeState": "Штат", + "typeObject": "Об'єкт", + "objectLabel": "Мітка об'єкта", + "objectLabelPlaceholder": "Виберіть тип об'єкта...", + "classificationType": "Тип класифікації", + "classificationTypeTip": "Дізнайтеся про типи класифікації", + "classificationTypeDesc": "Підмітки додають додатковий текст до мітки об’єкта (наприклад, «Особа: UPS»). Атрибути – це метадані для пошуку, що зберігаються окремо в метаданих об’єкта.", + "classificationSubLabel": "Підмітка", + "classificationAttribute": "Атрибут", + "classes": "Заняття", + "classesTip": "Дізнайтеся про заняття", + "classesStateDesc": "Визначте різні стани, в яких може перебувати зона вашої камери. Наприклад: «відкрито» та «закрито» для гаражних воріт.", + "classesObjectDesc": "Визначте різні категорії для класифікації виявлених об'єктів. Наприклад: «доставник», «мешканець», «незнайомець» для класифікації осіб.", + "classPlaceholder": "Введіть назву класу...", + "errors": { + "nameRequired": "Назва моделі обов'язкова", + "nameLength": "Назва моделі має містити не більше 64 символів", + "nameOnlyNumbers": "Назва моделі не може містити лише цифри", + "classRequired": "Потрібно хоча б 1 заняття", + "classesUnique": "Назви класів мають бути унікальними", + "stateRequiresTwoClasses": "Моделі станів вимагають щонайменше 2 класів", + "objectLabelRequired": "Будь ласка, виберіть мітку об'єкта", + "objectTypeRequired": "Будь ласка, виберіть тип класифікації" + }, + "states": "Штати" + }, + "step2": { + "description": "Виберіть камери та визначте область для моніторингу для кожної камери. Модель класифікуватиме стан цих областей.", + "cameras": "Камери", + "selectCamera": "Виберіть Камеру", + "noCameras": "Натисніть +, щоб додати камери", + "selectCameraPrompt": "Виберіть камеру зі списку, щоб визначити її зону спостереження" + }, + "step3": { + "selectImagesPrompt": "Виберіть усі зображення з: {{className}}", + "selectImagesDescription": "Натисніть на зображення, щоб вибрати їх. Натисніть «Продовжити», коли закінчите з цим уроком.", + "generating": { + "title": "Створення зразків зображень", + "description": "Фрегат отримує типові зображення з ваших записів. Це може зайняти деякий час..." + }, + "training": { + "title": "Модель навчання", + "description": "Ваша модель навчається у фоновому режимі. Закрийте це діалогове вікно, і ваша модель почне працювати, щойно навчання буде завершено." + }, + "retryGenerate": "Генерація повторних спроб", + "noImages": "Немає згенерованих зразків зображень", + "classifying": "Класифікація та навчання...", + "trainingStarted": "Навчання розпочалося успішно", + "errors": { + "noCameras": "Немає налаштованих камер", + "noObjectLabel": "Мітку об'єкта не вибрано", + "generateFailed": "Не вдалося створити приклади: {{error}}", + "generationFailed": "Помилка генерації. Будь ласка, спробуйте ще раз.", + "classifyFailed": "Не вдалося класифікувати зображення: {{error}}" + }, + "generateSuccess": "Зразки зображень успішно створено" + } + }, + "deleteModel": { + "title": "Видалити модель класифікації", + "single": "Ви впевнені, що хочете видалити {{name}}? Це назавжди видалить усі пов’язані дані, включаючи зображення та дані навчання. Цю дію не можна скасувати.", + "desc": "Ви впевнені, що хочете видалити {{count}} модель(і)? Це назавжди видалить усі пов’язані дані, включаючи зображення та навчальні дані. Цю дію не можна скасувати." + }, + "menu": { + "objects": "Об'єкти", + "states": "Стани" + }, + "details": { + "scoreInfo": "Оцінка представляє середню достовірність класифікації для всіх виявлень цього об'єкта." + }, + "edit": { + "title": "Редагувати модель класифікації", + "descriptionState": "Відредагуйте класи для цієї моделі класифікації штатів. Зміни вимагатимуть перенавчання моделі.", + "descriptionObject": "Відредагуйте тип об'єкта та тип класифікації для цієї моделі класифікації об'єктів.", + "stateClassesInfo": "Примітка: Зміна класів станів вимагає перенавчання моделі з використанням оновлених класів." + } +} diff --git a/web/public/locales/uk/views/events.json b/web/public/locales/uk/views/events.json index 7aa18b604..993933d6c 100644 --- a/web/public/locales/uk/views/events.json +++ b/web/public/locales/uk/views/events.json @@ -43,10 +43,17 @@ "trackedObject_one": "об'єкт", "trackedObject_other": "об'єкти", "noObjectDetailData": "Детальні дані про об'єкт недоступні.", - "label": "Деталь" + "label": "Деталь", + "settings": "Налаштування детального перегляду", + "alwaysExpandActive": { + "title": "Завжди розгортати активне", + "desc": "Завжди розгортайте деталі об'єкта активного елемента огляду, якщо вони доступні." + } }, "objectTrack": { "trackedPoint": "Відстежувана Точка", "clickToSeek": "Натисніть, щоб перейти до цього часу" - } + }, + "zoomIn": "Збільшити масштаб", + "zoomOut": "Зменшити масштаб" } diff --git a/web/public/locales/uk/views/explore.json b/web/public/locales/uk/views/explore.json index f4691c2ee..5d90544a6 100644 --- a/web/public/locales/uk/views/explore.json +++ b/web/public/locales/uk/views/explore.json @@ -168,7 +168,7 @@ "dialog": { "confirmDelete": { "title": "Підтвердити видалення", - "desc": "Видалення цього відстежуваного об’єкта призведе до видалення знімка, будь-яких збережених вбудованих елементів та будь-яких пов’язаних записів життєвого циклу об’єкта. Записані кадри цього відстежуваного об’єкта в режимі перегляду історії НЕ будуть видалені.

    Ви впевнені, що хочете продовжити?" + "desc": "Видалення цього відстежуваного об'єкта призведе до видалення знімка, усіх збережених вбудованих даних та усіх пов'язаних записів деталей відстеження. Записані кадри цього відстежуваного об'єкта в режимі перегляду історії НЕ будуть видалені.

    Ви впевнені, що хочете продовжити?" } }, "itemMenu": { @@ -206,6 +206,16 @@ "audioTranscription": { "label": "Транскрибувати", "aria": "Запит на аудіотранскрипцію" + }, + "viewTrackingDetails": { + "label": "Переглянути деталі відстеження", + "aria": "Показати деталі відстеження" + }, + "showObjectDetails": { + "label": "Показати шлях до об'єкта" + }, + "hideObjectDetails": { + "label": "Приховати шлях до об'єкта" } }, "noTrackedObjects": "Відстежуваних об'єктів не знайдено", @@ -216,7 +226,8 @@ "details": "деталі", "snapshot": "знімок", "video": "відео", - "object_lifecycle": "життєвий цикл об'єкта" + "object_lifecycle": "життєвий цикл об'єкта", + "thumbnail": "мініатюра" }, "exploreMore": "Дослідіть більше об'єктів {{label}}", "aiAnalysis": { @@ -224,5 +235,53 @@ }, "concerns": { "label": "Проблеми" + }, + "trackingDetails": { + "title": "Деталі відстеження", + "noImageFound": "Для цієї позначки часу не знайдено зображення.", + "createObjectMask": "Створити маску об'єкта", + "adjustAnnotationSettings": "Налаштування параметрів анотацій", + "scrollViewTips": "Натисніть, щоб переглянути важливі моменти життєвого циклу цього об'єкта.", + "autoTrackingTips": "Положення обмежувальних рамок будуть неточними для камер з автоматичним відстеженням.", + "count": "{{first}} з {{second}}", + "trackedPoint": "Відстежувана точка", + "lifecycleItemDesc": { + "visible": "Виявлено {{label}}", + "entered_zone": "{{label}} увійшов до {{zones}}", + "active": "{{label}} став активним", + "stationary": "{{label}} став нерухомим", + "attribute": { + "faceOrLicense_plate": "Виявлено атрибут {{attribute}} для {{label}}", + "other": "{{label}} розпізнано як {{attribute}}" + }, + "gone": "{{label}} залишилося", + "heard": "{{label}} почув(ла)", + "external": "Виявлено {{label}}", + "header": { + "zones": "Зони", + "ratio": "Співвідношення", + "area": "Площа" + } + }, + "annotationSettings": { + "title": "Налаштування анотацій", + "showAllZones": { + "title": "Показати всі зони", + "desc": "Завжди показувати зони на кадрах, де об'єкти увійшли в зону." + }, + "offset": { + "label": "Зсув анотації", + "desc": "Ці дані надходять із каналу виявлення вашої камери, але накладаються на зображення з каналу запису. Малоймовірно, що ці два потоки будуть ідеально синхронізовані. Як результат, обмежувальна рамка та відеоматеріал не будуть ідеально збігатися. Ви можете використовувати це налаштування, щоб змістити анотації вперед або назад у часі, щоб краще узгодити їх із записаним відеоматеріалом.", + "millisecondsToOffset": "Мілісекунди для зміщення виявлених анотацій. За замовчуванням: 0", + "tips": "ПІДКАЗКА: Уявіть, що є кліп події, на якому людина йде зліва направо. Якщо обмежувальний прямокутник часової шкали події постійно знаходиться ліворуч від людини, то значення слід зменшити. Аналогічно, якщо людина йде зліва направо, а обмежувальний прямокутник постійно знаходиться попереду людини, то значення слід збільшити.", + "toast": { + "success": "Зміщення анотації для {{camera}} збережено у файлі конфігурації. Перезапустіть Frigate, щоб застосувати зміни." + } + } + }, + "carousel": { + "previous": "Попередній слайд", + "next": "Наступний слайд" + } } } diff --git a/web/public/locales/uk/views/exports.json b/web/public/locales/uk/views/exports.json index 55ee0e3e8..6b4108f4d 100644 --- a/web/public/locales/uk/views/exports.json +++ b/web/public/locales/uk/views/exports.json @@ -13,5 +13,11 @@ "error": { "renameExportFailed": "Не вдалося перейменувати експорт: {{errorMessage}}" } + }, + "tooltip": { + "shareExport": "Поділитися експортом", + "downloadVideo": "Завантажити відео", + "editName": "Редагувати ім'я", + "deleteExport": "Видалити експорт" } } diff --git a/web/public/locales/uk/views/faceLibrary.json b/web/public/locales/uk/views/faceLibrary.json index 855b41fd3..621dc0e8b 100644 --- a/web/public/locales/uk/views/faceLibrary.json +++ b/web/public/locales/uk/views/faceLibrary.json @@ -71,7 +71,7 @@ "trainFaceAs": "Тренуйте обличчя як:", "trainFace": "Обличчя поїзда", "description": { - "addFace": "Покрокові інструкції з додавання нової колекції до Бібліотеки облич.", + "addFace": "Додайте нову колекцію до Бібліотеки облич, завантаживши своє перше зображення.", "placeholder": "Введіть назву для цієї колекції", "invalidName": "Недійсне ім'я. Ім'я може містити лише літери, цифри, пробіли, апострофи, символи підкреслення та дефіси." }, diff --git a/web/public/locales/uk/views/settings.json b/web/public/locales/uk/views/settings.json index 7884bfbc6..965cc8440 100644 --- a/web/public/locales/uk/views/settings.json +++ b/web/public/locales/uk/views/settings.json @@ -488,6 +488,10 @@ "playAlertVideos": { "label": "Відтворити відео зі сповіщеннями", "desc": "За замовчуванням останні сповіщення на панелі керування Live відтворюються як невеликі відеозаписи, що циклічно відтворюються. Вимкніть цю опцію, щоб відображати лише статичне зображення останніх сповіщень на цьому пристрої/у браузері." + }, + "displayCameraNames": { + "label": "Завжди показувати назви камер", + "desc": "Завжди відображати назви камер у чіпі на панелі керування режимом живого перегляду з кількох камер." } }, "storedLayouts": { @@ -745,7 +749,7 @@ "triggers": { "documentTitle": "Тригери", "management": { - "title": "Управління тригерами", + "title": "Тригери", "desc": "Керуйте тригерами для {{camera}}. Використовуйте тип мініатюри для спрацьовування на схожих мініатюрах до вибраного об’єкта відстеження, а тип опису – для спрацьовування на схожих описах до вказаного вами тексту." }, "addTrigger": "Додати Тригер", @@ -766,7 +770,9 @@ }, "actions": { "alert": "Позначити як сповіщення", - "notification": "Надіслати сповіщення" + "notification": "Надіслати сповіщення", + "sub_label": "Додати підмітку", + "attribute": "Додати атрибут" }, "dialog": { "createTrigger": { @@ -784,25 +790,28 @@ "form": { "name": { "title": "Ім'я", - "placeholder": "Введіть назву тригера", + "placeholder": "Назвіть цей тригер", "error": { - "minLength": "Ім'я має містити щонайменше 2 символи.", - "invalidCharacters": "Ім'я може містити лише літери, цифри, символи підкреслення та дефіси.", + "minLength": "Поле має містити щонайменше 2 символи.", + "invalidCharacters": "Поле може містити лише літери, цифри, символи підкреслення та дефіси.", "alreadyExists": "Тригер із такою назвою вже існує для цієї камери." - } + }, + "description": "Введіть унікальну назву або опис, щоб ідентифікувати цей тригер" }, "enabled": { "description": "Увімкнути або вимкнути цей тригер" }, "type": { "title": "Тип", - "placeholder": "Виберіть тип тригера" + "placeholder": "Виберіть тип тригера", + "description": "Спрацьовує, коли виявляється схожий опис відстежуваного об'єкта", + "thumbnail": "Спрацьовує, коли виявляється мініатюра схожого відстежуваного об'єкта" }, "content": { "title": "Зміст", - "imagePlaceholder": "Виберіть зображення", + "imagePlaceholder": "Виберіть мініатюру", "textPlaceholder": "Введіть текстовий вміст", - "imageDesc": "Виберіть зображення, щоб запустити цю дію, коли буде виявлено схоже зображення.", + "imageDesc": "Відображаються лише 100 останніх мініатюр. Якщо ви не можете знайти потрібну мініатюру, перегляньте попередні об’єкти в розділі «Огляд» і налаштуйте тригер у меню.", "textDesc": "Введіть текст, щоб запустити цю дію, коли буде виявлено схожий опис відстежуваного об’єкта.", "error": { "required": "Контент обов'язковий." @@ -813,11 +822,12 @@ "error": { "min": "Поріг має бути щонайменше 0", "max": "Поріг має бути не більше 1" - } + }, + "desc": "Встановіть поріг подібності для цього тригера. Вищий поріг означає, що для спрацьовування тригера потрібна ближча відповідність." }, "actions": { "title": "Дії", - "desc": "За замовчуванням Frigate надсилає повідомлення MQTT для всіх тригерів. Виберіть додаткову дію, яку потрібно виконати, коли цей тригер спрацьовує.", + "desc": "За замовчуванням Frigate надсилає повідомлення MQTT для всіх тригерів. Підмітки додають назву тригера до мітки об'єкта. Атрибути – це метадані, які можна шукати, що зберігаються окремо в метаданих відстежуваного об'єкта.", "error": { "min": "Потрібно вибрати принаймні одну дію." } @@ -844,6 +854,23 @@ "semanticSearch": { "title": "Семантичний пошук вимкнено", "desc": "Для використання тригерів необхідно ввімкнути семантичний пошук." + }, + "wizard": { + "title": "Створити тригер", + "step1": { + "description": "Налаштуйте основні параметри для вашого тригера." + }, + "step2": { + "description": "Налаштуйте контент, який запускатиме цю дію." + }, + "step3": { + "description": "Налаштуйте поріг та дії для цього тригера." + }, + "steps": { + "nameAndType": "Ім'я та тип", + "configureData": "Налаштувати дані", + "thresholdAndActions": "Поріг та дії" + } } }, "roles": { @@ -861,7 +888,9 @@ "createRole": "Роль {{role}} успішно створена", "updateCameras": "Камери оновлено для ролі {{role}}", "deleteRole": "Роль {{role}} успішно видалено", - "userRolesUpdated": "Користувачів ({{count}}), яким призначено цю роль, оновлено до ролі «глядача», що має доступ до всіх камер." + "userRolesUpdated_one": "Користувачів ({{count}}), яким призначено цю роль, оновлено до ролі «глядача», що має доступ до всіх камер.", + "userRolesUpdated_few": "", + "userRolesUpdated_many": "" }, "error": { "createRoleFailed": "Не вдалося створити роль: {{errorMessage}}", @@ -1050,7 +1079,9 @@ }, "resolutionHigh": "Роздільна здатність {{resolution}} може призвести до збільшення використання ресурсів.", "resolutionLow": "Роздільна здатність {{resolution}} може бути занадто низькою для надійного виявлення малих об'єктів." - } + }, + "ffmpegModule": "Використовувати режим сумісності з потоками", + "ffmpegModuleDescription": "Якщо потік не завантажується після кількох спроб, спробуйте ввімкнути цю функцію. Коли вона ввімкнена, Frigate використовуватиме модуль ffmpeg з go2rtc. Це може забезпечити кращу сумісність з деякими потоками камер." } }, "cameraManagement": { diff --git a/web/public/locales/vi/components/auth.json b/web/public/locales/vi/components/auth.json index 3d942b9c2..bc664d59c 100644 --- a/web/public/locales/vi/components/auth.json +++ b/web/public/locales/vi/components/auth.json @@ -10,6 +10,7 @@ "loginFailed": "Đăng nhập không thành công", "unknownError": "Lỗi không xác định. Kiểm tra nhật ký.", "webUnknownError": "Lỗi không xác định. Kiểm tra nhật ký bảng điều khiển." - } + }, + "firstTimeLogin": "Lần đầu đăng nhập? Thông tin đăng nhập được in trong nhật ký (log) của Frigate." } } diff --git a/web/public/locales/vi/views/classificationModel.json b/web/public/locales/vi/views/classificationModel.json index 0967ef424..1f0cf85be 100644 --- a/web/public/locales/vi/views/classificationModel.json +++ b/web/public/locales/vi/views/classificationModel.json @@ -1 +1,20 @@ -{} +{ + "documentTitle": "Mô Hình Phân Loại", + "button": { + "deleteClassificationAttempts": "Xóa Hình Ảnh Phân Loại", + "renameCategory": "Đổi Tên Lớp", + "deleteCategory": "Xoá Lớp", + "deleteImages": "Xoá Hình Ảnh", + "trainModel": "Huấn Luyện Mô Hình", + "addClassification": "Thêm Phân Loại", + "deleteModels": "Xoá Mô Hình" + }, + "toast": { + "success": { + "deletedCategory": "Lớp Đã Bị Xoá", + "deletedImage": "Hình ảnh đã bị xóa", + "deletedModel_other": "Đã xóa thành công {{count}} mô hình", + "categorizedImage": "Phân Loại Hình Ảnh Thành Công" + } + } +} diff --git a/web/public/locales/vi/views/events.json b/web/public/locales/vi/views/events.json index c3bdad497..c85f6cfdc 100644 --- a/web/public/locales/vi/views/events.json +++ b/web/public/locales/vi/views/events.json @@ -36,5 +36,6 @@ "markAsReviewed": "Đánh dấu là đã xem xét", "markTheseItemsAsReviewed": "Đánh dấu các mục này là đã xem xét", "suspiciousActivity": "Hoạt động đáng ngờ", - "threateningActivity": "Hoạt động đe dọa" + "threateningActivity": "Hoạt động đe dọa", + "zoomIn": "Phóng To" } diff --git a/web/public/locales/vi/views/exports.json b/web/public/locales/vi/views/exports.json index 6206f5821..6ae992551 100644 --- a/web/public/locales/vi/views/exports.json +++ b/web/public/locales/vi/views/exports.json @@ -13,5 +13,10 @@ "error": { "renameExportFailed": "Đổi tên tệp xuất thất bại: {{errorMessage}}" } + }, + "tooltip": { + "shareExport": "Chia sẻ bản xuất", + "downloadVideo": "Tải video", + "editName": "Chỉnh sửa tên" } } diff --git a/web/public/locales/vi/views/settings.json b/web/public/locales/vi/views/settings.json index 03b17d4ae..267948102 100644 --- a/web/public/locales/vi/views/settings.json +++ b/web/public/locales/vi/views/settings.json @@ -9,7 +9,9 @@ "object": "Gỡ lỗi - Frigate", "general": "Cài đặt Chung - Frigate", "frigatePlus": "Cài đặt Frigate+ - Frigate", - "motionTuner": "Bộ tinh chỉnh Chuyển động - Frigate" + "motionTuner": "Bộ tinh chỉnh Chuyển động - Frigate", + "cameraManagement": "Quản Lý Camera - Frigate", + "cameraReview": "Cài Đặt Xem Lại Camera - Frigate" }, "notification": { "toast": { diff --git a/web/public/locales/yue_Hant/views/classificationModel.json b/web/public/locales/yue-Hant/views/classificationModel.json similarity index 100% rename from web/public/locales/yue_Hant/views/classificationModel.json rename to web/public/locales/yue-Hant/views/classificationModel.json diff --git a/web/public/locales/yue-Hant/views/settings.json b/web/public/locales/yue-Hant/views/settings.json index 3e4e12073..34982abb4 100644 --- a/web/public/locales/yue-Hant/views/settings.json +++ b/web/public/locales/yue-Hant/views/settings.json @@ -753,7 +753,7 @@ "createRole": "角色 {{role}} 已成功建立", "updateCameras": "角色 {{role}} 的鏡頭已更新", "deleteRole": "角色 {{role}} 已成功刪除", - "userRolesUpdated": "{{count}} 位使用者被更新為「觀察者」角色,將可存取所有鏡頭。" + "userRolesUpdated_other": "{{count}} 位使用者被更新為「觀察者」角色,將可存取所有鏡頭。" }, "error": { "createRoleFailed": "建立角色失敗:{{errorMessage}}", diff --git a/web/public/locales/zh-CN/common.json b/web/public/locales/zh-CN/common.json index 55632e768..d4e3aba21 100644 --- a/web/public/locales/zh-CN/common.json +++ b/web/public/locales/zh-CN/common.json @@ -283,7 +283,8 @@ }, "list": { "two": "{{0}} 和 {{1}}", - "many": "{{items}} 以及 {{last}}" + "many": "{{items}} 以及 {{last}}", + "separatorWithSpace": ", " }, "field": { "optional": "可选", diff --git a/web/public/locales/zh-Hans/views/classificationModel.json b/web/public/locales/zh-CN/views/classificationModel.json similarity index 80% rename from web/public/locales/zh-Hans/views/classificationModel.json rename to web/public/locales/zh-CN/views/classificationModel.json index 1714168fc..6d59c1431 100644 --- a/web/public/locales/zh-Hans/views/classificationModel.json +++ b/web/public/locales/zh-CN/views/classificationModel.json @@ -5,7 +5,10 @@ "renameCategory": "重命名类别", "deleteCategory": "删除类别", "deleteImages": "删除图片", - "trainModel": "训练模型" + "trainModel": "训练模型", + "addClassification": "添加分类", + "deleteModels": "删除模型", + "editModel": "编辑模型" }, "toast": { "success": { @@ -13,13 +16,17 @@ "deletedImage": "删除图片", "categorizedImage": "成功分类图片", "trainedModel": "训练模型成功。", - "trainingModel": "已开始训练模型。" + "trainingModel": "已开始训练模型。", + "deletedModel_other": "已删除 {{count}} 个模型", + "updatedModel": "已更新模型配置" }, "error": { "deleteImageFailed": "删除失败:{{errorMessage}}", "deleteCategoryFailed": "删除类别失败:{{errorMessage}}", "categorizeFailed": "图片分类失败:{{errorMessage}}", - "trainingFailed": "开始训练模型失败:{{errorMessage}}" + "trainingFailed": "开始训练模型失败:{{errorMessage}}", + "deleteModelFailed": "删除模型失败:{{errorMessage}}", + "updateModelFailed": "更新模型失败:{{errorMessage}}" } }, "deleteCategory": { @@ -43,7 +50,8 @@ }, "train": { "title": "最近分类记录", - "aria": "选择最近分类记录" + "aria": "选择最近分类记录", + "titleShort": "最近" }, "categories": "类别", "createCategory": { @@ -98,7 +106,8 @@ "stateRequiresTwoClasses": "状态模型至少需要两个类别", "objectLabelRequired": "请选择一个目标标签", "objectTypeRequired": "请选择一个目标标签" - } + }, + "states": "状态" }, "step2": { "description": "选择摄像头,并为摄像头定义要监控的区域。模型将对这些区域的状态进行分类。", @@ -131,5 +140,23 @@ }, "generateSuccess": "样本图片生成成功" } + }, + "deleteModel": { + "title": "删除分类模型", + "single": "你确定要删除 {{name}} 吗?此操作将永久删除所有相关数据,包括图片和训练数据,且无法撤销。", + "desc": "你确定要删除 {{count}} 个模型吗?此操作将永久删除所有相关数据,包括图片和训练数据,且无法撤销。" + }, + "menu": { + "objects": "目标", + "states": "状态" + }, + "details": { + "scoreInfo": "得分表示该目标所有检测结果的平均分类置信度。" + }, + "edit": { + "title": "编辑分类模型", + "descriptionState": "编辑此状态分类模型的类别;更改后需要重新训练模型。", + "descriptionObject": "编辑此目标分类模型的目标类型和分类类型。", + "stateClassesInfo": "注意:更改状态类别后需使用更新后的类别重新训练模型。" } } diff --git a/web/public/locales/zh-CN/views/events.json b/web/public/locales/zh-CN/views/events.json index a598e68ba..8269da7d7 100644 --- a/web/public/locales/zh-CN/views/events.json +++ b/web/public/locales/zh-CN/views/events.json @@ -44,10 +44,17 @@ "trackedObject_one": "目标或物体", "trackedObject_other": "目标或物体", "noObjectDetailData": "没有目标详细信息。", - "label": "详细信息" + "label": "详细信息", + "settings": "详细视图设置", + "alwaysExpandActive": { + "title": "始终展开当前项", + "desc": "在可用情况下,将始终展开当前核查项的对象详细信息。" + } }, "objectTrack": { "trackedPoint": "追踪点", "clickToSeek": "点击从该时间进行寻找" - } + }, + "zoomIn": "放大", + "zoomOut": "缩小" } diff --git a/web/public/locales/zh-CN/views/explore.json b/web/public/locales/zh-CN/views/explore.json index fac329f39..45dcd46e8 100644 --- a/web/public/locales/zh-CN/views/explore.json +++ b/web/public/locales/zh-CN/views/explore.json @@ -34,7 +34,8 @@ "details": "详情", "snapshot": "快照", "video": "视频", - "object_lifecycle": "目标全周期" + "object_lifecycle": "目标全周期", + "thumbnail": "缩略图" }, "objectLifecycle": { "title": "目标全周期", @@ -236,7 +237,7 @@ "noImageFound": "在该时间内没找到图片。", "createObjectMask": "创建目标遮罩", "adjustAnnotationSettings": "调整注释设置", - "scrollViewTips": "滚动以查看该目标全周期中的关键时刻。", + "scrollViewTips": "点击以查看该目标全周期中的关键时刻。", "autoTrackingTips": "自动追踪摄像头的边框定位可能不准确。", "count": "{{first}} / {{second}}", "trackedPoint": "追踪点", @@ -266,7 +267,7 @@ }, "offset": { "label": "标记偏移量", - "desc": "此数据来自摄像头的检测视频流,但叠加在录制视频流的图像上。由于两个视频流通常不会完全同步,因此边框与画面可能无法完全对齐。不过,可以使用 annotation_offset 字段进行调整。", + "desc": "此数据来自摄像头的检测视频流,但叠加在录制视频流的画面上。两个视频流可能不会完全同步,因此边框与画面可能无法完全对齐。可以使用此设置将标记在时间轴上向前或向后偏移,以更好地与录制画面对齐。", "millisecondsToOffset": "用于偏移检测标记的毫秒数。 默认值:0", "tips": "提示:假设有一段人从左向右走的事件录制,如果事件时间轴中的边框始终在人的左侧(即后方),则应该减小偏移值;反之,如果边框始终领先于人物,则应增大偏移值。", "toast": { diff --git a/web/public/locales/zh-CN/views/settings.json b/web/public/locales/zh-CN/views/settings.json index 255587bfe..a12350c14 100644 --- a/web/public/locales/zh-CN/views/settings.json +++ b/web/public/locales/zh-CN/views/settings.json @@ -51,6 +51,10 @@ "playAlertVideos": { "label": "播放警报视频", "desc": "默认情况下,实时监控页面上的最新警报会以一小段循环视频的形式进行播放。禁用此选项将仅显示浏览器本地缓存的静态图片。" + }, + "displayCameraNames": { + "label": "始终显示摄像头名称", + "desc": "在有多摄像头情况下的实时监控页面,将始终显示摄像头名称标签。" } }, "storedLayouts": { @@ -761,7 +765,9 @@ }, "actions": { "alert": "标记为警报", - "notification": "发送通知" + "notification": "发送通知", + "sub_label": "添加子标签", + "attribute": "添加属性" }, "dialog": { "createTrigger": { @@ -816,7 +822,7 @@ }, "actions": { "title": "动作", - "desc": "默认情况下,Frigate 会为所有触发器发送 MQTT 消息。请选择此触发器触发时需要执行的附加操作。", + "desc": "默认情况下,Frigate 会为所有触发器发送 MQTT 消息。子标签会将触发器名称添加到对象标签中。属性是可搜索的元数据,独立存储在追踪对象的元数据中。", "error": { "min": "必须至少选择一项动作。" } @@ -881,7 +887,7 @@ "createRole": "权限组 {{role}} 创建成功", "updateCameras": "已更新摄像头至 {{role}} 权限组", "deleteRole": "已删除 {{role}} 权限组", - "userRolesUpdated": "已将分配到此权限组的 {{count}} 位用户更新为 “成员”,该权限组可访问所有摄像头。" + "userRolesUpdated_other": "已将分配到此权限组的 {{count}} 位用户更新为 “成员”,该权限组可访问所有摄像头。" }, "error": { "createRoleFailed": "创建权限组失败:{{errorMessage}}", @@ -1066,7 +1072,9 @@ }, "resolutionHigh": "使用 {{resolution}} 分辨率可能会导致占用更多的系统资源。", "resolutionLow": "使用 {{resolution}} 分辨率可能过低,难以检测较小的物体。" - } + }, + "ffmpegModule": "使用视频流兼容模式", + "ffmpegModuleDescription": "如果多次尝试后视频流仍无法加载,可以尝试启用此功能。启用后,Frigate 将使用集成 go2rtc 的 ffmpeg 模块,这可能会提高与某些摄像头视频流的兼容性。" } }, "cameraManagement": { diff --git a/web/public/locales/zh-Hant/views/classificationModel.json b/web/public/locales/zh-Hant/views/classificationModel.json new file mode 100644 index 000000000..1371f9212 --- /dev/null +++ b/web/public/locales/zh-Hant/views/classificationModel.json @@ -0,0 +1,8 @@ +{ + "toast": { + "success": { + "deletedImage": "已刪除的圖片", + "deletedModel_other": "成功刪除 {{count}} 個模型" + } + } +} diff --git a/web/public/locales/zh-Hant/views/events.json b/web/public/locales/zh-Hant/views/events.json index 8571ea39f..3a22512af 100644 --- a/web/public/locales/zh-Hant/views/events.json +++ b/web/public/locales/zh-Hant/views/events.json @@ -36,5 +36,7 @@ "camera": "鏡頭", "detected": "已偵測", "suspiciousActivity": "可疑的活動", - "threateningActivity": "有威脅性的活動" + "threateningActivity": "有威脅性的活動", + "zoomIn": "放大", + "zoomOut": "縮小" } diff --git a/web/public/locales/zh_Hant/views/classificationModel.json b/web/public/locales/zh_Hant/views/classificationModel.json deleted file mode 100644 index 0967ef424..000000000 --- a/web/public/locales/zh_Hant/views/classificationModel.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/web/src/components/card/ClassificationCard.tsx b/web/src/components/card/ClassificationCard.tsx index bde452770..cd7d89827 100644 --- a/web/src/components/card/ClassificationCard.tsx +++ b/web/src/components/card/ClassificationCard.tsx @@ -217,9 +217,7 @@ export function GroupedClassificationCard({ }); if (!best) { - // select an item from the middle of the time series as this usually correlates - // to a more representative image than the first or last - return group.at(Math.floor(group.length / 2)); + return group.at(-1); } const bestTyped: ClassificationItemData = best; @@ -230,7 +228,7 @@ export function GroupedClassificationCard({ ? event.sub_label : t(noClassificationLabel) : bestTyped.name, - score: event?.data?.sub_label_score || bestTyped.score, + score: event?.data?.sub_label_score, }; }, [group, event, noClassificationLabel, t]); diff --git a/web/src/components/card/ReviewCard.tsx b/web/src/components/card/ReviewCard.tsx index 6337ac4a9..8fc4024db 100644 --- a/web/src/components/card/ReviewCard.tsx +++ b/web/src/components/card/ReviewCard.tsx @@ -38,6 +38,7 @@ import { Button, buttonVariants } from "../ui/button"; import { Trans, useTranslation } from "react-i18next"; import { cn } from "@/lib/utils"; import { LuCircle } from "react-icons/lu"; +import { MdAutoAwesome } from "react-icons/md"; type ReviewCardProps = { event: ReviewSegment; @@ -164,29 +165,33 @@ export default function ReviewCard({
    -
    - <> - - {event.data.objects.map((object) => { - return getIconForLabel( - object, - "size-3 text-primary dark:text-white", - ); - })} - {event.data.audio.map((audio) => { - return getIconForLabel( - audio, - "size-3 text-primary dark:text-white", - ); - })} - +
    + +
    + {event.data.objects.map((object, idx) => ( +
    + {getIconForLabel(object, "size-3 text-white")} +
    + ))} + {event.data.audio.map((audio, idx) => ( +
    + {getIconForLabel(audio, "size-3 text-white")} +
    + ))} +
    {formattedDate}
    @@ -213,6 +218,14 @@ export default function ReviewCard({ dense />
    + {event.data.metadata?.title && ( +
    + + + {event.data.metadata.title} + +
    + )}
    ); diff --git a/web/src/components/overlay/detail/AnnotationOffsetSlider.tsx b/web/src/components/overlay/detail/AnnotationOffsetSlider.tsx index 4af982da5..9f4851d42 100644 --- a/web/src/components/overlay/detail/AnnotationOffsetSlider.tsx +++ b/web/src/components/overlay/detail/AnnotationOffsetSlider.tsx @@ -121,13 +121,13 @@ export default function AnnotationOffsetSlider({ className }: Props) { - {t("trackingDetails.annotationSettings.offset.desc")} + {t("trackingDetails.annotationSettings.offset.tips")} diff --git a/web/src/components/overlay/detail/AnnotationSettingsPane.tsx b/web/src/components/overlay/detail/AnnotationSettingsPane.tsx index c180502f4..33bf10c5c 100644 --- a/web/src/components/overlay/detail/AnnotationSettingsPane.tsx +++ b/web/src/components/overlay/detail/AnnotationSettingsPane.tsx @@ -1,6 +1,3 @@ -import Heading from "@/components/ui/heading"; -import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; import { Event } from "@/types/event"; import { FrigateConfig } from "@/types/frigateConfig"; import { zodResolver } from "@hookform/resolvers/zod"; @@ -8,7 +5,6 @@ import axios from "axios"; import { useCallback, useState } from "react"; import { useForm } from "react-hook-form"; import { LuExternalLink } from "react-icons/lu"; -import { PiWarningCircle } from "react-icons/pi"; import { Link } from "react-router-dom"; import { toast } from "sonner"; import useSWR from "swr"; @@ -31,15 +27,11 @@ import { useDocDomain } from "@/hooks/use-doc-domain"; type AnnotationSettingsPaneProps = { event: Event; - showZones: boolean; - setShowZones: React.Dispatch>; annotationOffset: number; setAnnotationOffset: React.Dispatch>; }; export function AnnotationSettingsPane({ event, - showZones, - setShowZones, annotationOffset, setAnnotationOffset, }: AnnotationSettingsPaneProps) { @@ -140,26 +132,12 @@ export function AnnotationSettingsPane({ } return ( -
    - +
    +
    {t("trackingDetails.annotationSettings.title")} - -
    -
    - - -
    -
    - {t("trackingDetails.annotationSettings.showAllZones.desc")} -
    - + +
    ( - - - {t("trackingDetails.annotationSettings.offset.label")} - -
    -
    - -
    - - trackingDetails.annotationSettings.offset.desc - + +
    + + {t("trackingDetails.annotationSettings.offset.label")} + + + + trackingDetails.annotationSettings.offset.millisecondsToOffset + + +
    + {t("trackingDetails.annotationSettings.offset.tips")}
    -
    -
    + +
    +
    +
    - - - trackingDetails.annotationSettings.offset.millisecondsToOffset - -
    - {t("trackingDetails.annotationSettings.offset.tips")} -
    -
    -
    )} /> @@ -220,7 +192,9 @@ export function AnnotationSettingsPane({
    + + + + + + +
    + ); +} + +type DialogContentComponentProps = { + page: SearchTab; + search: SearchResult; + isDesktop: boolean; + apiHost: string; + config?: FrigateConfig; + searchTabs: SearchTab[]; + pageToggle: SearchTab; + setPageToggle: (v: SearchTab) => void; + setSearch: (s: SearchResult | undefined) => void; + setInputFocused: React.Dispatch>; + setSimilarity?: () => void; + isPopoverOpen: boolean; + setIsPopoverOpen: (open: boolean) => void; + dialogContainer: HTMLDivElement | null; +}; + +function DialogContentComponent({ + page, + search, + isDesktop, + apiHost, + config, + searchTabs, + pageToggle, + setPageToggle, + setSearch, + setInputFocused, + setSimilarity, + isPopoverOpen, + setIsPopoverOpen, + dialogContainer, +}: DialogContentComponentProps) { + if (page === "tracking_details") { + return ( + + ) : undefined + } + /> + ); + } + + // Snapshot page content + const snapshotElement = search.has_snapshot ? ( + + ) : ( +
    + +
    + ); + + if (isDesktop) { + return ( +
    +
    + {snapshotElement} +
    +
    + +
    + +
    +
    +
    + ); + } + + // mobile + return ( + <> + {snapshotElement} + + + ); +} + type SearchDetailDialogProps = { search?: SearchResult; page: SearchTab; @@ -91,7 +415,10 @@ type SearchDetailDialogProps = { setSearchPage: (page: SearchTab) => void; setSimilarity?: () => void; setInputFocused: React.Dispatch>; + onPrevious?: () => void; + onNext?: () => void; }; + export default function SearchDetailDialog({ search, page, @@ -99,6 +426,8 @@ export default function SearchDetailDialog({ setSearchPage, setSimilarity, setInputFocused, + onPrevious, + onNext, }: SearchDetailDialogProps) { const { t } = useTranslation(["views/explore", "views/faceLibrary"]); const { data: config } = useSWR("config", { @@ -117,11 +446,17 @@ export default function SearchDetailDialog({ // dialog and mobile page const [isOpen, setIsOpen] = useState(search != undefined); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const dialogContentRef = useRef(null); + const [dialogContainer, setDialogContainer] = useState( + null, + ); const handleOpenChange = useCallback( (open: boolean) => { setIsOpen(open); if (!open) { + setIsPopoverOpen(false); // short timeout to allow the mobile page animation // to complete before updating the state setTimeout(() => { @@ -132,12 +467,18 @@ export default function SearchDetailDialog({ [setSearch], ); + useLayoutEffect(() => { + setDialogContainer(dialogContentRef.current); + }, [isOpen, search?.id]); + useEffect(() => { if (search) { setIsOpen(search != undefined); } }, [search]); + // show/hide annotation settings is handled inside TabsWithActions + const searchTabs = useMemo(() => { if (!config || !search) { return []; @@ -163,46 +504,6 @@ export default function SearchDetailDialog({ } }, [pageToggle, searchTabs, setSearchPage]); - // Tabs component for reuse - const tabsComponent = ( - -
    - { - if (value) { - setPageToggle(value); - } - }} - > - {Object.values(searchTabs).map((item) => ( - - {item == "snapshot" && } - {item == "tracking_details" && } -
    - {item === "snapshot" - ? search?.has_snapshot - ? t("type.snapshot") - : t("type.thumbnail") - : t(`type.${item}`)} -
    -
    - ))} -
    - -
    -
    - ); - if (!search) { return; } @@ -227,174 +528,115 @@ export default function SearchDetailDialog({ onOpenChange={handleOpenChange} enableHistoryBack={true} > + {isDesktop && onPrevious && onNext && ( + +
    +
    + + + + + + {t("searchResult.previousTrackedObject")} + + + + + + + + + {t("searchResult.nextTrackedObject")} + + +
    +
    +
    + )} { + if (isPopoverOpen) { + e.preventDefault(); + } + const target = e.target as HTMLElement; + if (target.closest(".nav-button")) { + e.preventDefault(); + } + }} >
    {t("trackedObjectDetails")} {t("trackedObjectDetails")} +
    - {isDesktop ? ( - page === "tracking_details" ? ( - + - ) : ( -
    -
    - {page === "snapshot" && search.has_snapshot && ( - { - search.plus_id = "new_upload"; - }} - /> - )} - {page === "snapshot" && !search.has_snapshot && ( - - )} -
    -
    - {tabsComponent} -
    - {page == "snapshot" && ( - - )} -
    -
    -
    - ) - ) : ( - <> - -
    - { - if (value) { - setPageToggle(value); - } - }} - > - {Object.values(searchTabs).map((item) => ( - - {item == "snapshot" && } - {item == "tracking_details" && ( - - )} -
    - {t(`type.${item}`)} -
    -
    - ))} -
    - -
    -
    - {page == "snapshot" && ( - <> - {search.has_snapshot && ( - { - search.plus_id = "new_upload"; - }} - /> - )} - {page == "snapshot" && !search.has_snapshot && ( - - )} - - {t("type.details")} - - - - )} - {page == "tracking_details" && ( - - )} - +
    )} + + @@ -405,19 +647,19 @@ type ObjectDetailsTabProps = { search: SearchResult; config?: FrigateConfig; setSearch: (search: SearchResult | undefined) => void; - setSimilarity?: () => void; setInputFocused: React.Dispatch>; - showThumbnail?: boolean; }; function ObjectDetailsTab({ search, config, setSearch, - setSimilarity, setInputFocused, - showThumbnail = true, }: ObjectDetailsTabProps) { - const { t } = useTranslation(["views/explore", "views/faceLibrary"]); + const { t, i18n } = useTranslation([ + "views/explore", + "views/faceLibrary", + "components/dialog", + ]); const apiHost = useApiHost(); @@ -783,57 +1025,6 @@ function ObjectDetailsTab({ [search, apiHost, mutate, setSearch, t], ); - // face training - - const hasFace = useMemo(() => { - if (!config?.face_recognition.enabled || !search) { - return false; - } - - return search.data.attributes?.find((attr) => attr.label == "face"); - }, [config, search]); - - const { data: faceData } = useSWR(hasFace ? "faces" : null); - - const faceNames = useMemo( - () => - faceData ? Object.keys(faceData).filter((face) => face != "train") : [], - [faceData], - ); - - const onTrainFace = useCallback( - (trainName: string) => { - axios - .post(`/faces/train/${trainName}/classify`, { event_id: search.id }) - .then((resp) => { - if (resp.status == 200) { - toast.success( - t("toast.success.trainedFace", { ns: "views/faceLibrary" }), - { - position: "top-center", - }, - ); - } - }) - .catch((error) => { - const errorMessage = - error.response?.data?.message || - error.response?.data?.detail || - "Unknown error"; - toast.error( - t("toast.error.trainFailed", { - ns: "views/faceLibrary", - errorMessage, - }), - { - position: "top-center", - }, - ); - }); - }, - [search, t], - ); - // speech transcription const onTranscribe = useCallback(() => { @@ -862,35 +1053,159 @@ function ObjectDetailsTab({ }); }, [search, t]); + // frigate+ submission + + type SubmissionState = "reviewing" | "uploading" | "submitted"; + const [state, setState] = useState( + search?.plus_id ? "submitted" : "reviewing", + ); + + useEffect( + () => setState(search?.plus_id ? "submitted" : "reviewing"), + [search], + ); + + const onSubmitToPlus = useCallback( + async (falsePositive: boolean) => { + if (!search) { + return; + } + + falsePositive + ? axios.put(`events/${search.id}/false_positive`) + : axios.post(`events/${search.id}/plus`, { + include_annotation: 1, + }); + + setState("submitted"); + setSearch({ + ...search, + plus_id: "new_upload", + }); + }, + [search, setSearch], + ); + + const popoverContainerRef = useRef(null); return ( -
    +
    -
    -
    {t("details.label")}
    -
    - {getIconForLabel(search.label, "size-4 text-primary")} - {getTranslatedLabel(search.label)} - {search.sub_label && ` (${search.sub_label})`} - {isAdmin && search.end_time && ( - - - - { - setIsSubLabelDialogOpen(true); - }} - /> - - - - - {t("details.editSubLabel.title")} - - - - )} +
    +
    +
    +
    +
    +
    + {t("details.label")} +
    +
    + {getIconForLabel(search.label, "size-4 text-primary")} + {getTranslatedLabel(search.label)} + {search.sub_label && ` (${search.sub_label})`} + {isAdmin && search.end_time && ( + + + + setIsSubLabelDialogOpen(true)} + /> + + + + + {t("details.editSubLabel.title")} + + + + )} +
    +
    + +
    +
    +
    + {t("details.topScore.label")} + + +
    + + Info +
    +
    + + {t("details.topScore.info")} + +
    +
    +
    +
    + {topScore}%{subLabelScore && ` (${subLabelScore}%)`} +
    +
    + +
    +
    + {t("details.camera")} +
    +
    + +
    +
    +
    +
    + +
    +
    + {snapScore != undefined && ( +
    +
    +
    + {t("details.snapshotScore.label")} +
    +
    +
    {snapScore}%
    +
    + )} + + {averageEstimatedSpeed && ( +
    +
    + {t("details.estimatedSpeed")} +
    +
    +
    + {averageEstimatedSpeed}{" "} + {config?.ui.unit_system == "imperial" + ? t("unit.speed.mph", { ns: "common" }) + : t("unit.speed.kph", { ns: "common" })} + {velocityAngle != undefined && ( + + + + )} +
    +
    +
    + )} + +
    +
    + {t("details.timestamp")} +
    +
    {formattedDate}
    +
    +
    +
    {search?.data.recognized_license_plate && ( @@ -909,9 +1224,7 @@ function ObjectDetailsTab({ { - setIsLPRDialogOpen(true); - }} + onClick={() => setIsLPRDialogOpen(true)} /> @@ -926,142 +1239,108 @@ function ObjectDetailsTab({
    )} -
    -
    -
    - {t("details.topScore.label")} - - -
    - - Info -
    -
    - - {t("details.topScore.info")} - -
    -
    -
    -
    - {topScore}%{subLabelScore && ` (${subLabelScore}%)`} -
    -
    - {snapScore != undefined && ( -
    -
    -
    - {t("details.snapshotScore.label")} +
    +
    + +
    +
    +
    + {t("explore.plus.submitToPlus.label", { + ns: "components/dialog", + })} + + +
    + + Info
    -
    -
    {snapScore}%
    -
    - )} - {averageEstimatedSpeed && ( -
    -
    - {t("details.estimatedSpeed")} -
    -
    - {averageEstimatedSpeed && ( -
    - {averageEstimatedSpeed}{" "} - {config?.ui.unit_system == "imperial" - ? t("unit.speed.mph", { ns: "common" }) - : t("unit.speed.kph", { ns: "common" })}{" "} - {velocityAngle != undefined && ( - - - - )} -
    - )} -
    -
    - )} -
    -
    {t("details.camera")}
    -
    - -
    -
    -
    -
    - {t("details.timestamp")} -
    -
    {formattedDate}
    + + + {t("explore.plus.submitToPlus.desc", { + ns: "components/dialog", + })} + +
    - {showThumbnail && ( -
    - -
    - {config?.semantic_search.enabled && - setSimilarity != undefined && - search.data.type == "object" && ( - + explore.plus.review.question.ask_full + )} - {hasFace && ( - +
    + - - )} - {config?.cameras[search?.camera].audio_transcription.enabled && - search?.label == "speech" && - search?.end_time && ( - - )} + {t("button.yes", { ns: "common" })} + + +
    + + )} + {state == "uploading" && } + {state == "submitted" && ( +
    + + {t("explore.plus.review.state.submitted")}
    -
    - )} + )} +
    {config?.cameras[search.camera].objects.genai.enabled && @@ -1103,6 +1382,15 @@ function ObjectDetailsTab({ )}
    + {config?.cameras[search?.camera].audio_transcription.enabled && + search?.label == "speech" && + search?.end_time && ( + + )} {config?.cameras[search.camera].objects.genai.enabled && search.end_time && (
    @@ -1154,6 +1442,7 @@ function ObjectDetailsTab({ {t("button.save", { ns: "common" })} )} + void; + className?: string; + onEventUploaded?: () => void; }; export function ObjectSnapshotTab({ search, - onEventUploaded, + className, }: ObjectSnapshotTabProps) { - const { t, i18n } = useTranslation(["components/dialog"]); - type SubmissionState = "reviewing" | "uploading" | "submitted"; - const [imgRef, imgLoaded, onImgLoad] = useImageLoaded(); - // upload - - const [state, setState] = useState( - search?.plus_id ? "submitted" : "reviewing", - ); - - useEffect( - () => setState(search?.plus_id ? "submitted" : "reviewing"), - [search], - ); - - const onSubmitToPlus = useCallback( - async (falsePositive: boolean) => { - if (!search) { - return; - } - - falsePositive - ? axios.put(`events/${search.id}/false_positive`) - : axios.post(`events/${search.id}/plus`, { - include_annotation: 1, - }); - - setState("submitted"); - onEventUploaded(); - }, - [search, onEventUploaded], - ); - return ( -
    +
    -
    +
    -
    +
    {search?.id && ( -
    +
    {`${search?.label}`} -
    - - - - - - - - - - - {t("button.download", { ns: "common" })} - - - -
    )} - {search.data.type == "object" && - search.plus_id !== "not_enabled" && - search.end_time && - search.label != "on_demand" && ( - - -
    -
    - {t("explore.plus.submitToPlus.label")} -
    -
    - {t("explore.plus.submitToPlus.desc")} -
    -
    - -
    - {state == "reviewing" && ( - <> -
    - {i18n.language === "en" ? ( - // English with a/an logic plus label - <> - {/^[aeiou]/i.test(search?.label || "") ? ( - - explore.plus.review.question.ask_an - - ) : ( - - explore.plus.review.question.ask_a - - )} - - ) : ( - // For other languages - - explore.plus.review.question.ask_full - - )} -
    -
    - - -
    - - )} - {state == "uploading" && } - {state == "submitted" && ( -
    - - {t("explore.plus.review.state.submitted")} -
    - )} -
    -
    -
    - )}
    @@ -1391,12 +1542,6 @@ type VideoTabProps = { }; export function VideoTab({ search }: VideoTabProps) { - const { t } = useTranslation(["views/explore"]); - const navigate = useNavigate(); - const { data: reviewItem } = useSWR([ - `review/event/${search.id}`, - ]); - const clipTimeRange = useMemo(() => { const startTime = search.start_time - REVIEW_PADDING; const endTime = (search.end_time ?? Date.now() / 1000) + REVIEW_PADDING; @@ -1408,56 +1553,7 @@ export function VideoTab({ search }: VideoTabProps) { return ( <> - -
    - {reviewItem && ( - - - { - if (reviewItem?.id) { - const params = new URLSearchParams({ - id: reviewItem.id, - }).toString(); - navigate(`/review?${params}`); - } - }} - > - - - - - - {t("itemMenu.viewInHistory.label")} - - - - )} - - - - - - - - - - - {t("button.download", { ns: "common" })} - - - -
    -
    + ); } diff --git a/web/src/components/overlay/detail/TrackingDetails.tsx b/web/src/components/overlay/detail/TrackingDetails.tsx index 4d0a4beb9..f1212fe3f 100644 --- a/web/src/components/overlay/detail/TrackingDetails.tsx +++ b/web/src/components/overlay/detail/TrackingDetails.tsx @@ -2,21 +2,12 @@ import useSWR from "swr"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Event } from "@/types/event"; import ActivityIndicator from "@/components/indicators/activity-indicator"; -import { Button } from "@/components/ui/button"; import { TrackingDetailsSequence } from "@/types/timeline"; -import Heading from "@/components/ui/heading"; import { FrigateConfig } from "@/types/frigateConfig"; import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; import { getIconForLabel } from "@/utils/iconUtil"; -import { LuCircle, LuFolderX, LuSettings } from "react-icons/lu"; +import { LuCircle, LuFolderX } from "react-icons/lu"; import { cn } from "@/lib/utils"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { AnnotationSettingsPane } from "./AnnotationSettingsPane"; -import { TooltipPortal } from "@radix-ui/react-tooltip"; import HlsVideoPlayer from "@/components/player/HlsVideoPlayer"; import { baseUrl } from "@/api/baseUrl"; import { REVIEW_PADDING } from "@/types/review"; @@ -39,8 +30,6 @@ import axios from "axios"; import { toast } from "sonner"; import { useDetailStream } from "@/context/detail-stream-context"; import { isDesktop, isIOS, isMobileOnly, isSafari } from "react-device-detect"; -import Chip from "@/components/indicators/Chip"; -import { FaDownload, FaHistory } from "react-icons/fa"; import { useApiHost } from "@/api"; import ImageLoadingIndicator from "@/components/indicators/ImageLoadingIndicator"; import ObjectTrackOverlay from "../ObjectTrackOverlay"; @@ -59,15 +48,13 @@ export function TrackingDetails({ }: TrackingDetailsProps) { const videoRef = useRef(null); const { t } = useTranslation(["views/explore"]); - const navigate = useNavigate(); const apiHost = useApiHost(); const imgRef = useRef(null); const [imgLoaded, setImgLoaded] = useState(false); const [displaySource, _setDisplaySource] = useState<"video" | "image">( "video", ); - const { setSelectedObjectIds, annotationOffset, setAnnotationOffset } = - useDetailStream(); + const { setSelectedObjectIds, annotationOffset } = useDetailStream(); // manualOverride holds a record-stream timestamp explicitly chosen by the // user (eg, clicking a lifecycle row). When null we display `currentTime`. @@ -104,8 +91,6 @@ export function TrackingDetails({ const containerRef = useRef(null); const [_selectedZone, setSelectedZone] = useState(""); const [_lifecycleZones, setLifecycleZones] = useState([]); - const [showControls, setShowControls] = useState(false); - const [showZones, setShowZones] = useState(true); const [seekToTimestamp, setSeekToTimestamp] = useState(null); const aspectRatio = useMemo(() => { @@ -366,7 +351,7 @@ export function TrackingDetails({
    )} -
    - {event && ( - - - { - if (event?.id) { - const params = new URLSearchParams({ - id: event.id, - }).toString(); - navigate(`/review?${params}`); - } - }} - > - - - - - - {t("itemMenu.viewInHistory.label")} - - - - )} - - - - - - - - - - - {t("button.download", { ns: "common" })} - - - -
    -
    - {isDesktop && tabs &&
    {tabs}
    } +
    + {isDesktop && tabs && ( +
    +
    {tabs}
    +
    + )}
    -
    - {t("trackingDetails.title")} - -
    - - - - - - - {t("trackingDetails.adjustAnnotationSettings")} - - - -
    -
    -
    -
    - {t("trackingDetails.scrollViewTips")} -
    -
    - {t("trackingDetails.count", { - first: eventSequence?.length ?? 0, - second: eventSequence?.length ?? 0, - })} -
    -
    {config?.cameras[event.camera]?.onvif.autotracking .enabled_in_config && ( -
    +
    {t("trackingDetails.autoTrackingTips")}
    )} - {showControls && ( - { - if (typeof value === "function") { - const newValue = value(annotationOffset); - setAnnotationOffset(newValue); - } else { - setAnnotationOffset(value); - } - }} - /> - )}
    {label} - + {formattedStart ?? ""} - {formattedEnd ?? ""} {event.data?.recognized_license_plate && ( diff --git a/web/src/components/timeline/DetailStream.tsx b/web/src/components/timeline/DetailStream.tsx index 7fc7c423c..8844f6a5a 100644 --- a/web/src/components/timeline/DetailStream.tsx +++ b/web/src/components/timeline/DetailStream.tsx @@ -16,12 +16,7 @@ import ActivityIndicator from "../indicators/activity-indicator"; import { Event } from "@/types/event"; import { getIconForLabel } from "@/utils/iconUtil"; import { ReviewSegment } from "@/types/review"; -import { - LuChevronDown, - LuCircle, - LuChevronRight, - LuSettings, -} from "react-icons/lu"; +import { LuChevronDown, LuCircle, LuChevronRight } from "react-icons/lu"; import { getTranslatedLabel } from "@/utils/i18n"; import EventMenu from "@/components/timeline/EventMenu"; import { FrigatePlusDialog } from "@/components/overlay/dialog/FrigatePlusDialog"; @@ -32,6 +27,8 @@ import { Switch } from "@/components/ui/switch"; import { usePersistence } from "@/hooks/use-persistence"; import { isDesktop } from "react-device-detect"; import { resolveZoneName } from "@/hooks/use-zone-friendly-name"; +import { PiSlidersHorizontalBold } from "react-icons/pi"; +import { MdAutoAwesome } from "react-icons/md"; type DetailStreamProps = { reviewItems?: ReviewSegment[]; @@ -237,7 +234,7 @@ export default function DetailStream({ className="flex w-full items-center justify-between p-3" >
    - + {t("detail.settings")}
    {controlsExpanded ? ( @@ -411,8 +408,9 @@ function ReviewGroup({
    {review.data.metadata?.title && ( -
    - {review.data.metadata.title} +
    + + {review.data.metadata.title}
    )}
    diff --git a/web/src/components/timeline/EventSegment.tsx b/web/src/components/timeline/EventSegment.tsx index e04841540..368e0fad5 100644 --- a/web/src/components/timeline/EventSegment.tsx +++ b/web/src/components/timeline/EventSegment.tsx @@ -1,4 +1,3 @@ -import { useApiHost } from "@/api"; import { useTimelineUtils } from "@/hooks/use-timeline-utils"; import { useEventSegmentUtils } from "@/hooks/use-event-segment-utils"; import { ReviewSegment, ReviewSeverity } from "@/types/review"; @@ -18,6 +17,7 @@ import { HoverCardPortal } from "@radix-ui/react-hover-card"; import scrollIntoView from "scroll-into-view-if-needed"; import { MinimapBounds, Tick, Timestamp } from "./segment-metadata"; import useTapUtils from "@/hooks/use-tap-utils"; +import ReviewCard from "../card/ReviewCard"; type EventSegmentProps = { events: ReviewSegment[]; @@ -54,7 +54,7 @@ export function EventSegment({ displaySeverityType, shouldShowRoundedCorners, getEventStart, - getEventThumbnail, + getEvent, } = useEventSegmentUtils(segmentDuration, events, severityType); const { alignStartDateToTimeline, alignEndDateToTimeline } = useTimelineUtils( @@ -87,13 +87,11 @@ export function EventSegment({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [getEventStart, segmentTime]); - const apiHost = useApiHost(); - const { handleTouchStart } = useTapUtils(); - const eventThumbnail = useMemo(() => { - return getEventThumbnail(segmentTime); - }, [getEventThumbnail, segmentTime]); + const segmentEvent = useMemo(() => { + return getEvent(segmentTime); + }, [getEvent, segmentTime]); const timestamp = useMemo(() => new Date(segmentTime * 1000), [segmentTime]); const segmentKey = useMemo( @@ -252,10 +250,7 @@ export function EventSegment({ className="w-[250px] rounded-lg p-2 md:rounded-2xl" side="left" > - + {segmentEvent && } diff --git a/web/src/components/ui/popover.tsx b/web/src/components/ui/popover.tsx index bba83f977..017d1bdc7 100644 --- a/web/src/components/ui/popover.tsx +++ b/web/src/components/ui/popover.tsx @@ -11,13 +11,21 @@ const PopoverContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { container?: HTMLElement | null; + disablePortal?: boolean; } >( ( - { className, container, align = "center", sideOffset = 4, ...props }, + { + className, + container, + disablePortal = false, + align = "center", + sideOffset = 4, + ...props + }, ref, - ) => ( - + ) => { + const content = ( - - ), + ); + + if (disablePortal) { + return content; + } + + return ( + + {content} + + ); + }, ); PopoverContent.displayName = PopoverPrimitive.Content.displayName; diff --git a/web/src/context/detail-stream-context.tsx b/web/src/context/detail-stream-context.tsx index ff909a30e..57971f7ac 100644 --- a/web/src/context/detail-stream-context.tsx +++ b/web/src/context/detail-stream-context.tsx @@ -8,7 +8,7 @@ export interface DetailStreamContextType { camera: string; annotationOffset: number; // milliseconds setSelectedObjectIds: React.Dispatch>; - setAnnotationOffset: (ms: number) => void; + setAnnotationOffset: React.Dispatch>; toggleObjectSelection: (id: string | undefined) => void; isDetailMode: boolean; } diff --git a/web/src/hooks/use-event-segment-utils.ts b/web/src/hooks/use-event-segment-utils.ts index 3ecafcded..b105c3bf8 100644 --- a/web/src/hooks/use-event-segment-utils.ts +++ b/web/src/hooks/use-event-segment-utils.ts @@ -191,8 +191,8 @@ export const useEventSegmentUtils = ( [events, getSegmentStart, getSegmentEnd, severityType], ); - const getEventThumbnail = useCallback( - (time: number): string => { + const getEvent = useCallback( + (time: number): ReviewSegment | undefined => { const matchingEvent = events.find((event) => { return ( time >= getSegmentStart(event.start_time) && @@ -201,7 +201,7 @@ export const useEventSegmentUtils = ( ); }); - return matchingEvent?.thumb_path ?? ""; + return matchingEvent; }, [events, getSegmentStart, getSegmentEnd, severityType], ); @@ -214,6 +214,6 @@ export const useEventSegmentUtils = ( getReviewed, shouldShowRoundedCorners, getEventStart, - getEventThumbnail, + getEvent, }; }; diff --git a/web/src/pages/FaceLibrary.tsx b/web/src/pages/FaceLibrary.tsx index b6a04ada9..6cc113e77 100644 --- a/web/src/pages/FaceLibrary.tsx +++ b/web/src/pages/FaceLibrary.tsx @@ -524,7 +524,7 @@ function LibrarySelector({ regexErrorMessage={t("description.invalidName")} /> - +