From dda1a3d85354d4c1d2070bbb887a70f350859f21 Mon Sep 17 00:00:00 2001
From: Travis Abendshien <46939827+CyanVoxel@users.noreply.github.com>
Date: Mon, 5 Oct 2026 11:58:18 -0700
Subject: [PATCH 1/4] fix: use translation keys where available (port #1290)
Co-authored-by: Math-Bee <172338034+Math-Bee@users.noreply.github.com>
---
.../controllers/edit_field_template_modal.py | 6 +--
src/tagstudio/qt/controllers/main_window.py | 12 +++---
src/tagstudio/qt/controllers/splash.py | 21 +++++-----
.../qt/controllers/tag_search_panel.py | 8 +++-
.../qt/controllers/tiles/color_data.py | 2 +-
.../qt/controllers/tiles/tile_list.py | 6 ++-
src/tagstudio/qt/mixed/about_modal.py | 15 ++++---
src/tagstudio/qt/mixed/folders_to_tags.py | 6 +--
src/tagstudio/qt/mixed/settings_panel.py | 40 ++++++++++---------
src/tagstudio/qt/qt_driver.py | 10 +++--
10 files changed, 67 insertions(+), 59 deletions(-)
diff --git a/src/tagstudio/qt/controllers/edit_field_template_modal.py b/src/tagstudio/qt/controllers/edit_field_template_modal.py
index f8ebaf990c..a8915bec39 100644
--- a/src/tagstudio/qt/controllers/edit_field_template_modal.py
+++ b/src/tagstudio/qt/controllers/edit_field_template_modal.py
@@ -19,8 +19,8 @@
# TODO: Use newer MVC style guidelines
class EditFieldTemplateModal(EditFieldTemplateModalView):
field_type_map: dict[str, str] = {
- "TextFieldTemplate": Translations["field_type.text"],
- "DatetimeFieldTemplate": Translations["field_type.datetime"],
+ "TextFieldTemplate": "field_type.text",
+ "DatetimeFieldTemplate": "field_type.datetime",
}
DEFAULT_TYPE_INDEX = 0
@@ -32,7 +32,7 @@ def __init__(self, field_template: BaseFieldTemplate | None = None) -> None:
self.old_field_type: str = ""
for k, v in EditFieldTemplateModal.field_type_map.items():
- self._type_combobox.addItem(v, k)
+ self._type_combobox.addItem(Translations[v], k)
self.__connect_callbacks()
self.set_field_template(field_template)
diff --git a/src/tagstudio/qt/controllers/main_window.py b/src/tagstudio/qt/controllers/main_window.py
index 46c50bd58d..ef13a769ff 100644
--- a/src/tagstudio/qt/controllers/main_window.py
+++ b/src/tagstudio/qt/controllers/main_window.py
@@ -455,11 +455,11 @@ def rebuild_open_recent_library_menu(
# View Component
class MainWindow(QMainWindow):
THUMB_SIZES: list[tuple[str, int]] = [
- (Translations["home.thumbnail_size.extra_large"], 256),
- (Translations["home.thumbnail_size.large"], 192),
- (Translations["home.thumbnail_size.medium"], 128),
- (Translations["home.thumbnail_size.small"], 96),
- (Translations["home.thumbnail_size.mini"], 76),
+ ("home.thumbnail_size.extra_large", 256),
+ ("home.thumbnail_size.large", 192),
+ ("home.thumbnail_size.medium", 128),
+ ("home.thumbnail_size.small", 96),
+ ("home.thumbnail_size.mini", 76),
]
def __init__(self, driver: QtDriver, parent: QWidget | None = None) -> None:
@@ -656,7 +656,7 @@ def setup_extra_input_bar(self):
self.thumb_size_combobox.setMaximumWidth(352)
self.extra_input_layout.addWidget(self.thumb_size_combobox)
for size in MainWindow.THUMB_SIZES:
- self.thumb_size_combobox.addItem(size[0], size[1])
+ self.thumb_size_combobox.addItem(Translations[size[0]], size[1])
self.thumb_size_combobox.setCurrentIndex(2) # Default: Medium
def setup_content(self, driver: QtDriver):
diff --git a/src/tagstudio/qt/controllers/splash.py b/src/tagstudio/qt/controllers/splash.py
index 2a39028f12..90866af52d 100644
--- a/src/tagstudio/qt/controllers/splash.py
+++ b/src/tagstudio/qt/controllers/splash.py
@@ -23,12 +23,6 @@
class SplashScreen:
"""The custom splash screen widget for TagStudio."""
- VERSION_STR: str = " ".join(
- [
- f"{Translations['about.version']}",
- f"{VERSION} {(' (' + Translations[BUILD_TYPE] + ')') if BUILD_TYPE else ''}",
- ]
- )
DEFAULT_SPLASH = Splash.AURORA
def __init__(
@@ -68,6 +62,13 @@ def get_pixmap(self) -> QPixmap:
case _:
pass
+ version_str = " ".join(
+ [
+ f"{Translations['about.version']}",
+ f"{VERSION} {(' (' + Translations[BUILD_TYPE] + ')') if BUILD_TYPE else ''}",
+ ]
+ )
+
# TODO: Store any differing data elsewhere and load dynamically instead of hardcoding.
match self.splash_name:
case Splash.CLASSIC:
@@ -88,7 +89,7 @@ def get_pixmap(self) -> QPixmap:
painter.drawText(
QRect(0, -50, 960, 540),
int(Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter),
- SplashScreen.VERSION_STR,
+ version_str,
)
case Splash.GOO_GEARS:
@@ -110,7 +111,7 @@ def get_pixmap(self) -> QPixmap:
painter.setPen(pen)
painter.drawText(
QRect(40, 420, 960, 540),
- SplashScreen.VERSION_STR,
+ version_str,
)
case Splash.NINETY_FIVE:
@@ -136,7 +137,7 @@ def get_pixmap(self) -> QPixmap:
painter.drawText(
QRect(-30, 25, 960, 540),
int(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignRight),
- SplashScreen.VERSION_STR,
+ version_str,
)
case Splash.AURORA:
@@ -157,7 +158,7 @@ def get_pixmap(self) -> QPixmap:
painter.drawText(
QRect(0, -50, 960, 540),
int(Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter),
- SplashScreen.VERSION_STR,
+ version_str,
)
case _:
diff --git a/src/tagstudio/qt/controllers/tag_search_panel.py b/src/tagstudio/qt/controllers/tag_search_panel.py
index c7f083721f..b297166c35 100644
--- a/src/tagstudio/qt/controllers/tag_search_panel.py
+++ b/src/tagstudio/qt/controllers/tag_search_panel.py
@@ -88,11 +88,17 @@ def _on_item_remove(self, item: Tag) -> None:
return
message_box = QMessageBox(
- QMessageBox.Icon.Question,
+ QMessageBox.Icon.Warning,
Translations["tag.remove"],
Translations.format("tag.confirm_delete", tag_name=self._lib.tag_display_name(item)),
QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel,
)
+ unwrap(message_box.button(QMessageBox.StandardButton.Ok)).setText(
+ Translations["generic.delete_alt"]
+ )
+ unwrap(message_box.button(QMessageBox.StandardButton.Cancel)).setText(
+ Translations["generic.cancel_alt"]
+ )
result = message_box.exec()
diff --git a/src/tagstudio/qt/controllers/tiles/color_data.py b/src/tagstudio/qt/controllers/tiles/color_data.py
index b232adf226..423c1fd4c9 100644
--- a/src/tagstudio/qt/controllers/tiles/color_data.py
+++ b/src/tagstudio/qt/controllers/tiles/color_data.py
@@ -95,7 +95,7 @@ def set_colors(self, colors: Iterable[TagColorGroup]):
TagColorGroup(
slug="slug",
namespace=self.namespace,
- name="Color",
+ name=Translations["color.placeholder"],
primary="#FFFFFF",
secondary=None,
)
diff --git a/src/tagstudio/qt/controllers/tiles/tile_list.py b/src/tagstudio/qt/controllers/tiles/tile_list.py
index ff3b792026..d2f7960422 100644
--- a/src/tagstudio/qt/controllers/tiles/tile_list.py
+++ b/src/tagstudio/qt/controllers/tiles/tile_list.py
@@ -420,12 +420,14 @@ def update_datetime_field(self, field: DatetimeField, name: str, value: str) ->
def remove_message_box(self, prompt: str, callback: Callable[..., None]) -> None:
remove_mb = QMessageBox()
remove_mb.setText(prompt)
- remove_mb.setWindowTitle(Translations["Remove Field"])
+ remove_mb.setWindowTitle(Translations["field.remove"])
remove_mb.setIcon(QMessageBox.Icon.Warning)
cancel_button = remove_mb.addButton(
Translations["generic.cancel_alt"], QMessageBox.ButtonRole.RejectRole
)
- remove_mb.addButton("&Remove", QMessageBox.ButtonRole.DestructiveRole)
+ remove_mb.addButton(
+ Translations["generic.remove_alt"], QMessageBox.ButtonRole.DestructiveRole
+ )
remove_mb.setEscapeButton(cancel_button)
result = remove_mb.exec_()
if result == QMessageBox.ButtonRole.ActionRole.value:
diff --git a/src/tagstudio/qt/mixed/about_modal.py b/src/tagstudio/qt/mixed/about_modal.py
index ad166f9fad..48298f07e7 100644
--- a/src/tagstudio/qt/mixed/about_modal.py
+++ b/src/tagstudio/qt/mixed/about_modal.py
@@ -44,13 +44,6 @@
class AboutModal(QWidget):
"""Modal window showing information about the TagStudio application."""
- VERSION_STR: str = " ".join(
- [
- f"{Translations['about.version']}",
- f"{VERSION} {(' (' + Translations[BUILD_TYPE] + ')') if BUILD_TYPE else ''}",
- ]
- )
-
def __init__(self, config_path: Path | str):
super().__init__()
self.setWindowTitle(Translations["about.title"])
@@ -89,7 +82,13 @@ def __init__(self, config_path: Path | str):
self.logo_widget.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Version --------------------------------------------------------------
- self.version_label = QLabel(header(AboutModal.VERSION_STR, 2))
+ version_str = " ".join(
+ [
+ f"{Translations['about.version']}",
+ f"{VERSION} {(' (' + Translations[BUILD_TYPE] + ')') if BUILD_TYPE else ''}",
+ ]
+ )
+ self.version_label = QLabel(header(version_str, 2))
self.version_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Copyright ------------------------------------------------------------
diff --git a/src/tagstudio/qt/mixed/folders_to_tags.py b/src/tagstudio/qt/mixed/folders_to_tags.py
index f2e6914c1a..47bfed84a2 100644
--- a/src/tagstudio/qt/mixed/folders_to_tags.py
+++ b/src/tagstudio/qt/mixed/folders_to_tags.py
@@ -182,13 +182,9 @@ def __init__(self, library: Library, driver: QtDriver):
self.title_widget.setWordWrap(True)
self.title_widget.setAlignment(Qt.AlignmentFlag.AlignCenter)
- self.desc_widget = QLabel()
+ self.desc_widget = QLabel(Translations["folders_to_tags.description"])
self.desc_widget.setObjectName("descriptionLabel")
self.desc_widget.setWordWrap(True)
- self.desc_widget.setText(
- """Creates tags based on your folder structure and applies them to your entries.
- This tree shows all tags to be created and which entries they will be applied to."""
- )
self.desc_widget.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.open_close_button_w = QWidget()
diff --git a/src/tagstudio/qt/mixed/settings_panel.py b/src/tagstudio/qt/mixed/settings_panel.py
index 26ffa079af..45557d0718 100644
--- a/src/tagstudio/qt/mixed/settings_panel.py
+++ b/src/tagstudio/qt/mixed/settings_panel.py
@@ -43,30 +43,30 @@ class SettingsPanel(ModalContent):
driver: QtDriver
filepath_option_map: dict[ShowFilepathOption, str] = {
- ShowFilepathOption.SHOW_FULL_PATHS: Translations["settings.filepath.option.full"],
- ShowFilepathOption.SHOW_RELATIVE_PATHS: Translations["settings.filepath.option.relative"],
- ShowFilepathOption.SHOW_FILENAMES_ONLY: Translations["settings.filepath.option.name"],
+ ShowFilepathOption.SHOW_FULL_PATHS: "settings.filepath.option.full",
+ ShowFilepathOption.SHOW_RELATIVE_PATHS: "settings.filepath.option.relative",
+ ShowFilepathOption.SHOW_FILENAMES_ONLY: "settings.filepath.option.name",
}
theme_map: dict[Theme, str] = {
- Theme.SYSTEM: Translations["settings.theme.system"],
- Theme.DARK: Translations["settings.theme.dark"],
- Theme.LIGHT: Translations["settings.theme.light"],
+ Theme.SYSTEM: "settings.theme.system",
+ Theme.DARK: "settings.theme.dark",
+ Theme.LIGHT: "settings.theme.light",
}
splash_map: dict[Splash, str] = {
- Splash.DEFAULT: Translations["settings.splash.option.default"],
- Splash.RANDOM: Translations["settings.splash.option.random"],
- Splash.CLASSIC: Translations["settings.splash.option.classic"],
- Splash.GOO_GEARS: Translations["settings.splash.option.goo_gears"],
- Splash.NINETY_FIVE: Translations["settings.splash.option.ninety_five"],
- Splash.AURORA: Translations["settings.splash.option.aurora"],
+ Splash.DEFAULT: "settings.splash.option.default",
+ Splash.RANDOM: "settings.splash.option.random",
+ Splash.CLASSIC: "settings.splash.option.classic",
+ Splash.GOO_GEARS: "settings.splash.option.goo_gears",
+ Splash.NINETY_FIVE: "settings.splash.option.ninety_five",
+ Splash.AURORA: "settings.splash.option.aurora",
}
tag_click_action_map: dict[TagClickActionOption, str] = {
- TagClickActionOption.OPEN_EDIT: Translations["settings.tag_click_action.open_edit"],
- TagClickActionOption.SET_SEARCH: Translations["settings.tag_click_action.set_search"],
- TagClickActionOption.ADD_TO_SEARCH: Translations["settings.tag_click_action.add_to_search"],
+ TagClickActionOption.OPEN_EDIT: "settings.tag_click_action.open_edit",
+ TagClickActionOption.SET_SEARCH: "settings.tag_click_action.set_search",
+ TagClickActionOption.ADD_TO_SEARCH: "settings.tag_click_action.add_to_search",
}
date_format_map: dict[str, str] = {
@@ -194,7 +194,7 @@ def on_page_size_changed():
# Show Filepath
self.filepath_combobox = QComboBox()
for k in SettingsPanel.filepath_option_map:
- self.filepath_combobox.addItem(SettingsPanel.filepath_option_map[k], k)
+ self.filepath_combobox.addItem(Translations[SettingsPanel.filepath_option_map[k]], k)
filepath_option: ShowFilepathOption = self.driver.settings.show_filepath
if filepath_option not in SettingsPanel.filepath_option_map:
filepath_option = ShowFilepathOption.DEFAULT
@@ -206,7 +206,9 @@ def on_page_size_changed():
# Tag Click Action
self.tag_click_action_combobox = QComboBox()
for k in SettingsPanel.tag_click_action_map:
- self.tag_click_action_combobox.addItem(SettingsPanel.tag_click_action_map[k], k)
+ self.tag_click_action_combobox.addItem(
+ Translations[SettingsPanel.tag_click_action_map[k]], k
+ )
tag_click_action = self.driver.settings.tag_click_action
if tag_click_action not in SettingsPanel.tag_click_action_map:
tag_click_action = TagClickActionOption.DEFAULT
@@ -375,7 +377,7 @@ def __build_appearance_settings(self):
# Dark Mode
self.theme_combobox = QComboBox()
for k in SettingsPanel.theme_map:
- self.theme_combobox.addItem(SettingsPanel.theme_map[k], k)
+ self.theme_combobox.addItem(Translations[SettingsPanel.theme_map[k]], k)
theme = self.driver.settings.theme
if theme not in SettingsPanel.theme_map:
theme = Theme.DEFAULT
@@ -386,7 +388,7 @@ def __build_appearance_settings(self):
# Splash Screen
self.splash_combobox = QComboBox()
for k in SettingsPanel.splash_map:
- self.splash_combobox.addItem(SettingsPanel.splash_map[k], k)
+ self.splash_combobox.addItem(Translations[SettingsPanel.splash_map[k]], k)
splash = self.driver.settings.splash
if splash not in SettingsPanel.splash_map:
splash = Splash.DEFAULT
diff --git a/src/tagstudio/qt/qt_driver.py b/src/tagstudio/qt/qt_driver.py
index f3f812e8d9..f090758901 100644
--- a/src/tagstudio/qt/qt_driver.py
+++ b/src/tagstudio/qt/qt_driver.py
@@ -1021,9 +1021,9 @@ def delete_file_confirmation(self, count: int, filename: Path | None = None) ->
msg.setStyleSheet("font-weight:normal;")
msg.setTextFormat(Qt.TextFormat.RichText)
msg.setWindowTitle(
- Translations["trash.title.singular"]
+ Translations["trash.dialog.title.singular"]
if count == 1
- else Translations["trash.title.plural"]
+ else Translations["trash.dialog.title.plural"]
)
msg.setIcon(QMessageBox.Icon.Warning)
if count <= 1:
@@ -1048,8 +1048,10 @@ def delete_file_confirmation(self, count: int, filename: Path | None = None) ->
f"{perm_warning}
"
)
- yes_button: QPushButton = msg.addButton("&Yes", QMessageBox.ButtonRole.YesRole)
- msg.addButton("&No", QMessageBox.ButtonRole.NoRole)
+ yes_button: QPushButton = msg.addButton(
+ Translations["generic.yes"], QMessageBox.ButtonRole.YesRole
+ )
+ msg.addButton(Translations["generic.no"], QMessageBox.ButtonRole.NoRole)
msg.setDefaultButton(yes_button)
return msg.exec()
From 6d1f267acfb58299f5cc3f723fc2e94969df64af Mon Sep 17 00:00:00 2001
From: Travis Abendshien <46939827+CyanVoxel@users.noreply.github.com>
Date: Mon, 5 Oct 2026 12:18:45 -0700
Subject: [PATCH 2/4] fix(translations): add missing/fix incorrect translations
---
src/tagstudio/qt/controllers/tiles/color_data.py | 2 +-
src/tagstudio/qt/views/library_info_window_view.py | 2 +-
src/tagstudio/resources/translations/en.json | 12 +++++++-----
3 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/tagstudio/qt/controllers/tiles/color_data.py b/src/tagstudio/qt/controllers/tiles/color_data.py
index 423c1fd4c9..e547f45432 100644
--- a/src/tagstudio/qt/controllers/tiles/color_data.py
+++ b/src/tagstudio/qt/controllers/tiles/color_data.py
@@ -108,7 +108,7 @@ def edit_color(self, color_group: TagColorGroup):
self.edit_modal = Modal(
build_color_panel,
- "Edit Color",
+ Translations["color.edit"],
is_savable=True,
)
diff --git a/src/tagstudio/qt/views/library_info_window_view.py b/src/tagstudio/qt/views/library_info_window_view.py
index c6de871b21..7c5a2b05d5 100644
--- a/src/tagstudio/qt/views/library_info_window_view.py
+++ b/src/tagstudio/qt/views/library_info_window_view.py
@@ -39,7 +39,7 @@ def __init__(self, library: Library, driver: QtDriver):
self.lib = library
self.driver = driver
- self.setWindowTitle("Library Information")
+ self.setWindowTitle(Translations["library_info.window_title"])
self.setMinimumSize(800, 480)
self.root_layout = QVBoxLayout(self)
self.root_layout.setContentsMargins(PAD, PAD, PAD, PAD)
diff --git a/src/tagstudio/resources/translations/en.json b/src/tagstudio/resources/translations/en.json
index 42d84dc44b..45f61b3c15 100644
--- a/src/tagstudio/resources/translations/en.json
+++ b/src/tagstudio/resources/translations/en.json
@@ -21,7 +21,8 @@
"color_manager.title": "Manage Tag Colors",
"color.color_border": "Use Secondary Color for Border",
"color.confirm_delete": "Are you sure you want to delete the color \"{color_name}\"?",
- "color.delete": "Delete Tag",
+ "color.delete": "Delete Color",
+ "color.edit": "Edit Color",
"color.import_pack": "Import Color Pack",
"color.name": "Name",
"color.namespace.delete.prompt": "Are you sure you want to delete this color namespace? This will delete ALL colors in the namespace along with it!",
@@ -38,7 +39,7 @@
"drop_import.duplicates_choice.singular": "The following file matches a file path that already exists in the library.",
"drop_import.progress.label.initial": "Importing New Files…",
"drop_import.progress.label.plural": "Importing New Files…\n{count} Files Imported.{suffix}",
- "drop_import.progress.label.singular": "Importing New Files…\n1 File imported.{suffix}",
+ "drop_import.progress.label.singular": "Importing New Files…\n1 File Imported.{suffix}",
"drop_import.progress.window_title": "Import Files",
"drop_import.title": "Conflicting File(s)",
"edit.color_manager": "Manage Tag Colors",
@@ -186,7 +187,7 @@
"json_migration.creating_database_tables": "Creating SQL Database Tables…",
"json_migration.description": "
Start and preview the results of the library migration process. The converted library will not be used unless you click \"Finish Migration\".
Library data should either have matching values or feature a \"Matched\" label. Values that do not match will be displayed in red and feature a \"(!)\" symbol next to them.