fix: restore translate_formatted() method as format() (#830)

* fix: restore `translate_formatted()` method

* fix: set "Create & Add" button text

* refactor: rename "translate_formatted" to "format"

* translations: replace invalid format key names with "{unknown_key}"
This commit is contained in:
Travis Abendshien
2025-03-06 13:05:56 -08:00
committed by GitHub
parent 07b7d40926
commit 7e75087b24
18 changed files with 83 additions and 57 deletions

View File

@@ -44,7 +44,8 @@ class AboutModal(QWidget):
if ff_version["ffprobe"] is not None:
ffprobe = '<span style="color:green">Found</span> (' + ff_version["ffprobe"] + ")"
self.content_widget = QLabel(
Translations["about.content"].format(
Translations.format(
"about.content",
version=VERSION,
branch=VERSION_BRANCH,
config_path=config_path,

View File

@@ -32,7 +32,8 @@ class DeleteUnlinkedEntriesModal(QWidget):
self.root_layout.setContentsMargins(6, 6, 6, 6)
self.desc_widget = QLabel(
Translations["entries.unlinked.delete.confirm"].format(
Translations.format(
"entries.unlinked.delete.confirm",
count=self.tracker.missing_file_entries_count,
)
)
@@ -65,8 +66,8 @@ class DeleteUnlinkedEntriesModal(QWidget):
def refresh_list(self):
self.desc_widget.setText(
Translations["entries.unlinked.delete.confirm"].format(
count=self.tracker.missing_file_entries_count
Translations.format(
"entries.unlinked.delete.confirm", count=self.tracker.missing_file_entries_count
)
)

View File

@@ -131,8 +131,8 @@ class DropImportModal(QWidget):
self.desc_widget.setText(
Translations["drop_import.duplicates_choice.singular"]
if len(self.duplicate_files) == 1
else Translations["drop_import.duplicates_choice.plural"].format(
count=len(self.duplicate_files)
else Translations.format(
"drop_import.duplicates_choice.plural", count=len(self.duplicate_files)
)
)
@@ -154,11 +154,10 @@ class DropImportModal(QWidget):
return
def displayed_text(x):
return Translations[
return Translations.format(
"drop_import.progress.label.singular"
if x[0] + 1 == 1
else "drop_import.progress.label.plural"
].format(
else "drop_import.progress.label.plural",
count=x[0] + 1,
suffix=f" {x[1]} {self.choice.value}" if self.choice else "",
)

View File

@@ -114,10 +114,10 @@ class FixDupeFilesModal(QWidget):
self.dupe_count.setText(Translations["file.duplicates.matches_uninitialized"])
elif count == 0:
self.mirror_button.setDisabled(True)
self.dupe_count.setText(Translations["file.duplicates.matches"].format(count=count))
self.dupe_count.setText(Translations.format("file.duplicates.matches", count=count))
else:
self.mirror_button.setDisabled(False)
self.dupe_count.setText(Translations["file.duplicates.matches"].format(count=count))
self.dupe_count.setText(Translations.format("file.duplicates.matches", count=count))
@override
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa N802

View File

@@ -135,7 +135,7 @@ class FixUnlinkedEntriesModal(QWidget):
self.search_button.setDisabled(self.missing_count == 0)
self.delete_button.setDisabled(self.missing_count == 0)
self.missing_count_label.setText(
Translations["entries.unlinked.missing_count.some"].format(count=self.missing_count)
Translations.format("entries.unlinked.missing_count.some", count=self.missing_count)
)
@override

View File

@@ -32,7 +32,7 @@ class MirrorEntriesModal(QWidget):
self.tracker = tracker
self.desc_widget = QLabel(
Translations["entries.mirror.confirmation"].format(count=self.tracker.groups_count)
Translations.format("entries.mirror.confirmation", count=self.tracker.groups_count)
)
self.desc_widget.setObjectName("descriptionLabel")
self.desc_widget.setWordWrap(True)
@@ -63,7 +63,7 @@ class MirrorEntriesModal(QWidget):
def refresh_list(self):
self.desc_widget.setText(
Translations["entries.mirror.confirmation"].format(count=self.tracker.groups_count)
Translations.format("entries.mirror.confirmation", count=self.tracker.groups_count)
)
self.model.clear()
@@ -72,8 +72,8 @@ class MirrorEntriesModal(QWidget):
def mirror_entries(self):
def displayed_text(x):
return Translations["entries.mirror.label"].format(
idx=x + 1, count=self.tracker.groups_count
return Translations.format(
"entries.mirror.label", idx=x + 1, count=self.tracker.groups_count
)
pw = ProgressWidget(

View File

@@ -18,7 +18,8 @@ class RelinkUnlinkedEntries(QObject):
def repair_entries(self):
def displayed_text(x):
return Translations["entries.unlinked.relink.attempting"].format(
return Translations.format(
"entries.unlinked.relink.attempting",
idx=x,
missing_count=self.tracker.missing_file_entries_count,
fixed_count=self.tracker.files_fixed_count,

View File

@@ -60,9 +60,7 @@ class TagDatabasePanel(TagSearchPanel):
message_box = QMessageBox(
QMessageBox.Question, # type: ignore
Translations["tag.remove"],
Translations["tag.confirm_delete"].format(
tag_name=self.lib.tag_display_name(tag.id),
),
Translations.format("tag.confirm_delete", tag_name=self.lib.tag_display_name(tag.id)),
QMessageBox.Ok | QMessageBox.Cancel, # type: ignore
)

View File

@@ -118,9 +118,9 @@ class TagSearchPanel(PanelWidget):
"""Set the QtDriver for this search panel. Used for main window operations."""
self.driver = driver
def build_create_button(self, query: str | None, key: str, format_args: dict):
def build_create_button(self, query: str | None):
"""Constructs a "Create & Add Tag" QPushButton."""
create_button = QPushButton(Translations[key].format(**format_args), self)
create_button = QPushButton(self)
create_button.setFlat(True)
create_button.setMinimumSize(22, 22)
@@ -244,7 +244,8 @@ class TagSearchPanel(PanelWidget):
# Add back the "Create & Add" button
if query and query.strip():
cb: QPushButton = self.build_create_button(query, "tag.create_add", {"query": query})
cb: QPushButton = self.build_create_button(query)
cb.setText(Translations.format("tag.create_add", query=query))
with catch_warnings(record=True):
cb.clicked.disconnect()
cb.clicked.connect(lambda: self.create_and_add_tag(query or ""))

View File

@@ -1,4 +1,6 @@
from collections import defaultdict
from pathlib import Path
from typing import Any
import structlog
import ujson
@@ -27,6 +29,23 @@ class Translator:
self._lang = lang
self._strings = self.__get_translation_dict(lang)
def __format(self, text: str, **kwargs) -> str:
try:
return text.format(**kwargs)
except (KeyError, ValueError):
logger.error(
"[Translations] Error while formatting translation.",
text=text,
kwargs=kwargs,
language=self._lang,
)
params: defaultdict[str, Any] = defaultdict(lambda: "{unknown_key}")
params.update(kwargs)
return text.format_map(params)
def format(self, key: str, **kwargs) -> str:
return self.__format(self[key], **kwargs)
def __getitem__(self, key: str) -> str:
return self._strings.get(key) or self._default_strings.get(key) or f"[{key}]"

View File

@@ -496,7 +496,7 @@ class QtDriver(DriverMixin, QObject):
edit_menu.addSeparator()
self.delete_file_action = QAction(
Translations["menu.delete_selected_files_ambiguous"].format(trash_term=trash_term()),
Translations.format("menu.delete_selected_files_ambiguous", trash_term=trash_term()),
menu_bar,
)
self.delete_file_action.triggered.connect(lambda f="": self.delete_files_callback(f))
@@ -876,8 +876,8 @@ class QtDriver(DriverMixin, QObject):
end_time = time.time()
self.main_window.statusbar.showMessage(
Translations["status.library_closed"].format(
time_span=format_timespan(end_time - start_time)
Translations.format(
"status.library_closed", time_span=format_timespan(end_time - start_time)
)
)
@@ -888,7 +888,8 @@ class QtDriver(DriverMixin, QObject):
target_path = self.lib.save_library_backup_to_disk()
end_time = time.time()
self.main_window.statusbar.showMessage(
Translations["status.library_backup_success"].format(
Translations.format(
"status.library_backup_success",
path=target_path,
time_span=format_timespan(end_time - start_time),
)
@@ -986,8 +987,8 @@ class QtDriver(DriverMixin, QObject):
self.preview_panel.thumb.stop_file_use()
if delete_file(self.lib.library_dir / f):
self.main_window.statusbar.showMessage(
Translations["status.deleting_file"].format(
i=i, count=len(pending), path=f
Translations.format(
"status.deleting_file", i=i, count=len(pending), path=f
)
)
self.main_window.statusbar.repaint()
@@ -1004,17 +1005,17 @@ class QtDriver(DriverMixin, QObject):
self.main_window.statusbar.showMessage(Translations["status.deleted_none"])
elif len(self.selected) <= 1 and deleted_count == 1:
self.main_window.statusbar.showMessage(
Translations["status.deleted_file_plural"].format(count=deleted_count)
Translations.format("status.deleted_file_plural", count=deleted_count)
)
elif len(self.selected) > 1 and deleted_count == 0:
self.main_window.statusbar.showMessage(Translations["status.deleted_none"])
elif len(self.selected) > 1 and deleted_count < len(self.selected):
self.main_window.statusbar.showMessage(
Translations["status.deleted_partial_warning"].format(count=deleted_count)
Translations.format("status.deleted_partial_warning", count=deleted_count)
)
elif len(self.selected) > 1 and deleted_count == len(self.selected):
self.main_window.statusbar.showMessage(
Translations["status.deleted_file_plural"].format(count=deleted_count)
Translations.format("status.deleted_file_plural", count=deleted_count)
)
self.main_window.statusbar.repaint()
@@ -1031,8 +1032,8 @@ class QtDriver(DriverMixin, QObject):
# https://github.com/arsenetar/send2trash/issues/28
# This warning is applied to all platforms until at least macOS and Linux can be verified
# to not exhibit this same behavior.
perm_warning_msg = Translations["trash.dialog.permanent_delete_warning"].format(
trash_term=trash_term()
perm_warning_msg = Translations.format(
"trash.dialog.permanent_delete_warning", trash_term=trash_term()
)
perm_warning: str = (
f"<h4 style='color: {get_ui_color(ColorType.PRIMARY, UiColor.RED)}'>"
@@ -1049,8 +1050,8 @@ class QtDriver(DriverMixin, QObject):
)
msg.setIcon(QMessageBox.Icon.Warning)
if count <= 1:
msg_text = Translations["trash.dialog.move.confirmation.singular"].format(
trash_term=trash_term()
msg_text = Translations.format(
"trash.dialog.move.confirmation.singular", trash_term=trash_term()
)
msg.setText(
f"<h3>{msg_text}</h3>"
@@ -1059,7 +1060,8 @@ class QtDriver(DriverMixin, QObject):
f"{perm_warning}<br>"
)
elif count > 1:
msg_text = Translations["trash.dialog.move.confirmation.plural"].format(
msg_text = Translations.format(
"trash.dialog.move.confirmation.plural",
count=count,
trash_term=trash_term(),
)
@@ -1094,11 +1096,10 @@ class QtDriver(DriverMixin, QObject):
lambda x: (
pw.update_progress(x + 1),
pw.update_label(
Translations[
Translations.format(
"library.refresh.scanning.plural"
if x + 1 != 1
else "library.refresh.scanning.singular"
].format(
else "library.refresh.scanning.singular",
searched_count=f"{x+1:n}",
found_count=f"{tracker.files_count:n}",
)
@@ -1130,15 +1131,15 @@ class QtDriver(DriverMixin, QObject):
)
pw.setWindowTitle(Translations["entries.running.dialog.title"])
pw.update_label(
Translations["entries.running.dialog.new_entries"].format(total=f"{files_count:n}")
Translations.format("entries.running.dialog.new_entries", total=f"{files_count:n}")
)
pw.show()
iterator.value.connect(
lambda: (
pw.update_label(
Translations["entries.running.dialog.new_entries"].format(
total=f"{files_count:n}"
Translations.format(
"entries.running.dialog.new_entries", total=f"{files_count:n}"
)
),
)
@@ -1698,7 +1699,8 @@ class QtDriver(DriverMixin, QObject):
# inform user about completed search
self.main_window.statusbar.showMessage(
Translations["status.results_found"].format(
Translations.format(
"status.results_found",
count=results.total_count,
time_span=format_timespan(end_time - start_time),
)
@@ -1824,7 +1826,7 @@ class QtDriver(DriverMixin, QObject):
def open_library(self, path: Path) -> None:
"""Open a TagStudio library."""
message = Translations["splash.opening_library"].format(library_path=str(path))
message = Translations.format("splash.opening_library", library_path=str(path))
self.main_window.landing_widget.set_status_label(message)
self.main_window.statusbar.showMessage(message, 3)
self.main_window.repaint()
@@ -1871,8 +1873,10 @@ class QtDriver(DriverMixin, QObject):
self.update_libs_list(path)
self.main_window.setWindowTitle(
Translations["app.title"].format(
base_title=self.base_title, library_dir=self.lib.library_dir
Translations.format(
"app.title",
base_title=self.base_title,
library_dir=self.lib.library_dir,
)
)
self.main_window.setAcceptDrops(True)

View File

@@ -146,7 +146,7 @@ class ColorBoxWidget(FieldWidget):
message_box = QMessageBox(
QMessageBox.Icon.Warning,
Translations["color.delete"],
Translations["color.confirm_delete"].format(color_name=color_group.name),
Translations.format("color.confirm_delete", color_name=color_group.name),
)
cancel_button = message_box.addButton(
Translations["generic.cancel_alt"], QMessageBox.ButtonRole.RejectRole

View File

@@ -222,7 +222,8 @@ class ItemThumb(FlowWidget):
open_explorer_action.triggered.connect(self.opener.open_explorer)
self.delete_action = QAction(
Translations["trash.context.ambiguous"].format(trash_term=trash_term()), self
Translations.format("trash.context.ambiguous", trash_term=trash_term()),
self,
)
self.thumb_button.addAction(open_file_action)

View File

@@ -62,7 +62,7 @@ class LandingWidget(QWidget):
else:
open_shortcut_text = "(Ctrl+O)"
self.open_button: QPushButton = QPushButton(
Translations["landing.open_create_library"].format(shortcut=open_shortcut_text)
Translations.format("landing.open_create_library", shortcut=open_shortcut_text)
)
self.open_button.setMinimumWidth(200)
self.open_button.clicked.connect(self.driver.open_library_from_dialog)

View File

@@ -57,7 +57,7 @@ class JsonMigrationModal(QObject):
self.is_migration_initialized: bool = False
self.discrepancies: list[str] = []
self.title: str = Translations["json_migration.title"].format(path=self.path)
self.title: str = Translations.format("json_migration.title", path=self.path)
self.warning: str = "<b><a style='color: #e22c3c'>(!)</a></b>"
self.old_entry_count: int = 0
@@ -405,8 +405,8 @@ class JsonMigrationModal(QObject):
logger.info('Temporary migration file "temp_path" already exists. Removing...')
self.temp_path.unlink()
self.sql_lib.open_sqlite_library(self.json_lib.library_dir, is_new=True)
yield Translations["json_migration.migrating_files_entries"].format(
entries=len(self.json_lib.entries)
yield Translations.format(
"json_migration.migrating_files_entries", entries=len(self.json_lib.entries)
)
self.sql_lib.migrate_json_to_sqlite(self.json_lib)
yield Translations["json_migration.checking_for_parity"]

View File

@@ -246,7 +246,7 @@ class FieldContainers(QWidget):
return cats
def remove_field_prompt(self, name: str) -> str:
return Translations["library.field.confirm_remove"].format(name=name)
return Translations.format("library.field.confirm_remove", name=name)
def add_field_to_selected(self, field_list: list):
"""Add list of entry fields to one or more selected items.

View File

@@ -231,7 +231,7 @@ class FileAttributes(QWidget):
"""Format attributes for multiple selected items."""
self.layout().setSpacing(0)
self.file_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.file_label.setText(Translations["preview.multiple_selection"].format(count=count))
self.file_label.setText(Translations.format("preview.multiple_selection", count=count))
self.file_label.setCursor(Qt.CursorShape.ArrowCursor)
self.file_label.set_file_path("")
self.dimensions_label.setText("")

View File

@@ -57,7 +57,8 @@ class PreviewThumb(QWidget):
self.open_file_action = QAction(Translations["file.open_file"], self)
self.open_explorer_action = QAction(open_file_str(), self)
self.delete_action = QAction(
Translations["trash.context.ambiguous"].format(trash_term=trash_term()), self
Translations.format("trash.context.ambiguous", trash_term=trash_term()),
self,
)
self.preview_img = QPushButtonWrapper()
@@ -378,7 +379,7 @@ class PreviewThumb(QWidget):
self.delete_action.triggered.disconnect()
self.delete_action.setText(
Translations["trash.context.singular"].format(trash_term=trash_term())
Translations.format("trash.context.singular", trash_term=trash_term())
)
self.delete_action.triggered.connect(
lambda checked=False, f=filepath: self.driver.delete_files_callback(f)