From 03b2e842fddf2ff9bd1ea02b242abf9310cb86b6 Mon Sep 17 00:00:00 2001 From: Jann Stute Date: Mon, 23 Dec 2024 19:21:50 +0100 Subject: [PATCH] feat: translate modals --- tagstudio/resources/translations/en.json | 63 ++++++++++++++----- tagstudio/src/qt/modals/add_field.py | 10 +-- tagstudio/src/qt/modals/build_tag.py | 25 +++++--- tagstudio/src/qt/modals/delete_unlinked.py | 33 ++++++---- tagstudio/src/qt/modals/drop_import.py | 40 +++++++----- tagstudio/src/qt/modals/file_extension.py | 18 ++++-- tagstudio/src/qt/modals/fix_dupes.py | 47 +++++++------- tagstudio/src/qt/modals/fix_unlinked.py | 34 +++++----- tagstudio/src/qt/modals/folders_to_tags.py | 12 ++-- tagstudio/src/qt/modals/merge_dupe_entries.py | 6 +- tagstudio/src/qt/modals/mirror_entities.py | 30 +++++---- tagstudio/src/qt/modals/relink_unlinked.py | 13 ++-- tagstudio/src/qt/modals/tag_database.py | 22 +++---- tagstudio/src/qt/modals/tag_search.py | 4 +- tagstudio/src/qt/translations.py | 4 +- tagstudio/src/qt/ts_qt.py | 2 +- 16 files changed, 216 insertions(+), 147 deletions(-) diff --git a/tagstudio/resources/translations/en.json b/tagstudio/resources/translations/en.json index 29fb8931..7d437814 100644 --- a/tagstudio/resources/translations/en.json +++ b/tagstudio/resources/translations/en.json @@ -3,27 +3,31 @@ "app.pre_release": "Pre-Release", "app.title": "{base_title} - Library '{library_dir}'", "edit.tag_manager": "Manage Tags", - "entries.duplicate.merge.label": "Merging Duplicate Entries", + "entries.duplicate.merge.label": "Merging Duplicate Entries...", "entries.duplicate.merge": "Merge Duplicate Entries", "entries.duplicate.refresh": "Refresh Duplicate Entries", "entries.duplicates.description": "Duplicate entries are defined as multiple entries which point to the same file on disk. Merging these will combine the tags and metadata from all duplicates into a single consolidated entry. These are not to be confused with \"duplicate files\", which are duplicates of your files themselves outside of TagStudio.", - "entries.mirror.confirmation": "Are you sure you want to mirror the following %{len(self.lib.dupe_files)} Entries?", - "entries.mirror.label": "Mirroring 1/%{count} Entries...", + "entries.mirror.confirmation": "Are you sure you want to mirror the following {count} Entries?", + "entries.mirror.label": "Mirroring {idx}/{total} Entries...", "entries.mirror.title": "Mirroring Entries", - "entries.mirror": "Mirror", + "entries.mirror.window_title": "Mirror Entries", + "entries.mirror": "&Mirror", "entries.tags": "Tags", - "entries.unlinked.delete.confirm": "Are you sure you want to delete the following %{len(self.lib.missing_files)} entries?", - "entries.unlinked.delete.deleting_count": "Deleting %{x[0]+1}/{len(self.lib.missing_files)} Unlinked Entries", + "entries.unlinked.delete.confirm": "Are you sure you want to delete the following {count} entries?", + "entries.unlinked.delete.deleting_count": "Deleting {idx}/{count} Unlinked Entries", "entries.unlinked.delete.deleting": "Deleting Entries", "entries.unlinked.delete": "Delete Unlinked Entries", + "entries.unlinked.delete_alt": "De&lete Unlinked Entries", "entries.unlinked.description": "Each library entry is linked to a file in one of your directories. If a file linked to an entry is moved or deleted outside of TagStudio, it is then considered unlinked. Unlinked entries may be automatically relinked via searching your directories or deleted if desired.", - "entries.unlinked.refresh_all": "Refresh All", - "entries.unlinked.relink.attempting": "Attempting to Relink %{x[0]+1}/%{len(self.lib.missing_files)} Entries, %{self.fixed} Successfully Relinked", - "entries.unlinked.relink.manual": "Manual Relink", + "entries.unlinked.refresh_all": "&Refresh All", + "entries.unlinked.relink.attempting": "Attempting to Relink {idx}/{missing_count} Entries, {fixed_count} Successfully Relinked", + "entries.unlinked.relink.manual": "&Manual Relink", "entries.unlinked.relink.title": "Relinking Entries", "entries.unlinked.scanning": "Scanning Library for Unlinked Entries...", - "entries.unlinked.search_and_relink": "Search && Relink", + "entries.unlinked.search_and_relink": "&Search && Relink", "entries.unlinked.title": "Fix Unlinked Entries", + "entries.unlinked.missing_count.none": "Unlinked Entries: N/A", + "entries.unlinked.missing_count.some": "Unlinked Entries: {count}", "field.copy": "Copy Field", "field.edit": "Edit Field", "field.paste": "Paste Field", @@ -31,15 +35,16 @@ "file.date_created": "Date Created", "file.date_modified": "Date Modified", "file.dimensions": "Dimensions", + "file.duplicates.description": "TagStudio supports importing DupeGuru results to manage duplicate files.", "file.duplicates.dupeguru.advice": "After mirroring, you're free to use DupeGuru to delete the unwanted files. Afterwards, use TagStudio's \"Fix Unlinked Entries\" feature in the Tools menu in order to delete the unlinked Entries.", "file.duplicates.dupeguru.file_extension": "DupeGuru Files (*.dupeguru)", - "file.duplicates.dupeguru.load_file": "Load DupeGuru File", + "file.duplicates.dupeguru.load_file": "&Load DupeGuru File", "file.duplicates.dupeguru.no_file": "No DupeGuru File Selected", "file.duplicates.dupeguru.open_file": "Open DupeGuru Results File", "file.duplicates.fix": "Fix Duplicate Files", "file.duplicates.matches_uninitialized": "Duplicate File Matches: N/A", - "file.duplicates.matches": "Duplicate File Matches: %{count}", - "file.duplicates.mirror_entries": "Mirror Entries", + "file.duplicates.matches": "Duplicate File Matches: {count}", + "file.duplicates.mirror_entries": "&Mirror Entries", "file.duplicates.mirror.description": "Mirror the Entry data across each duplicate match set, combining all data while not removing or duplicating fields. This operation will not delete any files or data.", "file.duration": "Length", "file.not_found": "File Not Found", @@ -55,12 +60,23 @@ "folders_to_tags.title": "Create Tags From Folders", "generic.add": "Add", "generic.apply": "Apply", + "generic.apply_alt": "&Apply", "generic.cancel": "Cancel", + "generic.cancel_alt": "&Cancel", + "generic.close": "Close", "generic.copy": "Copy", "generic.cut": "Cut", "generic.delete": "Delete", + "generic.delete_alt": "&Delete", "generic.done": "Done", + "generic.done_alt": "&Done", "generic.edit": "Edit", + "generic.rename": "Rename", + "generic.rename_alt": "&Rename", + "generic.overwrite": "Overwrite", + "generic.overwrite_alt": "&Overwrite", + "generic.skip": "Skip", + "generic.skip_alt": "&Skip", "generic.navigation.back": "Back", "generic.navigation.next": "Next", "generic.paste": "Paste", @@ -76,10 +92,10 @@ "home.thumbnail_size.small": "Small Thumbnails", "home.thumbnail_size.mini": "Mini Thumbnails", "home.thumbnail_size": "Thumbnail Size", - "ignore_list.add_extension": "Add Extension", + "ignore_list.add_extension": "&Add Extension", "ignore_list.mode.exclude": "Exclude", "ignore_list.mode.include": "Include", - "ignore_list.mode.label": "List Mode", + "ignore_list.mode.label": "List Mode:", "ignore_list.title": "File Extensions", "library.field.add": "Add Field", "library.field.confirm_remove": "Are you sure you want to remove this \"%{self.lib.get_field_attr(field, \"name\")}\" field?", @@ -134,7 +150,10 @@ "status.results": "Results", "tag_manager.title": "Library Tags", "tag.add_to_search": "Add to Search", + "tag.edit": "Edit Tag", "tag.add": "Add Tag", + "tag.create": "Create Tag", + "tag.remove": "Remove Tag", "tag.aliases": "Aliases", "tag.color": "Color", "tag.name": "Name", @@ -144,13 +163,23 @@ "tag.parent_tags": "Parent Tags", "tag.search_for_tag": "Search for Tag", "tag.shorthand": "Shorthand", + "tag.remove_alias": "Remove selected alias", + "tag.tag_name_required": "Tag Name (Required)", "view.size.0": "Mini", "view.size.1": "Small", "view.size.2": "Medium", "view.size.3": "Large", "view.size.4": "Extra Large", - "window.button.close": "Close", "window.title.error": "Error", "window.title.open_create_library": "Open/Create Library", - "window.message.error_opening_library": "Error opening library." + "window.message.error_opening_library": "Error opening library.", + "tag_database.confirmation": "Are you sure you want to delete the tag \"{tag_name}\"?", + "drop_import.title": "Conflicting File(s)", + "drop_import.decription": "The following files have filenames already exist in the library", + "drop_import.progress.label.initial": "Importing New Files...", + "drop_import.progress.label.singular": "Importing New Files...\n1 File imported.{suffix}", + "drop_import.progress.label.plural": "Importing New Files...\n{count} Files Imported.{suffix}", + "drop_import.progress.window_title": "Import Files", + "drop_import.duplicates_choice.singular": "The following file has a filename that already exists in the library.", + "drop_import.duplicates_choice.plural": "The following {count} files have filenames that already exist in the library.", } \ No newline at end of file diff --git a/tagstudio/src/qt/modals/add_field.py b/tagstudio/src/qt/modals/add_field.py index 5e0a054d..3e2a94b8 100644 --- a/tagstudio/src/qt/modals/add_field.py +++ b/tagstudio/src/qt/modals/add_field.py @@ -15,6 +15,8 @@ from PySide6.QtWidgets import ( ) from src.core.library import Library +from ..translations import Translations + class AddFieldModal(QWidget): done = Signal(list) @@ -26,7 +28,7 @@ class AddFieldModal(QWidget): super().__init__() self.is_connected = False self.lib = library - self.setWindowTitle("Add Field") # TODO translate + Translations.translate_with_setter(self.setWindowTitle, "library.field.add") self.setWindowModality(Qt.WindowModality.ApplicationModal) self.setMinimumSize(400, 300) self.root_layout = QVBoxLayout(self) @@ -40,7 +42,7 @@ class AddFieldModal(QWidget): # 'text-align:center;' "font-weight:bold;" "font-size:14px;" "padding-top: 6px" "" ) - self.title_widget.setText("Add Field") # TODO translate + Translations.translate_qobject(self.title_widget, "library.field.add") self.title_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) self.list_widget = QListWidget() @@ -54,13 +56,13 @@ class AddFieldModal(QWidget): # self.cancel_button.setText('Cancel') self.cancel_button = QPushButton() - self.cancel_button.setText("Cancel") # TODO translate + Translations.translate_qobject(self.cancel_button, "generic.cancel") self.cancel_button.clicked.connect(self.hide) # self.cancel_button.clicked.connect(widget.reset) self.button_layout.addWidget(self.cancel_button) self.save_button = QPushButton() - self.save_button.setText("Add") # TODO translate + Translations.translate_qobject(self.save_button, "generic.add") # self.save_button.setAutoDefault(True) self.save_button.setDefault(True) self.save_button.clicked.connect(self.hide) diff --git a/tagstudio/src/qt/modals/build_tag.py b/tagstudio/src/qt/modals/build_tag.py index 8e77248d..bfdc136c 100644 --- a/tagstudio/src/qt/modals/build_tag.py +++ b/tagstudio/src/qt/modals/build_tag.py @@ -29,6 +29,8 @@ from src.qt.modals.tag_search import TagSearchPanel from src.qt.widgets.panel import PanelModal, PanelWidget from src.qt.widgets.tag import TagAliasWidget, TagWidget +from ..translations import Translations + logger = structlog.get_logger(__name__) @@ -54,12 +56,14 @@ class BuildTagPanel(PanelWidget): self.name_layout.setSpacing(0) self.name_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.name_title = QLabel() - self.name_title.setText("Name") + Translations.translate_qobject(self.name_title, "tag.name") self.name_layout.addWidget(self.name_title) self.name_field = QLineEdit() self.name_field.setFixedHeight(24) self.name_field.textChanged.connect(self.on_name_changed) - self.name_field.setPlaceholderText("Tag Name (Required)") # TODO translate + Translations.translate_with_setter( + self.name_field.setPlaceholderText, "tag.tag_name_required" + ) self.name_layout.addWidget(self.name_field) # Shorthand ------------------------------------------------------------ @@ -70,7 +74,7 @@ class BuildTagPanel(PanelWidget): self.shorthand_layout.setSpacing(0) self.shorthand_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.shorthand_title = QLabel() - self.shorthand_title.setText("Shorthand") # TODO translate + Translations.translate_qobject(self.shorthand_title, "tag.shorthand") self.shorthand_layout.addWidget(self.shorthand_title) self.shorthand_field = QLineEdit() self.shorthand_layout.addWidget(self.shorthand_field) @@ -83,7 +87,7 @@ class BuildTagPanel(PanelWidget): self.aliases_layout.setSpacing(0) self.aliases_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.aliases_title = QLabel() - self.aliases_title.setText("Aliases") # TODO translate + Translations.translate_qobject(self.aliases_title, "tag.aliases") self.aliases_layout.addWidget(self.aliases_title) self.aliases_flow_widget = QWidget() @@ -134,7 +138,7 @@ class BuildTagPanel(PanelWidget): self.subtags_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.subtags_title = QLabel() - self.subtags_title.setText("Parent Tags") # TODO translate + Translations.translate_qobject(self.subtags_title, "tag.parent_tags") self.subtags_layout.addWidget(self.subtags_title) self.subtag_flow_widget = QWidget() @@ -180,7 +184,9 @@ class BuildTagPanel(PanelWidget): tsp = TagSearchPanel(self.lib, exclude_ids) tsp.tag_chosen.connect(lambda x: self.add_subtag_callback(x)) - self.add_tag_modal = PanelModal(tsp, "Add Parent Tags", "Add Parent Tags") # TODO translate + self.add_tag_modal = PanelModal(tsp) + Translations.translate_with_setter(self.add_tag_modal.setTitle, "tag.parent_tags.add") + Translations.translate_with_setter(self.add_tag_modal.setWindowTitle, "tag.parent_tags.add") self.subtags_add_button.clicked.connect(self.add_tag_modal.show) # self.subtags_layout.addWidget(self.subtags_add_button) @@ -196,7 +202,7 @@ class BuildTagPanel(PanelWidget): self.color_layout.setSpacing(0) self.color_layout.setAlignment(Qt.AlignmentFlag.AlignLeft) self.color_title = QLabel() - self.color_title.setText("Color") # TODO translate + Translations.translate_qobject(self.color_title, "tag.color") self.color_layout.addWidget(self.color_title) self.color_field = QComboBox() self.color_field.setEditable(False) @@ -218,7 +224,8 @@ class BuildTagPanel(PanelWidget): ) ) self.color_layout.addWidget(self.color_field) - remove_selected_alias_action = QAction("remove selected alias", self) # TODO translate + remove_selected_alias_action = QAction(self) + Translations.translate_qobject(remove_selected_alias_action, "tag.remove_alias") remove_selected_alias_action.triggered.connect(self.remove_selected_alias) remove_selected_alias_action.setShortcut( QtCore.QKeyCombination( @@ -243,7 +250,7 @@ class BuildTagPanel(PanelWidget): self.alias_names: set[str] = set() self.new_alias_names: dict = dict() - self.set_tag(tag or Tag(name="New Tag")) # TODO translate + self.set_tag(tag or Tag(name=Translations["tag.new"])) if tag is None: self.name_field.selectAll() diff --git a/tagstudio/src/qt/modals/delete_unlinked.py b/tagstudio/src/qt/modals/delete_unlinked.py index b1e1605c..180c6e75 100644 --- a/tagstudio/src/qt/modals/delete_unlinked.py +++ b/tagstudio/src/qt/modals/delete_unlinked.py @@ -17,6 +17,8 @@ from PySide6.QtWidgets import ( from src.core.utils.missing_files import MissingRegistry from src.qt.widgets.progress import ProgressWidget +from ..translations import Translations + # Only import for type checking/autocompletion, will not be imported at runtime. if typing.TYPE_CHECKING: from src.qt.ts_qt import QtDriver @@ -29,7 +31,7 @@ class DeleteUnlinkedEntriesModal(QWidget): super().__init__() self.driver = driver self.tracker = tracker - self.setWindowTitle("Delete Unlinked Entries") # TODO translate + Translations.translate_with_setter(self.setWindowTitle, "entries.unlinked.delete") self.setWindowModality(Qt.WindowModality.ApplicationModal) self.setMinimumSize(500, 400) self.root_layout = QVBoxLayout(self) @@ -38,9 +40,11 @@ class DeleteUnlinkedEntriesModal(QWidget): self.desc_widget = QLabel() self.desc_widget.setObjectName("descriptionLabel") self.desc_widget.setWordWrap(True) - self.desc_widget.setText(f""" - Are you sure you want to delete the following {self.tracker.missing_files_count} entries? - """) # TODO translate + Translations.translate_qobject( + self.desc_widget, + "entries.unlinked.delete.confirm", + count=self.tracker.missing_files_count, + ) self.desc_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) self.list_view = QListView() @@ -53,13 +57,13 @@ class DeleteUnlinkedEntriesModal(QWidget): self.button_layout.addStretch(1) self.cancel_button = QPushButton() - self.cancel_button.setText("&Cancel") # TODO translate + Translations.translate_qobject(self.cancel_button, "generic.cancel_alt") self.cancel_button.setDefault(True) self.cancel_button.clicked.connect(self.hide) self.button_layout.addWidget(self.cancel_button) self.delete_button = QPushButton() - self.delete_button.setText("&Delete") # TODO translate + Translations.translate_qobject(self.delete_button, "generic.delete_alt") self.delete_button.clicked.connect(self.hide) self.delete_button.clicked.connect(lambda: self.delete_entries()) self.button_layout.addWidget(self.delete_button) @@ -69,9 +73,11 @@ class DeleteUnlinkedEntriesModal(QWidget): self.root_layout.addWidget(self.button_container) def refresh_list(self): - self.desc_widget.setText(f""" - Are you sure you want to delete the following {self.tracker.missing_files_count} entries? - """) # TODO translate + self.desc_widget.setText( + Translations.translate_formatted( + "entries.unlinked.delete.confirm", count=self.tracker.missing_files_count + ) + ) self.model.clear() for i in self.tracker.missing_files: @@ -81,14 +87,17 @@ class DeleteUnlinkedEntriesModal(QWidget): def delete_entries(self): def displayed_text(x): - return f"Deleting {x}/{self.tracker.missing_files_count} Unlinked Entries" # TODO translate + return Translations.translate_formatted( + "entries.unlinked.delete.deleting_count", + idx=x, + count=self.tracker.missing_files_count, + ) pw = ProgressWidget( - window_title="Deleting Entries", # TODO translate - label_text="", cancel_button_text=None, minimum=0, maximum=self.tracker.missing_files_count, ) + Translations.translate_with_setter(pw.setWindowTitle, "entries.unlinked.delete.deleting") pw.from_iterable_function(self.tracker.execute_deletion, displayed_text, self.done.emit) diff --git a/tagstudio/src/qt/modals/drop_import.py b/tagstudio/src/qt/modals/drop_import.py index 7f4d77e8..7811a46d 100644 --- a/tagstudio/src/qt/modals/drop_import.py +++ b/tagstudio/src/qt/modals/drop_import.py @@ -19,6 +19,8 @@ from PySide6.QtWidgets import ( ) from src.qt.widgets.progress import ProgressWidget +from ..translations import Translations + if TYPE_CHECKING: from src.qt.ts_qt import QtDriver @@ -41,7 +43,7 @@ class DropImportModal(QWidget): self.driver: QtDriver = driver # Widget ====================== - self.setWindowTitle("Conflicting File(s)") # TODO translate + Translations.translate_with_setter(self.setWindowTitle, "drop_import.title") self.setWindowModality(Qt.WindowModality.ApplicationModal) self.setMinimumSize(500, 400) self.root_layout = QVBoxLayout(self) @@ -50,9 +52,7 @@ class DropImportModal(QWidget): self.desc_widget = QLabel() self.desc_widget.setObjectName("descriptionLabel") self.desc_widget.setWordWrap(True) - self.desc_widget.setText( - "The following files have filenames already exist in the library" - ) # TODO translate + self.desc_widget.setText(Translations["drop_import.decription"]) self.desc_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) # Duplicate File List ======== @@ -67,25 +67,25 @@ class DropImportModal(QWidget): self.button_layout.addStretch(1) self.skip_button = QPushButton() - self.skip_button.setText("&Skip") # TODO translate + Translations.translate_qobject(self.skip_button, "generic.skip_alt") self.skip_button.setDefault(True) self.skip_button.clicked.connect(lambda: self.begin_transfer(DuplicateChoice.SKIP)) self.button_layout.addWidget(self.skip_button) self.overwrite_button = QPushButton() - self.overwrite_button.setText("&Overwrite") # TODO translate + Translations.translate_qobject(self.overwrite_button, "generic.overwrite_alt") self.overwrite_button.clicked.connect( lambda: self.begin_transfer(DuplicateChoice.OVERWRITE) ) self.button_layout.addWidget(self.overwrite_button) self.rename_button = QPushButton() - self.rename_button.setText("&Rename") # TODO translate + Translations.translate_qobject(self.rename_button, "generic.rename_alt") self.rename_button.clicked.connect(lambda: self.begin_transfer(DuplicateChoice.RENAME)) self.button_layout.addWidget(self.rename_button) self.cancel_button = QPushButton() - self.cancel_button.setText("&Cancel") # TODO translate + Translations.translate_qobject(self.cancel_button, "generic.cancel_alt") self.cancel_button.clicked.connect(lambda: self.begin_transfer(DuplicateChoice.CANCEL)) self.button_layout.addWidget(self.cancel_button) @@ -139,8 +139,12 @@ class DropImportModal(QWidget): def ask_duplicates_choice(self): """Display the message widgeth with a list of the duplicated files.""" self.desc_widget.setText( - f"The following {len(self.duplicate_files)} file(s) have filenames already exist in the library." # noqa: E501 - ) # TODO translate + Translations["drop_import.duplicates_choice.singular"] + if len(self.duplicate_files) == 1 + else Translations.translate_formatted( + "drop_import.duplicates_choice.plural", count=len(self.duplicate_files) + ) + ) self.model.clear() for dupe in self.duplicate_files: @@ -160,19 +164,21 @@ class DropImportModal(QWidget): return def displayed_text(x): - text = f"Importing New Files...\n{x[0] + 1} File{'s' if x[0] + 1 != 1 else ''} Imported." # TODO translate - if self.choice: - text += f" {x[1]} {self.choice.value}" - - return text + return Translations.translate_formatted( + "drop_import.progress.label.singular" + if x[0] + 1 == 1 + else "drop_import.progress.label.plural", + count=x[0] + 1, + suffix=f" {x[1]} {self.choice.value}" if self.choice else "", + ) pw = ProgressWidget( - window_title="Import Files", # TODO translate - label_text="Importing New Files...", # TODO translate cancel_button_text=None, minimum=0, maximum=len(self.files), ) + Translations.translate_with_setter(pw.setWindowTitle, "drop_import.progress.window_title") + Translations.translate_with_setter(pw.update_label, "drop_import.progress.label.initial") pw.from_iterable_function( self.copy_files, diff --git a/tagstudio/src/qt/modals/file_extension.py b/tagstudio/src/qt/modals/file_extension.py index 19c6f06d..45ea0199 100644 --- a/tagstudio/src/qt/modals/file_extension.py +++ b/tagstudio/src/qt/modals/file_extension.py @@ -20,6 +20,8 @@ from src.core.enums import LibraryPrefs from src.core.library import Library from src.qt.widgets.panel import PanelWidget +from ..translations import Translations + class FileExtensionItemDelegate(QStyledItemDelegate): def setModelData(self, editor, model, index): # noqa: N802 @@ -35,7 +37,7 @@ class FileExtensionModal(PanelWidget): super().__init__() # Initialize Modal ===================================================== self.lib = library - self.setWindowTitle("File Extensions") # TODO translate + Translations.translate_with_setter(self.setWindowTitle, "ignore_list.title") self.setWindowModality(Qt.WindowModality.ApplicationModal) self.setMinimumSize(240, 400) self.root_layout = QVBoxLayout(self) @@ -50,7 +52,7 @@ class FileExtensionModal(PanelWidget): # Create "Add Button" Widget ------------------------------------------- self.add_button = QPushButton() - self.add_button.setText("&Add Extension") # TODO translate + Translations.translate_qobject(self.add_button, "ignore_list.add_extension") self.add_button.clicked.connect(self.add_item) self.add_button.setDefault(True) self.add_button.setMinimumWidth(100) @@ -61,11 +63,17 @@ class FileExtensionModal(PanelWidget): self.mode_layout.setContentsMargins(0, 0, 0, 0) self.mode_layout.setSpacing(12) self.mode_label = QLabel() - self.mode_label.setText("List Mode:") # TODO translate + Translations.translate_qobject(self.mode_label, "ignore_list.mode.label") self.mode_combobox = QComboBox() self.mode_combobox.setEditable(False) - self.mode_combobox.addItem("Include") # TODO translate - self.mode_combobox.addItem("Exclude") # TODO translate + self.mode_combobox.addItem("") + self.mode_combobox.addItem("") + Translations.translate_with_setter( + lambda text: self.mode_combobox.setItemText(0, text), "ignore_list.mode.include" + ) + Translations.translate_with_setter( + lambda text: self.mode_combobox.setItemText(0, text), "ignore_list.mode.exclude" + ) is_exclude_list = int(bool(self.lib.prefs(LibraryPrefs.IS_EXCLUDE_LIST))) diff --git a/tagstudio/src/qt/modals/fix_dupes.py b/tagstudio/src/qt/modals/fix_dupes.py index 0476e644..12095d9f 100644 --- a/tagstudio/src/qt/modals/fix_dupes.py +++ b/tagstudio/src/qt/modals/fix_dupes.py @@ -18,6 +18,8 @@ from src.core.library import Library from src.core.utils.dupe_files import DupeRegistry from src.qt.modals.mirror_entities import MirrorEntriesModal +from ..translations import Translations + # Only import for type checking/autocompletion, will not be imported at runtime. if typing.TYPE_CHECKING: from src.qt.ts_qt import QtDriver @@ -30,7 +32,7 @@ class FixDupeFilesModal(QWidget): self.driver = driver self.count = -1 self.filename = "" - self.setWindowTitle("Fix Duplicate Files") # TODO translate + Translations.translate_with_setter(self.setWindowTitle, "file.duplicates.fix") self.setWindowModality(Qt.WindowModality.ApplicationModal) self.setMinimumSize(400, 300) self.root_layout = QVBoxLayout(self) @@ -42,9 +44,7 @@ class FixDupeFilesModal(QWidget): self.desc_widget.setObjectName("descriptionLabel") self.desc_widget.setWordWrap(True) self.desc_widget.setStyleSheet("text-align:left;") - self.desc_widget.setText( - "TagStudio supports importing DupeGuru results to manage duplicate files." - ) # TODO translate + Translations.translate_qobject(self.desc_widget, "file.duplicates.description") self.desc_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) self.dupe_count = QLabel() @@ -54,34 +54,25 @@ class FixDupeFilesModal(QWidget): self.file_label = QLabel() self.file_label.setObjectName("fileLabel") - self.file_label.setText("No DupeGuru File Selected") # TODO translate + Translations.translate_qobject(self.file_label, "file.duplicates.dupeguru.no_file") self.open_button = QPushButton() - self.open_button.setText("&Load DupeGuru File") # TODO translate + Translations.translate_qobject(self.open_button, "file.duplicates.dupeguru.load_file") self.open_button.clicked.connect(self.select_file) self.mirror_modal = MirrorEntriesModal(self.driver, self.tracker) self.mirror_modal.done.connect(self.refresh_dupes) self.mirror_button = QPushButton() - self.mirror_button.setText("&Mirror Entries") # TODO translate + Translations.translate_qobject(self.mirror_button, "file.duplicates.mirror_entries") self.mirror_button.clicked.connect(self.mirror_modal.show) self.mirror_desc = QLabel() self.mirror_desc.setWordWrap(True) - self.mirror_desc.setText( - "Mirror the Entry data across each duplicate match set, combining all data while not " - "removing or duplicating fields. This operation will not delete any files or data." - ) # TODO translate + Translations.translate_qobject(self.mirror_desc, "file.duplicates.mirror.description") self.advice_label = QLabel() self.advice_label.setWordWrap(True) - # fmt: off - self.advice_label.setText( - "After mirroring, you're free to use DupeGuru to delete the unwanted files. " - "Afterwards, use TagStudio's \"Fix Unlinked Entries\" feature in the " - "Tools menu in order to delete the unlinked Entries." - )# TODO translate - # fmt: on + Translations.translate_qobject(self.advice_label, "file.duplicates.dupeguru.advice") self.button_container = QWidget() self.button_layout = QHBoxLayout(self.button_container) @@ -89,7 +80,7 @@ class FixDupeFilesModal(QWidget): self.button_layout.addStretch(1) self.done_button = QPushButton() - self.done_button.setText("&Done") # TODO translate + Translations.translate_qobject(self.done_button, "generic.done_alt") self.done_button.setDefault(True) self.done_button.clicked.connect(self.hide) self.button_layout.addWidget(self.done_button) @@ -109,10 +100,10 @@ class FixDupeFilesModal(QWidget): def select_file(self): qfd = QFileDialog( - self, "Open DupeGuru Results File", str(self.lib.library_dir) - ) # TODO translate + self, Translations["file.duplicates.dupeguru.open_file"], str(self.lib.library_dir) + ) qfd.setFileMode(QFileDialog.FileMode.ExistingFile) - qfd.setNameFilter("DupeGuru Files (*.dupeguru)") # TODO translate + qfd.setNameFilter(Translations["file.duplicates.dupeguru.file_extension"]) if qfd.exec_(): filename = qfd.selectedFiles() if filename: @@ -122,7 +113,7 @@ class FixDupeFilesModal(QWidget): if filename: self.file_label.setText(filename) else: - self.file_label.setText("No DupeGuru File Selected") # TODO translate + self.file_label.setText(Translations["file.duplicates.dupeguru.no_file"]) self.filename = filename self.refresh_dupes() self.mirror_modal.refresh_list() @@ -134,10 +125,14 @@ class FixDupeFilesModal(QWidget): def set_dupe_count(self, count: int): if count < 0: self.mirror_button.setDisabled(True) - self.dupe_count.setText("Duplicate File Matches: N/A") # TODO translate + self.dupe_count.setText(Translations["file.duplicates.matches_uninitialized"]) elif count == 0: self.mirror_button.setDisabled(True) - self.dupe_count.setText(f"Duplicate File Matches: {count}") # TODO translate + self.dupe_count.setText( + Translations.translate_formatted("file.duplicates.matches", count=count) + ) else: self.mirror_button.setDisabled(False) - self.dupe_count.setText(f"Duplicate File Matches: {count}") # TODO translate + self.dupe_count.setText( + Translations.translate_formatted("file.duplicates.matches", count=count) + ) diff --git a/tagstudio/src/qt/modals/fix_unlinked.py b/tagstudio/src/qt/modals/fix_unlinked.py index 2afae7fb..3226566f 100644 --- a/tagstudio/src/qt/modals/fix_unlinked.py +++ b/tagstudio/src/qt/modals/fix_unlinked.py @@ -14,6 +14,8 @@ from src.qt.modals.merge_dupe_entries import MergeDuplicateEntries from src.qt.modals.relink_unlinked import RelinkUnlinkedEntries from src.qt.widgets.progress import ProgressWidget +from ..translations import Translations + # Only import for type checking/autocompletion, will not be imported at runtime. if typing.TYPE_CHECKING: from src.qt.ts_qt import QtDriver @@ -29,7 +31,7 @@ class FixUnlinkedEntriesModal(QWidget): self.missing_count = -1 self.dupe_count = -1 - self.setWindowTitle("Fix Unlinked Entries") # TODO translate + Translations.translate_with_setter(self.setWindowTitle, "entries.unlinked.title") self.setWindowModality(Qt.WindowModality.ApplicationModal) self.setMinimumSize(400, 300) self.root_layout = QVBoxLayout(self) @@ -39,13 +41,7 @@ class FixUnlinkedEntriesModal(QWidget): self.unlinked_desc_widget.setObjectName("unlinkedDescriptionLabel") self.unlinked_desc_widget.setWordWrap(True) self.unlinked_desc_widget.setStyleSheet("text-align:left;") - self.unlinked_desc_widget.setText( - "Each library entry is linked to a file in one of your directories. " - "If a file linked to an entry is moved or deleted outside of TagStudio, " - "it is then considered unlinked.\n\n" - "Unlinked entries may be automatically relinked via searching your directories, " - "manually relinked by the user, or deleted if desired." - ) # TODO translate + Translations.translate_qobject(self.unlinked_desc_widget, "entries.unlinked.description") self.missing_count_label = QLabel() self.missing_count_label.setObjectName("missingCountLabel") @@ -58,14 +54,14 @@ class FixUnlinkedEntriesModal(QWidget): self.dupe_count_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.refresh_unlinked_button = QPushButton() - self.refresh_unlinked_button.setText("&Refresh All") # TODO translate + Translations.translate_qobject(self.refresh_unlinked_button, "entries.unlinked.refresh_all") self.refresh_unlinked_button.clicked.connect(self.refresh_missing_files) self.merge_class = MergeDuplicateEntries(self.lib, self.driver) self.relink_class = RelinkUnlinkedEntries(self.tracker) self.search_button = QPushButton() - self.search_button.setText("&Search && Relink") # TODO translate + Translations.translate_qobject(self.search_button, "entries.unlinked.search_and_relink") self.relink_class.done.connect( # refresh the grid lambda: ( @@ -76,7 +72,7 @@ class FixUnlinkedEntriesModal(QWidget): self.search_button.clicked.connect(self.relink_class.repair_entries) self.manual_button = QPushButton() - self.manual_button.setText("&Manual Relink") # TODO translate + Translations.translate_qobject(self.manual_button, "entries.unlinked.relink.manual") self.manual_button.setHidden(True) self.delete_button = QPushButton() @@ -88,7 +84,7 @@ class FixUnlinkedEntriesModal(QWidget): self.driver.filter_items(), ) ) - self.delete_button.setText("De&lete Unlinked Entries") # TODO translate + Translations.translate_qobject(self.delete_button, "entries.unlinked.delete_alt") self.delete_button.clicked.connect(self.delete_modal.show) self.button_container = QWidget() @@ -97,7 +93,7 @@ class FixUnlinkedEntriesModal(QWidget): self.button_layout.addStretch(1) self.done_button = QPushButton() - self.done_button.setText("&Done") # TODO translate + Translations.translate_qobject(self.done_button, "generic.done_alt") self.done_button.setDefault(True) self.done_button.clicked.connect(self.hide) self.button_layout.addWidget(self.done_button) @@ -116,12 +112,12 @@ class FixUnlinkedEntriesModal(QWidget): def refresh_missing_files(self): pw = ProgressWidget( - window_title="Scanning Library", # TODO translate - label_text="Scanning Library for Unlinked Entries...", # TODO translate cancel_button_text=None, minimum=0, maximum=self.lib.entries_count, ) + Translations.translate_with_setter(pw.setWindowTitle, "library.scan_library.title") + Translations.translate_with_setter(pw.update_label, "entries.unlinked.scanning") pw.from_iterable_function( self.tracker.refresh_missing_files, @@ -139,11 +135,13 @@ class FixUnlinkedEntriesModal(QWidget): if self.missing_count < 0: self.search_button.setDisabled(True) self.delete_button.setDisabled(True) - self.missing_count_label.setText("Unlinked Entries: N/A") # TODO translate + self.missing_count_label.setText(Translations["entries.unlinked.missing_count.none"]) else: # disable buttons if there are no files to fix self.search_button.setDisabled(self.missing_count == 0) self.delete_button.setDisabled(self.missing_count == 0) self.missing_count_label.setText( - f"Unlinked Entries: {self.missing_count}" - ) # TODO translate + Translations.translate_formatted( + "entries.unlinked.missing_count.some", count=self.missing_count + ) + ) diff --git a/tagstudio/src/qt/modals/folders_to_tags.py b/tagstudio/src/qt/modals/folders_to_tags.py index ca2d48cc..60fcd318 100644 --- a/tagstudio/src/qt/modals/folders_to_tags.py +++ b/tagstudio/src/qt/modals/folders_to_tags.py @@ -24,6 +24,8 @@ from src.core.library.alchemy.fields import _FieldID from src.core.palette import ColorType, get_tag_color from src.qt.flowlayout import FlowLayout +from ..translations import Translations + if typing.TYPE_CHECKING: from src.qt.ts_qt import QtDriver @@ -164,7 +166,7 @@ class FoldersToTagsModal(QWidget): self.count = -1 self.filename = "" - self.setWindowTitle("Create Tags From Folders") # TODO translate + Translations.translate_with_setter(self.setWindowTitle, "folders_to_tags.title") self.setWindowModality(Qt.WindowModality.ApplicationModal) self.setMinimumSize(640, 640) self.root_layout = QVBoxLayout(self) @@ -174,7 +176,7 @@ class FoldersToTagsModal(QWidget): self.title_widget.setObjectName("title") self.title_widget.setWordWrap(True) self.title_widget.setStyleSheet("font-weight:bold;" "font-size:14px;" "padding-top: 6px") - self.title_widget.setText("Create Tags From Folders") # TODO translate + Translations.translate_qobject(self.title_widget, "folders_to_tags.title") self.title_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) self.desc_widget = QLabel() @@ -190,10 +192,10 @@ class FoldersToTagsModal(QWidget): self.open_close_button_layout = QHBoxLayout(self.open_close_button_w) self.open_all_button = QPushButton() - self.open_all_button.setText("Open All") # TODO translate + Translations.translate_qobject(self.open_all_button, "folders_to_tags.open_all") self.open_all_button.clicked.connect(lambda: self.set_all_branches(False)) self.close_all_button = QPushButton() - self.close_all_button.setText("Close All") # TODO translate + Translations.translate_qobject(self.close_all_button, "folders_to_tags.close_all") self.close_all_button.clicked.connect(lambda: self.set_all_branches(True)) self.open_close_button_layout.addWidget(self.open_all_button) @@ -212,7 +214,7 @@ class FoldersToTagsModal(QWidget): self.scroll_area.setWidget(self.scroll_contents) self.apply_button = QPushButton() - self.apply_button.setText("&Apply") # TODO translate + Translations.translate_qobject(self.apply_button, "generic.apply_alt") self.apply_button.setMinimumWidth(100) self.apply_button.clicked.connect(self.on_apply) diff --git a/tagstudio/src/qt/modals/merge_dupe_entries.py b/tagstudio/src/qt/modals/merge_dupe_entries.py index 14891d47..5d2d49af 100644 --- a/tagstudio/src/qt/modals/merge_dupe_entries.py +++ b/tagstudio/src/qt/modals/merge_dupe_entries.py @@ -9,6 +9,8 @@ from src.core.library import Library from src.core.utils.dupe_files import DupeRegistry from src.qt.widgets.progress import ProgressWidget +from ..translations import Translations + # Only import for type checking/autocompletion, will not be imported at runtime. if typing.TYPE_CHECKING: from src.qt.ts_qt import QtDriver @@ -25,11 +27,11 @@ class MergeDuplicateEntries(QObject): def merge_entries(self): pw = ProgressWidget( - window_title="Merging Duplicate Entries", # TODO translate - label_text="Merging Duplicate Entries...", # TODO translate cancel_button_text=None, minimum=0, maximum=self.tracker.groups_count, ) + Translations.translate_with_setter(pw.setWindowTitle, "entries.duplicate.merge.label") + Translations.translate_with_setter(pw.update_label, "entries.duplicate.merge.label") pw.from_iterable_function(self.tracker.merge_dupe_entries, None, self.done.emit) diff --git a/tagstudio/src/qt/modals/mirror_entities.py b/tagstudio/src/qt/modals/mirror_entities.py index 4c0cd4aa..c872fa58 100644 --- a/tagstudio/src/qt/modals/mirror_entities.py +++ b/tagstudio/src/qt/modals/mirror_entities.py @@ -19,6 +19,8 @@ from PySide6.QtWidgets import ( from src.core.utils.dupe_files import DupeRegistry from src.qt.widgets.progress import ProgressWidget +from ..translations import Translations + # Only import for type checking/autocompletion, will not be imported at runtime. if typing.TYPE_CHECKING: from src.qt.ts_qt import QtDriver @@ -30,7 +32,7 @@ class MirrorEntriesModal(QWidget): def __init__(self, driver: "QtDriver", tracker: DupeRegistry): super().__init__() self.driver = driver - self.setWindowTitle("Mirror Entries") # TODO translate + Translations.translate_with_setter(self.setWindowTitle, "entries.mirror.window_title") self.setWindowModality(Qt.WindowModality.ApplicationModal) self.setMinimumSize(500, 400) self.root_layout = QVBoxLayout(self) @@ -40,10 +42,9 @@ class MirrorEntriesModal(QWidget): self.desc_widget = QLabel() self.desc_widget.setObjectName("descriptionLabel") self.desc_widget.setWordWrap(True) - - self.desc_widget.setText(f""" - Are you sure you want to mirror the following {self.tracker.groups_count} Entries? - """) # TODO translate + Translations.translate_qobject( + self.desc_widget, "entries.mirror.confirmation", count=self.tracker.groups_count + ) self.desc_widget.setAlignment(Qt.AlignmentFlag.AlignCenter) self.list_view = QListView() @@ -56,13 +57,13 @@ class MirrorEntriesModal(QWidget): self.button_layout.addStretch(1) self.cancel_button = QPushButton() - self.cancel_button.setText("&Cancel") # TODO translate + Translations.translate_qobject(self.cancel_button, "generic.cancel_alt") self.cancel_button.setDefault(True) self.cancel_button.clicked.connect(self.hide) self.button_layout.addWidget(self.cancel_button) self.mirror_button = QPushButton() - self.mirror_button.setText("&Mirror") # TODO translate + Translations.translate_qobject(self.mirror_button, "entries.mirror") self.mirror_button.clicked.connect(self.hide) self.mirror_button.clicked.connect(self.mirror_entries) self.button_layout.addWidget(self.mirror_button) @@ -72,9 +73,11 @@ class MirrorEntriesModal(QWidget): self.root_layout.addWidget(self.button_container) def refresh_list(self): - self.desc_widget.setText(f""" - Are you sure you want to mirror the following {self.tracker.groups_count} Entries? - """) + self.desc_widget.setText( + Translations.translate_formatted( + "entries.mirror.confirmation", count=self.tracker.groups_count + ) + ) self.model.clear() for i in self.tracker.groups: @@ -82,15 +85,16 @@ class MirrorEntriesModal(QWidget): def mirror_entries(self): def displayed_text(x): - return f"Mirroring {x + 1}/{self.tracker.groups_count} Entries..." # TODO translate + return Translations.translate_formatted( + "entries.mirror.label", idx=x + 1, count=self.tracker.groups_count + ) pw = ProgressWidget( - window_title="Mirroring Entries", # TODO translate - label_text="", cancel_button_text=None, minimum=0, maximum=self.tracker.groups_count, ) + Translations.translate_with_setter(pw.setWindowTitle, "entries.mirror.title") pw.from_iterable_function( self.mirror_entries_runnable, diff --git a/tagstudio/src/qt/modals/relink_unlinked.py b/tagstudio/src/qt/modals/relink_unlinked.py index 87d67a6c..366930a7 100644 --- a/tagstudio/src/qt/modals/relink_unlinked.py +++ b/tagstudio/src/qt/modals/relink_unlinked.py @@ -7,6 +7,8 @@ from PySide6.QtCore import QObject, Signal from src.core.utils.missing_files import MissingRegistry from src.qt.widgets.progress import ProgressWidget +from ..translations import Translations + class RelinkUnlinkedEntries(QObject): done = Signal() @@ -17,16 +19,19 @@ class RelinkUnlinkedEntries(QObject): def repair_entries(self): def displayed_text(x): - text = f"Attempting to Relink {x}/{self.tracker.missing_files_count} Entries. \n" # TODO translate - text += f"{self.tracker.files_fixed_count} Successfully Relinked." # TODO translate - return text + return Translations.translate_formatted( + "entries.unlinked.relink.attempting", + idx=x, + missing_count=self.tracker.missing_files_count, + fixed_count=self.tracker.files_fixed_count, + ) pw = ProgressWidget( - window_title="Relinking Entries", # TODO translate label_text="", cancel_button_text=None, minimum=0, maximum=self.tracker.missing_files_count, ) + Translations.translate_with_setter(pw.setWindowTitle, "entries.unlinked.relink.title") pw.from_iterable_function(self.tracker.fix_missing_files, displayed_text, self.done.emit) diff --git a/tagstudio/src/qt/modals/tag_database.py b/tagstudio/src/qt/modals/tag_database.py index 15f6289e..8a308cd8 100644 --- a/tagstudio/src/qt/modals/tag_database.py +++ b/tagstudio/src/qt/modals/tag_database.py @@ -21,6 +21,8 @@ from src.qt.modals.build_tag import BuildTagPanel from src.qt.widgets.panel import PanelModal, PanelWidget from src.qt.widgets.tag import TagWidget +from ..translations import Translations + logger = structlog.get_logger(__name__) # TODO: This class shares the majority of its code with tag_search.py. @@ -44,7 +46,7 @@ class TagDatabasePanel(PanelWidget): self.search_field = QLineEdit() self.search_field.setObjectName("searchField") self.search_field.setMinimumSize(QSize(0, 32)) - self.search_field.setPlaceholderText("Search Tags") # TODO translate + Translations.translate_with_setter(self.search_field.setPlaceholderText, "home.search_tags") self.search_field.textEdited.connect(lambda: self.update_tags(self.search_field.text())) self.search_field.returnPressed.connect( lambda checked=False: self.on_return(self.search_field.text()) @@ -63,7 +65,7 @@ class TagDatabasePanel(PanelWidget): self.scroll_area.setWidget(self.scroll_contents) self.create_tag_button = QPushButton() - self.create_tag_button.setText("Create Tag") # TODO translate + Translations.translate_qobject(self.create_tag_button, "tag.create") self.create_tag_button.clicked.connect(self.build_tag) self.root_layout.addWidget(self.search_field) @@ -72,14 +74,14 @@ class TagDatabasePanel(PanelWidget): self.update_tags() def build_tag(self): + panel = BuildTagPanel(self.lib) self.modal = PanelModal( - BuildTagPanel(self.lib), - "New Tag", # TODO translate - "Add Tag", # TODO translate + panel, has_save=True, ) + Translations.translate_with_setter(self.modal.setTitle, "tag.new") + Translations.translate_with_setter(self.modal.setWindowTitle, "tag.add") - panel: BuildTagPanel = self.modal.widget self.modal.saved.connect( lambda: ( self.lib.add_tag( @@ -134,10 +136,8 @@ class TagDatabasePanel(PanelWidget): return message_box = QMessageBox() - message_box.setWindowTitle("Remove Tag") # TODO translate - message_box.setText( - f'Are you sure you want to delete the tag "{tag.name}"?' - ) # TODO translate + Translations.translate_with_setter(message_box.setWindowTitle, "tag.remove") + Translations.translate_qobject(message_box, "tag_database.confirmation", tag_name=tag.name) message_box.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) # type: ignore message_box.setIcon(QMessageBox.Question) # type: ignore @@ -158,10 +158,10 @@ class TagDatabasePanel(PanelWidget): self.edit_modal = PanelModal( build_tag_panel, tag.name, - "Edit Tag", # TODO translate done_callback=(self.update_tags(self.search_field.text())), has_save=True, ) + Translations.translate_with_setter(self.edit_modal.setWindowTitle, "tag.edit") # TODO Check Warning: Expected type 'BuildTagPanel', got 'PanelWidget' instead self.edit_modal.saved.connect(lambda: self.edit_tag_callback(build_tag_panel)) self.edit_modal.show() diff --git a/tagstudio/src/qt/modals/tag_search.py b/tagstudio/src/qt/modals/tag_search.py index 2189b316..63cac736 100644 --- a/tagstudio/src/qt/modals/tag_search.py +++ b/tagstudio/src/qt/modals/tag_search.py @@ -22,6 +22,8 @@ from src.core.palette import ColorType, get_tag_color from src.qt.widgets.panel import PanelWidget from src.qt.widgets.tag import TagWidget +from ..translations import Translations + logger = structlog.get_logger(__name__) @@ -41,7 +43,7 @@ class TagSearchPanel(PanelWidget): self.search_field = QLineEdit() self.search_field.setObjectName("searchField") self.search_field.setMinimumSize(QSize(0, 32)) - self.search_field.setPlaceholderText("Search Tags") # TODO translate + Translations.translate_with_setter(self.search_field.setPlaceholderText, "home.search_tags") self.search_field.textEdited.connect(lambda: self.update_tags(self.search_field.text())) self.search_field.returnPressed.connect( lambda checked=False: self.on_return(self.search_field.text()) diff --git a/tagstudio/src/qt/translations.py b/tagstudio/src/qt/translations.py index 057c5da7..882c3712 100644 --- a/tagstudio/src/qt/translations.py +++ b/tagstudio/src/qt/translations.py @@ -4,7 +4,7 @@ from typing import Callable import ujson from PySide6.QtCore import QObject, Signal from PySide6.QtGui import QAction -from PySide6.QtWidgets import QLabel, QMenu, QPushButton +from PySide6.QtWidgets import QLabel, QMenu, QMessageBox, QPushButton DEFAULT_TRANSLATION = "de" @@ -49,7 +49,7 @@ class Translator: def translate_qobject(self, widget: QObject, key: str, **kwargs): """Translates the text of the QObject using :func:`translate_with_setter`.""" - if isinstance(widget, (QLabel, QAction, QPushButton)): + if isinstance(widget, (QLabel, QAction, QPushButton, QMessageBox)): self.translate_with_setter(widget.setText, key, **kwargs) elif isinstance(widget, (QMenu)): self.translate_with_setter(widget.setTitle, key, **kwargs) diff --git a/tagstudio/src/qt/ts_qt.py b/tagstudio/src/qt/ts_qt.py index a6c205c9..62fa51fc 100644 --- a/tagstudio/src/qt/ts_qt.py +++ b/tagstudio/src/qt/ts_qt.py @@ -522,7 +522,7 @@ class QtDriver(DriverMixin, QObject): msg_box.setIcon(QMessageBox.Icon.Critical) msg_box.setText(message) msg_box.setWindowTitle(Translations["window.title.error"]) - msg_box.addButton(Translations["window.button.close"], QMessageBox.ButtonRole.AcceptRole) + msg_box.addButton(Translations["generic.close"], QMessageBox.ButtonRole.AcceptRole) # Show the message box msg_box.exec()