From 76b8e52fe54b4c65b6b7a211dd323cdf40ec5ce9 Mon Sep 17 00:00:00 2001 From: Shlomi <81555468+shlomi-dr@users.noreply.github.com> Date: Sat, 6 Dec 2025 07:14:05 -0600 Subject: [PATCH] Shlomi/main panel improvements (#1239) Co-authored-by: Raivis Dejus --- buzz/db/dao/transcription_dao.py | 71 ++- buzz/db/entity/transcription.py | 2 + buzz/db/service/transcription_service.py | 9 + buzz/file_transcriber_queue_worker.py | 37 +- buzz/locale/ca_ES/LC_MESSAGES/buzz.po | 184 ++++-- buzz/locale/da_DK/LC_MESSAGES/buzz.po | 183 ++++-- buzz/locale/de_DE/LC_MESSAGES/buzz.po | 184 ++++-- buzz/locale/en_US/LC_MESSAGES/buzz.po | 178 ++++-- buzz/locale/es_ES/LC_MESSAGES/buzz.po | 187 ++++-- buzz/locale/it_IT/LC_MESSAGES/buzz.po | 184 ++++-- buzz/locale/ja_JP/LC_MESSAGES/buzz.po | 183 ++++-- buzz/locale/lv_LV/LC_MESSAGES/buzz.po | 183 ++++-- buzz/locale/nl/LC_MESSAGES/buzz.po | 184 ++++-- buzz/locale/pl_PL/LC_MESSAGES/buzz.po | 185 ++++-- buzz/locale/pt_BR/LC_MESSAGES/buzz.po | 184 ++++-- buzz/locale/uk_UA/LC_MESSAGES/buzz.po | 183 ++++-- buzz/locale/zh_CN/LC_MESSAGES/buzz.po | 185 ++++-- buzz/locale/zh_TW/LC_MESSAGES/buzz.po | 185 ++++-- buzz/schema.sql | 4 +- buzz/settings/settings.py | 6 + buzz/transcriber/whisper_file_transcriber.py | 15 +- buzz/widgets/main_window.py | 1 + .../transcription_tasks_table_widget.py | 568 ++++++++++++++++-- tests/db/dao/transcription_dao_test.py | 240 ++++++++ tests/db/entity/transcription_test.py | 286 +++++++++ .../db/service/transcription_service_test.py | 211 +++++++ tests/settings/settings_test.py | 133 ++++ tests/widgets/main_window_test.py | 72 ++- .../transcription_tasks_table_widget_test.py | 267 +++++++- 29 files changed, 3539 insertions(+), 955 deletions(-) create mode 100644 tests/db/dao/transcription_dao_test.py create mode 100644 tests/db/entity/transcription_test.py create mode 100644 tests/db/service/transcription_service_test.py create mode 100644 tests/settings/settings_test.py diff --git a/buzz/db/dao/transcription_dao.py b/buzz/db/dao/transcription_dao.py index f35e0db1..928099c3 100644 --- a/buzz/db/dao/transcription_dao.py +++ b/buzz/db/dao/transcription_dao.py @@ -34,7 +34,9 @@ class TranscriptionDAO(DAO[Transcription]): whisper_model_size, hugging_face_model_id, word_level_timings, - extract_speech + extract_speech, + name, + notes ) VALUES ( :id, :export_formats, @@ -50,7 +52,9 @@ class TranscriptionDAO(DAO[Transcription]): :whisper_model_size, :hugging_face_model_id, :word_level_timings, - :extract_speech + :extract_speech, + :name, + :notes ) """ ) @@ -95,6 +99,8 @@ class TranscriptionDAO(DAO[Transcription]): ":extract_speech", task.transcription_options.extract_speech ) + query.bindValue(":name", None) # name is not available in FileTranscriptionTask + query.bindValue(":notes", None) # notes is not available in FileTranscriptionTask if not query.exec(): raise Exception(query.lastError().text()) @@ -132,7 +138,9 @@ class TranscriptionDAO(DAO[Transcription]): whisper_model_size, hugging_face_model_id, word_level_timings, - extract_speech + extract_speech, + name, + notes ) VALUES ( :id, :export_formats, @@ -148,7 +156,9 @@ class TranscriptionDAO(DAO[Transcription]): :whisper_model_size, :hugging_face_model_id, :word_level_timings, - :extract_speech + :extract_speech, + :name, + :notes ) """ ) @@ -239,3 +249,56 @@ class TranscriptionDAO(DAO[Transcription]): query.bindValue(":time_ended", datetime.now().isoformat()) if not query.exec(): raise Exception(query.lastError().text()) + + def update_transcription_name(self, id: UUID, name: str): + query = self._create_query() + query.prepare( + """ + UPDATE transcription + SET name = :name + WHERE id = :id + """ + ) + + query.bindValue(":id", str(id)) + query.bindValue(":name", name) + if not query.exec(): + raise Exception(query.lastError().text()) + if query.numRowsAffected() == 0: + raise Exception("Transcription not found") + + def update_transcription_notes(self, id: UUID, notes: str): + query = self._create_query() + query.prepare( + """ + UPDATE transcription + SET notes = :notes + WHERE id = :id + """ + ) + + query.bindValue(":id", str(id)) + query.bindValue(":notes", notes) + if not query.exec(): + raise Exception(query.lastError().text()) + if query.numRowsAffected() == 0: + raise Exception("Transcription not found") + + def reset_transcription_for_restart(self, id: UUID): + """Reset a transcription to queued status for restart""" + query = self._create_query() + query.prepare( + """ + UPDATE transcription + SET status = :status, progress = :progress, time_started = NULL, time_ended = NULL, error_message = NULL + WHERE id = :id + """ + ) + + query.bindValue(":id", str(id)) + query.bindValue(":status", FileTranscriptionTask.Status.QUEUED.value) + query.bindValue(":progress", 0.0) + if not query.exec(): + raise Exception(query.lastError().text()) + if query.numRowsAffected() == 0: + raise Exception("Transcription not found") diff --git a/buzz/db/entity/transcription.py b/buzz/db/entity/transcription.py index 3692bbcc..ffb1b11a 100644 --- a/buzz/db/entity/transcription.py +++ b/buzz/db/entity/transcription.py @@ -30,6 +30,8 @@ class Transcription(Entity): output_folder: str | None = None source: str | None = None url: str | None = None + name: str | None = None + notes: str | None = None @property def id_as_uuid(self): diff --git a/buzz/db/service/transcription_service.py b/buzz/db/service/transcription_service.py index 20ef3bf4..4c500800 100644 --- a/buzz/db/service/transcription_service.py +++ b/buzz/db/service/transcription_service.py @@ -47,6 +47,15 @@ class TranscriptionService: ) ) + def update_transcription_name(self, id: UUID, name: str): + self.transcription_dao.update_transcription_name(id, name) + + def update_transcription_notes(self, id: UUID, notes: str): + self.transcription_dao.update_transcription_notes(id, notes) + + def reset_transcription_for_restart(self, id: UUID): + self.transcription_dao.reset_transcription_for_restart(id) + def replace_transcription_segments(self, id: UUID, segments: List[Segment]): self.transcription_segment_dao.delete_segments(id) for segment in segments: diff --git a/buzz/file_transcriber_queue_worker.py b/buzz/file_transcriber_queue_worker.py index 88d62eaa..6866ef7c 100644 --- a/buzz/file_transcriber_queue_worker.py +++ b/buzz/file_transcriber_queue_worker.py @@ -31,6 +31,7 @@ class FileTranscriberQueueWorker(QObject): task_error = pyqtSignal(FileTranscriptionTask, str) completed = pyqtSignal() + trigger_run = pyqtSignal() def __init__(self, parent: Optional[QObject] = None): super().__init__(parent) @@ -38,14 +39,20 @@ class FileTranscriberQueueWorker(QObject): self.canceled_tasks: Set[UUID] = set() self.current_transcriber = None self.speech_path = None + self.is_running = False + self.trigger_run.connect(self.run) @pyqtSlot() def run(self): + if self.is_running: + return + logging.debug("Waiting for next transcription task") # Clean up of previous run. if self.current_transcriber is not None: self.current_transcriber.stop() + self.current_transcriber = None # Get next non-canceled task from queue while True: @@ -53,6 +60,7 @@ class FileTranscriberQueueWorker(QObject): # Stop listening when a "None" task is received if self.current_task is None: + self.is_running = False self.completed.emit() return @@ -61,6 +69,9 @@ class FileTranscriberQueueWorker(QObject): break + # Set is_running AFTER we have a valid task to process + self.is_running = True + if self.current_task.transcription_options.extract_speech: logging.debug("Will extract speech") @@ -123,14 +134,27 @@ class FileTranscriberQueueWorker(QObject): self.current_transcriber.completed.connect(self.on_task_completed) # Wait for next item on the queue - self.current_transcriber.error.connect(self.run) - self.current_transcriber.completed.connect(self.run) + self.current_transcriber.error.connect(lambda: self._on_task_finished()) + self.current_transcriber.completed.connect(lambda: self._on_task_finished()) self.task_started.emit(self.current_task) self.current_transcriber_thread.start() + def _on_task_finished(self): + """Called when a task completes or errors, resets state and triggers next run""" + self.is_running = False + self.run() + def add_task(self, task: FileTranscriptionTask): + # Remove from canceled tasks if it was previously canceled (for restart functionality) + if task.uid in self.canceled_tasks: + self.canceled_tasks.remove(task.uid) + self.tasks_queue.put(task) + # If the worker is not currently running, trigger it to start processing + # Use signal to avoid blocking the main thread + if not self.is_running: + self.trigger_run.emit() def cancel_task(self, task_id: UUID): self.canceled_tasks.add(task_id) @@ -149,8 +173,13 @@ class FileTranscriberQueueWorker(QObject): self.current_task is not None and self.current_task.uid not in self.canceled_tasks ): - self.current_task.status = FileTranscriptionTask.Status.FAILED - self.current_task.error = error + # Check if the error indicates cancellation + if "canceled" in error.lower() or "cancelled" in error.lower(): + self.current_task.status = FileTranscriptionTask.Status.CANCELED + self.current_task.error = error + else: + self.current_task.status = FileTranscriptionTask.Status.FAILED + self.current_task.error = error self.task_error.emit(self.current_task, error) @pyqtSlot(tuple) diff --git a/buzz/locale/ca_ES/LC_MESSAGES/buzz.po b/buzz/locale/ca_ES/LC_MESSAGES/buzz.po index aaf56614..49f8ef9a 100644 --- a/buzz/locale/ca_ES/LC_MESSAGES/buzz.po +++ b/buzz/locale/ca_ES/LC_MESSAGES/buzz.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: buzz\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: 2025-10-17 07:59+0200\n" "Last-Translator: Éric Duarte \n" "Language-Team: Catalan \n" @@ -29,7 +29,7 @@ msgstr "https://exemple.com/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "D’acord" @@ -37,7 +37,7 @@ msgstr "D’acord" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "Cancel·lar" @@ -308,7 +308,10 @@ msgid "Download failed" msgstr "Descàrrega fallida" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "Error" @@ -436,54 +439,113 @@ msgstr "Obre una transcripció" msgid "Cancel Transcription" msgstr "Cancel·la la transcripció" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "Neteja l'historial" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "En progrés" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "Completat" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "Ha fallat" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "Cancel·lat" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "A la cua" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 msgid "File Name / URL" msgstr "Nom del fitxer / URL" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 msgid "Model" msgstr "Model" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 msgid "Task" msgstr "Tasca" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "Estat" -#: buzz/widgets/transcription_tasks_table_widget.py:129 +#: buzz/widgets/transcription_tasks_table_widget.py:133 +msgid "Date Completed" +msgstr "Data de finalització" + +#: buzz/widgets/transcription_tasks_table_widget.py:145 msgid "Date Added" msgstr "Data d'addició" -#: buzz/widgets/transcription_tasks_table_widget.py:140 -msgid "Date Completed" -msgstr "Data de finalització" +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "Cancel·la la transcripció" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +#, fuzzy +msgid "Rename" +msgstr "Vietnamita" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "Cancel·la la transcripció" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "Cancel·la la transcripció" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" @@ -521,7 +583,7 @@ msgstr "Comprova si hi ha actualitzacions" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "Estàs al dia!" @@ -554,68 +616,68 @@ msgstr "Veure" msgid "Timestamps" msgstr "Marqua de temps" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "Exporta" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "Traduir" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "Redimensionar" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "Cerca" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "Mostra/amaga la barra de cerca (Ctrl+F)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "Cerca:" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "Introduïu el text a cercar..." -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "Coincidència anterior (Maj+Retorn)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "Coincidència següent (retorn)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "Neteja" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "Controls de reproducció:" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "Segment de bucle" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "Activa/desactiva el bucle en fer clic als segments de transcripció" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "Segueix l'àudio" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." @@ -623,44 +685,44 @@ msgstr "" "Activa/desactiva seguint la posició d'àudio actual a la transcripció. Quan " "està activada, es desplaça automàticament al text actual." -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "Desplaça't fins a l'actual" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "Desplaçar-se fins al text que es parla actualment" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "1 de més de 100 coincidències" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "1 de " -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr " coincidències" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "No s'ha trobat cap coincidència" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr " de més de 100 coincidències" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr " de " -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "Clau API necessària" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "Introduïu la clau API d'OpenAI a les preferències" @@ -717,48 +779,48 @@ msgstr "Cancel·la la transcripció" msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "Desa el fitxer" @@ -826,7 +888,7 @@ msgstr "Ajuda" msgid "File" msgstr "Fitxer" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." @@ -834,11 +896,11 @@ msgstr "" "Esteu segur que voleu suprimir les transcripcions seleccionades? Aquesta " "acció no es pot desfer." -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "Selecciona un fitxer d'àudio" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "No s'ha pogut desar la clau OpenAI API a l'anell de claus" diff --git a/buzz/locale/da_DK/LC_MESSAGES/buzz.po b/buzz/locale/da_DK/LC_MESSAGES/buzz.po index fe698374..9ebdebcb 100644 --- a/buzz/locale/da_DK/LC_MESSAGES/buzz.po +++ b/buzz/locale/da_DK/LC_MESSAGES/buzz.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: \n" "Last-Translator: Ole Guldberg2 \n" "Language-Team: \n" @@ -26,7 +26,7 @@ msgstr "https://example.com/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "OK" @@ -34,7 +34,7 @@ msgstr "OK" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "Afbryd" @@ -307,7 +307,10 @@ msgid "Download failed" msgstr "Download mislykkedes" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "Fejl" @@ -434,54 +437,112 @@ msgstr "Åben transkription" msgid "Cancel Transcription" msgstr "Afbryd transkription" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "Ryd historik" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "Arbejder" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "Færdig" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "Mislykkedes" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "Afbrudt" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "Sat i kø" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 msgid "File Name / URL" msgstr "Filnavn / URL" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 msgid "Model" msgstr "Model" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 msgid "Task" msgstr "Opgave" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "Status" -#: buzz/widgets/transcription_tasks_table_widget.py:129 +#: buzz/widgets/transcription_tasks_table_widget.py:133 +msgid "Date Completed" +msgstr "Dato for færdiggørelse" + +#: buzz/widgets/transcription_tasks_table_widget.py:145 msgid "Date Added" msgstr "Dato for tilføjelse" -#: buzz/widgets/transcription_tasks_table_widget.py:140 -msgid "Date Completed" -msgstr "Dato for færdiggørelse" +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "Afbryd transkription" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +msgid "Rename" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "Afbryd transkription" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "Afbryd transkription" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" @@ -519,7 +580,7 @@ msgstr "Tjek for opdateringer" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "Du er opdateret!" @@ -552,111 +613,111 @@ msgstr "Vis" msgid "Timestamps" msgstr "Tidsstempler" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "Eksporter" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "Oversæt" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "Behandel størrelse" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "API-nøgle påkrævet" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "Indtast venligst OpenAI API-nøgle i indstillinger" @@ -713,48 +774,48 @@ msgstr "Afbryd transkription" msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "Gem fil" @@ -822,7 +883,7 @@ msgstr "Hjælp" msgid "File" msgstr "Fil" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." @@ -830,11 +891,11 @@ msgstr "" "Er du sikker på at du vil slette den valgte transkription? Denne handling " "kan ikke fortrydes." -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "Vælg audio-fil" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "Kan ikke gemme OpenAI API-nøgle i nøgleringen" diff --git a/buzz/locale/de_DE/LC_MESSAGES/buzz.po b/buzz/locale/de_DE/LC_MESSAGES/buzz.po index 1b547455..2e9294f4 100644 --- a/buzz/locale/de_DE/LC_MESSAGES/buzz.po +++ b/buzz/locale/de_DE/LC_MESSAGES/buzz.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: 2025-03-05 14:41+0100\n" "Last-Translator: \n" "Language-Team: \n" @@ -28,7 +28,7 @@ msgstr "https://example.com/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "OK" @@ -36,7 +36,7 @@ msgstr "OK" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "Abbrechen" @@ -307,7 +307,10 @@ msgid "Download failed" msgstr "Der Download ist fehlgeschlagen" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "Fehler" @@ -434,54 +437,113 @@ msgstr "Transkript öffnen" msgid "Cancel Transcription" msgstr "Transkription abbrechen" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "Verlauf löschen" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "Im Gange" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "Fertiggestellt" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "Fehlgeschlagen" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "Abgebrochen" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "In der Warteschlange" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 msgid "File Name / URL" msgstr "Dateiname/URL" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 msgid "Model" msgstr "Modell" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 msgid "Task" msgstr "Aufgabe" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "Status" -#: buzz/widgets/transcription_tasks_table_widget.py:129 +#: buzz/widgets/transcription_tasks_table_widget.py:133 +msgid "Date Completed" +msgstr "Datum abgeschlossen" + +#: buzz/widgets/transcription_tasks_table_widget.py:145 msgid "Date Added" msgstr "Datum hinzugefügt" -#: buzz/widgets/transcription_tasks_table_widget.py:140 -msgid "Date Completed" -msgstr "Datum abgeschlossen" +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "Transkription abbrechen" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +#, fuzzy +msgid "Rename" +msgstr "Vietnamesisch" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "Transkription abbrechen" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "Transkription abbrechen" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" @@ -519,7 +581,7 @@ msgstr "Nach Updates suchen" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "Sie sind auf dem Laufenden!" @@ -552,111 +614,111 @@ msgstr "Anzeigen" msgid "Timestamps" msgstr "Zeitstempel" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "Export" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "Übersetzen" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "Größe ändern" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "API-Schlüssel erforderlich" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "Bitte geben Sie den OpenAI-API-Schlüssel in den Einstellungen ein" @@ -713,48 +775,48 @@ msgstr "Transkription abbrechen" msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "Datei speichern" @@ -822,7 +884,7 @@ msgstr "Hilfe" msgid "File" msgstr "Datei" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." @@ -830,11 +892,11 @@ msgstr "" "Sind Sie sicher, dass Sie die ausgewählte(n) Transkription(en) löschen " "möchten? Diese Aktion kann nicht rückgängig gemacht werden." -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "Audiodatei auswählen" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "" "Der OpenAI-API-Schlüssel kann nicht im Schlüsselbund gespeichert werden" diff --git a/buzz/locale/en_US/LC_MESSAGES/buzz.po b/buzz/locale/en_US/LC_MESSAGES/buzz.po index 02bac9f4..d16cb5c7 100644 --- a/buzz/locale/en_US/LC_MESSAGES/buzz.po +++ b/buzz/locale/en_US/LC_MESSAGES/buzz.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -29,7 +29,7 @@ msgstr "" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "" @@ -37,7 +37,7 @@ msgstr "" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "" @@ -299,7 +299,10 @@ msgid "Download failed" msgstr "" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "" @@ -424,53 +427,108 @@ msgstr "" msgid "Cancel Transcription" msgstr "" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 msgid "File Name / URL" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 msgid "Model" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 msgid "Task" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:129 +#: buzz/widgets/transcription_tasks_table_widget.py:133 +msgid "Date Completed" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:145 msgid "Date Added" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:140 -msgid "Date Completed" +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +msgid "Restart Transcription" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +msgid "Rename" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +msgid "Rename Transcription" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +msgid "Failed to restart transcription: {}" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." msgstr "" #: buzz/widgets/recording_transcriber_widget.py:83 @@ -507,7 +565,7 @@ msgstr "" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "" @@ -540,111 +598,111 @@ msgstr "" msgid "Timestamps" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "" @@ -700,48 +758,48 @@ msgstr "" msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 msgid "Save" msgstr "" @@ -804,17 +862,17 @@ msgstr "" msgid "File" msgstr "" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." msgstr "" -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "" diff --git a/buzz/locale/es_ES/LC_MESSAGES/buzz.po b/buzz/locale/es_ES/LC_MESSAGES/buzz.po index 1c7d3e0c..2166f396 100644 --- a/buzz/locale/es_ES/LC_MESSAGES/buzz.po +++ b/buzz/locale/es_ES/LC_MESSAGES/buzz.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: 2025-09-08 12:43+0200\n" "Last-Translator: Éric Duarte \n" "Language-Team: \n" @@ -29,7 +29,7 @@ msgstr "https://ejemplo.com/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "Ok" @@ -37,7 +37,7 @@ msgstr "Ok" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "Cancelar" @@ -314,7 +314,10 @@ msgid "Download failed" msgstr "Descarga fallida" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "Error" @@ -460,57 +463,119 @@ msgid "Cancel Transcription" msgstr "Cancelar transcripción" # automatic translation -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "Vaciar historial" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "En Progreso" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "Completado" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "Fallido" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "Cancelado" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "En cola" # automatic translation -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 msgid "File Name / URL" msgstr "Nombre de archivo / URL" # automatic translation -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 msgid "Model" msgstr "Modelo" # automatic translation -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 msgid "Task" msgstr "Tarea" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "Estado" -#: buzz/widgets/transcription_tasks_table_widget.py:129 +#: buzz/widgets/transcription_tasks_table_widget.py:133 +msgid "Date Completed" +msgstr "Fecha de finalización" + +#: buzz/widgets/transcription_tasks_table_widget.py:145 msgid "Date Added" msgstr "Fecha de adición" -#: buzz/widgets/transcription_tasks_table_widget.py:140 -msgid "Date Completed" -msgstr "Fecha de finalización" +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +# automatic translation +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "Cancelar transcripción" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +#, fuzzy +msgid "Rename" +msgstr "Vietnamita" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +# automatic translation +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "Cancelar transcripción" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +# automatic translation +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "Cancelar transcripción" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" # automatic translation #: buzz/widgets/recording_transcriber_widget.py:83 @@ -555,7 +620,7 @@ msgid "Show logs" msgstr "" # automatic translation -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "¡Estás al día!" @@ -589,70 +654,70 @@ msgstr "Ver" msgid "Timestamps" msgstr "Marcas de tiempo" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "Exportar" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "Traducir" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "Cambiar el tamaño" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "Buscar" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "Mostrar/Ocultar barra de búsqueda (Ctrl+F)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "Encontrar:" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "Introducir texto para encontrar..." -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "Coincidencia anterior (Mayús+Intro)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "Siguiente coincidencia (Enter)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "Limpiar" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "Controles de reproducción:" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "Segmento de bucle" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "" "Activar/desactivar la reproducción en bucle al hacer clic en segmentos de la " "transcripción" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "Seguir audio" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." @@ -661,44 +726,44 @@ msgstr "" "transcripción. Cuando está activado, se desplaza automáticamente al texto " "actual." -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "Desplácese hasta Actual" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "Desplazarse hasta el texto hablado actualmente" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "1 de 100+ coincidencias" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "1 de " -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr " coincidencias" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "No se encontraron coincidencias" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr " de 100+ coincidencias" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr " de " -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "Clave de API requerida" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "Ingrese la clave API de OpenAI en las preferencias" @@ -756,49 +821,49 @@ msgstr "Cancelar transcripción" msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" # automatic translation -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "Guardar archivo" @@ -873,7 +938,7 @@ msgid "File" msgstr "Archivo" # automatic translation -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." @@ -882,11 +947,11 @@ msgstr "" "no se puede deshacer." # automatic translation -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "Seleccionar archivo de audio" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "No se puede guardar la clave de la API de OpenAI en el llavero" diff --git a/buzz/locale/it_IT/LC_MESSAGES/buzz.po b/buzz/locale/it_IT/LC_MESSAGES/buzz.po index fd231e6a..efb8cb82 100644 --- a/buzz/locale/it_IT/LC_MESSAGES/buzz.po +++ b/buzz/locale/it_IT/LC_MESSAGES/buzz.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: buzz\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: 2025-11-09 20:22+0200\n" "Language-Team: (Italiano) Albano Battistella \n" "Language: it_IT\n" @@ -28,7 +28,7 @@ msgstr "https://esempio.com/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "Ok" @@ -36,7 +36,7 @@ msgstr "Ok" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "Annulla" @@ -308,7 +308,10 @@ msgid "Download failed" msgstr "Download non riuscito" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "Errore" @@ -437,54 +440,113 @@ msgstr "Apri trascrizione" msgid "Cancel Transcription" msgstr "Annulla trascrizione" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "Elimina la cronologia" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "In corso" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "Completato" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "Non riuscito" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "Annullato" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "In coda" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 msgid "File Name / URL" msgstr "Nome file / URL" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 msgid "Model" msgstr "Modello" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 msgid "Task" msgstr "Compito" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "Stato" -#: buzz/widgets/transcription_tasks_table_widget.py:129 +#: buzz/widgets/transcription_tasks_table_widget.py:133 +msgid "Date Completed" +msgstr "Data completata" + +#: buzz/widgets/transcription_tasks_table_widget.py:145 msgid "Date Added" msgstr "Data aggiunta" -#: buzz/widgets/transcription_tasks_table_widget.py:140 -msgid "Date Completed" -msgstr "Data completata" +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "Inizio trascrizione..." + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +#, fuzzy +msgid "Rename" +msgstr "Vietnamita" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "Annulla trascrizione" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "Inizio trascrizione..." + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" @@ -522,7 +584,7 @@ msgstr "Controlla gli aggiornamenti" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "Il programma è aggiornato!" @@ -555,69 +617,69 @@ msgstr "Visualizza" msgid "Timestamps" msgstr "Timestamp" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "Esporta" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "Tradurre" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "Ridimensionare" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "Trova" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "Mostra/Nascondi barra di ricerca (Ctrl+F)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "Trova:" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "Inserisci il testo per trovare..." -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "Corrispondenza precedente (Maiusc+Invio)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "Prossima corrispondenza (Invio)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "Elimina" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "Controlli di riproduzione:" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "Ciclo di segmento" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "" "Abilita/disabilita il loop quando si fa clic sui segmenti della trascrizione" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "Segui Audio" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." @@ -626,44 +688,44 @@ msgstr "" "trascrizione. Quando abilitato, scorre automaticamente fino al testo " "corrente." -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "Scorri fino al Corrente" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "Scorrere fino al testo attualmente pronunciato" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "1 di 100+ corrispondenze" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "1 di" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr "corrispondenze" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "Nessuna corrispondenza trovata" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr " di oltre 100 corrispondenze" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr " di " -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "Chiave API richiesta" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "Inserisci la chiave API OpenAI nelle preferenze" @@ -720,48 +782,48 @@ msgstr "Inizio trascrizione..." msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "Salva file" @@ -829,7 +891,7 @@ msgstr "Aiuto" msgid "File" msgstr "File" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." @@ -837,11 +899,11 @@ msgstr "" "Sei certo di voler eliminare le trascrizioni selezionate? Questa azione non " "può essere annullata." -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "Seleziona file audio" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "Impossibile salvare la chiave API OpenAI nel portachiavi" diff --git a/buzz/locale/ja_JP/LC_MESSAGES/buzz.po b/buzz/locale/ja_JP/LC_MESSAGES/buzz.po index 2bdda8b2..574c9d6c 100644 --- a/buzz/locale/ja_JP/LC_MESSAGES/buzz.po +++ b/buzz/locale/ja_JP/LC_MESSAGES/buzz.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: \n" "Last-Translator: nunawa <71294849+nunawa@users.noreply.github.com>\n" "Language-Team: \n" @@ -24,7 +24,7 @@ msgstr "https://example.com/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "Ok" @@ -32,7 +32,7 @@ msgstr "Ok" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "キャンセル" @@ -303,7 +303,10 @@ msgid "Download failed" msgstr "ダウンロード失敗" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "エラー" @@ -430,54 +433,112 @@ msgstr "文字起こしを開く" msgid "Cancel Transcription" msgstr "文字起こしをキャンセルする" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "履歴を削除する" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "進行中" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "完了" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "失敗" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "キャンセル済み" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "キュー済み" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 msgid "File Name / URL" msgstr "ファイル名 / URL" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 msgid "Model" msgstr "モデル" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 msgid "Task" msgstr "タスク" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "ステータス" -#: buzz/widgets/transcription_tasks_table_widget.py:129 +#: buzz/widgets/transcription_tasks_table_widget.py:133 +msgid "Date Completed" +msgstr "完了日" + +#: buzz/widgets/transcription_tasks_table_widget.py:145 msgid "Date Added" msgstr "追加日" -#: buzz/widgets/transcription_tasks_table_widget.py:140 -msgid "Date Completed" -msgstr "完了日" +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "文字起こしをキャンセルする" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +msgid "Rename" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "文字起こしをキャンセルする" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "文字起こしをキャンセルする" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" @@ -515,7 +576,7 @@ msgstr "アップデートを確認する" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "最新の状態です!" @@ -548,111 +609,111 @@ msgstr "表示" msgid "Timestamps" msgstr "タイムスタンプ" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "出力" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "翻訳" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "リサイズ" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "APIキーが必要" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "設定画面でOpenAI APIキーを入力してください" @@ -710,48 +771,48 @@ msgstr "文字起こしをキャンセルする" msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "ファイルを保存" @@ -819,17 +880,17 @@ msgstr "ヘルプ" msgid "File" msgstr "ファイル" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." msgstr "本当に選択された文字起こしを削除しますか? この操作は元に戻せません。" -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "音声ファイルを選択" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "OpenAI API キーをkeyringに保存できません" diff --git a/buzz/locale/lv_LV/LC_MESSAGES/buzz.po b/buzz/locale/lv_LV/LC_MESSAGES/buzz.po index df528784..600fdf03 100644 --- a/buzz/locale/lv_LV/LC_MESSAGES/buzz.po +++ b/buzz/locale/lv_LV/LC_MESSAGES/buzz.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 13:02+0200\n" -"PO-Revision-Date: 2025-11-23 12:58+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" +"PO-Revision-Date: 2025-12-06 11:34+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: lv_LV\n" @@ -29,7 +29,7 @@ msgstr "https://example.com/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "Labi" @@ -37,7 +37,7 @@ msgstr "Labi" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "Atcelt" @@ -310,7 +310,10 @@ msgid "Download failed" msgstr "Lejupielāde neizdevās" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "Kļūda" @@ -439,54 +442,110 @@ msgstr "Atvērt transkriptu" msgid "Cancel Transcription" msgstr "Atcelt atpazīšanu" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "Notīrīt vēsturi" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "Apstrādā" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "Pabeigts" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "Neizdevās" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "Atcelts" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "Ierindots" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 msgid "File Name / URL" msgstr "Fails / URL" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 msgid "Model" msgstr "Modelis" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 msgid "Task" msgstr "Uzdevums" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "Statuss" -#: buzz/widgets/transcription_tasks_table_widget.py:129 +#: buzz/widgets/transcription_tasks_table_widget.py:133 +msgid "Date Completed" +msgstr "Pabeigts" + +#: buzz/widgets/transcription_tasks_table_widget.py:145 msgid "Date Added" msgstr "Pievienots" -#: buzz/widgets/transcription_tasks_table_widget.py:140 -msgid "Date Completed" -msgstr "Pabeigts" +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "Piezīmes" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "Atjaunot kolonas" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +msgid "Restart Transcription" +msgstr "Sāk atpazīšanu" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +msgid "Rename" +msgstr "Pārddēvēt" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "Rediģēt piezīmes" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +msgid "Rename Transcription" +msgstr "Pārdēvēt" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "Ievadiet jauno nosaukumu šim atpazīšanas ierakstam:" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "Ievadiet noderīgas piezīmēs par šo ierakstu:" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "Neizdodas sākt" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "Atkārtoti sākt var tikai kļūdainus vai atceltus ierakstus." + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +msgid "Failed to restart transcription: {}" +msgstr "Neizdevās sākt atpazīšanu: {}" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" +"Neizdevās sākt atpazīšanu: modelis nav pieejams un to nevar lejupielādēt." + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "Neizdevās sākt atpazīšanu: Kļūda lietotnē, pārstartējiet." #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" @@ -524,7 +583,7 @@ msgstr "Pārbaudīt atjauninājumus" msgid "Show logs" msgstr "Parādīt sistēmas žurnālu" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "Jums ir jaunākā versija!" @@ -557,68 +616,68 @@ msgstr "Skats" msgid "Timestamps" msgstr "Laiks" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "Eksportēt" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "Tulkot" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "Mainīt garumu" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "Noteikt runātājus" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "Meklēt" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "Rādīt/Slēpt meklēšanas joslu (Ctrl+F)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "Meklēt:" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "Ievadiet meklējamo..." -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "Iepriekšējais rezultāts (Shift+Enter)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "Nākamais rezultāts (Enter)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "Notīrīt" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "Atskaņošanas iespējas:" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "Atkārtot segmentu" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "Nosaka vai atkārtot izvēlēto segmentu" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "Sekot audio" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." @@ -626,44 +685,44 @@ msgstr "" "Nosaka vai atskaņojot audio iezīmētajam segmentam vajadzētu automātiski " "sekot tam kas tiek atskaņots." -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "Pāriet uz tekošo" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "Pāriet uz šobrīd atskaņojamo tesktu" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "1 no 100+ " -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "1 no " -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr " " -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "Nekas nav atrasts" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr " no 100+" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr " no " -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "API atslēgas kļūda" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "Lūdzu ievadiet OpenAI API atslēgu iestatījumos" @@ -719,48 +778,48 @@ msgstr "5/8 Sagatavo transkripcijas" msgid "6/8 Identifying speakers" msgstr "6/8 Nosaka runātājus" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "0/0 Kļūda nosakot runātājus" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "7/8 Marķē runātāju teikumus" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "8/8 Runātāju noteikšana pabeigta" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "1. solis: Runātāju noteikšana" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "Noteikt" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "Gatavs noteikt runātājus" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "Audio datne nav atrasta" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "2. solis: Runātāju identifikācija" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "Atskaņot paraugu" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "Apvienot secīgus runātāja teikumus" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 msgid "Save" msgstr "Saglabāt" @@ -825,7 +884,7 @@ msgstr "Palīdzība" msgid "File" msgstr "Fails" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." @@ -833,11 +892,11 @@ msgstr "" "Vai tiešām vēlaties dzēst izvēlētos transkriptus? Šī ir neatgriezeniska " "darbība." -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "Izvēlieties audio failu" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "Neizdevās saglabāt OpenAI API atslēgu atslēgu saišķī" diff --git a/buzz/locale/nl/LC_MESSAGES/buzz.po b/buzz/locale/nl/LC_MESSAGES/buzz.po index 75b59ea1..7ae6ad7d 100644 --- a/buzz/locale/nl/LC_MESSAGES/buzz.po +++ b/buzz/locale/nl/LC_MESSAGES/buzz.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: 2025-03-20 18:30+0100\n" "Last-Translator: Heimen Stoffels \n" "Language-Team: none\n" @@ -31,7 +31,7 @@ msgstr "https://voorbeeld.nl/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "Oké" @@ -39,7 +39,7 @@ msgstr "Oké" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "Annuleren" @@ -309,7 +309,10 @@ msgid "Download failed" msgstr "Het downloaden is mislukt" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "Foutmelding" @@ -436,54 +439,113 @@ msgstr "Transcriptie openen" msgid "Cancel Transcription" msgstr "Transcriptie wissen" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "Geschiedenis wissen" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "In behandeling" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "Afgerond" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "Mislukt" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "Afgebroken" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "In wachtrij" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 msgid "File Name / URL" msgstr "Bestandsnaam/Url" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 msgid "Model" msgstr "Model" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 msgid "Task" msgstr "Taak" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "Status" -#: buzz/widgets/transcription_tasks_table_widget.py:129 +#: buzz/widgets/transcription_tasks_table_widget.py:133 +msgid "Date Completed" +msgstr "Afgerond op" + +#: buzz/widgets/transcription_tasks_table_widget.py:145 msgid "Date Added" msgstr "Toegevoegd op" -#: buzz/widgets/transcription_tasks_table_widget.py:140 -msgid "Date Completed" -msgstr "Afgerond op" +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "Transcriptie wissen" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +#, fuzzy +msgid "Rename" +msgstr "Vietnamees" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "Transcriptie wissen" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "Transcriptie wissen" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" @@ -519,7 +581,7 @@ msgstr "Controleren op updates" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "De software is actueel!" @@ -552,111 +614,111 @@ msgstr "Bekijken" msgid "Timestamps" msgstr "Tijdstippen" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "Exporteren" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "Vertalen" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "Grootte" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "Api-sleutel vereist" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "Voer de OpenAI-api-sleutel in in de instellingen" @@ -713,48 +775,48 @@ msgstr "Transcriptie wissen" msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "Bestand opslaan" @@ -821,7 +883,7 @@ msgstr "Hulp" msgid "File" msgstr "Bestand" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." @@ -829,11 +891,11 @@ msgstr "" "Weet u zeker dat u de gekozen transcriptie(s) wilt verwijderen? Deze actie " "is onomkeerbaar." -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "Kies een audiobestand" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "De OpenAI-api-sleutel kan niet worden bewaard in de sleutelbos" diff --git a/buzz/locale/pl_PL/LC_MESSAGES/buzz.po b/buzz/locale/pl_PL/LC_MESSAGES/buzz.po index 261fcd5b..fb2ab0c0 100644 --- a/buzz/locale/pl_PL/LC_MESSAGES/buzz.po +++ b/buzz/locale/pl_PL/LC_MESSAGES/buzz.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: 2024-03-17 20:50+0200\n" "Last-Translator: \n" "Language-Team: \n" @@ -29,7 +29,7 @@ msgstr "https://przyklad.pl/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "" @@ -37,7 +37,7 @@ msgstr "" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "Anuluj" @@ -310,7 +310,10 @@ msgid "Download failed" msgstr "Pobrany" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "Błąd" @@ -438,59 +441,117 @@ msgstr "Otwórz transkrypt" msgid "Cancel Transcription" msgstr "Anuluj transkrypcję" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "Wyczyść historię" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "Ukończono" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "Anulowano" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "Kolejka" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 #, fuzzy msgid "File Name / URL" msgstr "Nazwa pliku" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 #, fuzzy msgid "Model" msgstr "Model:" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 #, fuzzy msgid "Task" msgstr "Zadanie:" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "Status" -#: buzz/widgets/transcription_tasks_table_widget.py:129 -msgid "Date Added" -msgstr "" - -#: buzz/widgets/transcription_tasks_table_widget.py:140 +#: buzz/widgets/transcription_tasks_table_widget.py:133 #, fuzzy msgid "Date Completed" msgstr "Ukończono" +#: buzz/widgets/transcription_tasks_table_widget.py:145 +msgid "Date Added" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "Anuluj transkrypcję" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +msgid "Rename" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "Anuluj transkrypcję" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "Anuluj transkrypcję" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" + #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" msgstr "Nagrywanie na żywo" @@ -527,7 +588,7 @@ msgstr "Sprawdź aktualizacje" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "Posiadasz najnowszą wersję!" @@ -561,111 +622,111 @@ msgstr "" msgid "Timestamps" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "" @@ -722,48 +783,48 @@ msgstr "Anuluj transkrypcję" msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "Zapisz plik" @@ -831,7 +892,7 @@ msgstr "Pomoc" msgid "File" msgstr "Plik" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." @@ -839,11 +900,11 @@ msgstr "" "Czy na pewno chcesz usunąć zaznaczone transkrypcje? Tej operacji nie można " "cofnąć." -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "Wybierz plik audio" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "" diff --git a/buzz/locale/pt_BR/LC_MESSAGES/buzz.po b/buzz/locale/pt_BR/LC_MESSAGES/buzz.po index 39ae4c38..3ec83eb3 100644 --- a/buzz/locale/pt_BR/LC_MESSAGES/buzz.po +++ b/buzz/locale/pt_BR/LC_MESSAGES/buzz.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Buzz\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: 2025-11-01 17:43-0300\n" "Last-Translator: Paulo Schopf \n" "Language-Team: none\n" @@ -29,7 +29,7 @@ msgstr "https://exemplo.com/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "Ok" @@ -37,7 +37,7 @@ msgstr "Ok" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "Cancelar" @@ -307,7 +307,10 @@ msgid "Download failed" msgstr "Falha ao baixar" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "Erro" @@ -434,54 +437,113 @@ msgstr "Abrir Transcrição" msgid "Cancel Transcription" msgstr "Cancelar Transcrição" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "Limpar Histórico" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "Em Progresso" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "Concluído" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "Falhou" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "Cancelado" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "Na fila" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 msgid "File Name / URL" msgstr "Nome do Arquivo / URL" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 msgid "Model" msgstr "Modelo" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 msgid "Task" msgstr "Tarefa" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "Status" -#: buzz/widgets/transcription_tasks_table_widget.py:129 +#: buzz/widgets/transcription_tasks_table_widget.py:133 +msgid "Date Completed" +msgstr "Data de Conclusão" + +#: buzz/widgets/transcription_tasks_table_widget.py:145 msgid "Date Added" msgstr "Data de Adição" -#: buzz/widgets/transcription_tasks_table_widget.py:140 -msgid "Date Completed" -msgstr "Data de Conclusão" +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "Iniciando transcrição..." + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +#, fuzzy +msgid "Rename" +msgstr "Vietnamita" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "Cancelar Transcrição" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "Iniciando transcrição..." + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" @@ -519,7 +581,7 @@ msgstr "Verificar atualizações" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "Você está atualizado!" @@ -552,68 +614,68 @@ msgstr "Visualizar" msgid "Timestamps" msgstr "Marcações de tempo" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "Exportar" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "Traduzir" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "Redimensionar" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "Procurar" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "Mostrar/Ocultar a Barra de Pesquisa" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "Procurar:" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "Digite o texto a procurar..." -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "Encontro prévio (Shift+Enter)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "Póximo encontro (Enter)" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "Limpar" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "Controles de Reprodução:" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "Segmento de Loop" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "Habilitar/desabilitar loop ao clicar em segmentos de transcrição" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "Siga o Áudio" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." @@ -621,44 +683,44 @@ msgstr "" "Ativar/desativar a opção de seguir a posição atual do áudio na transcrição. " "Quando ativado, rola automaticamente para o texto atual." -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "Rolar para o Atual" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "Role até o texto falado no momento" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "1 de 100+ encontros" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "1 de " -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr " encontros" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "Nada encontrado" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr " de 100+ encontros" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr " de " -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "Chave API Necessária" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "Insira a chave API OpenAI nas preferências" @@ -715,48 +777,48 @@ msgstr "Iniciando transcrição..." msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "Salvar Arquivo" @@ -824,7 +886,7 @@ msgstr "Ajuda" msgid "File" msgstr "Arquivo" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." @@ -832,11 +894,11 @@ msgstr "" "Tem certeza que deseja excluir a(s) transcrição(ões) selecionada(s)? Esta " "ação não pode ser desfeita." -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "Selecionar arquivo de áudio" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "Não foi possível salvar a chave da API OpenAI no cofre de chaves" diff --git a/buzz/locale/uk_UA/LC_MESSAGES/buzz.po b/buzz/locale/uk_UA/LC_MESSAGES/buzz.po index 2ef57f95..f99cb036 100644 --- a/buzz/locale/uk_UA/LC_MESSAGES/buzz.po +++ b/buzz/locale/uk_UA/LC_MESSAGES/buzz.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: \n" "Last-Translator: Yevhen Popok \n" "Language-Team: \n" @@ -26,7 +26,7 @@ msgstr "https://example.com/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "Гаразд" @@ -34,7 +34,7 @@ msgstr "Гаразд" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "Скасувати" @@ -305,7 +305,10 @@ msgid "Download failed" msgstr "Невдале завантаження" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "Помилка" @@ -432,54 +435,112 @@ msgstr "Відкрити транскрипцію" msgid "Cancel Transcription" msgstr "Скасувати транскрипцію" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "Очистити історію" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "В процесі" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "Завершено" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "Невдача" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "Скасовано" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "У черзі" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 msgid "File Name / URL" msgstr "Назва файлу / посилання" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 msgid "Model" msgstr "Модель" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 msgid "Task" msgstr "Завдання" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "Стан" -#: buzz/widgets/transcription_tasks_table_widget.py:129 +#: buzz/widgets/transcription_tasks_table_widget.py:133 +msgid "Date Completed" +msgstr "Дата завершення" + +#: buzz/widgets/transcription_tasks_table_widget.py:145 msgid "Date Added" msgstr "Дата додавання" -#: buzz/widgets/transcription_tasks_table_widget.py:140 -msgid "Date Completed" -msgstr "Дата завершення" +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "Скасувати транскрипцію" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +msgid "Rename" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "Скасувати транскрипцію" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "Скасувати транскрипцію" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" @@ -517,7 +578,7 @@ msgstr "Перевірити оновлення" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "У вас актуальна версія!" @@ -550,111 +611,111 @@ msgstr "Вигляд" msgid "Timestamps" msgstr "Позначки часу" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "Експорт" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "Перекласти" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "Потрібен API-ключ" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "Будь ласка, введіть API-ключ OpenAI в налаштуваннях" @@ -711,48 +772,48 @@ msgstr "Скасувати транскрипцію" msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "Зберегти файл" @@ -819,18 +880,18 @@ msgstr "Допомога" msgid "File" msgstr "Файл" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." msgstr "" "Ви впевнені, що хочете видалити вибрані транскрипції? Це незворотна дія." -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "Вибрати аудіофайл" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "Не вдається додати до звʼязки ключів API-ключ OpenAI" diff --git a/buzz/locale/zh_CN/LC_MESSAGES/buzz.po b/buzz/locale/zh_CN/LC_MESSAGES/buzz.po index 5cdb3a7b..ef775c6c 100644 --- a/buzz/locale/zh_CN/LC_MESSAGES/buzz.po +++ b/buzz/locale/zh_CN/LC_MESSAGES/buzz.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: 2023-05-01 15:45+0800\n" "Last-Translator: \n" "Language-Team: lamb \n" @@ -29,7 +29,7 @@ msgstr "https://example.com/audio.mp3" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "Ok" @@ -37,7 +37,7 @@ msgstr "Ok" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "取消" @@ -313,7 +313,10 @@ msgid "Download failed" msgstr "下载模型失败" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "错误" @@ -441,59 +444,117 @@ msgstr "打开识别结果" msgid "Cancel Transcription" msgstr "取消识别" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "清除历史纪录" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "运行中" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "完成" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "失败" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "取消" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "队列中" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 #, fuzzy msgid "File Name / URL" msgstr "文件名称/URL" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 #, fuzzy msgid "Model" msgstr "模型" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 #, fuzzy msgid "Task" msgstr "任务" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "状态" -#: buzz/widgets/transcription_tasks_table_widget.py:129 -msgid "Date Added" -msgstr "添加日期" - -#: buzz/widgets/transcription_tasks_table_widget.py:140 +#: buzz/widgets/transcription_tasks_table_widget.py:133 #, fuzzy msgid "Date Completed" msgstr "完成时间" +#: buzz/widgets/transcription_tasks_table_widget.py:145 +msgid "Date Added" +msgstr "添加日期" + +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "取消识别" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +msgid "Rename" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "取消识别" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "取消识别" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" + #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" msgstr "实时录制" @@ -528,7 +589,7 @@ msgstr "检查更新" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "已经是最新版本" @@ -562,111 +623,111 @@ msgstr "查看" msgid "Timestamps" msgstr "时间戳" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "导出" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "翻译" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "调整大小" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "需要API Key" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "请在偏好设置中输入OpenAI API Key" @@ -724,48 +785,48 @@ msgstr "取消识别" msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "保存文件" @@ -833,17 +894,17 @@ msgstr "帮助" msgid "File" msgstr "文件" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." msgstr "您确定要删除所选录制吗?此操作无法撤消。" -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "选择音频文件" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "无法将OpenAI API密钥保存到密钥串" diff --git a/buzz/locale/zh_TW/LC_MESSAGES/buzz.po b/buzz/locale/zh_TW/LC_MESSAGES/buzz.po index fd0fe400..62e33959 100644 --- a/buzz/locale/zh_TW/LC_MESSAGES/buzz.po +++ b/buzz/locale/zh_TW/LC_MESSAGES/buzz.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-11-23 12:55+0200\n" +"POT-Creation-Date: 2025-12-06 11:29+0200\n" "PO-Revision-Date: 2023-05-01 15:45+0800\n" "Last-Translator: \n" "Language-Team: Lamb\n" @@ -29,7 +29,7 @@ msgstr "" #: buzz/widgets/preferences_dialog/preferences_dialog.py:69 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:251 #: buzz/widgets/transcriber/advanced_settings_dialog.py:97 -#: buzz/widgets/main_window.py:238 +#: buzz/widgets/main_window.py:239 msgid "Ok" msgstr "" @@ -37,7 +37,7 @@ msgstr "" #: buzz/widgets/preferences_dialog/preferences_dialog.py:70 #: buzz/widgets/preferences_dialog/models_preferences_widget.py:252 #: buzz/widgets/model_download_progress_dialog.py:30 -#: buzz/widgets/main_window.py:239 +#: buzz/widgets/main_window.py:240 msgid "Cancel" msgstr "取消" @@ -308,7 +308,10 @@ msgid "Download failed" msgstr "下載模型" #: buzz/widgets/preferences_dialog/models_preferences_widget.py:275 -#: buzz/widgets/main_window.py:295 buzz/model_loader.py:539 +#: buzz/widgets/transcription_tasks_table_widget.py:665 +#: buzz/widgets/transcription_tasks_table_widget.py:735 +#: buzz/widgets/transcription_tasks_table_widget.py:766 +#: buzz/widgets/main_window.py:296 buzz/model_loader.py:539 #: buzz/model_loader.py:553 msgid "Error" msgstr "" @@ -436,59 +439,117 @@ msgstr "打開轉換結果" msgid "Cancel Transcription" msgstr "取消錄製" -#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:227 +#: buzz/widgets/main_window_toolbar.py:71 buzz/widgets/main_window.py:228 #: buzz/settings/shortcut.py:36 msgid "Clear History" msgstr "清除歷史紀錄" -#: buzz/widgets/transcription_tasks_table_widget.py:69 +#: buzz/widgets/transcription_tasks_table_widget.py:71 msgid "In Progress" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:72 +#: buzz/widgets/transcription_tasks_table_widget.py:74 msgid "Completed" msgstr "完成" -#: buzz/widgets/transcription_tasks_table_widget.py:79 +#: buzz/widgets/transcription_tasks_table_widget.py:81 msgid "Failed" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:82 +#: buzz/widgets/transcription_tasks_table_widget.py:84 msgid "Canceled" msgstr "取消" -#: buzz/widgets/transcription_tasks_table_widget.py:84 +#: buzz/widgets/transcription_tasks_table_widget.py:86 msgid "Queued" msgstr "" -#: buzz/widgets/transcription_tasks_table_widget.py:91 +#: buzz/widgets/transcription_tasks_table_widget.py:93 #, fuzzy msgid "File Name / URL" msgstr "檔案名稱" -#: buzz/widgets/transcription_tasks_table_widget.py:103 +#: buzz/widgets/transcription_tasks_table_widget.py:106 #, fuzzy msgid "Model" msgstr "模型:" -#: buzz/widgets/transcription_tasks_table_widget.py:112 +#: buzz/widgets/transcription_tasks_table_widget.py:115 #, fuzzy msgid "Task" msgstr "任務:" -#: buzz/widgets/transcription_tasks_table_widget.py:121 +#: buzz/widgets/transcription_tasks_table_widget.py:124 msgid "Status" msgstr "狀態" -#: buzz/widgets/transcription_tasks_table_widget.py:129 -msgid "Date Added" -msgstr "" - -#: buzz/widgets/transcription_tasks_table_widget.py:140 +#: buzz/widgets/transcription_tasks_table_widget.py:133 #, fuzzy msgid "Date Completed" msgstr "完成" +#: buzz/widgets/transcription_tasks_table_widget.py:145 +msgid "Date Added" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:156 +#: buzz/widgets/transcription_tasks_table_widget.py:624 +msgid "Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:174 +msgid "Reset Column Order" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:301 +#, fuzzy +msgid "Restart Transcription" +msgstr "取消錄製" + +#: buzz/widgets/transcription_tasks_table_widget.py:305 +msgid "Rename" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:308 +msgid "Add/Edit Notes" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:597 +#, fuzzy +msgid "Rename Transcription" +msgstr "取消錄製" + +#: buzz/widgets/transcription_tasks_table_widget.py:598 +msgid "Enter new name:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:625 +msgid "Enter some relevant notes for this transcription:" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:652 +msgid "Cannot Restart" +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:653 +msgid "Only failed or canceled transcriptions can be restarted." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:666 +#, fuzzy +msgid "Failed to restart transcription: {}" +msgstr "取消錄製" + +#: buzz/widgets/transcription_tasks_table_widget.py:736 +msgid "" +"Could not restart transcription: model not available and could not be " +"downloaded." +msgstr "" + +#: buzz/widgets/transcription_tasks_table_widget.py:767 +msgid "Could not restart transcription: transcriber worker not found." +msgstr "" + #: buzz/widgets/recording_transcriber_widget.py:83 msgid "Live Recording" msgstr "現場錄製" @@ -523,7 +584,7 @@ msgstr "檢查更新" msgid "Show logs" msgstr "" -#: buzz/widgets/about_dialog.py:118 +#: buzz/widgets/about_dialog.py:119 msgid "You're up to date!" msgstr "你是最新的!" @@ -557,111 +618,111 @@ msgstr "" msgid "Timestamps" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:215 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:218 msgid "Export" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:234 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:237 msgid "Translate" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:244 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:247 #: buzz/widgets/transcription_viewer/transcription_resizer_widget.py:175 msgid "Resize" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:257 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:260 msgid "Identify Speakers" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:269 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 msgid "Find" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:272 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:275 msgid "Show/Hide Search Bar (Ctrl+F)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:337 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:340 msgid "Find:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:343 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:346 msgid "Enter text to find..." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:356 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:359 msgid "Previous match (Shift+Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:364 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:367 msgid "Next match (Enter)" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:372 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:375 msgid "Clear" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:399 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:402 msgid "Playback Controls:" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:404 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:407 msgid "Loop Segment" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:406 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:409 msgid "Enable/disable looping when clicking on transcript segments" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:412 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:415 msgid "Follow Audio" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:414 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:417 msgid "" "Enable/disable following the current audio position in the transcript. When " "enabled, automatically scrolls to current text." msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:461 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:464 msgid "Scroll to Current" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:463 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:466 msgid "Scroll to the currently spoken text" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:785 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:788 msgid "1 of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 msgid "1 of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:787 -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:790 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:792 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:795 msgid "No matches found" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:851 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:854 msgid " of 100+ matches" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:853 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:856 msgid " of " msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1208 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1211 msgid "API Key Required" msgstr "" -#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1209 +#: buzz/widgets/transcription_viewer/transcription_viewer_widget.py:1212 msgid "Please enter OpenAI API Key in preferences" msgstr "" @@ -718,48 +779,48 @@ msgstr "取消錄製" msgid "6/8 Identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:160 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:167 msgid "0/0 Error identifying speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:168 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:175 msgid "7/8 Mapping speakers to transcripts" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:207 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:214 msgid "8/8 Identification done" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:243 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:251 msgid "Step 1: Identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:255 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:263 msgid "Identify" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:265 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:272 msgid "Ready to identify speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:267 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:274 msgid "Audio file not found" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:283 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 msgid "Step 2: Name speakers" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:298 -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:391 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:406 msgid "Play sample" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:313 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:328 msgid "Merge speaker sentences" msgstr "" -#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:318 +#: buzz/widgets/transcription_viewer/speaker_identification_widget.py:333 #, fuzzy msgid "Save" msgstr "檔案" @@ -827,17 +888,17 @@ msgstr "幫助" msgid "File" msgstr "檔案" -#: buzz/widgets/main_window.py:231 +#: buzz/widgets/main_window.py:232 msgid "" "Are you sure you want to delete the selected transcription(s)? This action " "cannot be undone." msgstr "您確定要刪除所選錄製嗎?此操作無法撤消。" -#: buzz/widgets/main_window.py:259 +#: buzz/widgets/main_window.py:260 msgid "Select audio file" msgstr "選擇聲音檔案" -#: buzz/widgets/main_window.py:295 +#: buzz/widgets/main_window.py:296 msgid "Unable to save OpenAI API key to keyring" msgstr "" diff --git a/buzz/schema.sql b/buzz/schema.sql index ea603128..a6a11bad 100644 --- a/buzz/schema.sql +++ b/buzz/schema.sql @@ -17,7 +17,9 @@ CREATE TABLE transcription ( whisper_model_size TEXT, hugging_face_model_id TEXT, word_level_timings BOOLEAN DEFAULT FALSE, - extract_speech BOOLEAN DEFAULT FALSE + extract_speech BOOLEAN DEFAULT FALSE, + name TEXT, + notes TEXT ); CREATE TABLE transcription_segment ( diff --git a/buzz/settings/settings.py b/buzz/settings/settings.py index 3d6c46ac..288b0c76 100644 --- a/buzz/settings/settings.py +++ b/buzz/settings/settings.py @@ -53,6 +53,12 @@ class Settings: TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY = ( "transcription-tasks-table/column-visibility" ) + TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER = ( + "transcription-tasks-table/column-order" + ) + TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS = ( + "transcription-tasks-table/column-widths" + ) MAIN_WINDOW = "main-window" TRANSCRIPTION_VIEWER = "transcription-viewer" diff --git a/buzz/transcriber/whisper_file_transcriber.py b/buzz/transcriber/whisper_file_transcriber.py index 08a20426..8faf016b 100644 --- a/buzz/transcriber/whisper_file_transcriber.py +++ b/buzz/transcriber/whisper_file_transcriber.py @@ -72,9 +72,11 @@ class WhisperFileTranscriber(FileTranscriber): self.read_line_thread = Thread(target=self.read_line, args=(self.recv_pipe,)) self.read_line_thread.start() - self.current_process.join() + # Only join the process if it was actually started + if self.started_process: + self.current_process.join() - if self.current_process.exitcode != 0: + if self.started_process and self.current_process.exitcode != 0: self.send_pipe.close() # Join read_line_thread with timeout to prevent hanging @@ -94,7 +96,14 @@ class WhisperFileTranscriber(FileTranscriber): ) if self.current_process.exitcode != 0: - raise Exception("Unknown error") + # Check if the process was terminated (likely due to cancellation) + # Exit codes 124-128 are often used for termination signals + if self.current_process.exitcode in [124, 125, 126, 127, 128, 130, 137, 143]: + # Process was likely terminated, treat as cancellation + logging.debug("Whisper process was terminated (exit code: %s), treating as cancellation", self.current_process.exitcode) + raise Exception("Transcription was canceled") + else: + raise Exception("Unknown error") return self.segments diff --git a/buzz/widgets/main_window.py b/buzz/widgets/main_window.py index 306bc3f8..88252032 100644 --- a/buzz/widgets/main_window.py +++ b/buzz/widgets/main_window.py @@ -110,6 +110,7 @@ class MainWindow(QMainWindow): self.setMenuBar(self.menu_bar) self.table_widget = TranscriptionTasksTableWidget(self) + self.table_widget.transcription_service = self.transcription_service self.table_widget.doubleClicked.connect(self.on_table_double_clicked) self.table_widget.return_clicked.connect(self.open_transcript_viewer) self.table_widget.selectionModel().selectionChanged.connect( diff --git a/buzz/widgets/transcription_tasks_table_widget.py b/buzz/widgets/transcription_tasks_table_widget.py index 24f5c7f2..0d79b35b 100644 --- a/buzz/widgets/transcription_tasks_table_widget.py +++ b/buzz/widgets/transcription_tasks_table_widget.py @@ -50,6 +50,8 @@ class Column(enum.Enum): HUGGING_FACE_MODEL_ID = 16 WORD_LEVEL_TIMINGS = 17 EXTRACT_SPEECH = 18 + NAME = 19 + NOTES = 20 @dataclass @@ -92,9 +94,10 @@ column_definitions = [ column=Column.FILE, width=400, delegate=RecordDelegate( - text_getter=lambda record: record.value("url") - if record.value("url") != "" - else os.path.basename(record.value("file")) + text_getter=lambda record: record.value("name") or ( + record.value("url") if record.value("url") != "" + else os.path.basename(record.value("file")) + ) ), hidden_toggleable=False, ), @@ -122,19 +125,9 @@ column_definitions = [ column=Column.STATUS, width=180, delegate=RecordDelegate(text_getter=format_record_status_text), - hidden_toggleable=False, - ), - ColDef( - id="date_added", - header=_("Date Added"), - column=Column.TIME_QUEUED, - width=180, - delegate=RecordDelegate( - text_getter=lambda record: datetime.fromisoformat( - record.value("time_queued") - ).strftime("%Y-%m-%d %H:%M:%S") - ), + hidden_toggleable=True, ), + ColDef( id="date_completed", header=_("Date Completed"), @@ -147,6 +140,26 @@ column_definitions = [ if record.value("time_ended") != "" else "" ), + ), ColDef( + id="date_added", + header=_("Date Added"), + column=Column.TIME_QUEUED, + width=180, + delegate=RecordDelegate( + text_getter=lambda record: datetime.fromisoformat( + record.value("time_queued") + ).strftime("%Y-%m-%d %H:%M:%S") + ), + ), + ColDef( + id="notes", + header=_("Notes"), + column=Column.NOTES, + width=300, + delegate=RecordDelegate( + text_getter=lambda record: record.value("notes") or "" + ), + hidden_toggleable=True, ), ] @@ -156,28 +169,71 @@ class TranscriptionTasksTableHeaderView(QHeaderView): def contextMenuEvent(self, event): menu = QMenu(self) + + # Add reset column order option + menu.addAction(_("Reset Column Order")).triggered.connect(self.parent().reset_column_order) + menu.addSeparator() + + # Add column visibility toggles for definition in column_definitions: - if not definition.hidden_toggleable: - continue - action = menu.addAction(definition.header) - action.setCheckable(True) - action.setChecked(not self.isSectionHidden(definition.column.value)) - action.toggled.connect( - lambda checked, column_index=definition.column.value: self.on_column_checked( - column_index, checked + if definition.hidden_toggleable: + action = menu.addAction(definition.header) + action.setCheckable(True) + action.setChecked(not self.parent().isColumnHidden(definition.column.value)) + action.toggled.connect( + lambda checked, column_index=definition.column.value: self.on_column_checked( + column_index, checked + ) ) - ) menu.exec(event.globalPos()) def on_column_checked(self, column_index: int, checked: bool): - self.setSectionHidden(column_index, not checked) + # Find the column definition for this index + column_def = None + for definition in column_definitions: + if definition.column.value == column_index: + column_def = definition + break + + # If we're hiding the column, save its current width first + if not checked and not self.parent().isColumnHidden(column_index): + current_width = self.parent().columnWidth(column_index) + if current_width > 0: # Only save if there's a meaningful width + self.parent().settings.begin_group(self.parent().settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS) + self.parent().settings.settings.setValue(column_def.id, current_width) + self.parent().settings.end_group() + + # Update the visibility state on the table view (not header view) + self.parent().setColumnHidden(column_index, not checked) + + # Save current column order before any reloading + self.parent().save_column_order() + + # Save both visibility and widths after the change self.parent().save_column_visibility() + self.parent().save_column_widths() + + # Ensure settings are synchronized + self.parent().settings.settings.sync() + + # Force a complete refresh of the table + self.parent().viewport().update() + self.parent().repaint() + self.parent().horizontalHeader().update() + self.parent().updateGeometry() + self.parent().adjustSize() + + # Force a model refresh to ensure the view is updated + self.parent().model().layoutChanged.emit() + + self.parent().reload_column_order_from_settings() class TranscriptionTasksTableWidget(QTableView): return_clicked = pyqtSignal() def __init__(self, parent: Optional[QWidget] = None): super().__init__(parent) + self.transcription_service = None self.setHorizontalHeader(TranscriptionTasksTableHeaderView(Qt.Orientation.Horizontal, self)) @@ -193,57 +249,66 @@ class TranscriptionTasksTableWidget(QTableView): self.settings = Settings() - self.settings.begin_group( - Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY - ) + # Set up column headers and delegates for definition in column_definitions: self.model().setHeaderData( definition.column.value, Qt.Orientation.Horizontal, definition.header, ) - - visible = True - if definition.hidden_toggleable: - visible = self.settings.settings.value(definition.id, "true") in {"true", "True", True} - - self.setColumnHidden(definition.column.value, not visible) - if definition.width is not None: - self.setColumnWidth(definition.column.value, definition.width) if definition.delegate is not None: self.setItemDelegateForColumn( definition.column.value, definition.delegate ) - self.settings.end_group() + + # Load column visibility + self.load_column_visibility() self.model().select() self.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) self.verticalHeader().hide() self.setAlternatingRowColors(True) + + # Enable column sorting and moving + self.setSortingEnabled(True) + self.horizontalHeader().setSectionsMovable(True) + self.horizontalHeader().setSectionsClickable(True) + self.horizontalHeader().setSortIndicatorShown(True) - # Show date added before date completed - self.horizontalHeader().swapSections(11, 12) + # Connect signals for column resize and move + self.horizontalHeader().sectionResized.connect(self.on_column_resized) + self.horizontalHeader().sectionMoved.connect(self.on_column_moved) + + # Load saved column order and widths + self.load_column_order() + self.load_column_widths() + + + # Reload column visibility after all reordering is complete + self.load_column_visibility() def contextMenuEvent(self, event): menu = QMenu(self) - for definition in column_definitions: - if not definition.hidden_toggleable: - continue - action = menu.addAction(definition.header) - action.setCheckable(True) - action.setChecked(not self.isColumnHidden(definition.column.value)) - action.toggled.connect( - lambda checked, - column_index=definition.column.value: self.on_column_checked( - column_index, checked - ) - ) - menu.exec(event.globalPos()) + + # Add transcription actions if a row is selected + selected_rows = self.selectionModel().selectedRows() + if selected_rows: + transcription = self.transcription(selected_rows[0]) - def on_column_checked(self, column_index: int, checked: bool): - self.setColumnHidden(column_index, not checked) - self.save_column_visibility() + # Add restart/continue action for failed/canceled tasks + if transcription.status in ["failed", "canceled"]: + restart_action = menu.addAction(_("Restart Transcription")) + restart_action.triggered.connect(self.on_restart_transcription_action) + menu.addSeparator() + + rename_action = menu.addAction(_("Rename")) + rename_action.triggered.connect(self.on_rename_action) + + notes_action = menu.addAction(_("Add/Edit Notes")) + notes_action.triggered.connect(self.on_notes_action) + + menu.exec(event.globalPos()) def save_column_visibility(self): self.settings.begin_group( @@ -255,6 +320,194 @@ class TranscriptionTasksTableWidget(QTableView): ) self.settings.end_group() + def on_column_resized(self, logical_index: int, old_size: int, new_size: int): + """Handle column resize events""" + self.save_column_widths() + + def on_column_moved(self, logical_index: int, old_visual_index: int, new_visual_index: int): + """Handle column move events""" + self.save_column_order() + # Refresh visibility after column move to ensure it's maintained + self.load_column_visibility() + + def on_double_click(self, index: QModelIndex): + """Handle double-click events - trigger notes edit for notes column""" + if index.column() == Column.NOTES.value: + self.on_notes_action() + + def save_column_widths(self): + """Save current column widths to settings""" + self.settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS) + for definition in column_definitions: + # Only save width if column is visible and has a meaningful width + if not self.isColumnHidden(definition.column.value): + width = self.columnWidth(definition.column.value) + if width > 0: # Only save if there's a meaningful width + self.settings.settings.setValue(definition.id, width) + self.settings.end_group() + + def save_column_order(self): + """Save current column order to settings""" + self.settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER) + header = self.horizontalHeader() + for visual_index in range(header.count()): + logical_index = header.logicalIndex(visual_index) + # Find the column definition for this logical index + for definition in column_definitions: + if definition.column.value == logical_index: + self.settings.settings.setValue(definition.id, visual_index) + break + self.settings.end_group() + + def load_column_widths(self): + """Load saved column widths from settings""" + self.settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS) + for definition in column_definitions: + if definition.width is not None: # Only load if column has a default width + saved_width = self.settings.settings.value(definition.id, definition.width) + if saved_width is not None: + self.setColumnWidth(definition.column.value, int(saved_width)) + self.settings.end_group() + + def load_column_visibility(self): + """Load saved column visibility from settings""" + self.settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY) + for definition in column_definitions: + visible = True + if definition.hidden_toggleable: + value = self.settings.settings.value(definition.id, "true") + visible = value in {"true", "True", True} + + self.setColumnHidden(definition.column.value, not visible) + self.settings.end_group() + + # Force a refresh of the table layout + self.horizontalHeader().update() + self.viewport().update() + self.updateGeometry() + + def load_column_order(self): + """Load saved column order from settings""" + self.settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER) + + # Create a mapping of column IDs to their saved visual positions + column_positions = {} + for definition in column_definitions: + saved_position = self.settings.settings.value(definition.id) + if saved_position is not None: + column_positions[definition.column.value] = int(saved_position) + + self.settings.end_group() + + # Apply the saved order + if column_positions: + header = self.horizontalHeader() + for logical_index, visual_position in column_positions.items(): + if 0 <= visual_position < header.count(): + header.moveSection(header.visualIndex(logical_index), visual_position) + + def reset_column_order(self): + """Reset column order to default""" + + # Reset column widths to defaults + for definition in column_definitions: + if definition.width is not None: + self.setColumnWidth(definition.column.value, definition.width) + + # Show all columns + for definition in column_definitions: + self.setColumnHidden(definition.column.value, False) + + # Restore default column order + header = self.horizontalHeader() + # Move each section to its default position in order + # To avoid index shifting, move from left to right + for target_visual_index, definition in enumerate(column_definitions): + logical_index = definition.column.value + current_visual_index = header.visualIndex(logical_index) + if current_visual_index != target_visual_index: + header.moveSection(current_visual_index, target_visual_index) + + # Clear saved settings + self.settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER) + self.settings.settings.remove("") + self.settings.end_group() + + self.settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS) + self.settings.settings.remove("") + self.settings.end_group() + + # Save the reset state for both visibility and widths + self.save_column_visibility() + self.save_column_widths() + + # Force a refresh of the table layout + self.horizontalHeader().update() + self.viewport().update() + self.updateGeometry() + + def reload_column_order_from_settings(self): + """Reload column order, width, and visibility from settings""" + + # --- Load column visibility --- + self.settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY) + visibility_settings = {} + for definition in column_definitions: + vis = self.settings.settings.value(definition.id) + if vis is not None: + visibility_settings[definition.id] = str(vis).lower() not in ("0", "false", "no") + self.settings.end_group() + + # --- Load column widths --- + self.settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS) + width_settings = {} + for definition in column_definitions: + width = self.settings.settings.value(definition.id) + if width is not None: + try: + width_settings[definition.id] = int(width) + except Exception: + pass + self.settings.end_group() + + # --- Load column order --- + self.settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER) + order_settings = {} + for definition in column_definitions: + pos = self.settings.settings.value(definition.id) + if pos is not None: + try: + order_settings[definition.column.value] = int(pos) + except Exception: + pass + self.settings.end_group() + + # --- Apply visibility, widths, and order --- + header = self.horizontalHeader() + + # First, set visibility and width for each column + for definition in column_definitions: + is_visible = visibility_settings.get(definition.id, True) + width = width_settings.get(definition.id, definition.width) + self.setColumnHidden(definition.column.value, not is_visible) + if width is not None: + self.setColumnWidth(definition.column.value, max(width, 100)) + + # Then, apply column order + # Build a list of (logical_index, visual_position) for ALL columns (including hidden ones) + all_columns = [ + (definition.column.value, order_settings.get(definition.column.value, idx)) + for idx, definition in enumerate(column_definitions) + ] + # Sort by saved visual position + all_columns.sort(key=lambda x: x[1]) + + # Move sections to match the saved order + for target_visual, (logical_index, _) in enumerate(all_columns): + current_visual = header.visualIndex(logical_index) + if current_visual != target_visual: + header.moveSection(current_visual, target_visual) + def copy_selected_fields(self): selected_text = "" for row in self.selectionModel().selectedRows(): @@ -267,6 +520,17 @@ class TranscriptionTasksTableWidget(QTableView): selected_text = selected_text.rstrip("\n") QApplication.clipboard().setText(selected_text) + def mouseDoubleClickEvent(self, event: QtGui.QMouseEvent) -> None: + """Override double-click to prevent default behavior when clicking on notes column""" + index = self.indexAt(event.pos()) + if index.isValid() and index.column() == Column.NOTES.value: + # Handle our custom double-click action without triggering default behavior + self.on_double_click(index) + event.accept() + else: + # For other columns, use default behavior + super().mouseDoubleClickEvent(event) + def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: if event.key() == Qt.Key.Key_Return: self.return_clicked.emit() @@ -309,4 +573,196 @@ class TranscriptionTasksTableWidget(QTableView): result = f"{mm}m {result}" if hh == 0: return result - return f"{hh}h {result}" \ No newline at end of file + return f"{hh}h {result}" + + def on_rename_action(self): + selected_rows = self.selectionModel().selectedRows() + if not selected_rows: + return + + # Get the first selected transcription + transcription = self.transcription(selected_rows[0]) + + # Get current name or fallback to file name + current_name = transcription.name or ( + transcription.url if transcription.url + else os.path.basename(transcription.file) if transcription.file + else "" + ) + + # Show input dialog + from PyQt6.QtWidgets import QInputDialog + new_name, ok = QInputDialog.getText( + self, + _("Rename Transcription"), + _("Enter new name:"), + text=current_name + ) + + if ok and new_name.strip(): + # Update the transcription name + from uuid import UUID + self.transcription_service.update_transcription_name( + UUID(transcription.id), + new_name.strip() + ) + self.refresh_all() + + def on_notes_action(self): + selected_rows = self.selectionModel().selectedRows() + if not selected_rows: + return + + # Get the first selected transcription + transcription = self.transcription(selected_rows[0]) + + # Show input dialog for notes + from PyQt6.QtWidgets import QInputDialog + current_notes = transcription.notes or "" + new_notes, ok = QInputDialog.getMultiLineText( + self, + _("Notes"), + _("Enter some relevant notes for this transcription:"), + text=current_notes + ) + + if ok: + # Update the transcription notes + from uuid import UUID + self.transcription_service.update_transcription_notes( + UUID(transcription.id), + new_notes + ) + self.refresh_all() + + def on_restart_transcription_action(self): + """Restart transcription for failed or canceled tasks""" + selected_rows = self.selectionModel().selectedRows() + if not selected_rows: + return + + # Get the first selected transcription + transcription = self.transcription(selected_rows[0]) + + # Check if the task can be restarted + if transcription.status not in ["failed", "canceled"]: + from PyQt6.QtWidgets import QMessageBox + QMessageBox.information( + self, + _("Cannot Restart"), + _("Only failed or canceled transcriptions can be restarted.") + ) + return + + try: + self.transcription_service.reset_transcription_for_restart(UUID(transcription.id)) + self._restart_transcription_task(transcription) + self.refresh_all() + except Exception as e: + from PyQt6.QtWidgets import QMessageBox + QMessageBox.warning( + self, + _("Error"), + _("Failed to restart transcription: {}").format(str(e)) + ) + + def _restart_transcription_task(self, transcription): + """Create a new FileTranscriptionTask and add it to the queue worker""" + from buzz.transcriber.transcriber import ( + FileTranscriptionTask, + TranscriptionOptions, + FileTranscriptionOptions, + Task + ) + from buzz.model_loader import TranscriptionModel, ModelType + from buzz.transcriber.transcriber import OutputFormat + + # Recreate the transcription options from the database record + from buzz.model_loader import WhisperModelSize + + # Convert string whisper_model_size to enum if it exists + whisper_model_size = None + if transcription.whisper_model_size: + try: + whisper_model_size = WhisperModelSize(transcription.whisper_model_size) + except ValueError: + # If the stored value is invalid, use a default + whisper_model_size = WhisperModelSize.TINY + + transcription_options = TranscriptionOptions( + language=transcription.language if transcription.language else None, + task=Task(transcription.task) if transcription.task else Task.TRANSCRIBE, + model=TranscriptionModel( + model_type=ModelType(transcription.model_type) if transcription.model_type else ModelType.WHISPER, + whisper_model_size=whisper_model_size, + hugging_face_model_id=transcription.hugging_face_model_id + ), + word_level_timings=transcription.word_level_timings == "1" if transcription.word_level_timings else False, + extract_speech=transcription.extract_speech == "1" if transcription.extract_speech else False, + initial_prompt="", # Not stored in database, use default + openai_access_token="", # Not stored in database, use default + enable_llm_translation=False, # Not stored in database, use default + llm_prompt="", # Not stored in database, use default + llm_model="" # Not stored in database, use default + ) + + # Recreate the file transcription options + output_formats = set() + if transcription.export_formats: + for format_str in transcription.export_formats.split(','): + try: + output_formats.add(OutputFormat(format_str.strip())) + except ValueError: + pass # Skip invalid formats + + file_transcription_options = FileTranscriptionOptions( + url=transcription.url if transcription.url else None, + output_formats=output_formats + ) + + # Get the model path from the transcription options + model_path = transcription_options.model.get_local_model_path() + if model_path is None: + # If model is not available locally, we need to download it + from buzz.model_loader import ModelDownloader + ModelDownloader(model=transcription_options.model).run() + model_path = transcription_options.model.get_local_model_path() + + if model_path is None: + from PyQt6.QtWidgets import QMessageBox + QMessageBox.warning( + self, + _("Error"), + _("Could not restart transcription: model not available and could not be downloaded.") + ) + return + + # Create the new task + task = FileTranscriptionTask( + transcription_options=transcription_options, + file_transcription_options=file_transcription_options, + model_path=model_path, + file_path=transcription.file if transcription.file else None, + url=transcription.url if transcription.url else None, + output_directory=transcription.output_folder if transcription.output_folder else None, + source=FileTranscriptionTask.Source(transcription.source) if transcription.source else FileTranscriptionTask.Source.FILE_IMPORT, + uid=UUID(transcription.id) + ) + + # Add the task to the queue worker + # We need to access the main window's transcriber worker + # This is a bit of a hack, but it's the cleanest way given the current architecture + main_window = self.parent() + while main_window and not hasattr(main_window, 'transcriber_worker'): + main_window = main_window.parent() + + if main_window and hasattr(main_window, 'transcriber_worker'): + main_window.transcriber_worker.add_task(task) + else: + # Fallback: show error if we can't find the transcriber worker + from PyQt6.QtWidgets import QMessageBox + QMessageBox.warning( + self, + _("Error"), + _("Could not restart transcription: transcriber worker not found.") + ) \ No newline at end of file diff --git a/tests/db/dao/transcription_dao_test.py b/tests/db/dao/transcription_dao_test.py new file mode 100644 index 00000000..6a0aa1fc --- /dev/null +++ b/tests/db/dao/transcription_dao_test.py @@ -0,0 +1,240 @@ +import pytest +from unittest.mock import Mock, patch +from uuid import UUID, uuid4 +from PyQt6.QtSql import QSqlDatabase, QSqlQuery + +from buzz.db.dao.transcription_dao import TranscriptionDAO +from buzz.db.entity.transcription import Transcription + + +@pytest.fixture +def db(): + """Create an in-memory SQLite database for testing""" + db = QSqlDatabase.addDatabase("QSQLITE") + db.setDatabaseName(":memory:") + assert db.open() + + # Create the transcription table with the new schema + query = QSqlQuery(db) + query.exec(""" + CREATE TABLE transcription ( + id TEXT PRIMARY KEY, + error_message TEXT, + export_formats TEXT, + file TEXT, + output_folder TEXT, + progress DOUBLE PRECISION DEFAULT 0.0, + language TEXT, + model_type TEXT, + source TEXT, + status TEXT, + task TEXT, + time_ended TIMESTAMP, + time_queued TIMESTAMP NOT NULL, + time_started TIMESTAMP, + url TEXT, + whisper_model_size TEXT, + hugging_face_model_id TEXT, + word_level_timings BOOLEAN DEFAULT FALSE, + extract_speech BOOLEAN DEFAULT FALSE, + name TEXT, + notes TEXT + ) + """) + + yield db + db.close() + + +@pytest.fixture +def transcription_dao(db): + """Create a TranscriptionDAO instance for testing""" + return TranscriptionDAO(db) + + +@pytest.fixture +def sample_transcription(): + """Create a sample transcription for testing""" + return Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="Test Transcription", + notes="This is a test transcription" + ) + + +class TestTranscriptionDAO: + def test_insert_transcription_with_name_and_notes(self, transcription_dao, sample_transcription): + """Test inserting a transcription with name and notes fields""" + transcription_dao.insert(sample_transcription) + + # Verify the transcription was inserted + query = QSqlQuery(transcription_dao.db) + query.prepare("SELECT * FROM transcription WHERE id = :id") + query.bindValue(":id", sample_transcription.id) + assert query.exec() + assert query.next() + + # Check that name and notes were stored + assert query.value("name") == "Test Transcription" + assert query.value("notes") == "This is a test transcription" + + def test_update_transcription_name(self, transcription_dao, sample_transcription): + """Test updating transcription name""" + # Insert the transcription first + transcription_dao.insert(sample_transcription) + + # Update the name + new_name = "Updated Transcription Name" + transcription_dao.update_transcription_name(UUID(sample_transcription.id), new_name) + + # Verify the name was updated + query = QSqlQuery(transcription_dao.db) + query.prepare("SELECT name FROM transcription WHERE id = :id") + query.bindValue(":id", sample_transcription.id) + assert query.exec() + assert query.next() + assert query.value("name") == new_name + + def test_update_transcription_notes(self, transcription_dao, sample_transcription): + """Test updating transcription notes""" + # Insert the transcription first + transcription_dao.insert(sample_transcription) + + # Update the notes + new_notes = "Updated transcription notes with more details" + transcription_dao.update_transcription_notes(UUID(sample_transcription.id), new_notes) + + # Verify the notes were updated + query = QSqlQuery(transcription_dao.db) + query.prepare("SELECT notes FROM transcription WHERE id = :id") + query.bindValue(":id", sample_transcription.id) + assert query.exec() + assert query.next() + assert query.value("notes") == new_notes + + def test_update_transcription_name_nonexistent_id(self, transcription_dao): + """Test updating name for non-existent transcription ID""" + nonexistent_id = uuid4() + + # This should raise an exception + with pytest.raises(Exception): + transcription_dao.update_transcription_name(nonexistent_id, "New Name") + + def test_update_transcription_notes_nonexistent_id(self, transcription_dao): + """Test updating notes for non-existent transcription ID""" + nonexistent_id = uuid4() + + # This should raise an exception + with pytest.raises(Exception): + transcription_dao.update_transcription_notes(nonexistent_id, "New Notes") + + def test_update_transcription_name_empty_string(self, transcription_dao, sample_transcription): + """Test updating transcription name to empty string""" + # Insert the transcription first + transcription_dao.insert(sample_transcription) + + # Update the name to empty string + transcription_dao.update_transcription_name(UUID(sample_transcription.id), "") + + # Verify the name was updated to empty string + query = QSqlQuery(transcription_dao.db) + query.prepare("SELECT name FROM transcription WHERE id = :id") + query.bindValue(":id", sample_transcription.id) + assert query.exec() + assert query.next() + assert query.value("name") == "" + + def test_update_transcription_notes_empty_string(self, transcription_dao, sample_transcription): + """Test updating transcription notes to empty string""" + # Insert the transcription first + transcription_dao.insert(sample_transcription) + + # Update the notes to empty string + transcription_dao.update_transcription_notes(UUID(sample_transcription.id), "") + + # Verify the notes were updated to empty string + query = QSqlQuery(transcription_dao.db) + query.prepare("SELECT notes FROM transcription WHERE id = :id") + query.bindValue(":id", sample_transcription.id) + assert query.exec() + assert query.next() + assert query.value("notes") == "" + + def test_update_transcription_name_with_none(self, transcription_dao, sample_transcription): + """Test updating transcription name to None (should be stored as NULL)""" + # Insert the transcription first + transcription_dao.insert(sample_transcription) + + # Update the name to None + transcription_dao.update_transcription_name(UUID(sample_transcription.id), None) + + # Verify the name was updated to None (NULL in database) + query = QSqlQuery(transcription_dao.db) + query.prepare("SELECT name FROM transcription WHERE id = :id") + query.bindValue(":id", sample_transcription.id) + assert query.exec() + assert query.next() + # In SQLite, None values are returned as empty strings + assert query.value("name") == "" + + def test_update_transcription_notes_with_none(self, transcription_dao, sample_transcription): + """Test updating transcription notes to None (should be stored as NULL)""" + # Insert the transcription first + transcription_dao.insert(sample_transcription) + + # Update the notes to None + transcription_dao.update_transcription_notes(UUID(sample_transcription.id), None) + + # Verify the notes were updated to None (NULL in database) + query = QSqlQuery(transcription_dao.db) + query.prepare("SELECT notes FROM transcription WHERE id = :id") + query.bindValue(":id", sample_transcription.id) + assert query.exec() + assert query.next() + # In SQLite, None values are returned as empty strings + assert query.value("notes") == "" + + def test_insert_transcription_without_name_and_notes(self, transcription_dao): + """Test inserting a transcription without name and notes (should be NULL)""" + transcription = Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER" + # name and notes not provided + ) + + transcription_dao.insert(transcription) + + # Verify the transcription was inserted with NULL name and notes + query = QSqlQuery(transcription_dao.db) + query.prepare("SELECT name, notes FROM transcription WHERE id = :id") + query.bindValue(":id", transcription.id) + assert query.exec() + assert query.next() + + # In SQLite, NULL values are returned as empty strings + assert query.value("name") == "" + assert query.value("notes") == "" + + def test_database_error_handling(self, transcription_dao): + """Test that database errors are properly handled""" + # Mock a database error by using an invalid query + with patch.object(transcription_dao, '_create_query') as mock_create_query: + mock_query = Mock() + mock_query.prepare.return_value = True + mock_query.bindValue.return_value = None + mock_query.exec.return_value = False + mock_query.lastError.return_value.text.return_value = "Database error" + mock_create_query.return_value = mock_query + + # This should raise an exception with the database error message + with pytest.raises(Exception, match="Database error"): + transcription_dao.update_transcription_name(uuid4(), "Test Name") diff --git a/tests/db/entity/transcription_test.py b/tests/db/entity/transcription_test.py new file mode 100644 index 00000000..1023719c --- /dev/null +++ b/tests/db/entity/transcription_test.py @@ -0,0 +1,286 @@ +import pytest +from uuid import uuid4 + +from buzz.db.entity.transcription import Transcription + + +class TestTranscription: + def test_transcription_creation_with_name_and_notes(self): + """Test creating a transcription with name and notes fields""" + transcription = Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="Test Transcription Name", + notes="This is a test transcription with notes" + ) + + assert transcription.name == "Test Transcription Name" + assert transcription.notes == "This is a test transcription with notes" + + def test_transcription_creation_without_name_and_notes(self): + """Test creating a transcription without name and notes (should be None)""" + transcription = Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER" + ) + + assert transcription.name is None + assert transcription.notes is None + + def test_transcription_creation_with_empty_name_and_notes(self): + """Test creating a transcription with empty name and notes""" + transcription = Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="", + notes="" + ) + + assert transcription.name == "" + assert transcription.notes == "" + + def test_transcription_name_assignment(self): + """Test assigning values to name field""" + transcription = Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER" + ) + + # Test assigning a name + transcription.name = "New Name" + assert transcription.name == "New Name" + + # Test assigning None + transcription.name = None + assert transcription.name is None + + # Test assigning empty string + transcription.name = "" + assert transcription.name == "" + + def test_transcription_notes_assignment(self): + """Test assigning values to notes field""" + transcription = Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER" + ) + + # Test assigning notes + transcription.notes = "New notes" + assert transcription.notes == "New notes" + + # Test assigning None + transcription.notes = None + assert transcription.notes is None + + # Test assigning empty string + transcription.notes = "" + assert transcription.notes == "" + + def test_transcription_with_unicode_name_and_notes(self): + """Test creating transcription with unicode characters in name and notes""" + transcription = Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="Transcription avec des caractères spéciaux: ñáéíóú", + notes="Notes avec des caractères spéciaux: ñáéíóú et émojis 🎵🎤" + ) + + assert transcription.name == "Transcription avec des caractères spéciaux: ñáéíóú" + assert transcription.notes == "Notes avec des caractères spéciaux: ñáéíóú et émojis 🎵🎤" + + def test_transcription_with_long_name_and_notes(self): + """Test creating transcription with very long name and notes""" + long_name = "A" * 1000 # 1000 character name + long_notes = "B" * 5000 # 5000 character notes + + transcription = Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name=long_name, + notes=long_notes + ) + + assert transcription.name == long_name + assert transcription.notes == long_notes + assert len(transcription.name) == 1000 + assert len(transcription.notes) == 5000 + + def test_transcription_name_with_special_characters(self): + """Test transcription name with special characters""" + special_name = "Transcription with special chars: !@#$%^&*()_+-=[]{}|;':\",./<>?" + + transcription = Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name=special_name + ) + + assert transcription.name == special_name + + def test_transcription_notes_with_newlines(self): + """Test transcription notes with newlines and special formatting""" + notes_with_newlines = """This is a multi-line note +with newlines and special characters: +- Bullet point 1 +- Bullet point 2 +- Bullet point 3 + +And some more text after the empty line.""" + + transcription = Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + notes=notes_with_newlines + ) + + assert transcription.notes == notes_with_newlines + assert "\n" in transcription.notes + + def test_transcription_equality_with_name_and_notes(self): + """Test transcription equality when name and notes are included""" + transcription_id = str(uuid4()) + + transcription1 = Transcription( + id=transcription_id, + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="Test Name", + notes="Test Notes" + ) + + transcription2 = Transcription( + id=transcription_id, + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="Test Name", + notes="Test Notes" + ) + + # Two transcriptions with same ID should be equal + assert transcription1 == transcription2 + + def test_transcription_inequality_with_different_name_and_notes(self): + """Test transcription inequality when name and notes are different""" + transcription_id = str(uuid4()) + + transcription1 = Transcription( + id=transcription_id, + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="Test Name 1", + notes="Test Notes 1" + ) + + transcription2 = Transcription( + id=transcription_id, + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="Test Name 2", + notes="Test Notes 2" + ) + + # Two transcriptions with different name/notes should not be equal + assert transcription1 != transcription2 + + def test_transcription_id_as_uuid_property(self): + """Test that id_as_uuid property works with name and notes fields""" + transcription_id = uuid4() + + transcription = Transcription( + id=str(transcription_id), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="Test Name", + notes="Test Notes" + ) + + assert transcription.id_as_uuid == transcription_id + assert isinstance(transcription.id_as_uuid, type(transcription_id)) + + def test_transcription_string_representation_with_name_and_notes(self): + """Test string representation of transcription includes name and notes""" + transcription = Transcription( + id="test-id-123", + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="Test Transcription", + notes="Test notes" + ) + + str_repr = str(transcription) + # The string representation should include the ID + assert "test-id-123" in str_repr + + def test_transcription_with_none_values_in_other_fields(self): + """Test transcription with None values in other fields but valid name and notes""" + transcription = Transcription( + id=str(uuid4()), + file=None, + url=None, + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="Valid Name", + notes="Valid Notes" + ) + + assert transcription.name == "Valid Name" + assert transcription.notes == "Valid Notes" + assert transcription.file is None + assert transcription.url is None diff --git a/tests/db/service/transcription_service_test.py b/tests/db/service/transcription_service_test.py new file mode 100644 index 00000000..2d267c52 --- /dev/null +++ b/tests/db/service/transcription_service_test.py @@ -0,0 +1,211 @@ +import pytest +from unittest.mock import Mock, patch +from uuid import UUID, uuid4 + +from buzz.db.service.transcription_service import TranscriptionService +from buzz.db.entity.transcription import Transcription + + +@pytest.fixture +def mock_transcription_dao(): + """Create a mock TranscriptionDAO for testing""" + return Mock() + + +@pytest.fixture +def mock_transcription_segment_dao(): + """Create a mock TranscriptionSegmentDAO for testing""" + return Mock() + + +@pytest.fixture +def transcription_service(mock_transcription_dao, mock_transcription_segment_dao): + """Create a TranscriptionService instance for testing""" + return TranscriptionService(mock_transcription_dao, mock_transcription_segment_dao) + + +@pytest.fixture +def sample_transcription(): + """Create a sample transcription for testing""" + return Transcription( + id=str(uuid4()), + file="/path/to/test.mp3", + status="completed", + time_queued="2023-01-01T00:00:00", + task="TRANSCRIBE", + model_type="WHISPER", + name="Test Transcription", + notes="This is a test transcription" + ) + + +class TestTranscriptionService: + def test_update_transcription_name(self, transcription_service, mock_transcription_dao): + """Test updating transcription name through service""" + transcription_id = uuid4() + new_name = "Updated Transcription Name" + + # Call the service method + transcription_service.update_transcription_name(transcription_id, new_name) + + # Verify the DAO method was called with correct parameters + mock_transcription_dao.update_transcription_name.assert_called_once_with(transcription_id, new_name) + + def test_update_transcription_notes(self, transcription_service, mock_transcription_dao): + """Test updating transcription notes through service""" + transcription_id = uuid4() + new_notes = "Updated transcription notes with more details" + + # Call the service method + transcription_service.update_transcription_notes(transcription_id, new_notes) + + # Verify the DAO method was called with correct parameters + mock_transcription_dao.update_transcription_notes.assert_called_once_with(transcription_id, new_notes) + + def test_update_transcription_name_with_empty_string(self, transcription_service, mock_transcription_dao): + """Test updating transcription name to empty string""" + transcription_id = uuid4() + empty_name = "" + + # Call the service method + transcription_service.update_transcription_name(transcription_id, empty_name) + + # Verify the DAO method was called with empty string + mock_transcription_dao.update_transcription_name.assert_called_once_with(transcription_id, empty_name) + + def test_update_transcription_notes_with_empty_string(self, transcription_service, mock_transcription_dao): + """Test updating transcription notes to empty string""" + transcription_id = uuid4() + empty_notes = "" + + # Call the service method + transcription_service.update_transcription_notes(transcription_id, empty_notes) + + # Verify the DAO method was called with empty string + mock_transcription_dao.update_transcription_notes.assert_called_once_with(transcription_id, empty_notes) + + def test_update_transcription_name_with_none(self, transcription_service, mock_transcription_dao): + """Test updating transcription name to None""" + transcription_id = uuid4() + + # Call the service method + transcription_service.update_transcription_name(transcription_id, None) + + # Verify the DAO method was called with None + mock_transcription_dao.update_transcription_name.assert_called_once_with(transcription_id, None) + + def test_update_transcription_notes_with_none(self, transcription_service, mock_transcription_dao): + """Test updating transcription notes to None""" + transcription_id = uuid4() + + # Call the service method + transcription_service.update_transcription_notes(transcription_id, None) + + # Verify the DAO method was called with None + mock_transcription_dao.update_transcription_notes.assert_called_once_with(transcription_id, None) + + def test_update_transcription_name_propagates_dao_exception(self, transcription_service, mock_transcription_dao): + """Test that DAO exceptions are propagated from service""" + transcription_id = uuid4() + new_name = "Updated Name" + + # Configure the mock to raise an exception + mock_transcription_dao.update_transcription_name.side_effect = Exception("Database error") + + # Call the service method and expect the exception to be raised + with pytest.raises(Exception, match="Database error"): + transcription_service.update_transcription_name(transcription_id, new_name) + + def test_update_transcription_notes_propagates_dao_exception(self, transcription_service, mock_transcription_dao): + """Test that DAO exceptions are propagated from service""" + transcription_id = uuid4() + new_notes = "Updated notes" + + # Configure the mock to raise an exception + mock_transcription_dao.update_transcription_notes.side_effect = Exception("Database error") + + # Call the service method and expect the exception to be raised + with pytest.raises(Exception, match="Database error"): + transcription_service.update_transcription_notes(transcription_id, new_notes) + + def test_update_transcription_name_with_string_uuid(self, transcription_service, mock_transcription_dao): + """Test updating transcription name with string UUID (should be converted to UUID)""" + transcription_id_str = str(uuid4()) + new_name = "Updated Name" + + # Call the service method + transcription_service.update_transcription_name(transcription_id_str, new_name) + + # Verify the DAO method was called with UUID object + mock_transcription_dao.update_transcription_name.assert_called_once() + call_args = mock_transcription_dao.update_transcription_name.call_args[0] + assert isinstance(call_args[0], str) # The service should pass the string as-is + assert call_args[1] == new_name + + def test_update_transcription_notes_with_string_uuid(self, transcription_service, mock_transcription_dao): + """Test updating transcription notes with string UUID (should be converted to UUID)""" + transcription_id_str = str(uuid4()) + new_notes = "Updated notes" + + # Call the service method + transcription_service.update_transcription_notes(transcription_id_str, new_notes) + + # Verify the DAO method was called with UUID object + mock_transcription_dao.update_transcription_notes.assert_called_once() + call_args = mock_transcription_dao.update_transcription_notes.call_args[0] + assert isinstance(call_args[0], str) # The service should pass the string as-is + assert call_args[1] == new_notes + + def test_update_transcription_name_multiple_calls(self, transcription_service, mock_transcription_dao): + """Test multiple calls to update transcription name""" + transcription_id = uuid4() + + # Make multiple calls + transcription_service.update_transcription_name(transcription_id, "Name 1") + transcription_service.update_transcription_name(transcription_id, "Name 2") + transcription_service.update_transcription_name(transcription_id, "Name 3") + + # Verify all calls were made + assert mock_transcription_dao.update_transcription_name.call_count == 3 + + # Verify the last call has the correct parameters + last_call = mock_transcription_dao.update_transcription_name.call_args_list[-1] + assert last_call[0] == (transcription_id, "Name 3") + + def test_update_transcription_notes_multiple_calls(self, transcription_service, mock_transcription_dao): + """Test multiple calls to update transcription notes""" + transcription_id = uuid4() + + # Make multiple calls + transcription_service.update_transcription_notes(transcription_id, "Notes 1") + transcription_service.update_transcription_notes(transcription_id, "Notes 2") + transcription_service.update_transcription_notes(transcription_id, "Notes 3") + + # Verify all calls were made + assert mock_transcription_dao.update_transcription_notes.call_count == 3 + + # Verify the last call has the correct parameters + last_call = mock_transcription_dao.update_transcription_notes.call_args_list[-1] + assert last_call[0] == (transcription_id, "Notes 3") + + def test_update_transcription_name_with_unicode(self, transcription_service, mock_transcription_dao): + """Test updating transcription name with unicode characters""" + transcription_id = uuid4() + unicode_name = "Transcription avec des caractères spéciaux: ñáéíóú" + + # Call the service method + transcription_service.update_transcription_name(transcription_id, unicode_name) + + # Verify the DAO method was called with unicode string + mock_transcription_dao.update_transcription_name.assert_called_once_with(transcription_id, unicode_name) + + def test_update_transcription_notes_with_unicode(self, transcription_service, mock_transcription_dao): + """Test updating transcription notes with unicode characters""" + transcription_id = uuid4() + unicode_notes = "Notes avec des caractères spéciaux: ñáéíóú et émojis 🎵🎤" + + # Call the service method + transcription_service.update_transcription_notes(transcription_id, unicode_notes) + + # Verify the DAO method was called with unicode string + mock_transcription_dao.update_transcription_notes.assert_called_once_with(transcription_id, unicode_notes) diff --git a/tests/settings/settings_test.py b/tests/settings/settings_test.py new file mode 100644 index 00000000..54a9439a --- /dev/null +++ b/tests/settings/settings_test.py @@ -0,0 +1,133 @@ +import pytest +from unittest.mock import Mock, patch + +from buzz.settings.settings import Settings + + +class TestSettings: + def test_transcription_tasks_table_column_order_key(self): + """Test that TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER key is defined""" + assert hasattr(Settings.Key, 'TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER') + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER.value == "transcription-tasks-table/column-order" + + def test_transcription_tasks_table_column_widths_key(self): + """Test that TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS key is defined""" + assert hasattr(Settings.Key, 'TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS') + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS.value == "transcription-tasks-table/column-widths" + + def test_transcription_tasks_table_column_visibility_key_exists(self): + """Test that TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY key still exists""" + assert hasattr(Settings.Key, 'TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY') + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY.value == "transcription-tasks-table/column-visibility" + + def test_all_transcription_tasks_table_keys_are_strings(self): + """Test that all transcription tasks table keys are strings""" + assert isinstance(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY.value, str) + assert isinstance(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER.value, str) + assert isinstance(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS.value, str) + + def test_transcription_tasks_table_keys_have_correct_prefix(self): + """Test that all transcription tasks table keys have the correct prefix""" + prefix = "transcription-tasks-table/" + + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY.value.startswith(prefix) + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER.value.startswith(prefix) + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS.value.startswith(prefix) + + def test_transcription_tasks_table_keys_are_unique(self): + """Test that all transcription tasks table keys are unique""" + keys = [ + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY.value, + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER.value, + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS.value + ] + + assert len(keys) == len(set(keys)), "All transcription tasks table keys should be unique" + + def test_settings_key_enum_values(self): + """Test that Settings.Key enum values are properly defined""" + # Test that the keys exist and have expected values + expected_keys = { + 'TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY': 'transcription-tasks-table/column-visibility', + 'TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER': 'transcription-tasks-table/column-order', + 'TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS': 'transcription-tasks-table/column-widths' + } + + for key_name, expected_value in expected_keys.items(): + assert hasattr(Settings.Key, key_name) + assert getattr(Settings.Key, key_name).value == expected_value + + def test_settings_key_immutability(self): + """Test that Settings.Key values cannot be modified""" + # This test ensures that the keys are defined as constants + original_visibility = Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY + original_order = Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER + original_widths = Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS + + # Attempting to modify these should not work (they should be immutable) + # If they were mutable, this test would fail + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY == original_visibility + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER == original_order + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS == original_widths + + def test_settings_key_format_consistency(self): + """Test that all transcription tasks table keys follow the same format""" + keys = [ + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY.value, + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER.value, + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS.value + ] + + for key in keys: + # All keys should start with the same prefix + assert key.startswith("transcription-tasks-table/") + # All keys should contain only lowercase letters, hyphens, and forward slashes + assert all(c.islower() or c in '-/' for c in key) + # All keys should end with a descriptive suffix + assert key.endswith(('visibility', 'order', 'widths')) + + def test_settings_key_length(self): + """Test that transcription tasks table keys have reasonable length""" + keys = [ + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY.value, + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER.value, + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS.value + ] + + for key in keys: + # Keys should be long enough to be descriptive but not excessively long + assert 20 <= len(key) <= 50, f"Key '{key}' has unexpected length: {len(key)}" + + def test_settings_key_naming_convention(self): + """Test that transcription tasks table keys follow proper naming convention""" + keys = [ + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY.value, + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER.value, + Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS.value + ] + + for key in keys: + # Keys should use kebab-case (lowercase with hyphens) + assert '-' in key, f"Key '{key}' should use kebab-case with hyphens" + assert not any(c.isupper() for c in key), f"Key '{key}' should not contain uppercase letters" + assert not '_' in key, f"Key '{key}' should use hyphens instead of underscores" + + def test_settings_key_usage_in_code(self): + """Test that the settings keys can be used in typical settings operations""" + # Mock a settings object to test key usage + mock_settings = Mock() + mock_settings.begin_group = Mock() + mock_settings.end_group = Mock() + mock_settings.settings = Mock() + + # Test that the keys can be used with begin_group + mock_settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY.value) + mock_settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER.value) + mock_settings.begin_group(Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS.value) + + # Verify that begin_group was called with the correct keys + assert mock_settings.begin_group.call_count == 3 + call_args = [call[0][0] for call in mock_settings.begin_group.call_args_list] + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY.value in call_args + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER.value in call_args + assert Settings.Key.TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS.value in call_args diff --git a/tests/widgets/main_window_test.py b/tests/widgets/main_window_test.py index 00341927..5bbb194a 100644 --- a/tests/widgets/main_window_test.py +++ b/tests/widgets/main_window_test.py @@ -1,7 +1,7 @@ import logging import os from typing import List -from unittest.mock import patch +from unittest.mock import patch, Mock import pytest from PyQt6.QtCore import QSize, Qt @@ -21,9 +21,6 @@ from buzz.db.service.transcription_service import TranscriptionService from buzz.widgets.main_window import MainWindow from buzz.widgets.snap_notice import SnapNotice from buzz.widgets.transcriber.file_transcriber_widget import FileTranscriberWidget -from buzz.widgets.transcription_viewer.transcription_viewer_widget import ( - TranscriptionViewerWidget, -) mock_transcriptions: List[Transcription] = [ Transcription(status="completed"), @@ -154,8 +151,22 @@ class TestMainWindow: @pytest.mark.parametrize("transcription_dao", [mock_transcriptions], indirect=True) def test_should_load_tasks_from_cache( - self, qtbot, transcription_dao, transcription_segment_dao + self, qtbot, transcription_dao, transcription_segment_dao, monkeypatch ): + # Mock the queue worker to prevent it from processing tasks + mock_queue_worker = Mock() + mock_queue_worker.task_started = Mock() + mock_queue_worker.task_progress = Mock() + mock_queue_worker.task_download_progress = Mock() + mock_queue_worker.task_error = Mock() + mock_queue_worker.task_completed = Mock() + mock_queue_worker.completed = Mock() + mock_queue_worker.cancel_task = Mock() + mock_queue_worker.add_task = Mock() + mock_queue_worker.stop = Mock() + + monkeypatch.setattr("buzz.widgets.main_window.FileTranscriberQueueWorker", Mock(return_value=mock_queue_worker)) + window = MainWindow( TranscriptionService(transcription_dao, transcription_segment_dao) ) @@ -164,17 +175,19 @@ class TestMainWindow: table_widget = self._get_tasks_table(window) assert table_widget.model().rowCount() == 3 - assert self._get_status(table_widget, 0) == "completed" - table_widget.selectRow(0) - assert window.toolbar.open_transcript_action.isEnabled() + # Get all statuses and verify they match expected values + statuses = [self._get_status(table_widget, i) for i in range(3)] + expected_statuses = {"completed", "canceled", "failed"} + assert set(statuses) == expected_statuses, f"Expected {expected_statuses}, got {statuses}" - assert self._get_status(table_widget, 1) == "canceled" - table_widget.selectRow(1) - assert window.toolbar.open_transcript_action.isEnabled() is False - - assert self._get_status(table_widget, 2) == "failed" - table_widget.selectRow(2) - assert window.toolbar.open_transcript_action.isEnabled() is False + # Test that completed transcriptions enable the open action, others don't + for i in range(3): + table_widget.selectRow(i) + status = self._get_status(table_widget, i) + if status == "completed": + assert window.toolbar.open_transcript_action.isEnabled() + else: + assert window.toolbar.open_transcript_action.isEnabled() is False window.close() @pytest.mark.parametrize("transcription_dao", [mock_transcriptions], indirect=True) @@ -218,12 +231,20 @@ class TestMainWindow: qtbot.add_widget(window) table_widget = self._get_tasks_table(window) - table_widget.selectRow(0) + + # Find and select the completed transcription row + completed_row = None + for i in range(table_widget.model().rowCount()): + if self._get_status(table_widget, i) == "completed": + completed_row = i + break + + assert completed_row is not None, "No completed transcription found" + table_widget.selectRow(completed_row) window.toolbar.open_transcript_action.trigger() - transcription_viewer = window.findChild(TranscriptionViewerWidget) - assert transcription_viewer is not None + assert window.transcription_viewer_widget is not None window.close() @@ -237,7 +258,17 @@ class TestMainWindow: qtbot.add_widget(window) table_widget = self._get_tasks_table(window) - table_widget.selectRow(0) + + # Find and select the completed transcription row + completed_row = None + for i in range(table_widget.model().rowCount()): + if self._get_status(table_widget, i) == "completed": + completed_row = i + break + + assert completed_row is not None, "No completed transcription found" + table_widget.selectRow(completed_row) + table_widget.keyPressEvent( QKeyEvent( QKeyEvent.Type.KeyPress, @@ -247,8 +278,7 @@ class TestMainWindow: ) ) - transcription_viewer = window.findChild(TranscriptionViewerWidget) - assert transcription_viewer is not None + assert window.transcription_viewer_widget is not None window.close() diff --git a/tests/widgets/transcription_tasks_table_widget_test.py b/tests/widgets/transcription_tasks_table_widget_test.py index 44dc9d2d..017a54f9 100644 --- a/tests/widgets/transcription_tasks_table_widget_test.py +++ b/tests/widgets/transcription_tasks_table_widget_test.py @@ -10,6 +10,7 @@ from PyQt6.QtGui import QKeyEvent from PyQt6.QtSql import QSqlDatabase, QSqlQuery, QSqlRecord, QSqlTableModel from PyQt6.QtWidgets import QApplication, QMenu, QStyledItemDelegate +from buzz.locale import _ from buzz.widgets.transcription_tasks_table_widget import ( TranscriptionTasksTableWidget, format_record_status_text, @@ -46,18 +47,36 @@ def mock_dependencies(monkeypatch): mock_settings = Mock() settings_store = {} + current_group = [""] + + def begin_group(group): + current_group[0] = group + "/" + + def end_group(): + current_group[0] = "" + + def set_value(k, v): + settings_store[current_group[0] + k] = v + + def get_value(k, default=None): + return settings_store.get(current_group[0] + k, default) + mock_settings.settings = Mock() - mock_settings.settings.setValue.side_effect = lambda k, v: settings_store.update({k: v}) - mock_settings.settings.value.side_effect = lambda k, default: settings_store.get( - k, default - ) + mock_settings.settings.setValue.side_effect = set_value + mock_settings.settings.value.side_effect = get_value + mock_settings.begin_group.side_effect = begin_group + mock_settings.end_group.side_effect = end_group monkeypatch.setattr( "buzz.widgets.transcription_tasks_table_widget.Settings", Mock(return_value=mock_settings), ) monkeypatch.setattr( "buzz.widgets.transcription_tasks_table_widget.Settings.Key", - Mock(TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY="visibility"), + Mock( + TRANSCRIPTION_TASKS_TABLE_COLUMN_VISIBILITY="visibility", + TRANSCRIPTION_TASKS_TABLE_COLUMN_ORDER="order", + TRANSCRIPTION_TASKS_TABLE_COLUMN_WIDTHS="widths" + ), ) @@ -87,13 +106,15 @@ def db(): "whisper_model_size TEXT," # 16 "hugging_face_model_id TEXT," # 17 "word_level_timings BOOLEAN DEFAULT FALSE," # 18 - "extract_speech BOOLEAN DEFAULT FALSE" # 19 + "extract_speech BOOLEAN DEFAULT FALSE," # 19 + "name TEXT," # 20 + "notes TEXT" # 21 ")" ) query.exec( - "INSERT INTO transcription (id, file, url, status, time_queued, task, model_type) VALUES " - "('1', '/a/b/c.mp3', '', 'QUEUED', '2023-01-01T00:00:00', 'TRANSCRIBE', 'WHISPER')," - "('2', '', 'http://example.com/d.wav', 'QUEUED', '2023-01-02T00:00:00', 'TRANSCRIBE', 'WHISPER')" + "INSERT INTO transcription (id, file, url, status, time_queued, task, model_type, name, notes) VALUES " + "('1', '/a/b/c.mp3', '', 'QUEUED', '2023-01-01T00:00:00', 'TRANSCRIBE', 'WHISPER', 'Test Audio File', 'This is a test transcription')," + "('2', '', 'http://example.com/d.wav', 'QUEUED', '2023-01-02T00:00:00', 'TRANSCRIBE', 'WHISPER', 'URL Audio', 'URL-based transcription')" ) yield db db.close() @@ -233,5 +254,233 @@ class TestTranscriptionTasksTableWidget: assert mock_menu.addAction.call_count > 0 menu_add_action_call_count = mock_menu.addAction.call_count + # Select a row so the widget context menu will add actions + widget.selectRow(0) widget.contextMenuEvent(Mock()) assert mock_menu.addAction.call_count > menu_add_action_call_count + + def test_new_column_definitions(self): + """Test that new NAME and NOTES columns are properly defined""" + # Check that NOTES column is defined + notes_column_def = next((col for col in column_definitions if col.column == Column.NOTES), None) + assert notes_column_def is not None + assert notes_column_def.id == "notes" + assert notes_column_def.header == _("Notes") + assert notes_column_def.width == 300 + assert notes_column_def.hidden_toggleable == True # Notes column should be toggleable + + # Check that FILE column has been updated to include name functionality + file_column_def = next((col for col in column_definitions if col.column == Column.FILE), None) + assert file_column_def is not None + assert file_column_def.id == "file_name" + assert file_column_def.header == _("File Name / URL") + assert file_column_def.width == 400 + assert file_column_def.hidden_toggleable == False # File column should not be toggleable + + def test_file_column_text_getter_with_name(self, widget): + """Test that file column displays name or falls back to file/url""" + # Test with name present + record_with_name = mock_record({"name": "Custom Name", "url": "http://example.com", "file": "/path/file.mp3"}) + file_column_def = next((col for col in column_definitions if col.column == Column.FILE), None) + text = file_column_def.delegate.callback(record_with_name) + assert text == "Custom Name" + + # Test fallback to URL when no name + record_url_fallback = mock_record({"name": None, "url": "http://example.com/audio.mp3", "file": "/path/file.mp3"}) + text = file_column_def.delegate.callback(record_url_fallback) + assert text == "http://example.com/audio.mp3" + + # Test fallback to filename when no name or URL + record_file_fallback = mock_record({"name": None, "url": "", "file": "/path/to/audio.mp3"}) + text = file_column_def.delegate.callback(record_file_fallback) + assert text == "audio.mp3" + + def test_notes_column_text_getter(self, widget): + """Test that notes column displays notes or empty string""" + notes_column_def = next((col for col in column_definitions if col.column == Column.NOTES), None) + + # Test with notes present + record_with_notes = mock_record({"notes": "Important transcription notes"}) + text = notes_column_def.delegate.callback(record_with_notes) + assert text == "Important transcription notes" + + # Test with no notes + record_no_notes = mock_record({"notes": None}) + text = notes_column_def.delegate.callback(record_no_notes) + assert text == "" + + def test_column_visibility_management(self, widget): + """Test column visibility save/load functionality""" + # Test saving column visibility + widget.setColumnHidden(Column.NOTES.value, True) + widget.save_column_visibility() + + # Create new widget to test loading + new_widget = TranscriptionTasksTableWidget() + assert new_widget.isColumnHidden(Column.NOTES.value) + + def test_column_width_management(self, widget): + """Test column width save/load functionality""" + # Test saving column widths + widget.setColumnWidth(Column.FILE.value, 500) + widget.save_column_widths() + + # Create new widget to test loading + new_widget = TranscriptionTasksTableWidget() + # Width should be loaded from settings (mocked to return 500) + assert new_widget.columnWidth(Column.FILE.value) == 500 + + def test_column_order_management(self, widget): + """Test column order save/load functionality""" + # Test saving column order + widget.save_column_order() + + # Test loading column order + widget.load_column_order() + + # Test resetting column order + widget.reset_column_order() + # After reset, columns should be in default order + header = widget.horizontalHeader() + for i, definition in enumerate(column_definitions): + assert header.visualIndex(definition.column.value) == i + + def test_context_menu_rename_action(self, widget, monkeypatch): + """Test rename action in context menu""" + # Mock the transcription service + mock_service = Mock() + widget.transcription_service = mock_service + + # Mock the transcription method to return a proper transcription object + mock_transcription = Mock() + mock_transcription.id = "12345678-1234-5678-1234-567812345678" # Valid UUID + mock_transcription.name = "Old Name" + mock_transcription.url = "http://example.com" + mock_transcription.file = "/path/file.mp3" + monkeypatch.setattr(widget, "transcription", Mock(return_value=mock_transcription)) + + # Mock QInputDialog + mock_dialog = Mock() + mock_dialog.getText.return_value = ("New Name", True) + monkeypatch.setattr("PyQt6.QtWidgets.QInputDialog", mock_dialog) + + # Select a row + widget.selectRow(0) + + # Call rename action + widget.on_rename_action() + + # Verify service was called + mock_service.update_transcription_name.assert_called_once() + mock_dialog.getText.assert_called_once() + + def test_context_menu_notes_action(self, widget, monkeypatch): + """Test notes action in context menu""" + # Mock the transcription service + mock_service = Mock() + widget.transcription_service = mock_service + + # Mock the transcription method to return a proper transcription object + mock_transcription = Mock() + mock_transcription.id = "12345678-1234-5678-1234-567812345678" # Valid UUID + mock_transcription.notes = "Old notes" + monkeypatch.setattr(widget, "transcription", Mock(return_value=mock_transcription)) + + # Mock QInputDialog + mock_dialog = Mock() + mock_dialog.getMultiLineText.return_value = ("New notes", True) + monkeypatch.setattr("PyQt6.QtWidgets.QInputDialog", mock_dialog) + + # Select a row + widget.selectRow(0) + + # Call notes action + widget.on_notes_action() + + # Verify service was called + mock_service.update_transcription_notes.assert_called_once() + mock_dialog.getMultiLineText.assert_called_once() + + def test_context_menu_restart_action_success(self, widget, monkeypatch): + """Test restart action for failed/canceled transcriptions""" + # Mock the transcription service + mock_service = Mock() + mock_service.reset_transcription_for_restart = Mock() + widget.transcription_service = mock_service + + # Mock QMessageBox + mock_messagebox = Mock() + monkeypatch.setattr("PyQt6.QtWidgets.QMessageBox", mock_messagebox) + + # Mock the _restart_transcription_task method to avoid complex setup + mock_restart = Mock() + monkeypatch.setattr(widget, "_restart_transcription_task", mock_restart) + + # Mock the transcription record to return failed status + mock_transcription = Mock() + mock_transcription.status = "failed" + mock_transcription.id = "12345678-1234-5678-1234-567812345678" # Valid UUID + monkeypatch.setattr(widget, "transcription", Mock(return_value=mock_transcription)) + + # Select a row + widget.selectRow(0) + + # Call restart action + widget.on_restart_transcription_action() + + # Verify service and restart were called + mock_service.reset_transcription_for_restart.assert_called_once() + mock_restart.assert_called_once_with(mock_transcription) + + def test_context_menu_restart_action_wrong_status(self, widget, monkeypatch): + """Test restart action shows error for non-failed/canceled transcriptions""" + # Mock QMessageBox + mock_messagebox = Mock() + monkeypatch.setattr("PyQt6.QtWidgets.QMessageBox", mock_messagebox) + + # Mock the transcription record to return completed status + mock_transcription = Mock() + mock_transcription.status = "completed" + monkeypatch.setattr(widget, "transcription", Mock(return_value=mock_transcription)) + + # Select a row + widget.selectRow(0) + + # Call restart action + widget.on_restart_transcription_action() + + # Verify error message was shown + mock_messagebox.information.assert_called_once() + + def test_column_resize_event(self, widget): + """Test column resize event handling""" + # Mock the save_column_widths method + with patch.object(widget, 'save_column_widths') as mock_save: + # Simulate column resize + widget.on_column_resized(0, 100, 200) + mock_save.assert_called_once() + + def test_column_move_event(self, widget): + """Test column move event handling""" + # Mock the save methods + with patch.object(widget, 'save_column_order') as mock_save_order, \ + patch.object(widget, 'load_column_visibility') as mock_load_vis: + # Simulate column move + widget.on_column_moved(0, 0, 1) + mock_save_order.assert_called_once() + mock_load_vis.assert_called_once() + + def test_reload_column_order_from_settings(self, widget): + """Test reloading column order from settings""" + # Mock settings to return specific values + widget.settings.settings.value.side_effect = lambda key, default=None: { + "file_name": "0", + "notes": "1", + "status": "2" + }.get(key, default) + + # Call reload method + widget.reload_column_order_from_settings() + + # Verify the method completes without error + assert True # If we get here, no exception was raised