From fada4f0a40a74591a374126f71f49ee6a927db06 Mon Sep 17 00:00:00 2001
From: Laurent Monin <github@norz.org>
Date: Sat, 20 Apr 2024 23:42:17 +0200
Subject: [PATCH 1/8] Import gettext-related methods, instead of monkeypatching
 builtins

---
 picard/acoustid/__init__.py                   |  1 +
 picard/acoustid/manager.py                    |  1 +
 picard/album.py                               |  4 +
 picard/browser/addrelease.py                  |  1 +
 picard/cluster.py                             |  4 +
 picard/collection.py                          |  4 +
 picard/config_upgrade.py                      |  4 +
 picard/const/__init__.py                      |  6 +-
 picard/const/languages.py                     |  2 +
 picard/const/locales.py                       |  2 +
 picard/const/scripts.py                       |  5 ++
 picard/coverart/__init__.py                   |  1 +
 picard/coverart/providers/caa.py              |  4 +
 .../coverart/providers/caa_release_group.py   |  1 +
 picard/coverart/providers/local.py            |  1 +
 picard/coverart/providers/urlrels.py          |  1 +
 picard/coverart/utils.py                      |  5 ++
 picard/debug_opts.py                          |  2 +
 picard/file.py                                |  4 +
 picard/i18n.py                                | 73 +++++++++++++------
 picard/log.py                                 |  1 +
 picard/oauth.py                               |  1 +
 picard/pluginmanager.py                       |  4 +
 picard/profile.py                             |  3 +-
 picard/releasegroup.py                        |  5 ++
 picard/script/__init__.py                     |  4 +
 picard/script/functions.py                    |  5 ++
 picard/script/serializer.py                   |  4 +
 picard/tagger.py                              |  6 +-
 picard/track.py                               |  1 +
 picard/ui/aboutdialog.py                      |  1 +
 picard/ui/caa_types_selector.py               |  5 ++
 picard/ui/cdlookup.py                         |  1 +
 picard/ui/collectionmenu.py                   |  4 +
 picard/ui/colors.py                           |  4 +
 picard/ui/coverartbox.py                      |  1 +
 picard/ui/edittagdialog.py                    |  1 +
 picard/ui/filebrowser.py                      |  1 +
 picard/ui/infodialog.py                       |  4 +
 picard/ui/infostatus.py                       |  1 +
 picard/ui/item.py                             |  2 +-
 picard/ui/itemviews.py                        |  4 +
 picard/ui/logview.py                          |  1 +
 picard/ui/mainwindow.py                       |  5 ++
 picard/ui/metadatabox.py                      |  4 +
 picard/ui/newuserdialog.py                    |  1 +
 picard/ui/options/__init__.py                 |  1 +
 picard/ui/options/advanced.py                 |  1 +
 picard/ui/options/cdlookup.py                 |  1 +
 picard/ui/options/cover.py                    |  4 +
 picard/ui/options/dialog.py                   |  4 +
 picard/ui/options/fingerprinting.py           |  4 +
 picard/ui/options/general.py                  |  5 ++
 picard/ui/options/genres.py                   |  4 +
 picard/ui/options/interface.py                |  5 ++
 picard/ui/options/interface_colors.py         |  4 +
 picard/ui/options/interface_toolbar.py        |  4 +
 picard/ui/options/interface_top_tags.py       |  1 +
 picard/ui/options/maintenance.py              |  4 +
 picard/ui/options/matching.py                 |  1 +
 picard/ui/options/metadata.py                 |  5 ++
 picard/ui/options/network.py                  |  1 +
 picard/ui/options/plugins.py                  |  4 +
 picard/ui/options/profiles.py                 |  5 ++
 picard/ui/options/ratings.py                  |  1 +
 picard/ui/options/releases.py                 |  6 ++
 picard/ui/options/renaming.py                 |  4 +
 picard/ui/options/renaming_compat.py          |  4 +
 picard/ui/options/scripting.py                |  4 +
 picard/ui/options/tags.py                     |  1 +
 picard/ui/options/tags_compatibility_aac.py   |  1 +
 picard/ui/options/tags_compatibility_ac3.py   |  1 +
 picard/ui/options/tags_compatibility_id3.py   |  1 +
 picard/ui/options/tags_compatibility_wave.py  |  1 +
 picard/ui/passworddialog.py                   |  1 +
 picard/ui/playertoolbar.py                    |  4 +
 picard/ui/pluginupdatedialog.py               |  5 ++
 picard/ui/ratingwidget.py                     |  1 +
 picard/ui/savewarningdialog.py                |  4 +
 picard/ui/scripteditor.py                     |  5 ++
 picard/ui/scriptsmenu.py                      |  1 +
 picard/ui/searchdialog/__init__.py            |  1 +
 picard/ui/searchdialog/album.py               |  1 +
 picard/ui/searchdialog/artist.py              |  1 +
 picard/ui/searchdialog/track.py               |  1 +
 picard/ui/tagsfromfilenames.py                |  1 +
 picard/ui/ui_aboutdialog.py                   | 16 ++--
 picard/ui/ui_cdlookup.py                      | 24 +++---
 picard/ui/ui_edittagdialog.py                 | 24 +++---
 picard/ui/ui_exception_script_selector.py     | 30 ++++----
 picard/ui/ui_infodialog.py                    | 20 ++---
 picard/ui/ui_infostatus.py                    | 28 +++----
 picard/ui/ui_multi_locale_selector.py         | 26 ++++---
 picard/ui/ui_options.py                       |  6 +-
 picard/ui/ui_options_advanced.py              |  8 +-
 picard/ui/ui_options_attached_profiles.py     | 12 +--
 picard/ui/ui_options_cdlookup.py              | 14 ++--
 picard/ui/ui_options_cdlookup_select.py       | 14 ++--
 picard/ui/ui_options_cover.py                 | 34 +++++----
 picard/ui/ui_options_fingerprinting.py        | 40 +++++-----
 picard/ui/ui_options_general.py               | 60 +++++++--------
 picard/ui/ui_options_genres.py                | 38 +++++-----
 picard/ui/ui_options_interface.py             | 46 ++++++------
 picard/ui/ui_options_interface_colors.py      | 12 +--
 picard/ui/ui_options_interface_toolbar.py     | 24 +++---
 picard/ui/ui_options_interface_top_tags.py    | 12 +--
 picard/ui/ui_options_maintenance.py           | 30 ++++----
 picard/ui/ui_options_matching.py              | 22 +++---
 picard/ui/ui_options_metadata.py              | 48 ++++++------
 picard/ui/ui_options_network.py               |  8 +-
 picard/ui/ui_options_plugins.py               | 26 ++++---
 picard/ui/ui_options_profiles.py              | 22 +++---
 picard/ui/ui_options_ratings.py               | 18 +++--
 picard/ui/ui_options_releases.py              | 30 ++++----
 picard/ui/ui_options_renaming.py              | 50 +++++++------
 picard/ui/ui_options_renaming_compat.py       | 24 +++---
 picard/ui/ui_options_script.py                | 36 ++++-----
 picard/ui/ui_options_tags.py                  | 28 +++----
 .../ui/ui_options_tags_compatibility_aac.py   | 18 +++--
 .../ui/ui_options_tags_compatibility_ac3.py   | 18 +++--
 .../ui/ui_options_tags_compatibility_id3.py   | 36 ++++-----
 .../ui/ui_options_tags_compatibility_wave.py  | 22 +++---
 picard/ui/ui_passworddialog.py                | 20 ++---
 picard/ui/ui_provider_options_caa.py          | 18 +++--
 picard/ui/ui_provider_options_local.py        | 18 +++--
 picard/ui/ui_scripteditor.py                  |  8 +-
 picard/ui/ui_scripteditor_details.py          | 36 ++++-----
 .../ui/ui_scripting_documentation_dialog.py   | 10 ++-
 picard/ui/ui_tagsfromfilenames.py             | 18 +++--
 picard/ui/ui_widget_taglisteditor.py          | 22 +++---
 picard/ui/ui_win_compat_dialog.py             | 42 ++++++-----
 picard/ui/util.py                             |  4 +
 picard/ui/widgets/profilelistwidget.py        |  4 +
 picard/ui/widgets/scriptdocumentation.py      |  1 +
 picard/ui/widgets/scriptlistwidget.py         |  4 +
 picard/ui/widgets/scripttextedit.py           |  1 +
 picard/ui/widgets/tristatesortheaderview.py   |  2 +
 picard/util/__init__.py                       |  4 +
 picard/util/bytes2human.py                    |  5 ++
 picard/util/checkupdate.py                    |  5 ++
 picard/util/tags.py                           |  5 ++
 picard/util/time.py                           |  2 +
 picard/util/versions.py                       |  4 +
 picard/util/webbrowser2.py                    |  1 +
 setup.py                                      |  7 +-
 test/test_i18n.py                             | 28 ++++---
 test/test_script.py                           | 11 +--
 test/test_utils.py                            |  7 +-
 148 files changed, 946 insertions(+), 573 deletions(-)

diff --git a/picard/acoustid/__init__.py b/picard/acoustid/__init__.py
index 2c1a577463..bbd6429c0a 100644
--- a/picard/acoustid/__init__.py
+++ b/picard/acoustid/__init__.py
@@ -43,6 +43,7 @@
 )
 from picard.const.sys import IS_WIN
 from picard.file import File
+from picard.i18n import N_
 from picard.util import (
     find_executable,
     win_prefix_longpath,
diff --git a/picard/acoustid/manager.py b/picard/acoustid/manager.py
index eb4e6ade76..ad84d876b6 100644
--- a/picard/acoustid/manager.py
+++ b/picard/acoustid/manager.py
@@ -29,6 +29,7 @@
 from PyQt6 import QtCore
 
 from picard import log
+from picard.i18n import N_
 from picard.util import load_json
 
 
diff --git a/picard/album.py b/picard/album.py
index 50ba8673d6..8421fa4961 100644
--- a/picard/album.py
+++ b/picard/album.py
@@ -59,6 +59,10 @@
 from picard.const import VARIOUS_ARTISTS_ID
 from picard.dataobj import DataObject
 from picard.file import File
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.mbjson import (
     medium_to_metadata,
     release_group_to_metadata,
diff --git a/picard/browser/addrelease.py b/picard/browser/addrelease.py
index 4fe3197716..c33728d214 100644
--- a/picard/browser/addrelease.py
+++ b/picard/browser/addrelease.py
@@ -28,6 +28,7 @@
 from PyQt6.QtCore import QCoreApplication
 
 from picard import log
+from picard.i18n import _
 from picard.util import format_time
 from picard.util.mbserver import build_submission_url
 from picard.util.webbrowser2 import open
diff --git a/picard/cluster.py b/picard/cluster.py
index 8fd6895910..b3e1c3fdab 100644
--- a/picard/cluster.py
+++ b/picard/cluster.py
@@ -46,6 +46,10 @@
 
 from picard.config import get_config
 from picard.file import File
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.metadata import (
     Metadata,
     SimMatchRelease,
diff --git a/picard/collection.py b/picard/collection.py
index d9529012c2..cf00bdad75 100644
--- a/picard/collection.py
+++ b/picard/collection.py
@@ -30,6 +30,10 @@
 
 from picard import log
 from picard.config import get_config
+from picard.i18n import (
+    N_,
+    ngettext,
+)
 from picard.webservice.api_helpers import MBAPIHelper
 
 
diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py
index 6931a0cffb..8337a9a59e 100644
--- a/picard/config_upgrade.py
+++ b/picard/config_upgrade.py
@@ -52,6 +52,10 @@
     DEFAULT_SCRIPT_NAME,
 )
 from picard.const.sys import IS_FROZEN
+from picard.i18n import (
+    _,
+    gettext_constants,
+)
 from picard.util import unique_numbered_title
 from picard.version import (
     Version,
diff --git a/picard/const/__init__.py b/picard/const/__init__.py
index d5a30175d2..5222fcf86a 100644
--- a/picard/const/__init__.py
+++ b/picard/const/__init__.py
@@ -32,16 +32,12 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
 
-import builtins
 from collections import OrderedDict
 
 from picard import PICARD_VERSION
 from picard.const import appdirs
 from picard.const.attributes import MB_ATTRIBUTES
-
-
-# Install gettext "noop" function in case const.py gets imported directly.
-builtins.__dict__['N_'] = lambda a: a
+from picard.i18n import N_
 
 
 # Config directory
diff --git a/picard/const/languages.py b/picard/const/languages.py
index 2958da6ee5..4b0c90ab73 100644
--- a/picard/const/languages.py
+++ b/picard/const/languages.py
@@ -22,6 +22,8 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
+from picard.i18n import N_
+
 
 # List of available user interface languages
 UI_LANGUAGES = [
diff --git a/picard/const/locales.py b/picard/const/locales.py
index bf290667fc..bf35bfbe42 100644
--- a/picard/const/locales.py
+++ b/picard/const/locales.py
@@ -21,6 +21,8 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
+from picard.i18n import N_
+
 
 # List of alias locales
 ALIAS_LOCALES = {
diff --git a/picard/const/scripts.py b/picard/const/scripts.py
index bf8efb337b..359b63292d 100644
--- a/picard/const/scripts.py
+++ b/picard/const/scripts.py
@@ -20,6 +20,11 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
+from picard.i18n import (
+    N_,
+    _,
+)
+
 
 # List of available scripts (character sets)
 SCRIPTS = {
diff --git a/picard/coverart/__init__.py b/picard/coverart/__init__.py
index e3aa94feb2..6c6a6f2833 100644
--- a/picard/coverart/__init__.py
+++ b/picard/coverart/__init__.py
@@ -40,6 +40,7 @@
     CoverArtProvider,
     cover_art_providers,
 )
+from picard.i18n import N_
 from picard.metadata import register_album_metadata_processor
 
 
diff --git a/picard/coverart/providers/caa.py b/picard/coverart/providers/caa.py
index bd716d801a..d32b8466e9 100644
--- a/picard/coverart/providers/caa.py
+++ b/picard/coverart/providers/caa.py
@@ -59,6 +59,10 @@
     CAA_TYPES,
     translate_caa_type,
 )
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.webservice import ratecontrol
 
 from picard.ui.caa_types_selector import display_caa_types_selector
diff --git a/picard/coverart/providers/caa_release_group.py b/picard/coverart/providers/caa_release_group.py
index 7d538b1ed4..1fbdacb960 100644
--- a/picard/coverart/providers/caa_release_group.py
+++ b/picard/coverart/providers/caa_release_group.py
@@ -26,6 +26,7 @@
     CaaThumbnailCoverArtImage,
 )
 from picard.coverart.providers.caa import CoverArtProviderCaa
+from picard.i18n import N_
 
 
 class CaaCoverArtImageRg(CaaCoverArtImage):
diff --git a/picard/coverart/providers/local.py b/picard/coverart/providers/local.py
index d231193b69..713afcc16f 100644
--- a/picard/coverart/providers/local.py
+++ b/picard/coverart/providers/local.py
@@ -35,6 +35,7 @@
     ProviderOptions,
 )
 from picard.coverart.utils import CAA_TYPES
+from picard.i18n import N_
 
 from picard.ui.ui_provider_options_local import Ui_LocalOptions
 
diff --git a/picard/coverart/providers/urlrels.py b/picard/coverart/providers/urlrels.py
index 5cc6a17436..19e092a751 100644
--- a/picard/coverart/providers/urlrels.py
+++ b/picard/coverart/providers/urlrels.py
@@ -28,6 +28,7 @@
 from picard import log
 from picard.coverart.image import CoverArtImage
 from picard.coverart.providers.provider import CoverArtProvider
+from picard.i18n import N_
 
 
 class CoverArtProviderUrlRelationships(CoverArtProvider):
diff --git a/picard/coverart/utils.py b/picard/coverart/utils.py
index 63e6452484..c6a08027f1 100644
--- a/picard/coverart/utils.py
+++ b/picard/coverart/utils.py
@@ -25,6 +25,11 @@
 from enum import IntEnum
 
 from picard.const import MB_ATTRIBUTES
+from picard.i18n import (
+    N_,
+    _,
+    pgettext_attributes,
+)
 
 
 # list of types from http://musicbrainz.org/doc/Cover_Art/Types
diff --git a/picard/debug_opts.py b/picard/debug_opts.py
index 328be1404f..e73ca56273 100644
--- a/picard/debug_opts.py
+++ b/picard/debug_opts.py
@@ -20,6 +20,8 @@
 
 from enum import Enum
 
+from picard.i18n import N_
+
 
 class DebugOptEnum(int, Enum):
     __registry__ = set()
diff --git a/picard/file.py b/picard/file.py
index dfac33a53b..5739158c91 100644
--- a/picard/file.py
+++ b/picard/file.py
@@ -71,6 +71,10 @@
     IS_MACOS,
     IS_WIN,
 )
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.metadata import (
     Metadata,
     SimMatchTrack,
diff --git a/picard/i18n.py b/picard/i18n.py
index 40a31f8ca1..6e7ca55d64 100644
--- a/picard/i18n.py
+++ b/picard/i18n.py
@@ -21,8 +21,6 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
-
-import builtins
 import gettext
 import locale
 import os
@@ -35,10 +33,8 @@
 )
 
 
-builtins.__dict__['N_'] = lambda a: a
-
-
 _logger = None
+_translation = dict()
 
 
 def set_locale_from_env():
@@ -171,20 +167,53 @@ def setup_gettext(localedir, ui_language=None, logger=None):
     _logger("Using locale: %r", current_locale)
     QLocale.setDefault(QLocale(current_locale))
 
-    trans = _load_translation('picard', localedir, language=current_locale)
-    trans_attributes = _load_translation('picard-attributes', localedir, language=current_locale)
-    trans_constants = _load_translation('picard-constants', localedir, language=current_locale)
-    trans_countries = _load_translation('picard-countries', localedir, language=current_locale)
-
-    trans.install(['ngettext'])
-    builtins.__dict__['gettext_attributes'] = trans_attributes.gettext
-    builtins.__dict__['gettext_constants'] = trans_constants.gettext
-    builtins.__dict__['gettext_countries'] = trans_countries.gettext
-    builtins.__dict__['pgettext_attributes'] = trans_attributes.pgettext
-
-    _logger("_ = %r", _)
-    _logger("N_ = %r", N_)
-    _logger("ngettext = %r", ngettext)
-    _logger("gettext_countries = %r", gettext_countries)
-    _logger("gettext_attributes = %r", gettext_attributes)
-    _logger("pgettext_attributes = %r", pgettext_attributes)
+    global _translation
+    _translation = {
+        'main': _load_translation('picard', localedir, language=current_locale),
+        'attributes': _load_translation('picard-attributes', localedir, language=current_locale),
+        'constants': _load_translation('picard-constants', localedir, language=current_locale),
+        'countries': _load_translation('picard-countries', localedir, language=current_locale),
+    }
+    _logger(_translation)
+
+
+def _get_translation(key: str) -> gettext.NullTranslations:
+    try:
+        return _translation[key]
+    except KeyError:
+        return gettext.NullTranslations()
+
+
+def _gettext(message: str) -> str:
+    """Translate the messsage using the current translator."""
+    return _get_translation('main').gettext(message)
+
+
+def _(message: str) -> str:
+    """Alias for gettext"""
+    return _gettext(message)
+
+
+def N_(message: str) -> str:
+    """No-op marker for translatable strings"""
+    return message
+
+
+def ngettext(singular: str, plural: str, n: int) -> str:
+    return _get_translation('main').ngettext(singular, plural, n)
+
+
+def pgettext_attributes(context: str, message: str) -> str:
+    return _get_translation('attributes').pgettext(context, message)
+
+
+def gettext_attributes(message: str) -> str:
+    return _get_translation('attributes').gettext(message)
+
+
+def gettext_countries(message: str) -> str:
+    return _get_translation('countries').gettext(message)
+
+
+def gettext_constants(message: str) -> str:
+    return _get_translation('constants').gettext(message)
diff --git a/picard/log.py b/picard/log.py
index 06a6d20ffa..b2b1b25580 100644
--- a/picard/log.py
+++ b/picard/log.py
@@ -48,6 +48,7 @@
     IS_FROZEN,
 )
 from picard.debug_opts import DebugOpt
+from picard.i18n import N_
 
 
 # Get the absolute path for the picard module
diff --git a/picard/oauth.py b/picard/oauth.py
index d72820a79a..d9f1a80d1e 100644
--- a/picard/oauth.py
+++ b/picard/oauth.py
@@ -36,6 +36,7 @@
     MUSICBRAINZ_OAUTH_CLIENT_ID,
     MUSICBRAINZ_OAUTH_CLIENT_SECRET,
 )
+from picard.i18n import _
 from picard.util import (
     build_qurl,
     load_json,
diff --git a/picard/pluginmanager.py b/picard/pluginmanager.py
index c54daefe3b..05ab484218 100644
--- a/picard/pluginmanager.py
+++ b/picard/pluginmanager.py
@@ -44,6 +44,10 @@
     USER_PLUGIN_DIR,
 )
 from picard.const.sys import IS_FROZEN
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.plugin import (
     _PLUGIN_MODULE_PREFIX,
     PluginData,
diff --git a/picard/profile.py b/picard/profile.py
index 360908b9a5..63ca5eeb3c 100644
--- a/picard/profile.py
+++ b/picard/profile.py
@@ -28,8 +28,7 @@
     namedtuple,
 )
 
-# Imported to trigger inclusion of N_() in builtins
-from picard import i18n  # noqa: F401,E402 # pylint: disable=unused-import
+from picard.i18n import N_
 
 
 SettingDesc = namedtuple('SettingDesc', ('name', 'fields'))
diff --git a/picard/releasegroup.py b/picard/releasegroup.py
index 0930b2dc0b..07be7f1ddd 100644
--- a/picard/releasegroup.py
+++ b/picard/releasegroup.py
@@ -32,6 +32,11 @@
 
 from picard import log
 from picard.dataobj import DataObject
+from picard.i18n import (
+    N_,
+    _,
+    pgettext_attributes,
+)
 from picard.mbjson import (
     countries_from_node,
     label_info_from_node,
diff --git a/picard/script/__init__.py b/picard/script/__init__.py
index c3b6f142f8..7a6cd75bb5 100644
--- a/picard/script/__init__.py
+++ b/picard/script/__init__.py
@@ -41,6 +41,10 @@
     DEFAULT_FILE_NAMING_FORMAT,
     DEFAULT_NAMING_PRESET_ID,
 )
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.script.functions import (  # noqa: F401 # pylint: disable=unused-import
     register_script_function,
     script_function,
diff --git a/picard/script/functions.py b/picard/script/functions.py
index 163295ed0c..0a1c52c003 100644
--- a/picard/script/functions.py
+++ b/picard/script/functions.py
@@ -45,6 +45,11 @@
 import unicodedata
 
 from picard.const.countries import RELEASE_COUNTRIES
+from picard.i18n import (
+    N_,
+    _,
+    gettext_countries,
+)
 from picard.metadata import MULTI_VALUED_JOINER
 from picard.script.parser import (
     MultiValue,
diff --git a/picard/script/serializer.py b/picard/script/serializer.py
index 7e03660129..2e81d9762f 100644
--- a/picard/script/serializer.py
+++ b/picard/script/serializer.py
@@ -43,6 +43,10 @@
     DEFAULT_SCRIPT_NAME,
     SCRIPT_LANGUAGE_VERSION,
 )
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.util import make_filename_from_title
 
 
diff --git a/picard/tagger.py b/picard/tagger.py
index b13eccc1dd..326328fc08 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -110,7 +110,11 @@
 )
 from picard.file import File
 from picard.formats import open_ as open_file
-from picard.i18n import setup_gettext
+from picard.i18n import (
+    N_,
+    _,
+    setup_gettext,
+)
 from picard.pluginmanager import (
     PluginManager,
     plugin_dirs,
diff --git a/picard/track.py b/picard/track.py
index 236e01b4ea..0e3c6bcd88 100644
--- a/picard/track.py
+++ b/picard/track.py
@@ -60,6 +60,7 @@
     run_file_post_addition_to_track_processors,
     run_file_post_removal_from_track_processors,
 )
+from picard.i18n import _
 from picard.mbjson import recording_to_metadata
 from picard.metadata import (
     Metadata,
diff --git a/picard/ui/aboutdialog.py b/picard/ui/aboutdialog.py
index 37418ffdc5..fbbe802779 100644
--- a/picard/ui/aboutdialog.py
+++ b/picard/ui/aboutdialog.py
@@ -31,6 +31,7 @@
 
 from picard.const import PICARD_URLS
 from picard.formats import supported_extensions
+from picard.i18n import _
 from picard.util import versions
 
 from picard.ui import (
diff --git a/picard/ui/caa_types_selector.py b/picard/ui/caa_types_selector.py
index 4361804cef..b1c860a679 100644
--- a/picard/ui/caa_types_selector.py
+++ b/picard/ui/caa_types_selector.py
@@ -37,6 +37,11 @@
     QtWidgets,
 )
 
+from picard.i18n import (
+    N_,
+    _,
+)
+
 from picard.ui import PicardDialog
 from picard.ui.util import (
     StandardButton,
diff --git a/picard/ui/cdlookup.py b/picard/ui/cdlookup.py
index ace394d2ae..b14061c134 100644
--- a/picard/ui/cdlookup.py
+++ b/picard/ui/cdlookup.py
@@ -37,6 +37,7 @@
     Option,
     get_config,
 )
+from picard.i18n import _
 from picard.mbjson import (
     artist_credit_from_node,
     label_info_from_node,
diff --git a/picard/ui/collectionmenu.py b/picard/ui/collectionmenu.py
index 8b0de31512..b59ebf0cb7 100644
--- a/picard/ui/collectionmenu.py
+++ b/picard/ui/collectionmenu.py
@@ -33,6 +33,10 @@
     load_user_collections,
     user_collections,
 )
+from picard.i18n import (
+    _,
+    ngettext,
+)
 from picard.util import strxfrm
 
 
diff --git a/picard/ui/colors.py b/picard/ui/colors.py
index 0015b0df53..de6184f9c2 100644
--- a/picard/ui/colors.py
+++ b/picard/ui/colors.py
@@ -25,6 +25,10 @@
 from PyQt6 import QtGui
 
 from picard.config import get_config
+from picard.i18n import (
+    N_,
+    _,
+)
 
 from picard.ui.theme import theme
 
diff --git a/picard/ui/coverartbox.py b/picard/ui/coverartbox.py
index fa6b4c3a1c..70a9e30451 100644
--- a/picard/ui/coverartbox.py
+++ b/picard/ui/coverartbox.py
@@ -55,6 +55,7 @@
     CoverArtImageIOError,
 )
 from picard.file import File
+from picard.i18n import _
 from picard.track import Track
 from picard.util import (
     imageinfo,
diff --git a/picard/ui/edittagdialog.py b/picard/ui/edittagdialog.py
index 9bfa4b2dc8..5e0531211f 100644
--- a/picard/ui/edittagdialog.py
+++ b/picard/ui/edittagdialog.py
@@ -39,6 +39,7 @@
     RELEASE_STATUS,
 )
 from picard.const.countries import RELEASE_COUNTRIES
+from picard.i18n import _
 from picard.util.tags import TAG_NAMES
 
 from picard.ui import PicardDialog
diff --git a/picard/ui/filebrowser.py b/picard/ui/filebrowser.py
index 3b602f5ba8..27ec6abc2f 100644
--- a/picard/ui/filebrowser.py
+++ b/picard/ui/filebrowser.py
@@ -46,6 +46,7 @@
 )
 from picard.const.sys import IS_MACOS
 from picard.formats import supported_formats
+from picard.i18n import _
 from picard.util import find_existing_path
 
 
diff --git a/picard/ui/infodialog.py b/picard/ui/infodialog.py
index 6d34cf1cc1..2be3c720a4 100644
--- a/picard/ui/infodialog.py
+++ b/picard/ui/infodialog.py
@@ -47,6 +47,10 @@
 from picard.album import Album
 from picard.coverart.image import CoverArtImageIOError
 from picard.file import File
+from picard.i18n import (
+    _,
+    ngettext,
+)
 from picard.track import Track
 from picard.util import (
     bytes2human,
diff --git a/picard/ui/infostatus.py b/picard/ui/infostatus.py
index 99865912d3..fdba9c49ec 100644
--- a/picard/ui/infostatus.py
+++ b/picard/ui/infostatus.py
@@ -30,6 +30,7 @@
     QtWidgets,
 )
 
+from picard.i18n import _
 from picard.util import icontheme
 from picard.util.time import get_timestamp
 
diff --git a/picard/ui/item.py b/picard/ui/item.py
index d42446ecb6..b193b382ef 100644
--- a/picard/ui/item.py
+++ b/picard/ui/item.py
@@ -25,8 +25,8 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
-
 from picard import log
+from picard.i18n import ngettext
 from picard.util.imagelist import update_metadata_images
 
 
diff --git a/picard/ui/itemviews.py b/picard/ui/itemviews.py
index 402da1a6c8..3cabb7f136 100644
--- a/picard/ui/itemviews.py
+++ b/picard/ui/itemviews.py
@@ -75,6 +75,10 @@
     File,
     FileErrorType,
 )
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.plugin import ExtensionPoint
 from picard.track import (
     NonAlbumTrack,
diff --git a/picard/ui/logview.py b/picard/ui/logview.py
index 50cd7edea3..67226b131b 100644
--- a/picard/ui/logview.py
+++ b/picard/ui/logview.py
@@ -44,6 +44,7 @@
     get_config,
 )
 from picard.debug_opts import DebugOpt
+from picard.i18n import _
 from picard.util import (
     reconnect,
     wildcards_to_regex_pattern,
diff --git a/picard/ui/mainwindow.py b/picard/ui/mainwindow.py
index ce91508668..d97f221a24 100644
--- a/picard/ui/mainwindow.py
+++ b/picard/ui/mainwindow.py
@@ -84,6 +84,11 @@
 )
 from picard.file import File
 from picard.formats import supported_formats
+from picard.i18n import (
+    N_,
+    _,
+    ngettext,
+)
 from picard.plugin import ExtensionPoint
 from picard.script import get_file_naming_script_presets
 from picard.track import Track
diff --git a/picard/ui/metadatabox.py b/picard/ui/metadatabox.py
index cfc1e32a64..0b416d0541 100644
--- a/picard/ui/metadatabox.py
+++ b/picard/ui/metadatabox.py
@@ -52,6 +52,10 @@
     get_config,
 )
 from picard.file import File
+from picard.i18n import (
+    _,
+    ngettext,
+)
 from picard.metadata import MULTI_VALUED_JOINER
 from picard.track import Track
 from picard.util import (
diff --git a/picard/ui/newuserdialog.py b/picard/ui/newuserdialog.py
index 1371075907..073de61c9f 100644
--- a/picard/ui/newuserdialog.py
+++ b/picard/ui/newuserdialog.py
@@ -27,6 +27,7 @@
 )
 
 from picard.const import PICARD_URLS
+from picard.i18n import _
 
 
 class NewUserDialog():
diff --git a/picard/ui/options/__init__.py b/picard/ui/options/__init__.py
index 411e8d5018..43c806c4cd 100644
--- a/picard/ui/options/__init__.py
+++ b/picard/ui/options/__init__.py
@@ -29,6 +29,7 @@
 
 from picard import log
 from picard.config import get_config
+from picard.i18n import _
 from picard.plugin import ExtensionPoint
 
 
diff --git a/picard/ui/options/advanced.py b/picard/ui/options/advanced.py
index 6c832d34c2..33817ff5f8 100644
--- a/picard/ui/options/advanced.py
+++ b/picard/ui/options/advanced.py
@@ -30,6 +30,7 @@
     get_config,
 )
 from picard.const import QUERY_LIMIT
+from picard.i18n import N_
 
 from picard.ui.options import (
     OptionsPage,
diff --git a/picard/ui/options/cdlookup.py b/picard/ui/options/cdlookup.py
index 0fe676daf8..42d1c5f977 100644
--- a/picard/ui/options/cdlookup.py
+++ b/picard/ui/options/cdlookup.py
@@ -28,6 +28,7 @@
     TextOption,
     get_config,
 )
+from picard.i18n import N_
 from picard.util.cdrom import (
     AUTO_DETECT_DRIVES,
     DEFAULT_DRIVES,
diff --git a/picard/ui/options/cover.py b/picard/ui/options/cover.py
index e1e66cacc0..a4806ace0e 100644
--- a/picard/ui/options/cover.py
+++ b/picard/ui/options/cover.py
@@ -35,6 +35,10 @@
 )
 from picard.const import DEFAULT_COVER_IMAGE_FILENAME
 from picard.coverart.providers import cover_art_providers
+from picard.i18n import (
+    N_,
+    _,
+)
 
 from picard.ui.checkbox_list_item import CheckboxListItem
 from picard.ui.moveable_list_view import MoveableListView
diff --git a/picard/ui/options/dialog.py b/picard/ui/options/dialog.py
index ca12ee07fe..6ace11ce1b 100644
--- a/picard/ui/options/dialog.py
+++ b/picard/ui/options/dialog.py
@@ -46,6 +46,10 @@
     TextOption,
     get_config,
 )
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.profile import UserProfileGroups
 from picard.util import restore_method
 
diff --git a/picard/ui/options/fingerprinting.py b/picard/ui/options/fingerprinting.py
index 253855989e..39886ab080 100644
--- a/picard/ui/options/fingerprinting.py
+++ b/picard/ui/options/fingerprinting.py
@@ -40,6 +40,10 @@
     get_config,
 )
 from picard.const import DEFAULT_FPCALC_THREADS
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.util import webbrowser2
 
 from picard.ui.options import (
diff --git a/picard/ui/options/general.py b/picard/ui/options/general.py
index eb937cf07c..446ca04a27 100644
--- a/picard/ui/options/general.py
+++ b/picard/ui/options/general.py
@@ -41,6 +41,11 @@
     MUSICBRAINZ_SERVERS,
     PROGRAM_UPDATE_LEVELS,
 )
+from picard.i18n import (
+    N_,
+    _,
+    gettext_constants,
+)
 from picard.util.mbserver import is_official_server
 
 from picard.ui.options import (
diff --git a/picard/ui/options/genres.py b/picard/ui/options/genres.py
index 2999f36dc7..81bed888fe 100644
--- a/picard/ui/options/genres.py
+++ b/picard/ui/options/genres.py
@@ -34,6 +34,10 @@
     TextOption,
     get_config,
 )
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.track import TagGenreFilter
 
 from picard.ui.options import (
diff --git a/picard/ui/options/interface.py b/picard/ui/options/interface.py
index 1841cee30f..e8a586bb88 100644
--- a/picard/ui/options/interface.py
+++ b/picard/ui/options/interface.py
@@ -44,6 +44,11 @@
 )
 from picard.const.languages import UI_LANGUAGES
 from picard.const.sys import IS_MACOS
+from picard.i18n import (
+    N_,
+    _,
+    gettext_constants,
+)
 from picard.util import strxfrm
 
 from picard.ui.options import (
diff --git a/picard/ui/options/interface_colors.py b/picard/ui/options/interface_colors.py
index 823a1024e4..2360f15f7d 100644
--- a/picard/ui/options/interface_colors.py
+++ b/picard/ui/options/interface_colors.py
@@ -30,6 +30,10 @@
 
 from picard.config import Option
 from picard.const.sys import IS_MACOS
+from picard.i18n import (
+    N_,
+    _,
+)
 
 from picard.ui.colors import (
     InterfaceColors,
diff --git a/picard/ui/options/interface_toolbar.py b/picard/ui/options/interface_toolbar.py
index d700da9f59..1bd841a245 100644
--- a/picard/ui/options/interface_toolbar.py
+++ b/picard/ui/options/interface_toolbar.py
@@ -40,6 +40,10 @@
     ListOption,
     get_config,
 )
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.util import icontheme
 
 from picard.ui import PicardDialog
diff --git a/picard/ui/options/interface_top_tags.py b/picard/ui/options/interface_top_tags.py
index 4b0c7cf4f6..41d048545d 100644
--- a/picard/ui/options/interface_top_tags.py
+++ b/picard/ui/options/interface_top_tags.py
@@ -24,6 +24,7 @@
     ListOption,
     get_config,
 )
+from picard.i18n import N_
 
 from picard.ui.options import (
     OptionsPage,
diff --git a/picard/ui/options/maintenance.py b/picard/ui/options/maintenance.py
index c69e0a33b3..162be31721 100644
--- a/picard/ui/options/maintenance.py
+++ b/picard/ui/options/maintenance.py
@@ -37,6 +37,10 @@
     load_new_config,
 )
 from picard.config_upgrade import upgrade_config
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.util import open_local_path
 
 from picard.ui.options import (
diff --git a/picard/ui/options/matching.py b/picard/ui/options/matching.py
index e5290104e6..da30fe173e 100644
--- a/picard/ui/options/matching.py
+++ b/picard/ui/options/matching.py
@@ -26,6 +26,7 @@
     FloatOption,
     get_config,
 )
+from picard.i18n import N_
 
 from picard.ui.options import (
     OptionsPage,
diff --git a/picard/ui/options/metadata.py b/picard/ui/options/metadata.py
index f1c34eae00..b63f195c4e 100644
--- a/picard/ui/options/metadata.py
+++ b/picard/ui/options/metadata.py
@@ -44,6 +44,11 @@
     SCRIPTS,
     scripts_sorted_by_localized_name,
 )
+from picard.i18n import (
+    N_,
+    _,
+    gettext_constants,
+)
 
 from picard.ui import PicardDialog
 from picard.ui.moveable_list_view import MoveableListView
diff --git a/picard/ui/options/network.py b/picard/ui/options/network.py
index 89ca2dae1a..82a801d2ac 100644
--- a/picard/ui/options/network.py
+++ b/picard/ui/options/network.py
@@ -32,6 +32,7 @@
     CACHE_SIZE_DISPLAY_UNIT,
     CACHE_SIZE_IN_BYTES,
 )
+from picard.i18n import N_
 
 from picard.ui.options import (
     OptionsPage,
diff --git a/picard/ui/options/plugins.py b/picard/ui/options/plugins.py
index 2cb05bb902..568dbd79ce 100644
--- a/picard/ui/options/plugins.py
+++ b/picard/ui/options/plugins.py
@@ -54,6 +54,10 @@
     PLUGINS_API,
     USER_PLUGIN_DIR,
 )
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.util import (
     icontheme,
     open_local_path,
diff --git a/picard/ui/options/profiles.py b/picard/ui/options/profiles.py
index ba03fd53ee..e7400fc4ce 100644
--- a/picard/ui/options/profiles.py
+++ b/picard/ui/options/profiles.py
@@ -39,6 +39,11 @@
     get_config,
 )
 from picard.const import DEFAULT_COPY_TEXT
+from picard.i18n import (
+    N_,
+    _,
+    gettext_constants,
+)
 from picard.profile import UserProfileGroups
 from picard.script import get_file_naming_script_presets
 from picard.util import get_base_title
diff --git a/picard/ui/options/ratings.py b/picard/ui/options/ratings.py
index 7fad0db5a4..e3a9c55c3c 100644
--- a/picard/ui/options/ratings.py
+++ b/picard/ui/options/ratings.py
@@ -27,6 +27,7 @@
     TextOption,
     get_config,
 )
+from picard.i18n import N_
 
 from picard.ui.options import (
     OptionsPage,
diff --git a/picard/ui/options/releases.py b/picard/ui/options/releases.py
index 780612d039..df2149f045 100644
--- a/picard/ui/options/releases.py
+++ b/picard/ui/options/releases.py
@@ -43,6 +43,12 @@
 )
 from picard.const.countries import RELEASE_COUNTRIES
 from picard.const.sys import IS_WIN
+from picard.i18n import (
+    N_,
+    _,
+    gettext_countries,
+    pgettext_attributes,
+)
 from picard.util import strxfrm
 
 from picard.ui.options import (
diff --git a/picard/ui/options/renaming.py b/picard/ui/options/renaming.py
index ecc78a8e2c..5058ed3208 100644
--- a/picard/ui/options/renaming.py
+++ b/picard/ui/options/renaming.py
@@ -44,6 +44,10 @@
     TextOption,
     get_config,
 )
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.script import ScriptParser
 
 from picard.ui.options import (
diff --git a/picard/ui/options/renaming_compat.py b/picard/ui/options/renaming_compat.py
index f5437750af..87801d0064 100644
--- a/picard/ui/options/renaming_compat.py
+++ b/picard/ui/options/renaming_compat.py
@@ -48,6 +48,10 @@
     get_config,
 )
 from picard.const.sys import IS_WIN
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.util import system_supports_long_paths
 
 from picard.ui import PicardDialog
diff --git a/picard/ui/options/scripting.py b/picard/ui/options/scripting.py
index f0238b8e7d..f30b8920cb 100644
--- a/picard/ui/options/scripting.py
+++ b/picard/ui/options/scripting.py
@@ -40,6 +40,10 @@
     get_config,
 )
 from picard.const.sys import IS_MACOS
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.script import ScriptParser
 from picard.script.serializer import (
     ScriptImportExportError,
diff --git a/picard/ui/options/tags.py b/picard/ui/options/tags.py
index 5b5f78c664..ab5d593997 100644
--- a/picard/ui/options/tags.py
+++ b/picard/ui/options/tags.py
@@ -33,6 +33,7 @@
     ListOption,
     get_config,
 )
+from picard.i18n import N_
 
 from picard.ui.options import (
     OptionsPage,
diff --git a/picard/ui/options/tags_compatibility_aac.py b/picard/ui/options/tags_compatibility_aac.py
index fca822a33f..9fac442a58 100644
--- a/picard/ui/options/tags_compatibility_aac.py
+++ b/picard/ui/options/tags_compatibility_aac.py
@@ -25,6 +25,7 @@
     BoolOption,
     get_config,
 )
+from picard.i18n import N_
 
 from picard.ui.options import (
     OptionsPage,
diff --git a/picard/ui/options/tags_compatibility_ac3.py b/picard/ui/options/tags_compatibility_ac3.py
index c2456f1cbd..10cf2f13c0 100644
--- a/picard/ui/options/tags_compatibility_ac3.py
+++ b/picard/ui/options/tags_compatibility_ac3.py
@@ -25,6 +25,7 @@
     BoolOption,
     get_config,
 )
+from picard.i18n import N_
 
 from picard.ui.options import (
     OptionsPage,
diff --git a/picard/ui/options/tags_compatibility_id3.py b/picard/ui/options/tags_compatibility_id3.py
index 2ae5517596..b4076ec4ac 100644
--- a/picard/ui/options/tags_compatibility_id3.py
+++ b/picard/ui/options/tags_compatibility_id3.py
@@ -28,6 +28,7 @@
     TextOption,
     get_config,
 )
+from picard.i18n import N_
 
 from picard.ui.options import (
     OptionsPage,
diff --git a/picard/ui/options/tags_compatibility_wave.py b/picard/ui/options/tags_compatibility_wave.py
index 3927fe181a..8877e610e9 100644
--- a/picard/ui/options/tags_compatibility_wave.py
+++ b/picard/ui/options/tags_compatibility_wave.py
@@ -27,6 +27,7 @@
     get_config,
 )
 from picard.formats.wav import WAVFile
+from picard.i18n import N_
 
 from picard.ui.options import (
     OptionsPage,
diff --git a/picard/ui/passworddialog.py b/picard/ui/passworddialog.py
index c72d1fd4dd..ec3eb03a75 100644
--- a/picard/ui/passworddialog.py
+++ b/picard/ui/passworddialog.py
@@ -27,6 +27,7 @@
 
 
 from picard.config import get_config
+from picard.i18n import _
 
 from picard.ui import PicardDialog
 from picard.ui.ui_passworddialog import Ui_PasswordDialog
diff --git a/picard/ui/playertoolbar.py b/picard/ui/playertoolbar.py
index ee51dba48d..c72ed477ad 100644
--- a/picard/ui/playertoolbar.py
+++ b/picard/ui/playertoolbar.py
@@ -34,6 +34,10 @@
 from picard import log
 from picard.config import get_config
 from picard.const.sys import IS_MACOS
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.util import (
     format_time,
     icontheme,
diff --git a/picard/ui/pluginupdatedialog.py b/picard/ui/pluginupdatedialog.py
index b31536a1b4..f4a7cafb91 100644
--- a/picard/ui/pluginupdatedialog.py
+++ b/picard/ui/pluginupdatedialog.py
@@ -27,6 +27,11 @@
     QMessageBox,
 )
 
+from picard.i18n import (
+    _,
+    ngettext,
+)
+
 
 UPDATE_LINES_TO_SHOW = 3
 
diff --git a/picard/ui/ratingwidget.py b/picard/ui/ratingwidget.py
index b6d9cdbdb1..47903a0af1 100644
--- a/picard/ui/ratingwidget.py
+++ b/picard/ui/ratingwidget.py
@@ -31,6 +31,7 @@
 
 from picard import log
 from picard.config import get_config
+from picard.i18n import N_
 
 
 class RatingWidget(QtWidgets.QWidget):
diff --git a/picard/ui/savewarningdialog.py b/picard/ui/savewarningdialog.py
index 784d33dc9c..60fa9e04d6 100644
--- a/picard/ui/savewarningdialog.py
+++ b/picard/ui/savewarningdialog.py
@@ -27,6 +27,10 @@
 )
 
 from picard.config import get_config
+from picard.i18n import (
+    _,
+    ngettext,
+)
 
 
 class SaveWarningDialog():
diff --git a/picard/ui/scripteditor.py b/picard/ui/scripteditor.py
index f2a7e07cc0..89ed1cf60e 100644
--- a/picard/ui/scripteditor.py
+++ b/picard/ui/scripteditor.py
@@ -49,6 +49,11 @@
     PICARD_URLS,
 )
 from picard.file import File
+from picard.i18n import (
+    N_,
+    _,
+    gettext_constants,
+)
 from picard.metadata import Metadata
 from picard.script import (
     ScriptError,
diff --git a/picard/ui/scriptsmenu.py b/picard/ui/scriptsmenu.py
index b2317b21f9..00f55b08be 100644
--- a/picard/ui/scriptsmenu.py
+++ b/picard/ui/scriptsmenu.py
@@ -31,6 +31,7 @@
     Cluster,
     ClusterList,
 )
+from picard.i18n import N_
 from picard.script import (
     ScriptError,
     ScriptParser,
diff --git a/picard/ui/searchdialog/__init__.py b/picard/ui/searchdialog/__init__.py
index 6cc4765be6..a70916cd57 100644
--- a/picard/ui/searchdialog/__init__.py
+++ b/picard/ui/searchdialog/__init__.py
@@ -32,6 +32,7 @@
 )
 
 from picard.config import get_config
+from picard.i18n import _
 from picard.util import (
     icontheme,
     restore_method,
diff --git a/picard/ui/searchdialog/album.py b/picard/ui/searchdialog/album.py
index e054803b81..06108fd146 100644
--- a/picard/ui/searchdialog/album.py
+++ b/picard/ui/searchdialog/album.py
@@ -36,6 +36,7 @@
     get_config,
 )
 from picard.const import CAA_URL
+from picard.i18n import _
 from picard.mbjson import (
     countries_from_node,
     media_formats_from_node,
diff --git a/picard/ui/searchdialog/artist.py b/picard/ui/searchdialog/artist.py
index e426159a5f..b1a3f4ca0c 100644
--- a/picard/ui/searchdialog/artist.py
+++ b/picard/ui/searchdialog/artist.py
@@ -27,6 +27,7 @@
     Option,
     get_config,
 )
+from picard.i18n import _
 from picard.mbjson import artist_to_metadata
 from picard.metadata import Metadata
 
diff --git a/picard/ui/searchdialog/track.py b/picard/ui/searchdialog/track.py
index d1bddc0c25..602004e486 100644
--- a/picard/ui/searchdialog/track.py
+++ b/picard/ui/searchdialog/track.py
@@ -29,6 +29,7 @@
     get_config,
 )
 from picard.file import FILE_COMPARISON_WEIGHTS
+from picard.i18n import _
 from picard.mbjson import (
     countries_from_node,
     recording_to_metadata,
diff --git a/picard/ui/tagsfromfilenames.py b/picard/ui/tagsfromfilenames.py
index 7815023a2a..da727b3365 100644
--- a/picard/ui/tagsfromfilenames.py
+++ b/picard/ui/tagsfromfilenames.py
@@ -36,6 +36,7 @@
     TextOption,
     get_config,
 )
+from picard.i18n import _
 from picard.script.parser import normalize_tagname
 from picard.util.tags import display_tag_name
 
diff --git a/picard/ui/ui_aboutdialog.py b/picard/ui/ui_aboutdialog.py
index 13f50004ac..0cb512062f 100644
--- a/picard/ui/ui_aboutdialog.py
+++ b/picard/ui/ui_aboutdialog.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/aboutdialog.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -23,7 +25,7 @@ def setupUi(self, AboutDialog):
         self.header.setObjectName("header")
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.header.addItem(spacerItem)
-        self.logo = QtWidgets.QLabel(AboutDialog)
+        self.logo = QtWidgets.QLabel(parent=AboutDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -35,7 +37,7 @@ def setupUi(self, AboutDialog):
         self.logo.setScaledContents(True)
         self.logo.setObjectName("logo")
         self.header.addWidget(self.logo)
-        self.app_name = QtWidgets.QLabel(AboutDialog)
+        self.app_name = QtWidgets.QLabel(parent=AboutDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -52,7 +54,7 @@ def setupUi(self, AboutDialog):
         spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.header.addItem(spacerItem1)
         self.vboxlayout.addLayout(self.header)
-        self.scrollArea = QtWidgets.QScrollArea(AboutDialog)
+        self.scrollArea = QtWidgets.QScrollArea(parent=AboutDialog)
         self.scrollArea.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
         self.scrollArea.setFrameShadow(QtWidgets.QFrame.Shadow.Plain)
         self.scrollArea.setLineWidth(0)
@@ -67,7 +69,7 @@ def setupUi(self, AboutDialog):
         self.verticalLayout.setContentsMargins(9, 0, 9, 9)
         self.verticalLayout.setSpacing(6)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.label = QtWidgets.QLabel(self.scrollAreaWidgetContents)
+        self.label = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents)
         self.label.setText("")
         self.label.setAlignment(QtCore.Qt.AlignmentFlag.AlignHCenter|QtCore.Qt.AlignmentFlag.AlignTop)
         self.label.setWordWrap(True)
diff --git a/picard/ui/ui_cdlookup.py b/picard/ui/ui_cdlookup.py
index c3ac413b64..a97ce35b97 100644
--- a/picard/ui/ui_cdlookup.py
+++ b/picard/ui/ui_cdlookup.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/cdlookup.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -17,17 +19,17 @@ def setupUi(self, Dialog):
         self.vboxlayout.setContentsMargins(9, 9, 9, 9)
         self.vboxlayout.setSpacing(6)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.results_view = QtWidgets.QStackedWidget(Dialog)
+        self.results_view = QtWidgets.QStackedWidget(parent=Dialog)
         self.results_view.setObjectName("results_view")
         self.results_page = QtWidgets.QWidget()
         self.results_page.setObjectName("results_page")
         self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.results_page)
         self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
         self.verticalLayout_4.setObjectName("verticalLayout_4")
-        self.label = QtWidgets.QLabel(self.results_page)
+        self.label = QtWidgets.QLabel(parent=self.results_page)
         self.label.setObjectName("label")
         self.verticalLayout_4.addWidget(self.label)
-        self.release_list = QtWidgets.QTreeWidget(self.results_page)
+        self.release_list = QtWidgets.QTreeWidget(parent=self.results_page)
         self.release_list.setObjectName("release_list")
         self.release_list.headerItem().setText(0, "1")
         self.verticalLayout_4.addWidget(self.release_list)
@@ -38,11 +40,11 @@ def setupUi(self, Dialog):
         self.verticalLayout_3.setObjectName("verticalLayout_3")
         spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
         self.verticalLayout_3.addItem(spacerItem)
-        self.no_results_label = QtWidgets.QLabel(self.no_results_page)
+        self.no_results_label = QtWidgets.QLabel(parent=self.no_results_page)
         self.no_results_label.setStyleSheet("margin-bottom: 9px;")
         self.no_results_label.setObjectName("no_results_label")
         self.verticalLayout_3.addWidget(self.no_results_label, 0, QtCore.Qt.AlignmentFlag.AlignHCenter)
-        self.submit_button = QtWidgets.QToolButton(self.no_results_page)
+        self.submit_button = QtWidgets.QToolButton(parent=self.no_results_page)
         self.submit_button.setStyleSheet("")
         icon = QtGui.QIcon.fromTheme("media-optical")
         self.submit_button.setIcon(icon)
@@ -60,14 +62,14 @@ def setupUi(self, Dialog):
         self.hboxlayout.setObjectName("hboxlayout")
         spacerItem2 = QtWidgets.QSpacerItem(111, 31, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.hboxlayout.addItem(spacerItem2)
-        self.ok_button = QtWidgets.QPushButton(Dialog)
+        self.ok_button = QtWidgets.QPushButton(parent=Dialog)
         self.ok_button.setEnabled(False)
         self.ok_button.setObjectName("ok_button")
         self.hboxlayout.addWidget(self.ok_button)
-        self.lookup_button = QtWidgets.QPushButton(Dialog)
+        self.lookup_button = QtWidgets.QPushButton(parent=Dialog)
         self.lookup_button.setObjectName("lookup_button")
         self.hboxlayout.addWidget(self.lookup_button)
-        self.cancel_button = QtWidgets.QPushButton(Dialog)
+        self.cancel_button = QtWidgets.QPushButton(parent=Dialog)
         self.cancel_button.setObjectName("cancel_button")
         self.hboxlayout.addWidget(self.cancel_button)
         self.vboxlayout.addLayout(self.hboxlayout)
diff --git a/picard/ui/ui_edittagdialog.py b/picard/ui/ui_edittagdialog.py
index 7f17acb97c..14dd606fe7 100644
--- a/picard/ui/ui_edittagdialog.py
+++ b/picard/ui/ui_edittagdialog.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/edittagdialog.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -18,13 +20,13 @@ def setupUi(self, EditTagDialog):
         EditTagDialog.setModal(True)
         self.verticalLayout_2 = QtWidgets.QVBoxLayout(EditTagDialog)
         self.verticalLayout_2.setObjectName("verticalLayout_2")
-        self.tag_names = QtWidgets.QComboBox(EditTagDialog)
+        self.tag_names = QtWidgets.QComboBox(parent=EditTagDialog)
         self.tag_names.setEditable(True)
         self.tag_names.setObjectName("tag_names")
         self.verticalLayout_2.addWidget(self.tag_names)
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.value_list = QtWidgets.QListWidget(EditTagDialog)
+        self.value_list = QtWidgets.QListWidget(parent=EditTagDialog)
         self.value_list.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
         self.value_list.setTabKeyNavigation(False)
         self.value_list.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.InternalMove)
@@ -33,7 +35,7 @@ def setupUi(self, EditTagDialog):
         self.horizontalLayout.addWidget(self.value_list)
         self.verticalLayout = QtWidgets.QVBoxLayout()
         self.verticalLayout.setObjectName("verticalLayout")
-        self.edit_value = QtWidgets.QPushButton(EditTagDialog)
+        self.edit_value = QtWidgets.QPushButton(parent=EditTagDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(100)
         sizePolicy.setVerticalStretch(0)
@@ -43,7 +45,7 @@ def setupUi(self, EditTagDialog):
         self.edit_value.setAutoDefault(False)
         self.edit_value.setObjectName("edit_value")
         self.verticalLayout.addWidget(self.edit_value)
-        self.add_value = QtWidgets.QPushButton(EditTagDialog)
+        self.add_value = QtWidgets.QPushButton(parent=EditTagDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(100)
         sizePolicy.setVerticalStretch(0)
@@ -53,7 +55,7 @@ def setupUi(self, EditTagDialog):
         self.add_value.setAutoDefault(False)
         self.add_value.setObjectName("add_value")
         self.verticalLayout.addWidget(self.add_value)
-        self.remove_value = QtWidgets.QPushButton(EditTagDialog)
+        self.remove_value = QtWidgets.QPushButton(parent=EditTagDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(120)
         sizePolicy.setVerticalStretch(0)
@@ -65,13 +67,13 @@ def setupUi(self, EditTagDialog):
         self.verticalLayout.addWidget(self.remove_value)
         spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Maximum)
         self.verticalLayout.addItem(spacerItem)
-        self.move_value_up = QtWidgets.QPushButton(EditTagDialog)
+        self.move_value_up = QtWidgets.QPushButton(parent=EditTagDialog)
         self.move_value_up.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-up.png")
         self.move_value_up.setIcon(icon)
         self.move_value_up.setObjectName("move_value_up")
         self.verticalLayout.addWidget(self.move_value_up)
-        self.move_value_down = QtWidgets.QPushButton(EditTagDialog)
+        self.move_value_down = QtWidgets.QPushButton(parent=EditTagDialog)
         self.move_value_down.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-down.png")
         self.move_value_down.setIcon(icon)
@@ -81,7 +83,7 @@ def setupUi(self, EditTagDialog):
         self.verticalLayout.addItem(spacerItem1)
         self.horizontalLayout.addLayout(self.verticalLayout)
         self.verticalLayout_2.addLayout(self.horizontalLayout)
-        self.buttonbox = QtWidgets.QDialogButtonBox(EditTagDialog)
+        self.buttonbox = QtWidgets.QDialogButtonBox(parent=EditTagDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(150)
         sizePolicy.setVerticalStretch(0)
diff --git a/picard/ui/ui_exception_script_selector.py b/picard/ui/ui_exception_script_selector.py
index d3cd93637a..50a9d6df5a 100644
--- a/picard/ui/ui_exception_script_selector.py
+++ b/picard/ui/ui_exception_script_selector.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/exception_script_selector.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -26,20 +28,20 @@ def setupUi(self, ExceptionScriptSelector):
         self.horizontalLayout.setObjectName("horizontalLayout")
         self.verticalLayout_2 = QtWidgets.QVBoxLayout()
         self.verticalLayout_2.setObjectName("verticalLayout_2")
-        self.label = QtWidgets.QLabel(ExceptionScriptSelector)
+        self.label = QtWidgets.QLabel(parent=ExceptionScriptSelector)
         self.label.setObjectName("label")
         self.verticalLayout_2.addWidget(self.label)
-        self.selected_scripts = QtWidgets.QListWidget(ExceptionScriptSelector)
+        self.selected_scripts = QtWidgets.QListWidget(parent=ExceptionScriptSelector)
         self.selected_scripts.setMaximumSize(QtCore.QSize(16777215, 16777215))
         self.selected_scripts.setObjectName("selected_scripts")
         self.verticalLayout_2.addWidget(self.selected_scripts)
         self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_2.setContentsMargins(-1, -1, -1, 0)
         self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.threshold_label = QtWidgets.QLabel(ExceptionScriptSelector)
+        self.threshold_label = QtWidgets.QLabel(parent=ExceptionScriptSelector)
         self.threshold_label.setObjectName("threshold_label")
         self.horizontalLayout_2.addWidget(self.threshold_label)
-        self.weighting_selector = QtWidgets.QSpinBox(ExceptionScriptSelector)
+        self.weighting_selector = QtWidgets.QSpinBox(parent=ExceptionScriptSelector)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Maximum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -56,25 +58,25 @@ def setupUi(self, ExceptionScriptSelector):
         self.verticalLayout_3.setObjectName("verticalLayout_3")
         spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
         self.verticalLayout_3.addItem(spacerItem)
-        self.move_up = QtWidgets.QToolButton(ExceptionScriptSelector)
+        self.move_up = QtWidgets.QToolButton(parent=ExceptionScriptSelector)
         self.move_up.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-up.png")
         self.move_up.setIcon(icon)
         self.move_up.setObjectName("move_up")
         self.verticalLayout_3.addWidget(self.move_up)
-        self.add_script = QtWidgets.QToolButton(ExceptionScriptSelector)
+        self.add_script = QtWidgets.QToolButton(parent=ExceptionScriptSelector)
         self.add_script.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-previous.png")
         self.add_script.setIcon(icon)
         self.add_script.setObjectName("add_script")
         self.verticalLayout_3.addWidget(self.add_script)
-        self.remove_script = QtWidgets.QToolButton(ExceptionScriptSelector)
+        self.remove_script = QtWidgets.QToolButton(parent=ExceptionScriptSelector)
         self.remove_script.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-next.png")
         self.remove_script.setIcon(icon)
         self.remove_script.setObjectName("remove_script")
         self.verticalLayout_3.addWidget(self.remove_script)
-        self.move_down = QtWidgets.QToolButton(ExceptionScriptSelector)
+        self.move_down = QtWidgets.QToolButton(parent=ExceptionScriptSelector)
         self.move_down.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-down.png")
         self.move_down.setIcon(icon)
@@ -85,15 +87,15 @@ def setupUi(self, ExceptionScriptSelector):
         self.horizontalLayout.addLayout(self.verticalLayout_3)
         self.verticalLayout_4 = QtWidgets.QVBoxLayout()
         self.verticalLayout_4.setObjectName("verticalLayout_4")
-        self.label_2 = QtWidgets.QLabel(ExceptionScriptSelector)
+        self.label_2 = QtWidgets.QLabel(parent=ExceptionScriptSelector)
         self.label_2.setObjectName("label_2")
         self.verticalLayout_4.addWidget(self.label_2)
-        self.available_scripts = QtWidgets.QListWidget(ExceptionScriptSelector)
+        self.available_scripts = QtWidgets.QListWidget(parent=ExceptionScriptSelector)
         self.available_scripts.setObjectName("available_scripts")
         self.verticalLayout_4.addWidget(self.available_scripts)
         self.horizontalLayout.addLayout(self.verticalLayout_4)
         self.verticalLayout.addLayout(self.horizontalLayout)
-        self.button_box = QtWidgets.QDialogButtonBox(ExceptionScriptSelector)
+        self.button_box = QtWidgets.QDialogButtonBox(parent=ExceptionScriptSelector)
         self.button_box.setOrientation(QtCore.Qt.Orientation.Horizontal)
         self.button_box.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Save)
         self.button_box.setObjectName("button_box")
diff --git a/picard/ui/ui_infodialog.py b/picard/ui/ui_infodialog.py
index 4420a67f12..86b9c8c4e4 100644
--- a/picard/ui/ui_infodialog.py
+++ b/picard/ui/ui_infodialog.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/infodialog.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,13 +17,13 @@ def setupUi(self, InfoDialog):
         InfoDialog.resize(665, 436)
         self.verticalLayout = QtWidgets.QVBoxLayout(InfoDialog)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.tabWidget = QtWidgets.QTabWidget(InfoDialog)
+        self.tabWidget = QtWidgets.QTabWidget(parent=InfoDialog)
         self.tabWidget.setObjectName("tabWidget")
         self.info_tab = QtWidgets.QWidget()
         self.info_tab.setObjectName("info_tab")
         self.vboxlayout = QtWidgets.QVBoxLayout(self.info_tab)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.info_scroll = QtWidgets.QScrollArea(self.info_tab)
+        self.info_scroll = QtWidgets.QScrollArea(parent=self.info_tab)
         self.info_scroll.setWidgetResizable(True)
         self.info_scroll.setObjectName("info_scroll")
         self.scrollAreaWidgetContents = QtWidgets.QWidget()
@@ -30,7 +32,7 @@ def setupUi(self, InfoDialog):
         self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
         self.verticalLayoutLabel = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
         self.verticalLayoutLabel.setObjectName("verticalLayoutLabel")
-        self.info = QtWidgets.QLabel(self.scrollAreaWidgetContents)
+        self.info = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents)
         self.info.setText("")
         self.info.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
         self.info.setWordWrap(True)
@@ -44,7 +46,7 @@ def setupUi(self, InfoDialog):
         self.error_tab.setObjectName("error_tab")
         self.vboxlayout1 = QtWidgets.QVBoxLayout(self.error_tab)
         self.vboxlayout1.setObjectName("vboxlayout1")
-        self.scrollArea = QtWidgets.QScrollArea(self.error_tab)
+        self.scrollArea = QtWidgets.QScrollArea(parent=self.error_tab)
         self.scrollArea.setWidgetResizable(True)
         self.scrollArea.setObjectName("scrollArea")
         self.scrollAreaWidgetContents_3 = QtWidgets.QWidget()
@@ -52,7 +54,7 @@ def setupUi(self, InfoDialog):
         self.scrollAreaWidgetContents_3.setObjectName("scrollAreaWidgetContents_3")
         self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents_3)
         self.verticalLayout_2.setObjectName("verticalLayout_2")
-        self.error = QtWidgets.QLabel(self.scrollAreaWidgetContents_3)
+        self.error = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_3)
         self.error.setText("")
         self.error.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
         self.error.setWordWrap(True)
@@ -68,7 +70,7 @@ def setupUi(self, InfoDialog):
         self.vboxlayout2.setObjectName("vboxlayout2")
         self.tabWidget.addTab(self.artwork_tab, "")
         self.verticalLayout.addWidget(self.tabWidget)
-        self.buttonBox = QtWidgets.QDialogButtonBox(InfoDialog)
+        self.buttonBox = QtWidgets.QDialogButtonBox(parent=InfoDialog)
         self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.NoButton)
         self.buttonBox.setObjectName("buttonBox")
         self.verticalLayout.addWidget(self.buttonBox)
diff --git a/picard/ui/ui_infostatus.py b/picard/ui/ui_infostatus.py
index a21d5dabc9..70519b0a35 100644
--- a/picard/ui/ui_infostatus.py
+++ b/picard/ui/ui_infostatus.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/infostatus.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -23,13 +25,13 @@ def setupUi(self, InfoStatus):
         self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
         self.horizontalLayout.setSpacing(2)
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.val1 = QtWidgets.QLabel(InfoStatus)
+        self.val1 = QtWidgets.QLabel(parent=InfoStatus)
         self.val1.setMinimumSize(QtCore.QSize(40, 0))
         self.val1.setText("")
         self.val1.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
         self.val1.setObjectName("val1")
         self.horizontalLayout.addWidget(self.val1)
-        self.label1 = QtWidgets.QLabel(InfoStatus)
+        self.label1 = QtWidgets.QLabel(parent=InfoStatus)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -41,13 +43,13 @@ def setupUi(self, InfoStatus):
         self.label1.setScaledContents(False)
         self.label1.setObjectName("label1")
         self.horizontalLayout.addWidget(self.label1)
-        self.val2 = QtWidgets.QLabel(InfoStatus)
+        self.val2 = QtWidgets.QLabel(parent=InfoStatus)
         self.val2.setMinimumSize(QtCore.QSize(40, 0))
         self.val2.setText("")
         self.val2.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
         self.val2.setObjectName("val2")
         self.horizontalLayout.addWidget(self.val2)
-        self.label2 = QtWidgets.QLabel(InfoStatus)
+        self.label2 = QtWidgets.QLabel(parent=InfoStatus)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -56,13 +58,13 @@ def setupUi(self, InfoStatus):
         self.label2.setText("")
         self.label2.setObjectName("label2")
         self.horizontalLayout.addWidget(self.label2)
-        self.val3 = QtWidgets.QLabel(InfoStatus)
+        self.val3 = QtWidgets.QLabel(parent=InfoStatus)
         self.val3.setMinimumSize(QtCore.QSize(40, 0))
         self.val3.setText("")
         self.val3.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
         self.val3.setObjectName("val3")
         self.horizontalLayout.addWidget(self.val3)
-        self.label3 = QtWidgets.QLabel(InfoStatus)
+        self.label3 = QtWidgets.QLabel(parent=InfoStatus)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -71,13 +73,13 @@ def setupUi(self, InfoStatus):
         self.label3.setText("")
         self.label3.setObjectName("label3")
         self.horizontalLayout.addWidget(self.label3)
-        self.val4 = QtWidgets.QLabel(InfoStatus)
+        self.val4 = QtWidgets.QLabel(parent=InfoStatus)
         self.val4.setMinimumSize(QtCore.QSize(40, 0))
         self.val4.setText("")
         self.val4.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
         self.val4.setObjectName("val4")
         self.horizontalLayout.addWidget(self.val4)
-        self.label4 = QtWidgets.QLabel(InfoStatus)
+        self.label4 = QtWidgets.QLabel(parent=InfoStatus)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -87,13 +89,13 @@ def setupUi(self, InfoStatus):
         self.label4.setScaledContents(False)
         self.label4.setObjectName("label4")
         self.horizontalLayout.addWidget(self.label4)
-        self.val5 = QtWidgets.QLabel(InfoStatus)
+        self.val5 = QtWidgets.QLabel(parent=InfoStatus)
         self.val5.setMinimumSize(QtCore.QSize(40, 0))
         self.val5.setText("")
         self.val5.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
         self.val5.setObjectName("val5")
         self.horizontalLayout.addWidget(self.val5)
-        self.label5 = QtWidgets.QLabel(InfoStatus)
+        self.label5 = QtWidgets.QLabel(parent=InfoStatus)
         self.label5.setMinimumSize(QtCore.QSize(0, 0))
         self.label5.setText("")
         self.label5.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
diff --git a/picard/ui/ui_multi_locale_selector.py b/picard/ui/ui_multi_locale_selector.py
index 0385c720d4..f971218169 100644
--- a/picard/ui/ui_multi_locale_selector.py
+++ b/picard/ui/ui_multi_locale_selector.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/multi_locale_selector.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -25,10 +27,10 @@ def setupUi(self, MultiLocaleSelector):
         self.horizontalLayout.setObjectName("horizontalLayout")
         self.verticalLayout_2 = QtWidgets.QVBoxLayout()
         self.verticalLayout_2.setObjectName("verticalLayout_2")
-        self.label = QtWidgets.QLabel(MultiLocaleSelector)
+        self.label = QtWidgets.QLabel(parent=MultiLocaleSelector)
         self.label.setObjectName("label")
         self.verticalLayout_2.addWidget(self.label)
-        self.selected_locales = QtWidgets.QListWidget(MultiLocaleSelector)
+        self.selected_locales = QtWidgets.QListWidget(parent=MultiLocaleSelector)
         self.selected_locales.setObjectName("selected_locales")
         self.verticalLayout_2.addWidget(self.selected_locales)
         self.horizontalLayout.addLayout(self.verticalLayout_2)
@@ -36,25 +38,25 @@ def setupUi(self, MultiLocaleSelector):
         self.verticalLayout_3.setObjectName("verticalLayout_3")
         spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
         self.verticalLayout_3.addItem(spacerItem)
-        self.move_up = QtWidgets.QToolButton(MultiLocaleSelector)
+        self.move_up = QtWidgets.QToolButton(parent=MultiLocaleSelector)
         self.move_up.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-up.png")
         self.move_up.setIcon(icon)
         self.move_up.setObjectName("move_up")
         self.verticalLayout_3.addWidget(self.move_up)
-        self.add_locale = QtWidgets.QToolButton(MultiLocaleSelector)
+        self.add_locale = QtWidgets.QToolButton(parent=MultiLocaleSelector)
         self.add_locale.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-previous.png")
         self.add_locale.setIcon(icon)
         self.add_locale.setObjectName("add_locale")
         self.verticalLayout_3.addWidget(self.add_locale)
-        self.remove_locale = QtWidgets.QToolButton(MultiLocaleSelector)
+        self.remove_locale = QtWidgets.QToolButton(parent=MultiLocaleSelector)
         self.remove_locale.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-next.png")
         self.remove_locale.setIcon(icon)
         self.remove_locale.setObjectName("remove_locale")
         self.verticalLayout_3.addWidget(self.remove_locale)
-        self.move_down = QtWidgets.QToolButton(MultiLocaleSelector)
+        self.move_down = QtWidgets.QToolButton(parent=MultiLocaleSelector)
         self.move_down.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-down.png")
         self.move_down.setIcon(icon)
@@ -65,15 +67,15 @@ def setupUi(self, MultiLocaleSelector):
         self.horizontalLayout.addLayout(self.verticalLayout_3)
         self.verticalLayout_4 = QtWidgets.QVBoxLayout()
         self.verticalLayout_4.setObjectName("verticalLayout_4")
-        self.label_2 = QtWidgets.QLabel(MultiLocaleSelector)
+        self.label_2 = QtWidgets.QLabel(parent=MultiLocaleSelector)
         self.label_2.setObjectName("label_2")
         self.verticalLayout_4.addWidget(self.label_2)
-        self.available_locales = QtWidgets.QListWidget(MultiLocaleSelector)
+        self.available_locales = QtWidgets.QListWidget(parent=MultiLocaleSelector)
         self.available_locales.setObjectName("available_locales")
         self.verticalLayout_4.addWidget(self.available_locales)
         self.horizontalLayout.addLayout(self.verticalLayout_4)
         self.verticalLayout.addLayout(self.horizontalLayout)
-        self.button_box = QtWidgets.QDialogButtonBox(MultiLocaleSelector)
+        self.button_box = QtWidgets.QDialogButtonBox(parent=MultiLocaleSelector)
         self.button_box.setOrientation(QtCore.Qt.Orientation.Horizontal)
         self.button_box.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Save)
         self.button_box.setObjectName("button_box")
diff --git a/picard/ui/ui_options.py b/picard/ui/ui_options.py
index 81e5ec214c..2a4cbab8b3 100644
--- a/picard/ui/ui_options.py
+++ b/picard/ui/ui_options.py
@@ -2,8 +2,10 @@
 #
 # Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_advanced.py b/picard/ui/ui_options_advanced.py
index 64a6332d83..695c2b94ca 100644
--- a/picard/ui/ui_options_advanced.py
+++ b/picard/ui/ui_options_advanced.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_advanced.ui'
 #
-# Created by: PyQt6 UI code generator 6.5.3
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_attached_profiles.py b/picard/ui/ui_options_attached_profiles.py
index 7db8a9e332..fda8e0b9e6 100644
--- a/picard/ui/ui_options_attached_profiles.py
+++ b/picard/ui/ui_options_attached_profiles.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_attached_profiles.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -17,13 +19,13 @@ def setupUi(self, AttachedProfilesDialog):
         self.vboxlayout.setContentsMargins(9, 9, 9, 9)
         self.vboxlayout.setSpacing(6)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.options_list = QtWidgets.QTableView(AttachedProfilesDialog)
+        self.options_list = QtWidgets.QTableView(parent=AttachedProfilesDialog)
         self.options_list.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
         self.options_list.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection)
         self.options_list.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
         self.options_list.setObjectName("options_list")
         self.vboxlayout.addWidget(self.options_list)
-        self.buttonBox = QtWidgets.QDialogButtonBox(AttachedProfilesDialog)
+        self.buttonBox = QtWidgets.QDialogButtonBox(parent=AttachedProfilesDialog)
         self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.NoButton)
         self.buttonBox.setObjectName("buttonBox")
         self.vboxlayout.addWidget(self.buttonBox)
diff --git a/picard/ui/ui_options_cdlookup.py b/picard/ui/ui_options_cdlookup.py
index 6bb84fda46..da021b3545 100644
--- a/picard/ui/ui_options_cdlookup.py
+++ b/picard/ui/ui_options_cdlookup.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_cdlookup.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -17,16 +19,16 @@ def setupUi(self, CDLookupOptionsPage):
         self.vboxlayout.setContentsMargins(9, 9, 9, 9)
         self.vboxlayout.setSpacing(6)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.rename_files = QtWidgets.QGroupBox(CDLookupOptionsPage)
+        self.rename_files = QtWidgets.QGroupBox(parent=CDLookupOptionsPage)
         self.rename_files.setObjectName("rename_files")
         self.gridlayout = QtWidgets.QGridLayout(self.rename_files)
         self.gridlayout.setContentsMargins(9, 9, 9, 9)
         self.gridlayout.setSpacing(2)
         self.gridlayout.setObjectName("gridlayout")
-        self.cd_lookup_device = QtWidgets.QLineEdit(self.rename_files)
+        self.cd_lookup_device = QtWidgets.QLineEdit(parent=self.rename_files)
         self.cd_lookup_device.setObjectName("cd_lookup_device")
         self.gridlayout.addWidget(self.cd_lookup_device, 1, 0, 1, 1)
-        self.label_3 = QtWidgets.QLabel(self.rename_files)
+        self.label_3 = QtWidgets.QLabel(parent=self.rename_files)
         self.label_3.setObjectName("label_3")
         self.gridlayout.addWidget(self.label_3, 0, 0, 1, 1)
         self.vboxlayout.addWidget(self.rename_files)
diff --git a/picard/ui/ui_options_cdlookup_select.py b/picard/ui/ui_options_cdlookup_select.py
index 08ba95e743..4a74e34381 100644
--- a/picard/ui/ui_options_cdlookup_select.py
+++ b/picard/ui/ui_options_cdlookup_select.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_cdlookup_select.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -17,20 +19,20 @@ def setupUi(self, CDLookupOptionsPage):
         self.vboxlayout.setContentsMargins(9, 9, 9, 9)
         self.vboxlayout.setSpacing(6)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.rename_files = QtWidgets.QGroupBox(CDLookupOptionsPage)
+        self.rename_files = QtWidgets.QGroupBox(parent=CDLookupOptionsPage)
         self.rename_files.setObjectName("rename_files")
         self.gridlayout = QtWidgets.QGridLayout(self.rename_files)
         self.gridlayout.setContentsMargins(9, 9, 9, 9)
         self.gridlayout.setSpacing(2)
         self.gridlayout.setObjectName("gridlayout")
-        self.cd_lookup_ = QtWidgets.QLabel(self.rename_files)
+        self.cd_lookup_ = QtWidgets.QLabel(parent=self.rename_files)
         self.cd_lookup_.setObjectName("cd_lookup_")
         self.gridlayout.addWidget(self.cd_lookup_, 0, 0, 1, 1)
         self.hboxlayout = QtWidgets.QHBoxLayout()
         self.hboxlayout.setContentsMargins(0, 0, 0, 0)
         self.hboxlayout.setSpacing(6)
         self.hboxlayout.setObjectName("hboxlayout")
-        self.cd_lookup_device = QtWidgets.QComboBox(self.rename_files)
+        self.cd_lookup_device = QtWidgets.QComboBox(parent=self.rename_files)
         self.cd_lookup_device.setObjectName("cd_lookup_device")
         self.hboxlayout.addWidget(self.cd_lookup_device)
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
diff --git a/picard/ui/ui_options_cover.py b/picard/ui/ui_options_cover.py
index 87fb4aa890..09b2d71e9b 100644
--- a/picard/ui/ui_options_cover.py
+++ b/picard/ui/ui_options_cover.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_cover.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,7 +17,7 @@ def setupUi(self, CoverOptionsPage):
         CoverOptionsPage.resize(632, 560)
         self.verticalLayout = QtWidgets.QVBoxLayout(CoverOptionsPage)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.save_images_to_tags = QtWidgets.QGroupBox(CoverOptionsPage)
+        self.save_images_to_tags = QtWidgets.QGroupBox(parent=CoverOptionsPage)
         self.save_images_to_tags.setCheckable(True)
         self.save_images_to_tags.setChecked(False)
         self.save_images_to_tags.setObjectName("save_images_to_tags")
@@ -23,33 +25,33 @@ def setupUi(self, CoverOptionsPage):
         self.vboxlayout.setContentsMargins(9, 9, 9, 9)
         self.vboxlayout.setSpacing(2)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.cb_embed_front_only = QtWidgets.QCheckBox(self.save_images_to_tags)
+        self.cb_embed_front_only = QtWidgets.QCheckBox(parent=self.save_images_to_tags)
         self.cb_embed_front_only.setObjectName("cb_embed_front_only")
         self.vboxlayout.addWidget(self.cb_embed_front_only)
         self.verticalLayout.addWidget(self.save_images_to_tags)
-        self.save_images_to_files = QtWidgets.QGroupBox(CoverOptionsPage)
+        self.save_images_to_files = QtWidgets.QGroupBox(parent=CoverOptionsPage)
         self.save_images_to_files.setCheckable(True)
         self.save_images_to_files.setChecked(False)
         self.save_images_to_files.setObjectName("save_images_to_files")
         self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.save_images_to_files)
         self.verticalLayout_2.setObjectName("verticalLayout_2")
-        self.label_use_filename = QtWidgets.QLabel(self.save_images_to_files)
+        self.label_use_filename = QtWidgets.QLabel(parent=self.save_images_to_files)
         self.label_use_filename.setObjectName("label_use_filename")
         self.verticalLayout_2.addWidget(self.label_use_filename)
-        self.cover_image_filename = QtWidgets.QLineEdit(self.save_images_to_files)
+        self.cover_image_filename = QtWidgets.QLineEdit(parent=self.save_images_to_files)
         self.cover_image_filename.setObjectName("cover_image_filename")
         self.verticalLayout_2.addWidget(self.cover_image_filename)
-        self.save_images_overwrite = QtWidgets.QCheckBox(self.save_images_to_files)
+        self.save_images_overwrite = QtWidgets.QCheckBox(parent=self.save_images_to_files)
         self.save_images_overwrite.setObjectName("save_images_overwrite")
         self.verticalLayout_2.addWidget(self.save_images_overwrite)
-        self.save_only_one_front_image = QtWidgets.QCheckBox(self.save_images_to_files)
+        self.save_only_one_front_image = QtWidgets.QCheckBox(parent=self.save_images_to_files)
         self.save_only_one_front_image.setObjectName("save_only_one_front_image")
         self.verticalLayout_2.addWidget(self.save_only_one_front_image)
-        self.image_type_as_filename = QtWidgets.QCheckBox(self.save_images_to_files)
+        self.image_type_as_filename = QtWidgets.QCheckBox(parent=self.save_images_to_files)
         self.image_type_as_filename.setObjectName("image_type_as_filename")
         self.verticalLayout_2.addWidget(self.image_type_as_filename)
         self.verticalLayout.addWidget(self.save_images_to_files)
-        self.ca_providers_groupbox = QtWidgets.QGroupBox(CoverOptionsPage)
+        self.ca_providers_groupbox = QtWidgets.QGroupBox(parent=CoverOptionsPage)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -58,15 +60,15 @@ def setupUi(self, CoverOptionsPage):
         self.ca_providers_groupbox.setObjectName("ca_providers_groupbox")
         self.ca_providers_layout = QtWidgets.QVBoxLayout(self.ca_providers_groupbox)
         self.ca_providers_layout.setObjectName("ca_providers_layout")
-        self.ca_providers_list = QtWidgets.QListWidget(self.ca_providers_groupbox)
+        self.ca_providers_list = QtWidgets.QListWidget(parent=self.ca_providers_groupbox)
         self.ca_providers_list.setObjectName("ca_providers_list")
         self.ca_providers_layout.addWidget(self.ca_providers_list)
         self.ca_layout = QtWidgets.QHBoxLayout()
         self.ca_layout.setObjectName("ca_layout")
-        self.move_label = QtWidgets.QLabel(self.ca_providers_groupbox)
+        self.move_label = QtWidgets.QLabel(parent=self.ca_providers_groupbox)
         self.move_label.setObjectName("move_label")
         self.ca_layout.addWidget(self.move_label)
-        self.up_button = QtWidgets.QToolButton(self.ca_providers_groupbox)
+        self.up_button = QtWidgets.QToolButton(parent=self.ca_providers_groupbox)
         self.up_button.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight)
         self.up_button.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-up.png")
@@ -75,7 +77,7 @@ def setupUi(self, CoverOptionsPage):
         self.up_button.setAutoRaise(False)
         self.up_button.setObjectName("up_button")
         self.ca_layout.addWidget(self.up_button)
-        self.down_button = QtWidgets.QToolButton(self.ca_providers_groupbox)
+        self.down_button = QtWidgets.QToolButton(parent=self.ca_providers_groupbox)
         self.down_button.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-down.png")
         self.down_button.setIcon(icon)
diff --git a/picard/ui/ui_options_fingerprinting.py b/picard/ui/ui_options_fingerprinting.py
index 4915a48374..0525959cad 100644
--- a/picard/ui/ui_options_fingerprinting.py
+++ b/picard/ui/ui_options_fingerprinting.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_fingerprinting.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,32 +17,32 @@ def setupUi(self, FingerprintingOptionsPage):
         FingerprintingOptionsPage.resize(371, 408)
         self.verticalLayout = QtWidgets.QVBoxLayout(FingerprintingOptionsPage)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.fingerprinting = QtWidgets.QGroupBox(FingerprintingOptionsPage)
+        self.fingerprinting = QtWidgets.QGroupBox(parent=FingerprintingOptionsPage)
         self.fingerprinting.setCheckable(False)
         self.fingerprinting.setObjectName("fingerprinting")
         self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.fingerprinting)
         self.verticalLayout_3.setObjectName("verticalLayout_3")
-        self.disable_fingerprinting = QtWidgets.QRadioButton(self.fingerprinting)
+        self.disable_fingerprinting = QtWidgets.QRadioButton(parent=self.fingerprinting)
         self.disable_fingerprinting.setObjectName("disable_fingerprinting")
         self.verticalLayout_3.addWidget(self.disable_fingerprinting)
-        self.use_acoustid = QtWidgets.QRadioButton(self.fingerprinting)
+        self.use_acoustid = QtWidgets.QRadioButton(parent=self.fingerprinting)
         self.use_acoustid.setObjectName("use_acoustid")
         self.verticalLayout_3.addWidget(self.use_acoustid)
         self.verticalLayout.addWidget(self.fingerprinting)
-        self.acoustid_settings = QtWidgets.QGroupBox(FingerprintingOptionsPage)
+        self.acoustid_settings = QtWidgets.QGroupBox(parent=FingerprintingOptionsPage)
         self.acoustid_settings.setObjectName("acoustid_settings")
         self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.acoustid_settings)
         self.verticalLayout_2.setObjectName("verticalLayout_2")
-        self.ignore_existing_acoustid_fingerprints = QtWidgets.QCheckBox(self.acoustid_settings)
+        self.ignore_existing_acoustid_fingerprints = QtWidgets.QCheckBox(parent=self.acoustid_settings)
         self.ignore_existing_acoustid_fingerprints.setObjectName("ignore_existing_acoustid_fingerprints")
         self.verticalLayout_2.addWidget(self.ignore_existing_acoustid_fingerprints)
-        self.save_acoustid_fingerprints = QtWidgets.QCheckBox(self.acoustid_settings)
+        self.save_acoustid_fingerprints = QtWidgets.QCheckBox(parent=self.acoustid_settings)
         self.save_acoustid_fingerprints.setObjectName("save_acoustid_fingerprints")
         self.verticalLayout_2.addWidget(self.save_acoustid_fingerprints)
         self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_3.setContentsMargins(-1, 0, -1, -1)
         self.horizontalLayout_3.setObjectName("horizontalLayout_3")
-        self.label_3 = QtWidgets.QLabel(self.acoustid_settings)
+        self.label_3 = QtWidgets.QLabel(parent=self.acoustid_settings)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -50,40 +52,40 @@ def setupUi(self, FingerprintingOptionsPage):
         self.horizontalLayout_3.addWidget(self.label_3)
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout_3.addItem(spacerItem)
-        self.fpcalc_threads = QtWidgets.QSpinBox(self.acoustid_settings)
+        self.fpcalc_threads = QtWidgets.QSpinBox(parent=self.acoustid_settings)
         self.fpcalc_threads.setMinimum(1)
         self.fpcalc_threads.setMaximum(9)
         self.fpcalc_threads.setObjectName("fpcalc_threads")
         self.horizontalLayout_3.addWidget(self.fpcalc_threads)
         self.verticalLayout_2.addLayout(self.horizontalLayout_3)
-        self.label = QtWidgets.QLabel(self.acoustid_settings)
+        self.label = QtWidgets.QLabel(parent=self.acoustid_settings)
         self.label.setObjectName("label")
         self.verticalLayout_2.addWidget(self.label)
         self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.acoustid_fpcalc = QtWidgets.QLineEdit(self.acoustid_settings)
+        self.acoustid_fpcalc = QtWidgets.QLineEdit(parent=self.acoustid_settings)
         self.acoustid_fpcalc.setObjectName("acoustid_fpcalc")
         self.horizontalLayout_2.addWidget(self.acoustid_fpcalc)
-        self.acoustid_fpcalc_browse = QtWidgets.QPushButton(self.acoustid_settings)
+        self.acoustid_fpcalc_browse = QtWidgets.QPushButton(parent=self.acoustid_settings)
         self.acoustid_fpcalc_browse.setObjectName("acoustid_fpcalc_browse")
         self.horizontalLayout_2.addWidget(self.acoustid_fpcalc_browse)
-        self.acoustid_fpcalc_download = QtWidgets.QPushButton(self.acoustid_settings)
+        self.acoustid_fpcalc_download = QtWidgets.QPushButton(parent=self.acoustid_settings)
         self.acoustid_fpcalc_download.setObjectName("acoustid_fpcalc_download")
         self.horizontalLayout_2.addWidget(self.acoustid_fpcalc_download)
         self.verticalLayout_2.addLayout(self.horizontalLayout_2)
-        self.acoustid_fpcalc_info = QtWidgets.QLabel(self.acoustid_settings)
+        self.acoustid_fpcalc_info = QtWidgets.QLabel(parent=self.acoustid_settings)
         self.acoustid_fpcalc_info.setText("")
         self.acoustid_fpcalc_info.setObjectName("acoustid_fpcalc_info")
         self.verticalLayout_2.addWidget(self.acoustid_fpcalc_info)
-        self.label_2 = QtWidgets.QLabel(self.acoustid_settings)
+        self.label_2 = QtWidgets.QLabel(parent=self.acoustid_settings)
         self.label_2.setObjectName("label_2")
         self.verticalLayout_2.addWidget(self.label_2)
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.acoustid_apikey = QtWidgets.QLineEdit(self.acoustid_settings)
+        self.acoustid_apikey = QtWidgets.QLineEdit(parent=self.acoustid_settings)
         self.acoustid_apikey.setObjectName("acoustid_apikey")
         self.horizontalLayout.addWidget(self.acoustid_apikey)
-        self.acoustid_apikey_get = QtWidgets.QPushButton(self.acoustid_settings)
+        self.acoustid_apikey_get = QtWidgets.QPushButton(parent=self.acoustid_settings)
         self.acoustid_apikey_get.setObjectName("acoustid_apikey_get")
         self.horizontalLayout.addWidget(self.acoustid_apikey_get)
         self.verticalLayout_2.addLayout(self.horizontalLayout)
diff --git a/picard/ui/ui_options_general.py b/picard/ui/ui_options_general.py
index 728732d38b..eb4aba6d83 100644
--- a/picard/ui/ui_options_general.py
+++ b/picard/ui/ui_options_general.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_general.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -20,33 +22,33 @@ def setupUi(self, GeneralOptionsPage):
         GeneralOptionsPage.setSizePolicy(sizePolicy)
         self.vboxlayout = QtWidgets.QVBoxLayout(GeneralOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.groupBox = QtWidgets.QGroupBox(GeneralOptionsPage)
+        self.groupBox = QtWidgets.QGroupBox(parent=GeneralOptionsPage)
         self.groupBox.setObjectName("groupBox")
         self.gridlayout = QtWidgets.QGridLayout(self.groupBox)
         self.gridlayout.setSpacing(2)
         self.gridlayout.setObjectName("gridlayout")
-        self.server_port = QtWidgets.QSpinBox(self.groupBox)
+        self.server_port = QtWidgets.QSpinBox(parent=self.groupBox)
         self.server_port.setMinimum(1)
         self.server_port.setMaximum(65535)
         self.server_port.setProperty("value", 80)
         self.server_port.setObjectName("server_port")
         self.gridlayout.addWidget(self.server_port, 1, 1, 1, 1)
-        self.server_host_primary_warning = QtWidgets.QFrame(self.groupBox)
+        self.server_host_primary_warning = QtWidgets.QFrame(parent=self.groupBox)
         self.server_host_primary_warning.setStyleSheet("QFrame { background-color: #ffc107; color: black }\n"
 "QCheckBox { color: black }")
         self.server_host_primary_warning.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
         self.server_host_primary_warning.setObjectName("server_host_primary_warning")
         self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.server_host_primary_warning)
         self.verticalLayout_4.setObjectName("verticalLayout_4")
-        self.label_4 = QtWidgets.QLabel(self.server_host_primary_warning)
+        self.label_4 = QtWidgets.QLabel(parent=self.server_host_primary_warning)
         self.label_4.setWordWrap(True)
         self.label_4.setObjectName("label_4")
         self.verticalLayout_4.addWidget(self.label_4)
-        self.use_server_for_submission = QtWidgets.QCheckBox(self.server_host_primary_warning)
+        self.use_server_for_submission = QtWidgets.QCheckBox(parent=self.server_host_primary_warning)
         self.use_server_for_submission.setObjectName("use_server_for_submission")
         self.verticalLayout_4.addWidget(self.use_server_for_submission)
         self.gridlayout.addWidget(self.server_host_primary_warning, 3, 0, 1, 2)
-        self.server_host = QtWidgets.QComboBox(self.groupBox)
+        self.server_host = QtWidgets.QComboBox(parent=self.groupBox)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -55,56 +57,56 @@ def setupUi(self, GeneralOptionsPage):
         self.server_host.setEditable(True)
         self.server_host.setObjectName("server_host")
         self.gridlayout.addWidget(self.server_host, 1, 0, 1, 1)
-        self.label_7 = QtWidgets.QLabel(self.groupBox)
+        self.label_7 = QtWidgets.QLabel(parent=self.groupBox)
         self.label_7.setObjectName("label_7")
         self.gridlayout.addWidget(self.label_7, 0, 1, 1, 1)
-        self.label = QtWidgets.QLabel(self.groupBox)
+        self.label = QtWidgets.QLabel(parent=self.groupBox)
         self.label.setObjectName("label")
         self.gridlayout.addWidget(self.label, 0, 0, 1, 1)
         spacerItem = QtWidgets.QSpacerItem(1, 4, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         self.gridlayout.addItem(spacerItem, 2, 0, 1, 1)
         self.vboxlayout.addWidget(self.groupBox)
-        self.rename_files_2 = QtWidgets.QGroupBox(GeneralOptionsPage)
+        self.rename_files_2 = QtWidgets.QGroupBox(parent=GeneralOptionsPage)
         self.rename_files_2.setObjectName("rename_files_2")
         self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.rename_files_2)
         self.verticalLayout_3.setSpacing(2)
         self.verticalLayout_3.setObjectName("verticalLayout_3")
-        self.login_error = QtWidgets.QLabel(self.rename_files_2)
+        self.login_error = QtWidgets.QLabel(parent=self.rename_files_2)
         self.login_error.setText("")
         self.login_error.setObjectName("login_error")
         self.verticalLayout_3.addWidget(self.login_error)
-        self.logged_in = QtWidgets.QLabel(self.rename_files_2)
+        self.logged_in = QtWidgets.QLabel(parent=self.rename_files_2)
         self.logged_in.setText("")
         self.logged_in.setObjectName("logged_in")
         self.verticalLayout_3.addWidget(self.logged_in)
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setSpacing(6)
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.login = QtWidgets.QPushButton(self.rename_files_2)
+        self.login = QtWidgets.QPushButton(parent=self.rename_files_2)
         self.login.setObjectName("login")
         self.horizontalLayout.addWidget(self.login)
-        self.logout = QtWidgets.QPushButton(self.rename_files_2)
+        self.logout = QtWidgets.QPushButton(parent=self.rename_files_2)
         self.logout.setObjectName("logout")
         self.horizontalLayout.addWidget(self.logout)
         spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout.addItem(spacerItem1)
         self.verticalLayout_3.addLayout(self.horizontalLayout)
         self.vboxlayout.addWidget(self.rename_files_2)
-        self.groupBox_2 = QtWidgets.QGroupBox(GeneralOptionsPage)
+        self.groupBox_2 = QtWidgets.QGroupBox(parent=GeneralOptionsPage)
         self.groupBox_2.setObjectName("groupBox_2")
         self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox_2)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.analyze_new_files = QtWidgets.QCheckBox(self.groupBox_2)
+        self.analyze_new_files = QtWidgets.QCheckBox(parent=self.groupBox_2)
         self.analyze_new_files.setObjectName("analyze_new_files")
         self.verticalLayout.addWidget(self.analyze_new_files)
-        self.cluster_new_files = QtWidgets.QCheckBox(self.groupBox_2)
+        self.cluster_new_files = QtWidgets.QCheckBox(parent=self.groupBox_2)
         self.cluster_new_files.setObjectName("cluster_new_files")
         self.verticalLayout.addWidget(self.cluster_new_files)
-        self.ignore_file_mbids = QtWidgets.QCheckBox(self.groupBox_2)
+        self.ignore_file_mbids = QtWidgets.QCheckBox(parent=self.groupBox_2)
         self.ignore_file_mbids.setObjectName("ignore_file_mbids")
         self.verticalLayout.addWidget(self.ignore_file_mbids)
         self.vboxlayout.addWidget(self.groupBox_2)
-        self.update_check_groupbox = QtWidgets.QGroupBox(GeneralOptionsPage)
+        self.update_check_groupbox = QtWidgets.QGroupBox(parent=GeneralOptionsPage)
         self.update_check_groupbox.setEnabled(True)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
@@ -114,22 +116,22 @@ def setupUi(self, GeneralOptionsPage):
         self.update_check_groupbox.setObjectName("update_check_groupbox")
         self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.update_check_groupbox)
         self.verticalLayout_2.setObjectName("verticalLayout_2")
-        self.check_for_plugin_updates = QtWidgets.QCheckBox(self.update_check_groupbox)
+        self.check_for_plugin_updates = QtWidgets.QCheckBox(parent=self.update_check_groupbox)
         self.check_for_plugin_updates.setObjectName("check_for_plugin_updates")
         self.verticalLayout_2.addWidget(self.check_for_plugin_updates)
-        self.program_update_check_group = QtWidgets.QWidget(self.update_check_groupbox)
+        self.program_update_check_group = QtWidgets.QWidget(parent=self.update_check_groupbox)
         self.program_update_check_group.setMinimumSize(QtCore.QSize(0, 0))
         self.program_update_check_group.setObjectName("program_update_check_group")
         self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.program_update_check_group)
         self.verticalLayout_6.setContentsMargins(0, 0, 0, 0)
         self.verticalLayout_6.setObjectName("verticalLayout_6")
-        self.check_for_updates = QtWidgets.QCheckBox(self.program_update_check_group)
+        self.check_for_updates = QtWidgets.QCheckBox(parent=self.program_update_check_group)
         self.check_for_updates.setObjectName("check_for_updates")
         self.verticalLayout_6.addWidget(self.check_for_updates)
         self.gridLayout = QtWidgets.QGridLayout()
         self.gridLayout.setContentsMargins(-1, -1, -1, 0)
         self.gridLayout.setObjectName("gridLayout")
-        self.label_2 = QtWidgets.QLabel(self.program_update_check_group)
+        self.label_2 = QtWidgets.QLabel(parent=self.program_update_check_group)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -137,7 +139,7 @@ def setupUi(self, GeneralOptionsPage):
         self.label_2.setSizePolicy(sizePolicy)
         self.label_2.setObjectName("label_2")
         self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1)
-        self.update_check_days = QtWidgets.QSpinBox(self.program_update_check_group)
+        self.update_check_days = QtWidgets.QSpinBox(parent=self.program_update_check_group)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -150,10 +152,10 @@ def setupUi(self, GeneralOptionsPage):
         self.gridLayout_2 = QtWidgets.QGridLayout()
         self.gridLayout_2.setContentsMargins(-1, -1, -1, 0)
         self.gridLayout_2.setObjectName("gridLayout_2")
-        self.label_3 = QtWidgets.QLabel(self.program_update_check_group)
+        self.label_3 = QtWidgets.QLabel(parent=self.program_update_check_group)
         self.label_3.setObjectName("label_3")
         self.gridLayout_2.addWidget(self.label_3, 0, 0, 1, 1)
-        self.update_level = QtWidgets.QComboBox(self.program_update_check_group)
+        self.update_level = QtWidgets.QComboBox(parent=self.program_update_check_group)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -165,7 +167,7 @@ def setupUi(self, GeneralOptionsPage):
         self.gridLayout.addLayout(self.gridLayout_2, 1, 0, 1, 1)
         self.verticalLayout_6.addLayout(self.gridLayout)
         self.verticalLayout_2.addWidget(self.program_update_check_group)
-        self.program_update_check_frame = QtWidgets.QFrame(self.update_check_groupbox)
+        self.program_update_check_frame = QtWidgets.QFrame(parent=self.update_check_groupbox)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
diff --git a/picard/ui/ui_options_genres.py b/picard/ui/ui_options_genres.py
index 5218eb53b7..a24741f5e0 100644
--- a/picard/ui/ui_options_genres.py
+++ b/picard/ui/ui_options_genres.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_genres.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,27 +17,27 @@ def setupUi(self, GenresOptionsPage):
         GenresOptionsPage.resize(590, 471)
         self.verticalLayout_2 = QtWidgets.QVBoxLayout(GenresOptionsPage)
         self.verticalLayout_2.setObjectName("verticalLayout_2")
-        self.use_genres = QtWidgets.QGroupBox(GenresOptionsPage)
+        self.use_genres = QtWidgets.QGroupBox(parent=GenresOptionsPage)
         self.use_genres.setFlat(False)
         self.use_genres.setCheckable(True)
         self.use_genres.setChecked(False)
         self.use_genres.setObjectName("use_genres")
         self.verticalLayout = QtWidgets.QVBoxLayout(self.use_genres)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.only_my_genres = QtWidgets.QCheckBox(self.use_genres)
+        self.only_my_genres = QtWidgets.QCheckBox(parent=self.use_genres)
         self.only_my_genres.setObjectName("only_my_genres")
         self.verticalLayout.addWidget(self.only_my_genres)
-        self.artists_genres = QtWidgets.QCheckBox(self.use_genres)
+        self.artists_genres = QtWidgets.QCheckBox(parent=self.use_genres)
         self.artists_genres.setObjectName("artists_genres")
         self.verticalLayout.addWidget(self.artists_genres)
-        self.folksonomy_tags = QtWidgets.QCheckBox(self.use_genres)
+        self.folksonomy_tags = QtWidgets.QCheckBox(parent=self.use_genres)
         self.folksonomy_tags.setObjectName("folksonomy_tags")
         self.verticalLayout.addWidget(self.folksonomy_tags)
         self.hboxlayout = QtWidgets.QHBoxLayout()
         self.hboxlayout.setContentsMargins(0, 0, 0, 0)
         self.hboxlayout.setSpacing(6)
         self.hboxlayout.setObjectName("hboxlayout")
-        self.label_5 = QtWidgets.QLabel(self.use_genres)
+        self.label_5 = QtWidgets.QLabel(parent=self.use_genres)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -43,7 +45,7 @@ def setupUi(self, GenresOptionsPage):
         self.label_5.setSizePolicy(sizePolicy)
         self.label_5.setObjectName("label_5")
         self.hboxlayout.addWidget(self.label_5)
-        self.min_genre_usage = QtWidgets.QSpinBox(self.use_genres)
+        self.min_genre_usage = QtWidgets.QSpinBox(parent=self.use_genres)
         self.min_genre_usage.setMaximum(100)
         self.min_genre_usage.setObjectName("min_genre_usage")
         self.hboxlayout.addWidget(self.min_genre_usage)
@@ -52,7 +54,7 @@ def setupUi(self, GenresOptionsPage):
         self.hboxlayout1.setContentsMargins(0, 0, 0, 0)
         self.hboxlayout1.setSpacing(6)
         self.hboxlayout1.setObjectName("hboxlayout1")
-        self.label_6 = QtWidgets.QLabel(self.use_genres)
+        self.label_6 = QtWidgets.QLabel(parent=self.use_genres)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -60,7 +62,7 @@ def setupUi(self, GenresOptionsPage):
         self.label_6.setSizePolicy(sizePolicy)
         self.label_6.setObjectName("label_6")
         self.hboxlayout1.addWidget(self.label_6)
-        self.max_genres = QtWidgets.QSpinBox(self.use_genres)
+        self.max_genres = QtWidgets.QSpinBox(parent=self.use_genres)
         self.max_genres.setMaximum(100)
         self.max_genres.setObjectName("max_genres")
         self.hboxlayout1.addWidget(self.max_genres)
@@ -69,7 +71,7 @@ def setupUi(self, GenresOptionsPage):
         self.hboxlayout2.setContentsMargins(0, 0, 0, 0)
         self.hboxlayout2.setSpacing(6)
         self.hboxlayout2.setObjectName("hboxlayout2")
-        self.ignore_genres_4 = QtWidgets.QLabel(self.use_genres)
+        self.ignore_genres_4 = QtWidgets.QLabel(parent=self.use_genres)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(4)
         sizePolicy.setVerticalStretch(0)
@@ -77,7 +79,7 @@ def setupUi(self, GenresOptionsPage):
         self.ignore_genres_4.setSizePolicy(sizePolicy)
         self.ignore_genres_4.setObjectName("ignore_genres_4")
         self.hboxlayout2.addWidget(self.ignore_genres_4)
-        self.join_genres = QtWidgets.QComboBox(self.use_genres)
+        self.join_genres = QtWidgets.QComboBox(parent=self.use_genres)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(1)
         sizePolicy.setVerticalStretch(0)
@@ -91,19 +93,19 @@ def setupUi(self, GenresOptionsPage):
         self.join_genres.addItem("")
         self.hboxlayout2.addWidget(self.join_genres)
         self.verticalLayout.addLayout(self.hboxlayout2)
-        self.label_genres_filter = QtWidgets.QLabel(self.use_genres)
+        self.label_genres_filter = QtWidgets.QLabel(parent=self.use_genres)
         self.label_genres_filter.setObjectName("label_genres_filter")
         self.verticalLayout.addWidget(self.label_genres_filter)
-        self.genres_filter = QtWidgets.QPlainTextEdit(self.use_genres)
+        self.genres_filter = QtWidgets.QPlainTextEdit(parent=self.use_genres)
         self.genres_filter.setObjectName("genres_filter")
         self.verticalLayout.addWidget(self.genres_filter)
-        self.label_test_genres_filter = QtWidgets.QLabel(self.use_genres)
+        self.label_test_genres_filter = QtWidgets.QLabel(parent=self.use_genres)
         self.label_test_genres_filter.setObjectName("label_test_genres_filter")
         self.verticalLayout.addWidget(self.label_test_genres_filter)
-        self.test_genres_filter = QtWidgets.QPlainTextEdit(self.use_genres)
+        self.test_genres_filter = QtWidgets.QPlainTextEdit(parent=self.use_genres)
         self.test_genres_filter.setObjectName("test_genres_filter")
         self.verticalLayout.addWidget(self.test_genres_filter)
-        self.label_test_genres_filter_error = QtWidgets.QLabel(self.use_genres)
+        self.label_test_genres_filter_error = QtWidgets.QLabel(parent=self.use_genres)
         self.label_test_genres_filter_error.setText("")
         self.label_test_genres_filter_error.setObjectName("label_test_genres_filter_error")
         self.verticalLayout.addWidget(self.label_test_genres_filter_error)
diff --git a/picard/ui/ui_options_interface.py b/picard/ui/ui_options_interface.py
index c7b2b3f06f..3d4a077d84 100644
--- a/picard/ui/ui_options_interface.py
+++ b/picard/ui/ui_options_interface.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_interface.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,80 +17,80 @@ def setupUi(self, InterfaceOptionsPage):
         InterfaceOptionsPage.resize(466, 543)
         self.vboxlayout = QtWidgets.QVBoxLayout(InterfaceOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.groupBox = QtWidgets.QGroupBox(InterfaceOptionsPage)
+        self.groupBox = QtWidgets.QGroupBox(parent=InterfaceOptionsPage)
         self.groupBox.setObjectName("groupBox")
         self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox)
         self.verticalLayout_3.setObjectName("verticalLayout_3")
-        self.toolbar_show_labels = QtWidgets.QCheckBox(self.groupBox)
+        self.toolbar_show_labels = QtWidgets.QCheckBox(parent=self.groupBox)
         self.toolbar_show_labels.setObjectName("toolbar_show_labels")
         self.verticalLayout_3.addWidget(self.toolbar_show_labels)
-        self.show_menu_icons = QtWidgets.QCheckBox(self.groupBox)
+        self.show_menu_icons = QtWidgets.QCheckBox(parent=self.groupBox)
         self.show_menu_icons.setObjectName("show_menu_icons")
         self.verticalLayout_3.addWidget(self.show_menu_icons)
-        self.label = QtWidgets.QLabel(self.groupBox)
+        self.label = QtWidgets.QLabel(parent=self.groupBox)
         self.label.setObjectName("label")
         self.verticalLayout_3.addWidget(self.label)
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.ui_language = QtWidgets.QComboBox(self.groupBox)
+        self.ui_language = QtWidgets.QComboBox(parent=self.groupBox)
         self.ui_language.setObjectName("ui_language")
         self.horizontalLayout.addWidget(self.ui_language)
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout.addItem(spacerItem)
         self.verticalLayout_3.addLayout(self.horizontalLayout)
-        self.label_theme = QtWidgets.QLabel(self.groupBox)
+        self.label_theme = QtWidgets.QLabel(parent=self.groupBox)
         self.label_theme.setObjectName("label_theme")
         self.verticalLayout_3.addWidget(self.label_theme)
         self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.ui_theme = QtWidgets.QComboBox(self.groupBox)
+        self.ui_theme = QtWidgets.QComboBox(parent=self.groupBox)
         self.ui_theme.setObjectName("ui_theme")
         self.horizontalLayout_2.addWidget(self.ui_theme)
         spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout_2.addItem(spacerItem1)
         self.verticalLayout_3.addLayout(self.horizontalLayout_2)
         self.vboxlayout.addWidget(self.groupBox)
-        self.miscellaneous_box = QtWidgets.QGroupBox(InterfaceOptionsPage)
+        self.miscellaneous_box = QtWidgets.QGroupBox(parent=InterfaceOptionsPage)
         self.miscellaneous_box.setObjectName("miscellaneous_box")
         self.vboxlayout1 = QtWidgets.QVBoxLayout(self.miscellaneous_box)
         self.vboxlayout1.setObjectName("vboxlayout1")
-        self.allow_multi_dirs_selection = QtWidgets.QCheckBox(self.miscellaneous_box)
+        self.allow_multi_dirs_selection = QtWidgets.QCheckBox(parent=self.miscellaneous_box)
         self.allow_multi_dirs_selection.setObjectName("allow_multi_dirs_selection")
         self.vboxlayout1.addWidget(self.allow_multi_dirs_selection)
-        self.builtin_search = QtWidgets.QCheckBox(self.miscellaneous_box)
+        self.builtin_search = QtWidgets.QCheckBox(parent=self.miscellaneous_box)
         self.builtin_search.setObjectName("builtin_search")
         self.vboxlayout1.addWidget(self.builtin_search)
-        self.use_adv_search_syntax = QtWidgets.QCheckBox(self.miscellaneous_box)
+        self.use_adv_search_syntax = QtWidgets.QCheckBox(parent=self.miscellaneous_box)
         self.use_adv_search_syntax.setObjectName("use_adv_search_syntax")
         self.vboxlayout1.addWidget(self.use_adv_search_syntax)
-        self.new_user_dialog = QtWidgets.QCheckBox(self.miscellaneous_box)
+        self.new_user_dialog = QtWidgets.QCheckBox(parent=self.miscellaneous_box)
         self.new_user_dialog.setObjectName("new_user_dialog")
         self.vboxlayout1.addWidget(self.new_user_dialog)
-        self.quit_confirmation = QtWidgets.QCheckBox(self.miscellaneous_box)
+        self.quit_confirmation = QtWidgets.QCheckBox(parent=self.miscellaneous_box)
         self.quit_confirmation.setObjectName("quit_confirmation")
         self.vboxlayout1.addWidget(self.quit_confirmation)
-        self.file_save_warning = QtWidgets.QCheckBox(self.miscellaneous_box)
+        self.file_save_warning = QtWidgets.QCheckBox(parent=self.miscellaneous_box)
         self.file_save_warning.setObjectName("file_save_warning")
         self.vboxlayout1.addWidget(self.file_save_warning)
-        self.filebrowser_horizontal_autoscroll = QtWidgets.QCheckBox(self.miscellaneous_box)
+        self.filebrowser_horizontal_autoscroll = QtWidgets.QCheckBox(parent=self.miscellaneous_box)
         self.filebrowser_horizontal_autoscroll.setObjectName("filebrowser_horizontal_autoscroll")
         self.vboxlayout1.addWidget(self.filebrowser_horizontal_autoscroll)
-        self.starting_directory = QtWidgets.QCheckBox(self.miscellaneous_box)
+        self.starting_directory = QtWidgets.QCheckBox(parent=self.miscellaneous_box)
         self.starting_directory.setObjectName("starting_directory")
         self.vboxlayout1.addWidget(self.starting_directory)
         self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_4.setSpacing(2)
         self.horizontalLayout_4.setObjectName("horizontalLayout_4")
-        self.starting_directory_path = QtWidgets.QLineEdit(self.miscellaneous_box)
+        self.starting_directory_path = QtWidgets.QLineEdit(parent=self.miscellaneous_box)
         self.starting_directory_path.setEnabled(False)
         self.starting_directory_path.setObjectName("starting_directory_path")
         self.horizontalLayout_4.addWidget(self.starting_directory_path)
-        self.starting_directory_browse = QtWidgets.QPushButton(self.miscellaneous_box)
+        self.starting_directory_browse = QtWidgets.QPushButton(parent=self.miscellaneous_box)
         self.starting_directory_browse.setEnabled(False)
         self.starting_directory_browse.setObjectName("starting_directory_browse")
         self.horizontalLayout_4.addWidget(self.starting_directory_browse)
         self.vboxlayout1.addLayout(self.horizontalLayout_4)
-        self.ui_theme_container = QtWidgets.QWidget(self.miscellaneous_box)
+        self.ui_theme_container = QtWidgets.QWidget(parent=self.miscellaneous_box)
         self.ui_theme_container.setEnabled(True)
         self.ui_theme_container.setObjectName("ui_theme_container")
         self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.ui_theme_container)
diff --git a/picard/ui/ui_options_interface_colors.py b/picard/ui/ui_options_interface_colors.py
index ba81199421..dd45202a0a 100644
--- a/picard/ui/ui_options_interface_colors.py
+++ b/picard/ui/ui_options_interface_colors.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_interface_colors.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -17,7 +19,7 @@ def setupUi(self, InterfaceColorsOptionsPage):
         self.vboxlayout.setContentsMargins(0, 0, 0, 0)
         self.vboxlayout.setSpacing(6)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.scrollArea = QtWidgets.QScrollArea(InterfaceColorsOptionsPage)
+        self.scrollArea = QtWidgets.QScrollArea(parent=InterfaceColorsOptionsPage)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -37,7 +39,7 @@ def setupUi(self, InterfaceColorsOptionsPage):
         self.verticalLayout.setContentsMargins(9, 9, 9, 9)
         self.verticalLayout.setSpacing(6)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.colors = QtWidgets.QGroupBox(self.scrollAreaWidgetContents)
+        self.colors = QtWidgets.QGroupBox(parent=self.scrollAreaWidgetContents)
         self.colors.setObjectName("colors")
         self.verticalLayout.addWidget(self.colors)
         self.scrollArea.setWidget(self.scrollAreaWidgetContents)
diff --git a/picard/ui/ui_options_interface_toolbar.py b/picard/ui/ui_options_interface_toolbar.py
index bde15cd3bb..7259328f7f 100644
--- a/picard/ui/ui_options_interface_toolbar.py
+++ b/picard/ui/ui_options_interface_toolbar.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_interface_toolbar.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,7 +17,7 @@ def setupUi(self, InterfaceToolbarOptionsPage):
         InterfaceToolbarOptionsPage.resize(466, 317)
         self.vboxlayout = QtWidgets.QVBoxLayout(InterfaceToolbarOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.customize_toolbar_box = QtWidgets.QGroupBox(InterfaceToolbarOptionsPage)
+        self.customize_toolbar_box = QtWidgets.QGroupBox(parent=InterfaceToolbarOptionsPage)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -24,7 +26,7 @@ def setupUi(self, InterfaceToolbarOptionsPage):
         self.customize_toolbar_box.setObjectName("customize_toolbar_box")
         self.verticalLayout = QtWidgets.QVBoxLayout(self.customize_toolbar_box)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.toolbar_layout_list = QtWidgets.QListWidget(self.customize_toolbar_box)
+        self.toolbar_layout_list = QtWidgets.QListWidget(parent=self.customize_toolbar_box)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -32,30 +34,30 @@ def setupUi(self, InterfaceToolbarOptionsPage):
         self.toolbar_layout_list.setSizePolicy(sizePolicy)
         self.toolbar_layout_list.setObjectName("toolbar_layout_list")
         self.verticalLayout.addWidget(self.toolbar_layout_list)
-        self.edit_button_box = QtWidgets.QWidget(self.customize_toolbar_box)
+        self.edit_button_box = QtWidgets.QWidget(parent=self.customize_toolbar_box)
         self.edit_button_box.setObjectName("edit_button_box")
         self.edit_box_layout = QtWidgets.QHBoxLayout(self.edit_button_box)
         self.edit_box_layout.setContentsMargins(0, 0, 0, 0)
         self.edit_box_layout.setObjectName("edit_box_layout")
-        self.add_button = QtWidgets.QToolButton(self.edit_button_box)
+        self.add_button = QtWidgets.QToolButton(parent=self.edit_button_box)
         self.add_button.setObjectName("add_button")
         self.edit_box_layout.addWidget(self.add_button)
-        self.insert_separator_button = QtWidgets.QToolButton(self.edit_button_box)
+        self.insert_separator_button = QtWidgets.QToolButton(parent=self.edit_button_box)
         self.insert_separator_button.setObjectName("insert_separator_button")
         self.edit_box_layout.addWidget(self.insert_separator_button)
         spacerItem = QtWidgets.QSpacerItem(50, 20, QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.edit_box_layout.addItem(spacerItem)
-        self.up_button = QtWidgets.QToolButton(self.edit_button_box)
+        self.up_button = QtWidgets.QToolButton(parent=self.edit_button_box)
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-up.png")
         self.up_button.setIcon(icon)
         self.up_button.setObjectName("up_button")
         self.edit_box_layout.addWidget(self.up_button)
-        self.down_button = QtWidgets.QToolButton(self.edit_button_box)
+        self.down_button = QtWidgets.QToolButton(parent=self.edit_button_box)
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-down.png")
         self.down_button.setIcon(icon)
         self.down_button.setObjectName("down_button")
         self.edit_box_layout.addWidget(self.down_button)
-        self.remove_button = QtWidgets.QToolButton(self.edit_button_box)
+        self.remove_button = QtWidgets.QToolButton(parent=self.edit_button_box)
         self.remove_button.setObjectName("remove_button")
         self.edit_box_layout.addWidget(self.remove_button)
         self.verticalLayout.addWidget(self.edit_button_box)
diff --git a/picard/ui/ui_options_interface_top_tags.py b/picard/ui/ui_options_interface_top_tags.py
index 00bb6d94e0..8d248f55c8 100644
--- a/picard/ui/ui_options_interface_top_tags.py
+++ b/picard/ui/ui_options_interface_top_tags.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_interface_top_tags.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -17,11 +19,11 @@ def setupUi(self, InterfaceTopTagsOptionsPage):
         self.vboxlayout.setContentsMargins(9, 9, 9, 9)
         self.vboxlayout.setSpacing(6)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.top_tags_groupBox = QtWidgets.QGroupBox(InterfaceTopTagsOptionsPage)
+        self.top_tags_groupBox = QtWidgets.QGroupBox(parent=InterfaceTopTagsOptionsPage)
         self.top_tags_groupBox.setObjectName("top_tags_groupBox")
         self.verticalLayout = QtWidgets.QVBoxLayout(self.top_tags_groupBox)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.top_tags_list = TagListEditor(self.top_tags_groupBox)
+        self.top_tags_list = TagListEditor(parent=self.top_tags_groupBox)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
diff --git a/picard/ui/ui_options_maintenance.py b/picard/ui/ui_options_maintenance.py
index 96195fd457..6bfab728f6 100644
--- a/picard/ui/ui_options_maintenance.py
+++ b/picard/ui/ui_options_maintenance.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_maintenance.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,17 +17,17 @@ def setupUi(self, MaintenanceOptionsPage):
         MaintenanceOptionsPage.resize(334, 397)
         self.vboxlayout = QtWidgets.QVBoxLayout(MaintenanceOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.label = QtWidgets.QLabel(MaintenanceOptionsPage)
+        self.label = QtWidgets.QLabel(parent=MaintenanceOptionsPage)
         self.label.setObjectName("label")
         self.vboxlayout.addWidget(self.label)
         self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_3.setContentsMargins(-1, -1, -1, 0)
         self.horizontalLayout_3.setObjectName("horizontalLayout_3")
-        self.config_file = QtWidgets.QLineEdit(MaintenanceOptionsPage)
+        self.config_file = QtWidgets.QLineEdit(parent=MaintenanceOptionsPage)
         self.config_file.setReadOnly(True)
         self.config_file.setObjectName("config_file")
         self.horizontalLayout_3.addWidget(self.config_file)
-        self.open_folder_button = QtWidgets.QToolButton(MaintenanceOptionsPage)
+        self.open_folder_button = QtWidgets.QToolButton(parent=MaintenanceOptionsPage)
         self.open_folder_button.setObjectName("open_folder_button")
         self.horizontalLayout_3.addWidget(self.open_folder_button)
         self.vboxlayout.addLayout(self.horizontalLayout_3)
@@ -34,14 +36,14 @@ def setupUi(self, MaintenanceOptionsPage):
         self.horizontalLayout.setObjectName("horizontalLayout")
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout.addItem(spacerItem)
-        self.load_backup_button = QtWidgets.QToolButton(MaintenanceOptionsPage)
+        self.load_backup_button = QtWidgets.QToolButton(parent=MaintenanceOptionsPage)
         self.load_backup_button.setObjectName("load_backup_button")
         self.horizontalLayout.addWidget(self.load_backup_button)
-        self.save_backup_button = QtWidgets.QToolButton(MaintenanceOptionsPage)
+        self.save_backup_button = QtWidgets.QToolButton(parent=MaintenanceOptionsPage)
         self.save_backup_button.setObjectName("save_backup_button")
         self.horizontalLayout.addWidget(self.save_backup_button)
         self.vboxlayout.addLayout(self.horizontalLayout)
-        self.option_counts = QtWidgets.QLabel(MaintenanceOptionsPage)
+        self.option_counts = QtWidgets.QLabel(parent=MaintenanceOptionsPage)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -50,10 +52,10 @@ def setupUi(self, MaintenanceOptionsPage):
         self.option_counts.setText("")
         self.option_counts.setObjectName("option_counts")
         self.vboxlayout.addWidget(self.option_counts)
-        self.enable_cleanup = QtWidgets.QCheckBox(MaintenanceOptionsPage)
+        self.enable_cleanup = QtWidgets.QCheckBox(parent=MaintenanceOptionsPage)
         self.enable_cleanup.setObjectName("enable_cleanup")
         self.vboxlayout.addWidget(self.enable_cleanup)
-        self.description = QtWidgets.QLabel(MaintenanceOptionsPage)
+        self.description = QtWidgets.QLabel(parent=MaintenanceOptionsPage)
         self.description.setText("")
         self.description.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
         self.description.setWordWrap(True)
@@ -62,15 +64,15 @@ def setupUi(self, MaintenanceOptionsPage):
         self.vboxlayout.addWidget(self.description)
         spacerItem1 = QtWidgets.QSpacerItem(20, 8, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         self.vboxlayout.addItem(spacerItem1)
-        self.line = QtWidgets.QFrame(MaintenanceOptionsPage)
+        self.line = QtWidgets.QFrame(parent=MaintenanceOptionsPage)
         self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine)
         self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
         self.line.setObjectName("line")
         self.vboxlayout.addWidget(self.line)
-        self.select_all = QtWidgets.QCheckBox(MaintenanceOptionsPage)
+        self.select_all = QtWidgets.QCheckBox(parent=MaintenanceOptionsPage)
         self.select_all.setObjectName("select_all")
         self.vboxlayout.addWidget(self.select_all)
-        self.tableWidget = QtWidgets.QTableWidget(MaintenanceOptionsPage)
+        self.tableWidget = QtWidgets.QTableWidget(parent=MaintenanceOptionsPage)
         self.tableWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents)
         self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
         self.tableWidget.setColumnCount(2)
diff --git a/picard/ui/ui_options_matching.py b/picard/ui/ui_options_matching.py
index 6b8eb6fa74..756ff7db53 100644
--- a/picard/ui/ui_options_matching.py
+++ b/picard/ui/ui_options_matching.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_matching.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,12 +17,12 @@ def setupUi(self, MatchingOptionsPage):
         MatchingOptionsPage.resize(413, 612)
         self.vboxlayout = QtWidgets.QVBoxLayout(MatchingOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.rename_files = QtWidgets.QGroupBox(MatchingOptionsPage)
+        self.rename_files = QtWidgets.QGroupBox(parent=MatchingOptionsPage)
         self.rename_files.setObjectName("rename_files")
         self.gridlayout = QtWidgets.QGridLayout(self.rename_files)
         self.gridlayout.setSpacing(2)
         self.gridlayout.setObjectName("gridlayout")
-        self.label_6 = QtWidgets.QLabel(self.rename_files)
+        self.label_6 = QtWidgets.QLabel(parent=self.rename_files)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -28,19 +30,19 @@ def setupUi(self, MatchingOptionsPage):
         self.label_6.setSizePolicy(sizePolicy)
         self.label_6.setObjectName("label_6")
         self.gridlayout.addWidget(self.label_6, 2, 0, 1, 1)
-        self.track_matching_threshold = QtWidgets.QSpinBox(self.rename_files)
+        self.track_matching_threshold = QtWidgets.QSpinBox(parent=self.rename_files)
         self.track_matching_threshold.setMaximum(100)
         self.track_matching_threshold.setObjectName("track_matching_threshold")
         self.gridlayout.addWidget(self.track_matching_threshold, 2, 1, 1, 1)
-        self.cluster_lookup_threshold = QtWidgets.QSpinBox(self.rename_files)
+        self.cluster_lookup_threshold = QtWidgets.QSpinBox(parent=self.rename_files)
         self.cluster_lookup_threshold.setMaximum(100)
         self.cluster_lookup_threshold.setObjectName("cluster_lookup_threshold")
         self.gridlayout.addWidget(self.cluster_lookup_threshold, 1, 1, 1, 1)
-        self.file_lookup_threshold = QtWidgets.QSpinBox(self.rename_files)
+        self.file_lookup_threshold = QtWidgets.QSpinBox(parent=self.rename_files)
         self.file_lookup_threshold.setMaximum(100)
         self.file_lookup_threshold.setObjectName("file_lookup_threshold")
         self.gridlayout.addWidget(self.file_lookup_threshold, 0, 1, 1, 1)
-        self.label_4 = QtWidgets.QLabel(self.rename_files)
+        self.label_4 = QtWidgets.QLabel(parent=self.rename_files)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -48,7 +50,7 @@ def setupUi(self, MatchingOptionsPage):
         self.label_4.setSizePolicy(sizePolicy)
         self.label_4.setObjectName("label_4")
         self.gridlayout.addWidget(self.label_4, 0, 0, 1, 1)
-        self.label_5 = QtWidgets.QLabel(self.rename_files)
+        self.label_5 = QtWidgets.QLabel(parent=self.rename_files)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
diff --git a/picard/ui/ui_options_metadata.py b/picard/ui/ui_options_metadata.py
index cd6cfe2a48..442739ac7d 100644
--- a/picard/ui/ui_options_metadata.py
+++ b/picard/ui/ui_options_metadata.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_metadata.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,7 +17,7 @@ def setupUi(self, MetadataOptionsPage):
         MetadataOptionsPage.resize(423, 553)
         self.verticalLayout = QtWidgets.QVBoxLayout(MetadataOptionsPage)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.metadata_groupbox = QtWidgets.QGroupBox(MetadataOptionsPage)
+        self.metadata_groupbox = QtWidgets.QGroupBox(parent=MetadataOptionsPage)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Maximum)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -26,54 +28,54 @@ def setupUi(self, MetadataOptionsPage):
         self.metadata_groupbox.setObjectName("metadata_groupbox")
         self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.metadata_groupbox)
         self.verticalLayout_3.setObjectName("verticalLayout_3")
-        self.translate_artist_names = QtWidgets.QCheckBox(self.metadata_groupbox)
+        self.translate_artist_names = QtWidgets.QCheckBox(parent=self.metadata_groupbox)
         self.translate_artist_names.setObjectName("translate_artist_names")
         self.verticalLayout_3.addWidget(self.translate_artist_names)
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setContentsMargins(-1, -1, -1, 0)
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.selected_locales = QtWidgets.QLineEdit(self.metadata_groupbox)
+        self.selected_locales = QtWidgets.QLineEdit(parent=self.metadata_groupbox)
         self.selected_locales.setReadOnly(True)
         self.selected_locales.setObjectName("selected_locales")
         self.horizontalLayout.addWidget(self.selected_locales)
-        self.select_locales = QtWidgets.QPushButton(self.metadata_groupbox)
+        self.select_locales = QtWidgets.QPushButton(parent=self.metadata_groupbox)
         self.select_locales.setObjectName("select_locales")
         self.horizontalLayout.addWidget(self.select_locales)
         self.verticalLayout_3.addLayout(self.horizontalLayout)
-        self.translate_artist_names_script_exception = QtWidgets.QCheckBox(self.metadata_groupbox)
+        self.translate_artist_names_script_exception = QtWidgets.QCheckBox(parent=self.metadata_groupbox)
         self.translate_artist_names_script_exception.setObjectName("translate_artist_names_script_exception")
         self.verticalLayout_3.addWidget(self.translate_artist_names_script_exception)
         self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_4.setContentsMargins(-1, -1, -1, 0)
         self.horizontalLayout_4.setObjectName("horizontalLayout_4")
-        self.selected_scripts = QtWidgets.QLineEdit(self.metadata_groupbox)
+        self.selected_scripts = QtWidgets.QLineEdit(parent=self.metadata_groupbox)
         self.selected_scripts.setReadOnly(True)
         self.selected_scripts.setObjectName("selected_scripts")
         self.horizontalLayout_4.addWidget(self.selected_scripts)
-        self.select_scripts = QtWidgets.QPushButton(self.metadata_groupbox)
+        self.select_scripts = QtWidgets.QPushButton(parent=self.metadata_groupbox)
         self.select_scripts.setObjectName("select_scripts")
         self.horizontalLayout_4.addWidget(self.select_scripts)
         self.verticalLayout_3.addLayout(self.horizontalLayout_4)
-        self.standardize_artists = QtWidgets.QCheckBox(self.metadata_groupbox)
+        self.standardize_artists = QtWidgets.QCheckBox(parent=self.metadata_groupbox)
         self.standardize_artists.setObjectName("standardize_artists")
         self.verticalLayout_3.addWidget(self.standardize_artists)
-        self.standardize_instruments = QtWidgets.QCheckBox(self.metadata_groupbox)
+        self.standardize_instruments = QtWidgets.QCheckBox(parent=self.metadata_groupbox)
         self.standardize_instruments.setObjectName("standardize_instruments")
         self.verticalLayout_3.addWidget(self.standardize_instruments)
-        self.convert_punctuation = QtWidgets.QCheckBox(self.metadata_groupbox)
+        self.convert_punctuation = QtWidgets.QCheckBox(parent=self.metadata_groupbox)
         self.convert_punctuation.setObjectName("convert_punctuation")
         self.verticalLayout_3.addWidget(self.convert_punctuation)
-        self.release_ars = QtWidgets.QCheckBox(self.metadata_groupbox)
+        self.release_ars = QtWidgets.QCheckBox(parent=self.metadata_groupbox)
         self.release_ars.setObjectName("release_ars")
         self.verticalLayout_3.addWidget(self.release_ars)
-        self.track_ars = QtWidgets.QCheckBox(self.metadata_groupbox)
+        self.track_ars = QtWidgets.QCheckBox(parent=self.metadata_groupbox)
         self.track_ars.setObjectName("track_ars")
         self.verticalLayout_3.addWidget(self.track_ars)
-        self.guess_tracknumber_and_title = QtWidgets.QCheckBox(self.metadata_groupbox)
+        self.guess_tracknumber_and_title = QtWidgets.QCheckBox(parent=self.metadata_groupbox)
         self.guess_tracknumber_and_title.setObjectName("guess_tracknumber_and_title")
         self.verticalLayout_3.addWidget(self.guess_tracknumber_and_title)
         self.verticalLayout.addWidget(self.metadata_groupbox)
-        self.custom_fields_groupbox = QtWidgets.QGroupBox(MetadataOptionsPage)
+        self.custom_fields_groupbox = QtWidgets.QGroupBox(parent=MetadataOptionsPage)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Maximum)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -84,22 +86,22 @@ def setupUi(self, MetadataOptionsPage):
         self.gridlayout = QtWidgets.QGridLayout(self.custom_fields_groupbox)
         self.gridlayout.setSpacing(2)
         self.gridlayout.setObjectName("gridlayout")
-        self.label_6 = QtWidgets.QLabel(self.custom_fields_groupbox)
+        self.label_6 = QtWidgets.QLabel(parent=self.custom_fields_groupbox)
         self.label_6.setObjectName("label_6")
         self.gridlayout.addWidget(self.label_6, 0, 0, 1, 2)
-        self.label_7 = QtWidgets.QLabel(self.custom_fields_groupbox)
+        self.label_7 = QtWidgets.QLabel(parent=self.custom_fields_groupbox)
         self.label_7.setObjectName("label_7")
         self.gridlayout.addWidget(self.label_7, 2, 0, 1, 2)
-        self.nat_name = QtWidgets.QLineEdit(self.custom_fields_groupbox)
+        self.nat_name = QtWidgets.QLineEdit(parent=self.custom_fields_groupbox)
         self.nat_name.setObjectName("nat_name")
         self.gridlayout.addWidget(self.nat_name, 3, 0, 1, 1)
-        self.nat_name_default = QtWidgets.QPushButton(self.custom_fields_groupbox)
+        self.nat_name_default = QtWidgets.QPushButton(parent=self.custom_fields_groupbox)
         self.nat_name_default.setObjectName("nat_name_default")
         self.gridlayout.addWidget(self.nat_name_default, 3, 1, 1, 1)
-        self.va_name_default = QtWidgets.QPushButton(self.custom_fields_groupbox)
+        self.va_name_default = QtWidgets.QPushButton(parent=self.custom_fields_groupbox)
         self.va_name_default.setObjectName("va_name_default")
         self.gridlayout.addWidget(self.va_name_default, 1, 1, 1, 1)
-        self.va_name = QtWidgets.QLineEdit(self.custom_fields_groupbox)
+        self.va_name = QtWidgets.QLineEdit(parent=self.custom_fields_groupbox)
         self.va_name.setObjectName("va_name")
         self.gridlayout.addWidget(self.va_name, 1, 0, 1, 1)
         self.verticalLayout.addWidget(self.custom_fields_groupbox)
diff --git a/picard/ui/ui_options_network.py b/picard/ui/ui_options_network.py
index 9927a25861..7b7b2cd9aa 100644
--- a/picard/ui/ui_options_network.py
+++ b/picard/ui/ui_options_network.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_network.ui'
 #
-# Created by: PyQt6 UI code generator 6.5.3
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_plugins.py b/picard/ui/ui_options_plugins.py
index e5a6b9d910..0c6e0aa303 100644
--- a/picard/ui/ui_options_plugins.py
+++ b/picard/ui/ui_options_plugins.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_plugins.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,17 +17,17 @@ def setupUi(self, PluginsOptionsPage):
         PluginsOptionsPage.resize(697, 441)
         self.vboxlayout = QtWidgets.QVBoxLayout(PluginsOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.plugins_container = QtWidgets.QSplitter(PluginsOptionsPage)
+        self.plugins_container = QtWidgets.QSplitter(parent=PluginsOptionsPage)
         self.plugins_container.setEnabled(True)
         self.plugins_container.setOrientation(QtCore.Qt.Orientation.Vertical)
         self.plugins_container.setHandleWidth(2)
         self.plugins_container.setObjectName("plugins_container")
-        self.groupBox_2 = QtWidgets.QGroupBox(self.plugins_container)
+        self.groupBox_2 = QtWidgets.QGroupBox(parent=self.plugins_container)
         self.groupBox_2.setObjectName("groupBox_2")
         self.vboxlayout1 = QtWidgets.QVBoxLayout(self.groupBox_2)
         self.vboxlayout1.setSpacing(2)
         self.vboxlayout1.setObjectName("vboxlayout1")
-        self.plugins = QtWidgets.QTreeWidget(self.groupBox_2)
+        self.plugins = QtWidgets.QTreeWidget(parent=self.groupBox_2)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -39,7 +41,7 @@ def setupUi(self, PluginsOptionsPage):
         self.vboxlayout1.addWidget(self.plugins)
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.install_plugin = QtWidgets.QPushButton(self.groupBox_2)
+        self.install_plugin = QtWidgets.QPushButton(parent=self.groupBox_2)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -47,7 +49,7 @@ def setupUi(self, PluginsOptionsPage):
         self.install_plugin.setSizePolicy(sizePolicy)
         self.install_plugin.setObjectName("install_plugin")
         self.horizontalLayout.addWidget(self.install_plugin)
-        self.folder_open = QtWidgets.QPushButton(self.groupBox_2)
+        self.folder_open = QtWidgets.QPushButton(parent=self.groupBox_2)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -55,7 +57,7 @@ def setupUi(self, PluginsOptionsPage):
         self.folder_open.setSizePolicy(sizePolicy)
         self.folder_open.setObjectName("folder_open")
         self.horizontalLayout.addWidget(self.folder_open)
-        self.reload_list_of_plugins = QtWidgets.QPushButton(self.groupBox_2)
+        self.reload_list_of_plugins = QtWidgets.QPushButton(parent=self.groupBox_2)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -64,7 +66,7 @@ def setupUi(self, PluginsOptionsPage):
         self.reload_list_of_plugins.setObjectName("reload_list_of_plugins")
         self.horizontalLayout.addWidget(self.reload_list_of_plugins)
         self.vboxlayout1.addLayout(self.horizontalLayout)
-        self.groupBox = QtWidgets.QGroupBox(self.plugins_container)
+        self.groupBox = QtWidgets.QGroupBox(parent=self.plugins_container)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -74,7 +76,7 @@ def setupUi(self, PluginsOptionsPage):
         self.vboxlayout2 = QtWidgets.QVBoxLayout(self.groupBox)
         self.vboxlayout2.setSpacing(0)
         self.vboxlayout2.setObjectName("vboxlayout2")
-        self.scrollArea = QtWidgets.QScrollArea(self.groupBox)
+        self.scrollArea = QtWidgets.QScrollArea(parent=self.groupBox)
         self.scrollArea.setEnabled(True)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
@@ -100,7 +102,7 @@ def setupUi(self, PluginsOptionsPage):
         self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetNoConstraint)
         self.verticalLayout.setContentsMargins(0, 0, 6, 0)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.details = QtWidgets.QLabel(self.scrollAreaWidgetContents)
+        self.details = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
diff --git a/picard/ui/ui_options_profiles.py b/picard/ui/ui_options_profiles.py
index 67b7aba918..e6c2b26735 100644
--- a/picard/ui/ui_options_profiles.py
+++ b/picard/ui/ui_options_profiles.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_profiles.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -17,12 +19,12 @@ def setupUi(self, ProfileEditorDialog):
         self.vboxlayout.setContentsMargins(9, 9, 9, 9)
         self.vboxlayout.setSpacing(6)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.option_profiles_groupbox = QtWidgets.QGroupBox(ProfileEditorDialog)
+        self.option_profiles_groupbox = QtWidgets.QGroupBox(parent=ProfileEditorDialog)
         self.option_profiles_groupbox.setCheckable(False)
         self.option_profiles_groupbox.setObjectName("option_profiles_groupbox")
         self.verticalLayout = QtWidgets.QVBoxLayout(self.option_profiles_groupbox)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.profile_editor_splitter = QtWidgets.QSplitter(self.option_profiles_groupbox)
+        self.profile_editor_splitter = QtWidgets.QSplitter(parent=self.option_profiles_groupbox)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -31,7 +33,7 @@ def setupUi(self, ProfileEditorDialog):
         self.profile_editor_splitter.setOrientation(QtCore.Qt.Orientation.Horizontal)
         self.profile_editor_splitter.setChildrenCollapsible(False)
         self.profile_editor_splitter.setObjectName("profile_editor_splitter")
-        self.profile_list = ProfileListWidget(self.profile_editor_splitter)
+        self.profile_list = ProfileListWidget(parent=self.profile_editor_splitter)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -39,7 +41,7 @@ def setupUi(self, ProfileEditorDialog):
         self.profile_list.setSizePolicy(sizePolicy)
         self.profile_list.setMinimumSize(QtCore.QSize(120, 0))
         self.profile_list.setObjectName("profile_list")
-        self.settings_tree = QtWidgets.QTreeWidget(self.profile_editor_splitter)
+        self.settings_tree = QtWidgets.QTreeWidget(parent=self.profile_editor_splitter)
         self.settings_tree.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.MultiSelection)
         self.settings_tree.setColumnCount(1)
         self.settings_tree.setObjectName("settings_tree")
@@ -49,17 +51,17 @@ def setupUi(self, ProfileEditorDialog):
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setContentsMargins(-1, 0, -1, -1)
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.move_up_button = QtWidgets.QToolButton(self.option_profiles_groupbox)
+        self.move_up_button = QtWidgets.QToolButton(parent=self.option_profiles_groupbox)
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-up.png")
         self.move_up_button.setIcon(icon)
         self.move_up_button.setObjectName("move_up_button")
         self.horizontalLayout.addWidget(self.move_up_button)
-        self.move_down_button = QtWidgets.QToolButton(self.option_profiles_groupbox)
+        self.move_down_button = QtWidgets.QToolButton(parent=self.option_profiles_groupbox)
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-down.png")
         self.move_down_button.setIcon(icon)
         self.move_down_button.setObjectName("move_down_button")
         self.horizontalLayout.addWidget(self.move_down_button)
-        self.profile_list_buttonbox = QtWidgets.QDialogButtonBox(self.option_profiles_groupbox)
+        self.profile_list_buttonbox = QtWidgets.QDialogButtonBox(parent=self.option_profiles_groupbox)
         self.profile_list_buttonbox.setMinimumSize(QtCore.QSize(0, 10))
         self.profile_list_buttonbox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.NoButton)
         self.profile_list_buttonbox.setObjectName("profile_list_buttonbox")
diff --git a/picard/ui/ui_options_ratings.py b/picard/ui/ui_options_ratings.py
index 3cf98edfe3..559f312c80 100644
--- a/picard/ui/ui_options_ratings.py
+++ b/picard/ui/ui_options_ratings.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_ratings.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,26 +17,26 @@ def setupUi(self, RatingsOptionsPage):
         RatingsOptionsPage.resize(397, 267)
         self.vboxlayout = QtWidgets.QVBoxLayout(RatingsOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.enable_ratings = QtWidgets.QGroupBox(RatingsOptionsPage)
+        self.enable_ratings = QtWidgets.QGroupBox(parent=RatingsOptionsPage)
         self.enable_ratings.setCheckable(True)
         self.enable_ratings.setChecked(True)
         self.enable_ratings.setObjectName("enable_ratings")
         self.vboxlayout1 = QtWidgets.QVBoxLayout(self.enable_ratings)
         self.vboxlayout1.setObjectName("vboxlayout1")
-        self.label = QtWidgets.QLabel(self.enable_ratings)
+        self.label = QtWidgets.QLabel(parent=self.enable_ratings)
         self.label.setWordWrap(True)
         self.label.setObjectName("label")
         self.vboxlayout1.addWidget(self.label)
-        self.ignore_tags_2 = QtWidgets.QLabel(self.enable_ratings)
+        self.ignore_tags_2 = QtWidgets.QLabel(parent=self.enable_ratings)
         self.ignore_tags_2.setEnabled(True)
         self.ignore_tags_2.setWordWrap(True)
         self.ignore_tags_2.setObjectName("ignore_tags_2")
         self.vboxlayout1.addWidget(self.ignore_tags_2)
-        self.rating_user_email = QtWidgets.QLineEdit(self.enable_ratings)
+        self.rating_user_email = QtWidgets.QLineEdit(parent=self.enable_ratings)
         self.rating_user_email.setReadOnly(False)
         self.rating_user_email.setObjectName("rating_user_email")
         self.vboxlayout1.addWidget(self.rating_user_email)
-        self.submit_ratings = QtWidgets.QCheckBox(self.enable_ratings)
+        self.submit_ratings = QtWidgets.QCheckBox(parent=self.enable_ratings)
         self.submit_ratings.setObjectName("submit_ratings")
         self.vboxlayout1.addWidget(self.submit_ratings)
         self.vboxlayout.addWidget(self.enable_ratings)
diff --git a/picard/ui/ui_options_releases.py b/picard/ui/ui_options_releases.py
index 3df458df87..5d3ab4bf9d 100644
--- a/picard/ui/ui_options_releases.py
+++ b/picard/ui/ui_options_releases.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_releases.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,18 +17,18 @@ def setupUi(self, ReleasesOptionsPage):
         ReleasesOptionsPage.resize(551, 497)
         self.verticalLayout_3 = QtWidgets.QVBoxLayout(ReleasesOptionsPage)
         self.verticalLayout_3.setObjectName("verticalLayout_3")
-        self.type_group = QtWidgets.QGroupBox(ReleasesOptionsPage)
+        self.type_group = QtWidgets.QGroupBox(parent=ReleasesOptionsPage)
         self.type_group.setObjectName("type_group")
         self.gridLayout = QtWidgets.QGridLayout(self.type_group)
         self.gridLayout.setVerticalSpacing(6)
         self.gridLayout.setObjectName("gridLayout")
         self.verticalLayout_3.addWidget(self.type_group)
-        self.country_group = QtWidgets.QGroupBox(ReleasesOptionsPage)
+        self.country_group = QtWidgets.QGroupBox(parent=ReleasesOptionsPage)
         self.country_group.setObjectName("country_group")
         self.horizontalLayout = QtWidgets.QHBoxLayout(self.country_group)
         self.horizontalLayout.setSpacing(4)
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.country_list = QtWidgets.QListWidget(self.country_group)
+        self.country_list = QtWidgets.QListWidget(parent=self.country_group)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -38,12 +40,12 @@ def setupUi(self, ReleasesOptionsPage):
         self.verticalLayout.setObjectName("verticalLayout")
         spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
         self.verticalLayout.addItem(spacerItem)
-        self.add_countries = QtWidgets.QPushButton(self.country_group)
+        self.add_countries = QtWidgets.QPushButton(parent=self.country_group)
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-next.png")
         self.add_countries.setIcon(icon)
         self.add_countries.setObjectName("add_countries")
         self.verticalLayout.addWidget(self.add_countries)
-        self.remove_countries = QtWidgets.QPushButton(self.country_group)
+        self.remove_countries = QtWidgets.QPushButton(parent=self.country_group)
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-previous.png")
         self.remove_countries.setIcon(icon)
         self.remove_countries.setObjectName("remove_countries")
@@ -51,7 +53,7 @@ def setupUi(self, ReleasesOptionsPage):
         spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
         self.verticalLayout.addItem(spacerItem1)
         self.horizontalLayout.addLayout(self.verticalLayout)
-        self.preferred_country_list = QtWidgets.QListWidget(self.country_group)
+        self.preferred_country_list = QtWidgets.QListWidget(parent=self.country_group)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -62,12 +64,12 @@ def setupUi(self, ReleasesOptionsPage):
         self.preferred_country_list.setObjectName("preferred_country_list")
         self.horizontalLayout.addWidget(self.preferred_country_list)
         self.verticalLayout_3.addWidget(self.country_group)
-        self.format_group = QtWidgets.QGroupBox(ReleasesOptionsPage)
+        self.format_group = QtWidgets.QGroupBox(parent=ReleasesOptionsPage)
         self.format_group.setObjectName("format_group")
         self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.format_group)
         self.horizontalLayout_2.setSpacing(4)
         self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.format_list = QtWidgets.QListWidget(self.format_group)
+        self.format_list = QtWidgets.QListWidget(parent=self.format_group)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -79,12 +81,12 @@ def setupUi(self, ReleasesOptionsPage):
         self.verticalLayout_2.setObjectName("verticalLayout_2")
         spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
         self.verticalLayout_2.addItem(spacerItem2)
-        self.add_formats = QtWidgets.QPushButton(self.format_group)
+        self.add_formats = QtWidgets.QPushButton(parent=self.format_group)
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-next.png")
         self.add_formats.setIcon(icon)
         self.add_formats.setObjectName("add_formats")
         self.verticalLayout_2.addWidget(self.add_formats)
-        self.remove_formats = QtWidgets.QPushButton(self.format_group)
+        self.remove_formats = QtWidgets.QPushButton(parent=self.format_group)
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-previous.png")
         self.remove_formats.setIcon(icon)
         self.remove_formats.setObjectName("remove_formats")
@@ -92,7 +94,7 @@ def setupUi(self, ReleasesOptionsPage):
         spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
         self.verticalLayout_2.addItem(spacerItem3)
         self.horizontalLayout_2.addLayout(self.verticalLayout_2)
-        self.preferred_format_list = QtWidgets.QListWidget(self.format_group)
+        self.preferred_format_list = QtWidgets.QListWidget(parent=self.format_group)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
diff --git a/picard/ui/ui_options_renaming.py b/picard/ui/ui_options_renaming.py
index 299e0a4cd4..98d64d84c0 100644
--- a/picard/ui/ui_options_renaming.py
+++ b/picard/ui/ui_options_renaming.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_renaming.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -21,46 +23,46 @@ def setupUi(self, RenamingOptionsPage):
         RenamingOptionsPage.setSizePolicy(sizePolicy)
         self.verticalLayout_5 = QtWidgets.QVBoxLayout(RenamingOptionsPage)
         self.verticalLayout_5.setObjectName("verticalLayout_5")
-        self.move_files = QtWidgets.QGroupBox(RenamingOptionsPage)
+        self.move_files = QtWidgets.QGroupBox(parent=RenamingOptionsPage)
         self.move_files.setFlat(False)
         self.move_files.setCheckable(True)
         self.move_files.setChecked(False)
         self.move_files.setObjectName("move_files")
         self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.move_files)
         self.verticalLayout_4.setObjectName("verticalLayout_4")
-        self.label = QtWidgets.QLabel(self.move_files)
+        self.label = QtWidgets.QLabel(parent=self.move_files)
         self.label.setObjectName("label")
         self.verticalLayout_4.addWidget(self.label)
         self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_4.setSpacing(2)
         self.horizontalLayout_4.setObjectName("horizontalLayout_4")
-        self.move_files_to = QtWidgets.QLineEdit(self.move_files)
+        self.move_files_to = QtWidgets.QLineEdit(parent=self.move_files)
         self.move_files_to.setObjectName("move_files_to")
         self.horizontalLayout_4.addWidget(self.move_files_to)
-        self.move_files_to_browse = QtWidgets.QPushButton(self.move_files)
+        self.move_files_to_browse = QtWidgets.QPushButton(parent=self.move_files)
         self.move_files_to_browse.setObjectName("move_files_to_browse")
         self.horizontalLayout_4.addWidget(self.move_files_to_browse)
         self.verticalLayout_4.addLayout(self.horizontalLayout_4)
-        self.move_additional_files = QtWidgets.QCheckBox(self.move_files)
+        self.move_additional_files = QtWidgets.QCheckBox(parent=self.move_files)
         self.move_additional_files.setObjectName("move_additional_files")
         self.verticalLayout_4.addWidget(self.move_additional_files)
-        self.move_additional_files_pattern = QtWidgets.QLineEdit(self.move_files)
+        self.move_additional_files_pattern = QtWidgets.QLineEdit(parent=self.move_files)
         self.move_additional_files_pattern.setObjectName("move_additional_files_pattern")
         self.verticalLayout_4.addWidget(self.move_additional_files_pattern)
-        self.delete_empty_dirs = QtWidgets.QCheckBox(self.move_files)
+        self.delete_empty_dirs = QtWidgets.QCheckBox(parent=self.move_files)
         self.delete_empty_dirs.setObjectName("delete_empty_dirs")
         self.verticalLayout_4.addWidget(self.delete_empty_dirs)
         self.verticalLayout_5.addWidget(self.move_files)
-        self.rename_files = QtWidgets.QCheckBox(RenamingOptionsPage)
+        self.rename_files = QtWidgets.QCheckBox(parent=RenamingOptionsPage)
         self.rename_files.setObjectName("rename_files")
         self.verticalLayout_5.addWidget(self.rename_files)
-        self.label_2 = QtWidgets.QLabel(RenamingOptionsPage)
+        self.label_2 = QtWidgets.QLabel(parent=RenamingOptionsPage)
         self.label_2.setObjectName("label_2")
         self.verticalLayout_5.addWidget(self.label_2)
         self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_2.setSpacing(2)
         self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.naming_script_selector = QtWidgets.QComboBox(RenamingOptionsPage)
+        self.naming_script_selector = QtWidgets.QComboBox(parent=RenamingOptionsPage)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -68,11 +70,11 @@ def setupUi(self, RenamingOptionsPage):
         self.naming_script_selector.setSizePolicy(sizePolicy)
         self.naming_script_selector.setObjectName("naming_script_selector")
         self.horizontalLayout_2.addWidget(self.naming_script_selector)
-        self.open_script_editor = QtWidgets.QPushButton(RenamingOptionsPage)
+        self.open_script_editor = QtWidgets.QPushButton(parent=RenamingOptionsPage)
         self.open_script_editor.setObjectName("open_script_editor")
         self.horizontalLayout_2.addWidget(self.open_script_editor)
         self.verticalLayout_5.addLayout(self.horizontalLayout_2)
-        self.groupBox = QtWidgets.QGroupBox(RenamingOptionsPage)
+        self.groupBox = QtWidgets.QGroupBox(parent=RenamingOptionsPage)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.MinimumExpanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -83,10 +85,10 @@ def setupUi(self, RenamingOptionsPage):
         self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.groupBox)
         self.verticalLayout_6.setContentsMargins(3, 3, 3, 3)
         self.verticalLayout_6.setObjectName("verticalLayout_6")
-        self.renaming_options_examples_splitter = QtWidgets.QSplitter(self.groupBox)
+        self.renaming_options_examples_splitter = QtWidgets.QSplitter(parent=self.groupBox)
         self.renaming_options_examples_splitter.setOrientation(QtCore.Qt.Orientation.Horizontal)
         self.renaming_options_examples_splitter.setObjectName("renaming_options_examples_splitter")
-        self.frame = QtWidgets.QFrame(self.renaming_options_examples_splitter)
+        self.frame = QtWidgets.QFrame(parent=self.renaming_options_examples_splitter)
         self.frame.setMinimumSize(QtCore.QSize(100, 0))
         self.frame.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
         self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
@@ -95,13 +97,13 @@ def setupUi(self, RenamingOptionsPage):
         self.verticalLayout.setContentsMargins(0, 0, 0, 0)
         self.verticalLayout.setSpacing(3)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.example_filename_before_label = QtWidgets.QLabel(self.frame)
+        self.example_filename_before_label = QtWidgets.QLabel(parent=self.frame)
         self.example_filename_before_label.setObjectName("example_filename_before_label")
         self.verticalLayout.addWidget(self.example_filename_before_label)
-        self.example_filename_before = QtWidgets.QListWidget(self.frame)
+        self.example_filename_before = QtWidgets.QListWidget(parent=self.frame)
         self.example_filename_before.setObjectName("example_filename_before")
         self.verticalLayout.addWidget(self.example_filename_before)
-        self.frame_2 = QtWidgets.QFrame(self.renaming_options_examples_splitter)
+        self.frame_2 = QtWidgets.QFrame(parent=self.renaming_options_examples_splitter)
         self.frame_2.setMinimumSize(QtCore.QSize(100, 0))
         self.frame_2.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
         self.frame_2.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
@@ -110,15 +112,15 @@ def setupUi(self, RenamingOptionsPage):
         self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
         self.verticalLayout_3.setSpacing(3)
         self.verticalLayout_3.setObjectName("verticalLayout_3")
-        self.example_filename_after_label = QtWidgets.QLabel(self.frame_2)
+        self.example_filename_after_label = QtWidgets.QLabel(parent=self.frame_2)
         self.example_filename_after_label.setObjectName("example_filename_after_label")
         self.verticalLayout_3.addWidget(self.example_filename_after_label)
-        self.example_filename_after = QtWidgets.QListWidget(self.frame_2)
+        self.example_filename_after = QtWidgets.QListWidget(parent=self.frame_2)
         self.example_filename_after.setObjectName("example_filename_after")
         self.verticalLayout_3.addWidget(self.example_filename_after)
         self.verticalLayout_6.addWidget(self.renaming_options_examples_splitter)
         self.verticalLayout_5.addWidget(self.groupBox)
-        self.example_selection_note = QtWidgets.QLabel(RenamingOptionsPage)
+        self.example_selection_note = QtWidgets.QLabel(parent=RenamingOptionsPage)
         self.example_selection_note.setText("")
         self.example_selection_note.setWordWrap(True)
         self.example_selection_note.setObjectName("example_selection_note")
@@ -126,7 +128,7 @@ def setupUi(self, RenamingOptionsPage):
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setSpacing(2)
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.example_filename_sample_files_button = QtWidgets.QPushButton(RenamingOptionsPage)
+        self.example_filename_sample_files_button = QtWidgets.QPushButton(parent=RenamingOptionsPage)
         self.example_filename_sample_files_button.setObjectName("example_filename_sample_files_button")
         self.horizontalLayout.addWidget(self.example_filename_sample_files_button)
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
diff --git a/picard/ui/ui_options_renaming_compat.py b/picard/ui/ui_options_renaming_compat.py
index 161866b10b..42f3e84134 100644
--- a/picard/ui/ui_options_renaming_compat.py
+++ b/picard/ui/ui_options_renaming_compat.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_renaming_compat.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -21,12 +23,12 @@ def setupUi(self, RenamingCompatOptionsPage):
         RenamingCompatOptionsPage.setSizePolicy(sizePolicy)
         self.verticalLayout_5 = QtWidgets.QVBoxLayout(RenamingCompatOptionsPage)
         self.verticalLayout_5.setObjectName("verticalLayout_5")
-        self.ascii_filenames = QtWidgets.QCheckBox(RenamingCompatOptionsPage)
+        self.ascii_filenames = QtWidgets.QCheckBox(parent=RenamingCompatOptionsPage)
         self.ascii_filenames.setObjectName("ascii_filenames")
         self.verticalLayout_5.addWidget(self.ascii_filenames)
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.windows_compatibility = QtWidgets.QCheckBox(RenamingCompatOptionsPage)
+        self.windows_compatibility = QtWidgets.QCheckBox(parent=RenamingCompatOptionsPage)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -34,21 +36,21 @@ def setupUi(self, RenamingCompatOptionsPage):
         self.windows_compatibility.setSizePolicy(sizePolicy)
         self.windows_compatibility.setObjectName("windows_compatibility")
         self.horizontalLayout.addWidget(self.windows_compatibility)
-        self.btn_windows_compatibility_change = QtWidgets.QPushButton(RenamingCompatOptionsPage)
+        self.btn_windows_compatibility_change = QtWidgets.QPushButton(parent=RenamingCompatOptionsPage)
         self.btn_windows_compatibility_change.setEnabled(False)
         self.btn_windows_compatibility_change.setObjectName("btn_windows_compatibility_change")
         self.horizontalLayout.addWidget(self.btn_windows_compatibility_change)
         self.verticalLayout_5.addLayout(self.horizontalLayout)
-        self.windows_long_paths = QtWidgets.QCheckBox(RenamingCompatOptionsPage)
+        self.windows_long_paths = QtWidgets.QCheckBox(parent=RenamingCompatOptionsPage)
         self.windows_long_paths.setEnabled(False)
         self.windows_long_paths.setObjectName("windows_long_paths")
         self.verticalLayout_5.addWidget(self.windows_long_paths)
-        self.replace_spaces_with_underscores = QtWidgets.QCheckBox(RenamingCompatOptionsPage)
+        self.replace_spaces_with_underscores = QtWidgets.QCheckBox(parent=RenamingCompatOptionsPage)
         self.replace_spaces_with_underscores.setObjectName("replace_spaces_with_underscores")
         self.verticalLayout_5.addWidget(self.replace_spaces_with_underscores)
         self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.label_replace_dir_separator = QtWidgets.QLabel(RenamingCompatOptionsPage)
+        self.label_replace_dir_separator = QtWidgets.QLabel(parent=RenamingCompatOptionsPage)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -56,7 +58,7 @@ def setupUi(self, RenamingCompatOptionsPage):
         self.label_replace_dir_separator.setSizePolicy(sizePolicy)
         self.label_replace_dir_separator.setObjectName("label_replace_dir_separator")
         self.horizontalLayout_2.addWidget(self.label_replace_dir_separator)
-        self.replace_dir_separator = QtWidgets.QLineEdit(RenamingCompatOptionsPage)
+        self.replace_dir_separator = QtWidgets.QLineEdit(parent=RenamingCompatOptionsPage)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -70,7 +72,7 @@ def setupUi(self, RenamingCompatOptionsPage):
         self.verticalLayout_5.addLayout(self.horizontalLayout_2)
         spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
         self.verticalLayout_5.addItem(spacerItem)
-        self.example_selection_note = QtWidgets.QLabel(RenamingCompatOptionsPage)
+        self.example_selection_note = QtWidgets.QLabel(parent=RenamingCompatOptionsPage)
         self.example_selection_note.setText("")
         self.example_selection_note.setWordWrap(True)
         self.example_selection_note.setObjectName("example_selection_note")
diff --git a/picard/ui/ui_options_script.py b/picard/ui/ui_options_script.py
index 23048e8c42..cf3fb08e76 100644
--- a/picard/ui/ui_options_script.py
+++ b/picard/ui/ui_options_script.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_script.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -17,7 +19,7 @@ def setupUi(self, ScriptingOptionsPage):
         self.vboxlayout.setContentsMargins(9, 9, 9, 0)
         self.vboxlayout.setSpacing(6)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.enable_tagger_scripts = QtWidgets.QGroupBox(ScriptingOptionsPage)
+        self.enable_tagger_scripts = QtWidgets.QGroupBox(parent=ScriptingOptionsPage)
         self.enable_tagger_scripts.setCheckable(True)
         self.enable_tagger_scripts.setObjectName("enable_tagger_scripts")
         self.verticalLayout = QtWidgets.QVBoxLayout(self.enable_tagger_scripts)
@@ -25,12 +27,12 @@ def setupUi(self, ScriptingOptionsPage):
         self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_2.setContentsMargins(-1, -1, -1, 0)
         self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.label = QtWidgets.QLabel(self.enable_tagger_scripts)
+        self.label = QtWidgets.QLabel(parent=self.enable_tagger_scripts)
         self.label.setWordWrap(True)
         self.label.setObjectName("label")
         self.horizontalLayout_2.addWidget(self.label)
         self.verticalLayout.addLayout(self.horizontalLayout_2)
-        self.scripting_options_splitter = QtWidgets.QSplitter(self.enable_tagger_scripts)
+        self.scripting_options_splitter = QtWidgets.QSplitter(parent=self.enable_tagger_scripts)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -39,7 +41,7 @@ def setupUi(self, ScriptingOptionsPage):
         self.scripting_options_splitter.setOrientation(QtCore.Qt.Orientation.Horizontal)
         self.scripting_options_splitter.setChildrenCollapsible(False)
         self.scripting_options_splitter.setObjectName("scripting_options_splitter")
-        self.script_list = ScriptListWidget(self.scripting_options_splitter)
+        self.script_list = ScriptListWidget(parent=self.scripting_options_splitter)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -47,47 +49,47 @@ def setupUi(self, ScriptingOptionsPage):
         self.script_list.setSizePolicy(sizePolicy)
         self.script_list.setMinimumSize(QtCore.QSize(120, 0))
         self.script_list.setObjectName("script_list")
-        self.formWidget = QtWidgets.QWidget(self.scripting_options_splitter)
+        self.formWidget = QtWidgets.QWidget(parent=self.scripting_options_splitter)
         self.formWidget.setObjectName("formWidget")
         self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.formWidget)
         self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
         self.verticalLayout_2.setObjectName("verticalLayout_2")
-        self.tagger_script = ScriptTextEdit(self.formWidget)
+        self.tagger_script = ScriptTextEdit(parent=self.formWidget)
         self.tagger_script.setAcceptRichText(False)
         self.tagger_script.setObjectName("tagger_script")
         self.verticalLayout_2.addWidget(self.tagger_script)
         self.verticalLayout.addWidget(self.scripting_options_splitter)
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.move_up_button = QtWidgets.QToolButton(self.enable_tagger_scripts)
+        self.move_up_button = QtWidgets.QToolButton(parent=self.enable_tagger_scripts)
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-up.png")
         self.move_up_button.setIcon(icon)
         self.move_up_button.setObjectName("move_up_button")
         self.horizontalLayout.addWidget(self.move_up_button)
-        self.move_down_button = QtWidgets.QToolButton(self.enable_tagger_scripts)
+        self.move_down_button = QtWidgets.QToolButton(parent=self.enable_tagger_scripts)
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-down.png")
         self.move_down_button.setIcon(icon)
         self.move_down_button.setObjectName("move_down_button")
         self.horizontalLayout.addWidget(self.move_down_button)
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout.addItem(spacerItem)
-        self.add_button = QtWidgets.QToolButton(self.enable_tagger_scripts)
+        self.add_button = QtWidgets.QToolButton(parent=self.enable_tagger_scripts)
         self.add_button.setObjectName("add_button")
         self.horizontalLayout.addWidget(self.add_button)
-        self.remove_button = QtWidgets.QToolButton(self.enable_tagger_scripts)
+        self.remove_button = QtWidgets.QToolButton(parent=self.enable_tagger_scripts)
         self.remove_button.setObjectName("remove_button")
         self.horizontalLayout.addWidget(self.remove_button)
         spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout.addItem(spacerItem1)
-        self.import_button = QtWidgets.QToolButton(self.enable_tagger_scripts)
+        self.import_button = QtWidgets.QToolButton(parent=self.enable_tagger_scripts)
         self.import_button.setObjectName("import_button")
         self.horizontalLayout.addWidget(self.import_button)
-        self.export_button = QtWidgets.QToolButton(self.enable_tagger_scripts)
+        self.export_button = QtWidgets.QToolButton(parent=self.enable_tagger_scripts)
         self.export_button.setObjectName("export_button")
         self.horizontalLayout.addWidget(self.export_button)
         spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout.addItem(spacerItem2)
-        self.scripting_documentation_button = QtWidgets.QToolButton(self.enable_tagger_scripts)
+        self.scripting_documentation_button = QtWidgets.QToolButton(parent=self.enable_tagger_scripts)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -96,7 +98,7 @@ def setupUi(self, ScriptingOptionsPage):
         self.scripting_documentation_button.setObjectName("scripting_documentation_button")
         self.horizontalLayout.addWidget(self.scripting_documentation_button)
         self.verticalLayout.addLayout(self.horizontalLayout)
-        self.script_error = QtWidgets.QLabel(self.enable_tagger_scripts)
+        self.script_error = QtWidgets.QLabel(parent=self.enable_tagger_scripts)
         self.script_error.setText("")
         self.script_error.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
         self.script_error.setObjectName("script_error")
diff --git a/picard/ui/ui_options_tags.py b/picard/ui/ui_options_tags.py
index 28e1b5fc24..56cb7e46c3 100644
--- a/picard/ui/ui_options_tags.py
+++ b/picard/ui/ui_options_tags.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_tags.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,40 +17,40 @@ def setupUi(self, TagsOptionsPage):
         TagsOptionsPage.resize(567, 525)
         self.vboxlayout = QtWidgets.QVBoxLayout(TagsOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.write_tags = QtWidgets.QCheckBox(TagsOptionsPage)
+        self.write_tags = QtWidgets.QCheckBox(parent=TagsOptionsPage)
         self.write_tags.setObjectName("write_tags")
         self.vboxlayout.addWidget(self.write_tags)
-        self.preserve_timestamps = QtWidgets.QCheckBox(TagsOptionsPage)
+        self.preserve_timestamps = QtWidgets.QCheckBox(parent=TagsOptionsPage)
         self.preserve_timestamps.setObjectName("preserve_timestamps")
         self.vboxlayout.addWidget(self.preserve_timestamps)
-        self.before_tagging = QtWidgets.QGroupBox(TagsOptionsPage)
+        self.before_tagging = QtWidgets.QGroupBox(parent=TagsOptionsPage)
         self.before_tagging.setObjectName("before_tagging")
         self.vboxlayout1 = QtWidgets.QVBoxLayout(self.before_tagging)
         self.vboxlayout1.setContentsMargins(-1, 6, -1, 7)
         self.vboxlayout1.setSpacing(2)
         self.vboxlayout1.setObjectName("vboxlayout1")
-        self.clear_existing_tags = QtWidgets.QCheckBox(self.before_tagging)
+        self.clear_existing_tags = QtWidgets.QCheckBox(parent=self.before_tagging)
         self.clear_existing_tags.setObjectName("clear_existing_tags")
         self.vboxlayout1.addWidget(self.clear_existing_tags)
-        self.preserve_images = QtWidgets.QCheckBox(self.before_tagging)
+        self.preserve_images = QtWidgets.QCheckBox(parent=self.before_tagging)
         self.preserve_images.setEnabled(False)
         self.preserve_images.setObjectName("preserve_images")
         self.vboxlayout1.addWidget(self.preserve_images)
-        self.remove_id3_from_flac = QtWidgets.QCheckBox(self.before_tagging)
+        self.remove_id3_from_flac = QtWidgets.QCheckBox(parent=self.before_tagging)
         self.remove_id3_from_flac.setObjectName("remove_id3_from_flac")
         self.vboxlayout1.addWidget(self.remove_id3_from_flac)
-        self.remove_ape_from_mp3 = QtWidgets.QCheckBox(self.before_tagging)
+        self.remove_ape_from_mp3 = QtWidgets.QCheckBox(parent=self.before_tagging)
         self.remove_ape_from_mp3.setObjectName("remove_ape_from_mp3")
         self.vboxlayout1.addWidget(self.remove_ape_from_mp3)
-        self.fix_missing_seekpoints_flac = QtWidgets.QCheckBox(self.before_tagging)
+        self.fix_missing_seekpoints_flac = QtWidgets.QCheckBox(parent=self.before_tagging)
         self.fix_missing_seekpoints_flac.setObjectName("fix_missing_seekpoints_flac")
         self.vboxlayout1.addWidget(self.fix_missing_seekpoints_flac)
         spacerItem = QtWidgets.QSpacerItem(20, 6, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         self.vboxlayout1.addItem(spacerItem)
-        self.preserved_tags_label = QtWidgets.QLabel(self.before_tagging)
+        self.preserved_tags_label = QtWidgets.QLabel(parent=self.before_tagging)
         self.preserved_tags_label.setObjectName("preserved_tags_label")
         self.vboxlayout1.addWidget(self.preserved_tags_label)
-        self.preserved_tags = TagListEditor(self.before_tagging)
+        self.preserved_tags = TagListEditor(parent=self.before_tagging)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
diff --git a/picard/ui/ui_options_tags_compatibility_aac.py b/picard/ui/ui_options_tags_compatibility_aac.py
index c4cd557544..ae3a6efd2a 100644
--- a/picard/ui/ui_options_tags_compatibility_aac.py
+++ b/picard/ui/ui_options_tags_compatibility_aac.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_tags_compatibility_aac.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,24 +17,24 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         TagsCompatibilityOptionsPage.resize(539, 705)
         self.vboxlayout = QtWidgets.QVBoxLayout(TagsCompatibilityOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.aac_tags = QtWidgets.QGroupBox(TagsCompatibilityOptionsPage)
+        self.aac_tags = QtWidgets.QGroupBox(parent=TagsCompatibilityOptionsPage)
         self.aac_tags.setObjectName("aac_tags")
         self.verticalLayout = QtWidgets.QVBoxLayout(self.aac_tags)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.info_label = QtWidgets.QLabel(self.aac_tags)
+        self.info_label = QtWidgets.QLabel(parent=self.aac_tags)
         self.info_label.setWordWrap(True)
         self.info_label.setObjectName("info_label")
         self.verticalLayout.addWidget(self.info_label)
         spacerItem = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         self.verticalLayout.addItem(spacerItem)
-        self.aac_save_ape = QtWidgets.QRadioButton(self.aac_tags)
+        self.aac_save_ape = QtWidgets.QRadioButton(parent=self.aac_tags)
         self.aac_save_ape.setChecked(True)
         self.aac_save_ape.setObjectName("aac_save_ape")
         self.verticalLayout.addWidget(self.aac_save_ape)
-        self.aac_no_tags = QtWidgets.QRadioButton(self.aac_tags)
+        self.aac_no_tags = QtWidgets.QRadioButton(parent=self.aac_tags)
         self.aac_no_tags.setObjectName("aac_no_tags")
         self.verticalLayout.addWidget(self.aac_no_tags)
-        self.remove_ape_from_aac = QtWidgets.QCheckBox(self.aac_tags)
+        self.remove_ape_from_aac = QtWidgets.QCheckBox(parent=self.aac_tags)
         self.remove_ape_from_aac.setObjectName("remove_ape_from_aac")
         self.verticalLayout.addWidget(self.remove_ape_from_aac)
         self.vboxlayout.addWidget(self.aac_tags)
diff --git a/picard/ui/ui_options_tags_compatibility_ac3.py b/picard/ui/ui_options_tags_compatibility_ac3.py
index 32b478eb68..7d8035a473 100644
--- a/picard/ui/ui_options_tags_compatibility_ac3.py
+++ b/picard/ui/ui_options_tags_compatibility_ac3.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_tags_compatibility_ac3.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,24 +17,24 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         TagsCompatibilityOptionsPage.resize(539, 705)
         self.vboxlayout = QtWidgets.QVBoxLayout(TagsCompatibilityOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.ac3_files = QtWidgets.QGroupBox(TagsCompatibilityOptionsPage)
+        self.ac3_files = QtWidgets.QGroupBox(parent=TagsCompatibilityOptionsPage)
         self.ac3_files.setObjectName("ac3_files")
         self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.ac3_files)
         self.verticalLayout_2.setObjectName("verticalLayout_2")
-        self.info_label = QtWidgets.QLabel(self.ac3_files)
+        self.info_label = QtWidgets.QLabel(parent=self.ac3_files)
         self.info_label.setWordWrap(True)
         self.info_label.setObjectName("info_label")
         self.verticalLayout_2.addWidget(self.info_label)
         spacerItem = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         self.verticalLayout_2.addItem(spacerItem)
-        self.ac3_save_ape = QtWidgets.QRadioButton(self.ac3_files)
+        self.ac3_save_ape = QtWidgets.QRadioButton(parent=self.ac3_files)
         self.ac3_save_ape.setChecked(True)
         self.ac3_save_ape.setObjectName("ac3_save_ape")
         self.verticalLayout_2.addWidget(self.ac3_save_ape)
-        self.ac3_no_tags = QtWidgets.QRadioButton(self.ac3_files)
+        self.ac3_no_tags = QtWidgets.QRadioButton(parent=self.ac3_files)
         self.ac3_no_tags.setObjectName("ac3_no_tags")
         self.verticalLayout_2.addWidget(self.ac3_no_tags)
-        self.remove_ape_from_ac3 = QtWidgets.QCheckBox(self.ac3_files)
+        self.remove_ape_from_ac3 = QtWidgets.QCheckBox(parent=self.ac3_files)
         self.remove_ape_from_ac3.setObjectName("remove_ape_from_ac3")
         self.verticalLayout_2.addWidget(self.remove_ape_from_ac3)
         self.vboxlayout.addWidget(self.ac3_files)
diff --git a/picard/ui/ui_options_tags_compatibility_id3.py b/picard/ui/ui_options_tags_compatibility_id3.py
index f089dc535f..2f34b20ad3 100644
--- a/picard/ui/ui_options_tags_compatibility_id3.py
+++ b/picard/ui/ui_options_tags_compatibility_id3.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_tags_compatibility_id3.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,28 +17,28 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         TagsCompatibilityOptionsPage.resize(539, 705)
         self.vboxlayout = QtWidgets.QVBoxLayout(TagsCompatibilityOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.tag_compatibility = QtWidgets.QGroupBox(TagsCompatibilityOptionsPage)
+        self.tag_compatibility = QtWidgets.QGroupBox(parent=TagsCompatibilityOptionsPage)
         self.tag_compatibility.setObjectName("tag_compatibility")
         self.vboxlayout1 = QtWidgets.QVBoxLayout(self.tag_compatibility)
         self.vboxlayout1.setContentsMargins(-1, 6, -1, 7)
         self.vboxlayout1.setSpacing(2)
         self.vboxlayout1.setObjectName("vboxlayout1")
-        self.id3v2_version = QtWidgets.QGroupBox(self.tag_compatibility)
+        self.id3v2_version = QtWidgets.QGroupBox(parent=self.tag_compatibility)
         self.id3v2_version.setFlat(False)
         self.id3v2_version.setCheckable(False)
         self.id3v2_version.setObjectName("id3v2_version")
         self.horizontalLayout = QtWidgets.QHBoxLayout(self.id3v2_version)
         self.horizontalLayout.setContentsMargins(-1, 6, -1, 7)
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.write_id3v24 = QtWidgets.QRadioButton(self.id3v2_version)
+        self.write_id3v24 = QtWidgets.QRadioButton(parent=self.id3v2_version)
         self.write_id3v24.setChecked(True)
         self.write_id3v24.setObjectName("write_id3v24")
         self.horizontalLayout.addWidget(self.write_id3v24)
-        self.write_id3v23 = QtWidgets.QRadioButton(self.id3v2_version)
+        self.write_id3v23 = QtWidgets.QRadioButton(parent=self.id3v2_version)
         self.write_id3v23.setChecked(False)
         self.write_id3v23.setObjectName("write_id3v23")
         self.horizontalLayout.addWidget(self.write_id3v23)
-        self.label = QtWidgets.QLabel(self.id3v2_version)
+        self.label = QtWidgets.QLabel(parent=self.id3v2_version)
         self.label.setText("")
         self.label.setWordWrap(True)
         self.label.setObjectName("label")
@@ -44,23 +46,23 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout.addItem(spacerItem)
         self.vboxlayout1.addWidget(self.id3v2_version)
-        self.id3v2_text_encoding = QtWidgets.QGroupBox(self.tag_compatibility)
+        self.id3v2_text_encoding = QtWidgets.QGroupBox(parent=self.tag_compatibility)
         self.id3v2_text_encoding.setObjectName("id3v2_text_encoding")
         self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.id3v2_text_encoding)
         self.horizontalLayout_2.setContentsMargins(-1, 6, -1, 7)
         self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.enc_utf8 = QtWidgets.QRadioButton(self.id3v2_text_encoding)
+        self.enc_utf8 = QtWidgets.QRadioButton(parent=self.id3v2_text_encoding)
         self.enc_utf8.setObjectName("enc_utf8")
         self.horizontalLayout_2.addWidget(self.enc_utf8)
-        self.enc_utf16 = QtWidgets.QRadioButton(self.id3v2_text_encoding)
+        self.enc_utf16 = QtWidgets.QRadioButton(parent=self.id3v2_text_encoding)
         self.enc_utf16.setObjectName("enc_utf16")
         self.horizontalLayout_2.addWidget(self.enc_utf16)
-        self.enc_iso88591 = QtWidgets.QRadioButton(self.id3v2_text_encoding)
+        self.enc_iso88591 = QtWidgets.QRadioButton(parent=self.id3v2_text_encoding)
         self.enc_iso88591.setObjectName("enc_iso88591")
         self.horizontalLayout_2.addWidget(self.enc_iso88591)
         spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout_2.addItem(spacerItem1)
-        self.label_2 = QtWidgets.QLabel(self.id3v2_text_encoding)
+        self.label_2 = QtWidgets.QLabel(parent=self.id3v2_text_encoding)
         self.label_2.setText("")
         self.label_2.setWordWrap(True)
         self.label_2.setObjectName("label_2")
@@ -68,7 +70,7 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         self.vboxlayout1.addWidget(self.id3v2_text_encoding)
         self.hbox_id3v23_join_with = QtWidgets.QHBoxLayout()
         self.hbox_id3v23_join_with.setObjectName("hbox_id3v23_join_with")
-        self.label_id3v23_join_with = QtWidgets.QLabel(self.tag_compatibility)
+        self.label_id3v23_join_with = QtWidgets.QLabel(parent=self.tag_compatibility)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(4)
         sizePolicy.setVerticalStretch(0)
@@ -76,7 +78,7 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         self.label_id3v23_join_with.setSizePolicy(sizePolicy)
         self.label_id3v23_join_with.setObjectName("label_id3v23_join_with")
         self.hbox_id3v23_join_with.addWidget(self.label_id3v23_join_with)
-        self.id3v23_join_with = QtWidgets.QComboBox(self.tag_compatibility)
+        self.id3v23_join_with = QtWidgets.QComboBox(parent=self.tag_compatibility)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(1)
         sizePolicy.setVerticalStretch(0)
@@ -92,10 +94,10 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         self.id3v23_join_with.setItemText(2, " / ")
         self.hbox_id3v23_join_with.addWidget(self.id3v23_join_with)
         self.vboxlayout1.addLayout(self.hbox_id3v23_join_with)
-        self.itunes_compatible_grouping = QtWidgets.QCheckBox(self.tag_compatibility)
+        self.itunes_compatible_grouping = QtWidgets.QCheckBox(parent=self.tag_compatibility)
         self.itunes_compatible_grouping.setObjectName("itunes_compatible_grouping")
         self.vboxlayout1.addWidget(self.itunes_compatible_grouping)
-        self.write_id3v1 = QtWidgets.QCheckBox(self.tag_compatibility)
+        self.write_id3v1 = QtWidgets.QCheckBox(parent=self.tag_compatibility)
         self.write_id3v1.setObjectName("write_id3v1")
         self.vboxlayout1.addWidget(self.write_id3v1)
         self.vboxlayout.addWidget(self.tag_compatibility)
diff --git a/picard/ui/ui_options_tags_compatibility_wave.py b/picard/ui/ui_options_tags_compatibility_wave.py
index b5c19a6e87..ef1d8c6bd0 100644
--- a/picard/ui/ui_options_tags_compatibility_wave.py
+++ b/picard/ui/ui_options_tags_compatibility_wave.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/options_tags_compatibility_wave.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,31 +17,31 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         TagsCompatibilityOptionsPage.resize(539, 705)
         self.vboxlayout = QtWidgets.QVBoxLayout(TagsCompatibilityOptionsPage)
         self.vboxlayout.setObjectName("vboxlayout")
-        self.wave_files = QtWidgets.QGroupBox(TagsCompatibilityOptionsPage)
+        self.wave_files = QtWidgets.QGroupBox(parent=TagsCompatibilityOptionsPage)
         self.wave_files.setObjectName("wave_files")
         self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.wave_files)
         self.verticalLayout_3.setObjectName("verticalLayout_3")
-        self.label = QtWidgets.QLabel(self.wave_files)
+        self.label = QtWidgets.QLabel(parent=self.wave_files)
         self.label.setWordWrap(True)
         self.label.setObjectName("label")
         self.verticalLayout_3.addWidget(self.label)
         spacerItem = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         self.verticalLayout_3.addItem(spacerItem)
-        self.write_wave_riff_info = QtWidgets.QCheckBox(self.wave_files)
+        self.write_wave_riff_info = QtWidgets.QCheckBox(parent=self.wave_files)
         self.write_wave_riff_info.setObjectName("write_wave_riff_info")
         self.verticalLayout_3.addWidget(self.write_wave_riff_info)
-        self.remove_wave_riff_info = QtWidgets.QCheckBox(self.wave_files)
+        self.remove_wave_riff_info = QtWidgets.QCheckBox(parent=self.wave_files)
         self.remove_wave_riff_info.setObjectName("remove_wave_riff_info")
         self.verticalLayout_3.addWidget(self.remove_wave_riff_info)
-        self.wave_riff_info_encoding = QtWidgets.QGroupBox(self.wave_files)
+        self.wave_riff_info_encoding = QtWidgets.QGroupBox(parent=self.wave_files)
         self.wave_riff_info_encoding.setObjectName("wave_riff_info_encoding")
         self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.wave_riff_info_encoding)
         self.horizontalLayout_3.setObjectName("horizontalLayout_3")
-        self.wave_riff_info_enc_cp1252 = QtWidgets.QRadioButton(self.wave_riff_info_encoding)
+        self.wave_riff_info_enc_cp1252 = QtWidgets.QRadioButton(parent=self.wave_riff_info_encoding)
         self.wave_riff_info_enc_cp1252.setChecked(True)
         self.wave_riff_info_enc_cp1252.setObjectName("wave_riff_info_enc_cp1252")
         self.horizontalLayout_3.addWidget(self.wave_riff_info_enc_cp1252)
-        self.wave_riff_info_enc_utf8 = QtWidgets.QRadioButton(self.wave_riff_info_encoding)
+        self.wave_riff_info_enc_utf8 = QtWidgets.QRadioButton(parent=self.wave_riff_info_encoding)
         self.wave_riff_info_enc_utf8.setObjectName("wave_riff_info_enc_utf8")
         self.horizontalLayout_3.addWidget(self.wave_riff_info_enc_utf8)
         spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
diff --git a/picard/ui/ui_passworddialog.py b/picard/ui/ui_passworddialog.py
index 8f8d048c65..f9f606f97c 100644
--- a/picard/ui/ui_passworddialog.py
+++ b/picard/ui/ui_passworddialog.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/passworddialog.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -21,17 +23,17 @@ def setupUi(self, PasswordDialog):
         PasswordDialog.setSizePolicy(sizePolicy)
         self.verticalLayout = QtWidgets.QVBoxLayout(PasswordDialog)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.info_text = QtWidgets.QLabel(PasswordDialog)
+        self.info_text = QtWidgets.QLabel(parent=PasswordDialog)
         self.info_text.setText("")
         self.info_text.setWordWrap(True)
         self.info_text.setObjectName("info_text")
         self.verticalLayout.addWidget(self.info_text)
         spacerItem = QtWidgets.QSpacerItem(20, 60, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
         self.verticalLayout.addItem(spacerItem)
-        self.label = QtWidgets.QLabel(PasswordDialog)
+        self.label = QtWidgets.QLabel(parent=PasswordDialog)
         self.label.setObjectName("label")
         self.verticalLayout.addWidget(self.label)
-        self.username = QtWidgets.QLineEdit(PasswordDialog)
+        self.username = QtWidgets.QLineEdit(parent=PasswordDialog)
         self.username.setWindowModality(QtCore.Qt.WindowModality.NonModal)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
@@ -40,16 +42,16 @@ def setupUi(self, PasswordDialog):
         self.username.setSizePolicy(sizePolicy)
         self.username.setObjectName("username")
         self.verticalLayout.addWidget(self.username)
-        self.label_2 = QtWidgets.QLabel(PasswordDialog)
+        self.label_2 = QtWidgets.QLabel(parent=PasswordDialog)
         self.label_2.setObjectName("label_2")
         self.verticalLayout.addWidget(self.label_2)
-        self.password = QtWidgets.QLineEdit(PasswordDialog)
+        self.password = QtWidgets.QLineEdit(parent=PasswordDialog)
         self.password.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password)
         self.password.setObjectName("password")
         self.verticalLayout.addWidget(self.password)
         spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
         self.verticalLayout.addItem(spacerItem1)
-        self.buttonbox = QtWidgets.QDialogButtonBox(PasswordDialog)
+        self.buttonbox = QtWidgets.QDialogButtonBox(parent=PasswordDialog)
         self.buttonbox.setOrientation(QtCore.Qt.Orientation.Horizontal)
         self.buttonbox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
         self.buttonbox.setObjectName("buttonbox")
diff --git a/picard/ui/ui_provider_options_caa.py b/picard/ui/ui_provider_options_caa.py
index 705f8231c2..65b27c012b 100644
--- a/picard/ui/ui_provider_options_caa.py
+++ b/picard/ui/ui_provider_options_caa.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/provider_options_caa.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -17,12 +19,12 @@ def setupUi(self, CaaOptions):
         self.verticalLayout.setObjectName("verticalLayout")
         self.select_caa_types_group = QtWidgets.QHBoxLayout()
         self.select_caa_types_group.setObjectName("select_caa_types_group")
-        self.restrict_images_types = QtWidgets.QCheckBox(CaaOptions)
+        self.restrict_images_types = QtWidgets.QCheckBox(parent=CaaOptions)
         self.restrict_images_types.setObjectName("restrict_images_types")
         self.select_caa_types_group.addWidget(self.restrict_images_types)
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.select_caa_types_group.addItem(spacerItem)
-        self.select_caa_types = QtWidgets.QPushButton(CaaOptions)
+        self.select_caa_types = QtWidgets.QPushButton(parent=CaaOptions)
         self.select_caa_types.setEnabled(False)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(100)
@@ -34,7 +36,7 @@ def setupUi(self, CaaOptions):
         self.verticalLayout.addLayout(self.select_caa_types_group)
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.label = QtWidgets.QLabel(CaaOptions)
+        self.label = QtWidgets.QLabel(parent=CaaOptions)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -44,7 +46,7 @@ def setupUi(self, CaaOptions):
         self.horizontalLayout.addWidget(self.label)
         spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Ignored, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout.addItem(spacerItem1)
-        self.cb_image_size = QtWidgets.QComboBox(CaaOptions)
+        self.cb_image_size = QtWidgets.QComboBox(parent=CaaOptions)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -53,7 +55,7 @@ def setupUi(self, CaaOptions):
         self.cb_image_size.setObjectName("cb_image_size")
         self.horizontalLayout.addWidget(self.cb_image_size)
         self.verticalLayout.addLayout(self.horizontalLayout)
-        self.cb_approved_only = QtWidgets.QCheckBox(CaaOptions)
+        self.cb_approved_only = QtWidgets.QCheckBox(parent=CaaOptions)
         self.cb_approved_only.setObjectName("cb_approved_only")
         self.verticalLayout.addWidget(self.cb_approved_only)
         spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
diff --git a/picard/ui/ui_provider_options_local.py b/picard/ui/ui_provider_options_local.py
index 96c0c63f83..bd06fa9576 100644
--- a/picard/ui/ui_provider_options_local.py
+++ b/picard/ui/ui_provider_options_local.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/provider_options_local.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -15,19 +17,19 @@ def setupUi(self, LocalOptions):
         LocalOptions.resize(472, 215)
         self.verticalLayout = QtWidgets.QVBoxLayout(LocalOptions)
         self.verticalLayout.setObjectName("verticalLayout")
-        self.local_cover_regex_label = QtWidgets.QLabel(LocalOptions)
+        self.local_cover_regex_label = QtWidgets.QLabel(parent=LocalOptions)
         self.local_cover_regex_label.setObjectName("local_cover_regex_label")
         self.verticalLayout.addWidget(self.local_cover_regex_label)
-        self.local_cover_regex_edit = QtWidgets.QLineEdit(LocalOptions)
+        self.local_cover_regex_edit = QtWidgets.QLineEdit(parent=LocalOptions)
         self.local_cover_regex_edit.setObjectName("local_cover_regex_edit")
         self.verticalLayout.addWidget(self.local_cover_regex_edit)
         self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
         self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.local_cover_regex_error = QtWidgets.QLabel(LocalOptions)
+        self.local_cover_regex_error = QtWidgets.QLabel(parent=LocalOptions)
         self.local_cover_regex_error.setText("")
         self.local_cover_regex_error.setObjectName("local_cover_regex_error")
         self.horizontalLayout_2.addWidget(self.local_cover_regex_error)
-        self.local_cover_regex_default = QtWidgets.QPushButton(LocalOptions)
+        self.local_cover_regex_default = QtWidgets.QPushButton(parent=LocalOptions)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -36,7 +38,7 @@ def setupUi(self, LocalOptions):
         self.local_cover_regex_default.setObjectName("local_cover_regex_default")
         self.horizontalLayout_2.addWidget(self.local_cover_regex_default)
         self.verticalLayout.addLayout(self.horizontalLayout_2)
-        self.note = QtWidgets.QLabel(LocalOptions)
+        self.note = QtWidgets.QLabel(parent=LocalOptions)
         font = QtGui.QFont()
         font.setItalic(True)
         self.note.setFont(font)
diff --git a/picard/ui/ui_scripteditor.py b/picard/ui/ui_scripteditor.py
index c37f4a317d..e18d621c37 100644
--- a/picard/ui/ui_scripteditor.py
+++ b/picard/ui/ui_scripteditor.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/scripteditor.ui'
 #
-# Created by: PyQt6 UI code generator 6.5.2
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_scripteditor_details.py b/picard/ui/ui_scripteditor_details.py
index 78588bf925..7fda2553b8 100644
--- a/picard/ui/ui_scripteditor_details.py
+++ b/picard/ui/ui_scripteditor_details.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/scripteditor_details.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -25,7 +27,7 @@ def setupUi(self, ScriptDetails):
         self.gridLayout.setObjectName("gridLayout")
         self.horizontalLayout = QtWidgets.QHBoxLayout()
         self.horizontalLayout.setObjectName("horizontalLayout")
-        self.script_version = QtWidgets.QLineEdit(ScriptDetails)
+        self.script_version = QtWidgets.QLineEdit(parent=ScriptDetails)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -38,48 +40,48 @@ def setupUi(self, ScriptDetails):
         self.horizontalLayout.addWidget(self.script_version)
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout.addItem(spacerItem)
-        self.label_4 = QtWidgets.QLabel(ScriptDetails)
+        self.label_4 = QtWidgets.QLabel(parent=ScriptDetails)
         self.label_4.setObjectName("label_4")
         self.horizontalLayout.addWidget(self.label_4)
-        self.script_last_updated = QtWidgets.QLineEdit(ScriptDetails)
+        self.script_last_updated = QtWidgets.QLineEdit(parent=ScriptDetails)
         self.script_last_updated.setMinimumSize(QtCore.QSize(200, 0))
         self.script_last_updated.setMaximumSize(QtCore.QSize(200, 16777215))
         self.script_last_updated.setObjectName("script_last_updated")
         self.horizontalLayout.addWidget(self.script_last_updated)
-        self.last_updated_now = QtWidgets.QPushButton(ScriptDetails)
+        self.last_updated_now = QtWidgets.QPushButton(parent=ScriptDetails)
         self.last_updated_now.setObjectName("last_updated_now")
         self.horizontalLayout.addWidget(self.last_updated_now)
         self.gridLayout.addLayout(self.horizontalLayout, 2, 2, 1, 1)
-        self.label_2 = QtWidgets.QLabel(ScriptDetails)
+        self.label_2 = QtWidgets.QLabel(parent=ScriptDetails)
         self.label_2.setObjectName("label_2")
         self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
-        self.label_3 = QtWidgets.QLabel(ScriptDetails)
+        self.label_3 = QtWidgets.QLabel(parent=ScriptDetails)
         self.label_3.setObjectName("label_3")
         self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
-        self.label_5 = QtWidgets.QLabel(ScriptDetails)
+        self.label_5 = QtWidgets.QLabel(parent=ScriptDetails)
         self.label_5.setObjectName("label_5")
         self.gridLayout.addWidget(self.label_5, 3, 0, 1, 1)
-        self.label = QtWidgets.QLabel(ScriptDetails)
+        self.label = QtWidgets.QLabel(parent=ScriptDetails)
         self.label.setObjectName("label")
         self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
-        self.script_license = QtWidgets.QLineEdit(ScriptDetails)
+        self.script_license = QtWidgets.QLineEdit(parent=ScriptDetails)
         self.script_license.setObjectName("script_license")
         self.gridLayout.addWidget(self.script_license, 3, 2, 1, 1)
-        self.label_6 = QtWidgets.QLabel(ScriptDetails)
+        self.label_6 = QtWidgets.QLabel(parent=ScriptDetails)
         self.label_6.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
         self.label_6.setObjectName("label_6")
         self.gridLayout.addWidget(self.label_6, 4, 0, 1, 1)
-        self.script_description = QtWidgets.QPlainTextEdit(ScriptDetails)
+        self.script_description = QtWidgets.QPlainTextEdit(parent=ScriptDetails)
         self.script_description.setObjectName("script_description")
         self.gridLayout.addWidget(self.script_description, 4, 2, 1, 1)
-        self.script_author = QtWidgets.QLineEdit(ScriptDetails)
+        self.script_author = QtWidgets.QLineEdit(parent=ScriptDetails)
         self.script_author.setObjectName("script_author")
         self.gridLayout.addWidget(self.script_author, 1, 2, 1, 1)
-        self.script_title = QtWidgets.QLineEdit(ScriptDetails)
+        self.script_title = QtWidgets.QLineEdit(parent=ScriptDetails)
         self.script_title.setObjectName("script_title")
         self.gridLayout.addWidget(self.script_title, 0, 2, 1, 1)
         self.verticalLayout.addLayout(self.gridLayout)
-        self.buttonBox = QtWidgets.QDialogButtonBox(ScriptDetails)
+        self.buttonBox = QtWidgets.QDialogButtonBox(parent=ScriptDetails)
         self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
         self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Close|QtWidgets.QDialogButtonBox.StandardButton.Save)
         self.buttonBox.setObjectName("buttonBox")
diff --git a/picard/ui/ui_scripting_documentation_dialog.py b/picard/ui/ui_scripting_documentation_dialog.py
index b89a188cf6..9b95932233 100644
--- a/picard/ui/ui_scripting_documentation_dialog.py
+++ b/picard/ui/ui_scripting_documentation_dialog.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/scripting_documentation_dialog.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -24,7 +26,7 @@ def setupUi(self, ScriptingDocumentationDialog):
         self.documentation_layout = QtWidgets.QVBoxLayout()
         self.documentation_layout.setObjectName("documentation_layout")
         self.verticalLayout.addLayout(self.documentation_layout)
-        self.buttonBox = QtWidgets.QDialogButtonBox(ScriptingDocumentationDialog)
+        self.buttonBox = QtWidgets.QDialogButtonBox(parent=ScriptingDocumentationDialog)
         self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
         self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Close)
         self.buttonBox.setObjectName("buttonBox")
diff --git a/picard/ui/ui_tagsfromfilenames.py b/picard/ui/ui_tagsfromfilenames.py
index cd9c218e77..91e21ccee5 100644
--- a/picard/ui/ui_tagsfromfilenames.py
+++ b/picard/ui/ui_tagsfromfilenames.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/tagsfromfilenames.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -17,23 +19,23 @@ def setupUi(self, TagsFromFileNamesDialog):
         self.gridlayout.setContentsMargins(9, 9, 9, 9)
         self.gridlayout.setSpacing(6)
         self.gridlayout.setObjectName("gridlayout")
-        self.files = QtWidgets.QTreeWidget(TagsFromFileNamesDialog)
+        self.files = QtWidgets.QTreeWidget(parent=TagsFromFileNamesDialog)
         self.files.setAlternatingRowColors(True)
         self.files.setRootIsDecorated(False)
         self.files.setObjectName("files")
         self.files.headerItem().setText(0, "1")
         self.gridlayout.addWidget(self.files, 1, 0, 1, 2)
-        self.replace_underscores = QtWidgets.QCheckBox(TagsFromFileNamesDialog)
+        self.replace_underscores = QtWidgets.QCheckBox(parent=TagsFromFileNamesDialog)
         self.replace_underscores.setObjectName("replace_underscores")
         self.gridlayout.addWidget(self.replace_underscores, 2, 0, 1, 2)
-        self.buttonbox = QtWidgets.QDialogButtonBox(TagsFromFileNamesDialog)
+        self.buttonbox = QtWidgets.QDialogButtonBox(parent=TagsFromFileNamesDialog)
         self.buttonbox.setOrientation(QtCore.Qt.Orientation.Horizontal)
         self.buttonbox.setObjectName("buttonbox")
         self.gridlayout.addWidget(self.buttonbox, 3, 0, 1, 2)
-        self.preview = QtWidgets.QPushButton(TagsFromFileNamesDialog)
+        self.preview = QtWidgets.QPushButton(parent=TagsFromFileNamesDialog)
         self.preview.setObjectName("preview")
         self.gridlayout.addWidget(self.preview, 0, 1, 1, 1)
-        self.format = QtWidgets.QComboBox(TagsFromFileNamesDialog)
+        self.format = QtWidgets.QComboBox(parent=TagsFromFileNamesDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
diff --git a/picard/ui/ui_widget_taglisteditor.py b/picard/ui/ui_widget_taglisteditor.py
index 1bca6f1021..5597d79cc8 100644
--- a/picard/ui/ui_widget_taglisteditor.py
+++ b/picard/ui/ui_widget_taglisteditor.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/widget_taglisteditor.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -19,40 +21,40 @@ def setupUi(self, TagListEditor):
         self.horizontalLayout.setObjectName("horizontalLayout")
         self.verticalLayout = QtWidgets.QVBoxLayout()
         self.verticalLayout.setObjectName("verticalLayout")
-        self.tag_list_view = UniqueEditableListView(TagListEditor)
+        self.tag_list_view = UniqueEditableListView(parent=TagListEditor)
         self.tag_list_view.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.InternalMove)
         self.tag_list_view.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection)
         self.tag_list_view.setObjectName("tag_list_view")
         self.verticalLayout.addWidget(self.tag_list_view)
-        self.edit_buttons = QtWidgets.QWidget(TagListEditor)
+        self.edit_buttons = QtWidgets.QWidget(parent=TagListEditor)
         self.edit_buttons.setObjectName("edit_buttons")
         self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.edit_buttons)
         self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
         self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.tags_add_btn = QtWidgets.QToolButton(self.edit_buttons)
+        self.tags_add_btn = QtWidgets.QToolButton(parent=self.edit_buttons)
         self.tags_add_btn.setObjectName("tags_add_btn")
         self.horizontalLayout_2.addWidget(self.tags_add_btn)
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.horizontalLayout_2.addItem(spacerItem)
-        self.sort_buttons = QtWidgets.QWidget(self.edit_buttons)
+        self.sort_buttons = QtWidgets.QWidget(parent=self.edit_buttons)
         self.sort_buttons.setObjectName("sort_buttons")
         self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.sort_buttons)
         self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
         self.horizontalLayout_3.setObjectName("horizontalLayout_3")
-        self.tags_move_up_btn = QtWidgets.QToolButton(self.sort_buttons)
+        self.tags_move_up_btn = QtWidgets.QToolButton(parent=self.sort_buttons)
         self.tags_move_up_btn.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-up.png")
         self.tags_move_up_btn.setIcon(icon)
         self.tags_move_up_btn.setObjectName("tags_move_up_btn")
         self.horizontalLayout_3.addWidget(self.tags_move_up_btn)
-        self.tags_move_down_btn = QtWidgets.QToolButton(self.sort_buttons)
+        self.tags_move_down_btn = QtWidgets.QToolButton(parent=self.sort_buttons)
         self.tags_move_down_btn.setText("")
         icon = QtGui.QIcon.fromTheme(":/images/16x16/go-down.png")
         self.tags_move_down_btn.setIcon(icon)
         self.tags_move_down_btn.setObjectName("tags_move_down_btn")
         self.horizontalLayout_3.addWidget(self.tags_move_down_btn)
         self.horizontalLayout_2.addWidget(self.sort_buttons)
-        self.tags_remove_btn = QtWidgets.QToolButton(self.edit_buttons)
+        self.tags_remove_btn = QtWidgets.QToolButton(parent=self.edit_buttons)
         self.tags_remove_btn.setObjectName("tags_remove_btn")
         self.horizontalLayout_2.addWidget(self.tags_remove_btn)
         self.verticalLayout.addWidget(self.edit_buttons)
diff --git a/picard/ui/ui_win_compat_dialog.py b/picard/ui/ui_win_compat_dialog.py
index 5512293964..1c60925c91 100644
--- a/picard/ui/ui_win_compat_dialog.py
+++ b/picard/ui/ui_win_compat_dialog.py
@@ -1,9 +1,11 @@
 # Form implementation generated from reading ui file 'ui/win_compat_dialog.ui'
 #
-# Created by: PyQt6 UI code generator 6.3.1
+# Created by: PyQt6 UI code generator 6.6.1
 #
-# WARNING: Any manual changes made to this file will be lost when pyuic6 is
-# run again.  Do not edit this file unless you know what you are doing.
+# Automatically generated - do not edit.
+# Use `python setup.py build_ui` to update it.
+
+from picard.i18n import _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
@@ -24,14 +26,14 @@ def setupUi(self, WinCompatDialog):
         self.verticalLayout.setObjectName("verticalLayout")
         self.gridLayout = QtWidgets.QGridLayout()
         self.gridLayout.setObjectName("gridLayout")
-        self.label_header_character = QtWidgets.QLabel(WinCompatDialog)
+        self.label_header_character = QtWidgets.QLabel(parent=WinCompatDialog)
         font = QtGui.QFont()
         font.setBold(True)
         font.setWeight(75)
         self.label_header_character.setFont(font)
         self.label_header_character.setObjectName("label_header_character")
         self.gridLayout.addWidget(self.label_header_character, 0, 0, 1, 1)
-        self.label_header_replace = QtWidgets.QLabel(WinCompatDialog)
+        self.label_header_replace = QtWidgets.QLabel(parent=WinCompatDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -43,28 +45,28 @@ def setupUi(self, WinCompatDialog):
         self.label_header_replace.setFont(font)
         self.label_header_replace.setObjectName("label_header_replace")
         self.gridLayout.addWidget(self.label_header_replace, 0, 2, 1, 1)
-        self.label_lt = QtWidgets.QLabel(WinCompatDialog)
+        self.label_lt = QtWidgets.QLabel(parent=WinCompatDialog)
         font = QtGui.QFont()
         font.setFamily("Monospace")
         self.label_lt.setFont(font)
         self.label_lt.setText("<")
         self.label_lt.setObjectName("label_lt")
         self.gridLayout.addWidget(self.label_lt, 3, 0, 1, 1)
-        self.label_colon = QtWidgets.QLabel(WinCompatDialog)
+        self.label_colon = QtWidgets.QLabel(parent=WinCompatDialog)
         font = QtGui.QFont()
         font.setFamily("Monospace")
         self.label_colon.setFont(font)
         self.label_colon.setText(":")
         self.label_colon.setObjectName("label_colon")
         self.gridLayout.addWidget(self.label_colon, 2, 0, 1, 1)
-        self.label_gt = QtWidgets.QLabel(WinCompatDialog)
+        self.label_gt = QtWidgets.QLabel(parent=WinCompatDialog)
         font = QtGui.QFont()
         font.setFamily("Monospace")
         self.label_gt.setFont(font)
         self.label_gt.setText(">")
         self.label_gt.setObjectName("label_gt")
         self.gridLayout.addWidget(self.label_gt, 4, 0, 1, 1)
-        self.replace_questionmark = QtWidgets.QLineEdit(WinCompatDialog)
+        self.replace_questionmark = QtWidgets.QLineEdit(parent=WinCompatDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -75,21 +77,21 @@ def setupUi(self, WinCompatDialog):
         self.replace_questionmark.setMaxLength(1)
         self.replace_questionmark.setObjectName("replace_questionmark")
         self.gridLayout.addWidget(self.replace_questionmark, 5, 2, 1, 1)
-        self.label_questionmark = QtWidgets.QLabel(WinCompatDialog)
+        self.label_questionmark = QtWidgets.QLabel(parent=WinCompatDialog)
         font = QtGui.QFont()
         font.setFamily("Monospace")
         self.label_questionmark.setFont(font)
         self.label_questionmark.setText("?")
         self.label_questionmark.setObjectName("label_questionmark")
         self.gridLayout.addWidget(self.label_questionmark, 5, 0, 1, 1)
-        self.label_pipe = QtWidgets.QLabel(WinCompatDialog)
+        self.label_pipe = QtWidgets.QLabel(parent=WinCompatDialog)
         font = QtGui.QFont()
         font.setFamily("Monospace")
         self.label_pipe.setFont(font)
         self.label_pipe.setText("|")
         self.label_pipe.setObjectName("label_pipe")
         self.gridLayout.addWidget(self.label_pipe, 6, 0, 1, 1)
-        self.replace_asterisk = QtWidgets.QLineEdit(WinCompatDialog)
+        self.replace_asterisk = QtWidgets.QLineEdit(parent=WinCompatDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Minimum)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -100,7 +102,7 @@ def setupUi(self, WinCompatDialog):
         self.replace_asterisk.setMaxLength(1)
         self.replace_asterisk.setObjectName("replace_asterisk")
         self.gridLayout.addWidget(self.replace_asterisk, 1, 2, 1, 1)
-        self.replace_gt = QtWidgets.QLineEdit(WinCompatDialog)
+        self.replace_gt = QtWidgets.QLineEdit(parent=WinCompatDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -113,7 +115,7 @@ def setupUi(self, WinCompatDialog):
         self.gridLayout.addWidget(self.replace_gt, 4, 2, 1, 1)
         spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
         self.gridLayout.addItem(spacerItem, 0, 3, 1, 1)
-        self.replace_lt = QtWidgets.QLineEdit(WinCompatDialog)
+        self.replace_lt = QtWidgets.QLineEdit(parent=WinCompatDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -124,14 +126,14 @@ def setupUi(self, WinCompatDialog):
         self.replace_lt.setMaxLength(1)
         self.replace_lt.setObjectName("replace_lt")
         self.gridLayout.addWidget(self.replace_lt, 3, 2, 1, 1)
-        self.label_asterisk = QtWidgets.QLabel(WinCompatDialog)
+        self.label_asterisk = QtWidgets.QLabel(parent=WinCompatDialog)
         font = QtGui.QFont()
         font.setFamily("Monospace")
         self.label_asterisk.setFont(font)
         self.label_asterisk.setText("*")
         self.label_asterisk.setObjectName("label_asterisk")
         self.gridLayout.addWidget(self.label_asterisk, 1, 0, 1, 1)
-        self.replace_pipe = QtWidgets.QLineEdit(WinCompatDialog)
+        self.replace_pipe = QtWidgets.QLineEdit(parent=WinCompatDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -142,7 +144,7 @@ def setupUi(self, WinCompatDialog):
         self.replace_pipe.setMaxLength(1)
         self.replace_pipe.setObjectName("replace_pipe")
         self.gridLayout.addWidget(self.replace_pipe, 6, 2, 1, 1)
-        self.replace_colon = QtWidgets.QLineEdit(WinCompatDialog)
+        self.replace_colon = QtWidgets.QLineEdit(parent=WinCompatDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -153,14 +155,14 @@ def setupUi(self, WinCompatDialog):
         self.replace_colon.setMaxLength(1)
         self.replace_colon.setObjectName("replace_colon")
         self.gridLayout.addWidget(self.replace_colon, 2, 2, 1, 1)
-        self.label_quotationmark = QtWidgets.QLabel(WinCompatDialog)
+        self.label_quotationmark = QtWidgets.QLabel(parent=WinCompatDialog)
         font = QtGui.QFont()
         font.setFamily("Monospace")
         self.label_quotationmark.setFont(font)
         self.label_quotationmark.setText("\"")
         self.label_quotationmark.setObjectName("label_quotationmark")
         self.gridLayout.addWidget(self.label_quotationmark, 7, 0, 1, 1)
-        self.replace_quotationmark = QtWidgets.QLineEdit(WinCompatDialog)
+        self.replace_quotationmark = QtWidgets.QLineEdit(parent=WinCompatDialog)
         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
@@ -173,7 +175,7 @@ def setupUi(self, WinCompatDialog):
         self.verticalLayout.addLayout(self.gridLayout)
         spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
         self.verticalLayout.addItem(spacerItem1)
-        self.buttonbox = QtWidgets.QDialogButtonBox(WinCompatDialog)
+        self.buttonbox = QtWidgets.QDialogButtonBox(parent=WinCompatDialog)
         self.buttonbox.setOrientation(QtCore.Qt.Orientation.Horizontal)
         self.buttonbox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Save)
         self.buttonbox.setObjectName("buttonbox")
diff --git a/picard/ui/util.py b/picard/ui/util.py
index 717f894394..fcc58361fd 100644
--- a/picard/ui/util.py
+++ b/picard/ui/util.py
@@ -38,6 +38,10 @@
     IS_MACOS,
     IS_WIN,
 )
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.util import find_existing_path
 
 
diff --git a/picard/ui/widgets/profilelistwidget.py b/picard/ui/widgets/profilelistwidget.py
index d3457a5567..bec41bd4c8 100644
--- a/picard/ui/widgets/profilelistwidget.py
+++ b/picard/ui/widgets/profilelistwidget.py
@@ -31,6 +31,10 @@
 )
 
 from picard.const import DEFAULT_PROFILE_NAME
+from picard.i18n import (
+    _,
+    gettext_constants,
+)
 from picard.util import unique_numbered_title
 
 from picard.ui import HashableListWidgetItem
diff --git a/picard/ui/widgets/scriptdocumentation.py b/picard/ui/widgets/scriptdocumentation.py
index 05dfafd816..2b6560366a 100644
--- a/picard/ui/widgets/scriptdocumentation.py
+++ b/picard/ui/widgets/scriptdocumentation.py
@@ -27,6 +27,7 @@
 )
 
 from picard.const import PICARD_URLS
+from picard.i18n import _
 from picard.script import script_function_documentation_all
 
 from picard.ui import FONT_FAMILY_MONOSPACE
diff --git a/picard/ui/widgets/scriptlistwidget.py b/picard/ui/widgets/scriptlistwidget.py
index 78c3828311..de9c07076b 100644
--- a/picard/ui/widgets/scriptlistwidget.py
+++ b/picard/ui/widgets/scriptlistwidget.py
@@ -31,6 +31,10 @@
 )
 
 from picard.const import DEFAULT_SCRIPT_NAME
+from picard.i18n import (
+    _,
+    gettext_constants,
+)
 from picard.util import unique_numbered_title
 
 from picard.ui import HashableListWidgetItem
diff --git a/picard/ui/widgets/scripttextedit.py b/picard/ui/widgets/scripttextedit.py
index 25a10f32da..d5d4667504 100644
--- a/picard/ui/widgets/scripttextedit.py
+++ b/picard/ui/widgets/scripttextedit.py
@@ -48,6 +48,7 @@
     get_config,
 )
 from picard.const.sys import IS_MACOS
+from picard.i18n import _
 from picard.script import (
     ScriptFunctionDocError,
     script_function_documentation,
diff --git a/picard/ui/widgets/tristatesortheaderview.py b/picard/ui/widgets/tristatesortheaderview.py
index 7758ce4513..16c2005353 100644
--- a/picard/ui/widgets/tristatesortheaderview.py
+++ b/picard/ui/widgets/tristatesortheaderview.py
@@ -25,6 +25,8 @@
     QtWidgets,
 )
 
+from picard.i18n import _
+
 
 class TristateSortHeaderView(QtWidgets.QHeaderView):
     """A QHeaderView implementation supporting tristate sorting.
diff --git a/picard/util/__init__.py b/picard/util/__init__.py
index 214f8ffef7..22290f7d02 100644
--- a/picard/util/__init__.py
+++ b/picard/util/__init__.py
@@ -82,6 +82,10 @@
     IS_MACOS,
     IS_WIN,
 )
+from picard.i18n import (
+    _,
+    gettext_constants,
+)
 
 
 if IS_WIN:
diff --git a/picard/util/bytes2human.py b/picard/util/bytes2human.py
index cce456e37f..2e67ceb647 100644
--- a/picard/util/bytes2human.py
+++ b/picard/util/bytes2human.py
@@ -32,6 +32,11 @@
 
 import locale
 
+from picard.i18n import (
+    N_,
+    _,
+)
+
 
 # used to force gettextization
 _BYTES_STRINGS_I18N = (
diff --git a/picard/util/checkupdate.py b/picard/util/checkupdate.py
index 66aa666d2f..33408bfa53 100644
--- a/picard/util/checkupdate.py
+++ b/picard/util/checkupdate.py
@@ -35,6 +35,11 @@
     PLUGINS_API,
     PROGRAM_UPDATE_LEVELS,
 )
+from picard.i18n import (
+    N_,
+    _,
+    gettext_constants,
+)
 from picard.util import webbrowser2
 from picard.version import (
     Version,
diff --git a/picard/util/tags.py b/picard/util/tags.py
index 29162b21f3..47bcbc9915 100644
--- a/picard/util/tags.py
+++ b/picard/util/tags.py
@@ -31,6 +31,11 @@
 
 import re
 
+from picard.i18n import (
+    N_,
+    _,
+)
+
 
 TAG_NAMES = {
     'acoustid_fingerprint': N_('AcoustID Fingerprint'),
diff --git a/picard/util/time.py b/picard/util/time.py
index 40e9ddf852..5a13a7a6ff 100644
--- a/picard/util/time.py
+++ b/picard/util/time.py
@@ -23,6 +23,8 @@
 
 from collections import namedtuple
 
+from picard.i18n import _
+
 
 SECS_IN_DAY = 86400
 SECS_IN_HOUR = 3600
diff --git a/picard/util/versions.py b/picard/util/versions.py
index 2b33004597..7ea27a9657 100644
--- a/picard/util/versions.py
+++ b/picard/util/versions.py
@@ -35,6 +35,10 @@
 
 from picard import PICARD_FANCY_VERSION_STR
 from picard.disc import discid_version
+from picard.i18n import (
+    N_,
+    _,
+)
 from picard.util.astrcmp import astrcmp_implementation
 
 
diff --git a/picard/util/webbrowser2.py b/picard/util/webbrowser2.py
index 3a3d5af670..fa661b497d 100644
--- a/picard/util/webbrowser2.py
+++ b/picard/util/webbrowser2.py
@@ -34,6 +34,7 @@
 from PyQt6 import QtWidgets
 
 from picard.const import PICARD_URLS
+from picard.i18n import _
 
 
 def open(url):
diff --git a/setup.py b/setup.py
index a20f0c5240..ce66c6c025 100644
--- a/setup.py
+++ b/setup.py
@@ -382,9 +382,10 @@ def compile_ui(uifile, pyfile):
             tmp = StringIO()
             uic.compileUi(uifile, tmp)
             source = tmp.getvalue()
-            rc = re.compile(r'\n\n#.*?(?=\n\n)', re.MULTILINE | re.DOTALL)
-            comment = ("\n\n# Automatically generated - don't edit.\n"
-                       "# Use `python setup.py %s` to update it."
+            rc = re.compile(r'\n# WARNING.*?(?=\n\n)', re.MULTILINE | re.DOTALL)
+            comment = ("\n# Automatically generated - do not edit.\n"
+                       "# Use `python setup.py %s` to update it.\n\n"
+                       "from picard.i18n import _"
                        % _get_option_name(self))
             for r in list(_translate_re):
                 source = r.sub(r'_(\1)', source)
diff --git a/test/test_i18n.py b/test/test_i18n.py
index 7aa2eb0715..a864f588fe 100644
--- a/test/test_i18n.py
+++ b/test/test_i18n.py
@@ -30,7 +30,17 @@
 
 from test.picardtestcase import PicardTestCase
 
-from picard import i18n
+from picard.i18n import (
+    N_,
+    _,
+    _try_encodings,
+    _try_locales,
+    gettext_constants,
+    gettext_countries,
+    ngettext,
+    pgettext_attributes,
+    setup_gettext,
+)
 
 
 localedir = os.path.join(os.path.dirname(__file__), '..', 'locale')
@@ -47,7 +57,7 @@ def cleanup_tmplocale():
         self.addCleanup(cleanup_tmplocale)
         locale_de = os.path.join(tmplocaledir, 'de', 'LC_MESSAGES', 'picard.mo')
         self.assertFalse(os.path.exists(locale_de), 'unexpected file %s' % locale_de)
-        i18n.setup_gettext(tmplocaledir, 'de')
+        setup_gettext(tmplocaledir, 'de')
         self.assertEqual('foo', _('foo'))
         self.assertEqual('Country', _('Country'))
         self.assertEqual('Country', N_('Country'))
@@ -63,11 +73,7 @@ def test_existing_locales(self):
         locale_de = os.path.join(localedir, 'de', 'LC_MESSAGES', 'picard.mo')
         self.assertTrue(os.path.exists(locale_de), 'expected file %s' % locale_de)
 
-        gettext_before_setup = _
-        i18n.setup_gettext(localedir, 'de')
-        gettext_after_setup = _
-
-        self.assertNotEqual(gettext_before_setup, gettext_after_setup)
+        setup_gettext(localedir, 'de')
 
         self.assertEqual('foo', _('foo'))
         self.assertEqual('Land', _('Country'))
@@ -83,14 +89,14 @@ def test_existing_locales(self):
 class TestTryEncodingsLocales(PicardTestCase):
     def test_try_encodings_iso(self, locale_getpreferredencoding_mock):
         locale_getpreferredencoding_mock.return_value = 'ISO-8859-1'
-        result = tuple(i18n._try_encodings())
+        result = tuple(_try_encodings())
         expected = ('ISO-8859-1', 'UTF-8', None)
         self.assertEqual(expected, result)
         locale_getpreferredencoding_mock.assert_called_once()
 
     def test_try_encodings_utf8(self, locale_getpreferredencoding_mock):
         locale_getpreferredencoding_mock.return_value = 'UTF-8'
-        result = tuple(i18n._try_encodings())
+        result = tuple(_try_encodings())
         expected = ('UTF-8', None)
         self.assertEqual(expected, result)
         locale_getpreferredencoding_mock.assert_called_once()
@@ -99,7 +105,7 @@ def test_try_encodings_utf8(self, locale_getpreferredencoding_mock):
     def test_try_locales_utf8_en(self, locale_nomalize_mock, locale_getpreferredencoding_mock):
         locale_getpreferredencoding_mock.return_value = 'UTF-8'
         locale_nomalize_mock.return_value = 'en_US.UTF-8'
-        result = tuple(i18n._try_locales('en'))
+        result = tuple(_try_locales('en'))
         expected = ('en_US.UTF-8', 'en')
         self.assertEqual(expected, result)
         locale_getpreferredencoding_mock.assert_called_once()
@@ -110,7 +116,7 @@ def test_try_locales_utf8_en(self, locale_nomalize_mock, locale_getpreferredenco
     def test_try_locales_iso_en(self, locale_nomalize_mock, locale_getpreferredencoding_mock):
         locale_getpreferredencoding_mock.return_value = 'ISO-8859-1'
         locale_nomalize_mock.side_effect = lambda x: x.lower()
-        result = tuple(i18n._try_locales('EN'))
+        result = tuple(_try_locales('EN'))
         expected = ('en.iso-8859-1', 'en.utf-8', 'EN')
         self.assertEqual(expected, result)
         locale_getpreferredencoding_mock.assert_called_once()
diff --git a/test/test_script.py b/test/test_script.py
index 8674023e0a..2d242f3f8a 100644
--- a/test/test_script.py
+++ b/test/test_script.py
@@ -30,7 +30,6 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
 
-import builtins
 import copy
 import datetime
 import re
@@ -1970,12 +1969,6 @@ def test_cmd_countryname(self):
         context["bar"] = ""
         context["baz"] = "INVALID"
 
-        # Ensure that `builtins` contains a `gettext_countries` attribute to avoid an `AttributeError`
-        # exception when mocking the function, in case the `picard.i18n` module has not been loaded.
-        # This is required by the $countryname() function in order to translate the country names.
-        if not hasattr(builtins, 'gettext_countries'):
-            builtins.__dict__['gettext_countries'] = None
-
         # Mock function to simulate English locale.
         def mock_gettext_countries_en(arg):
             return arg
@@ -1985,7 +1978,7 @@ def mock_gettext_countries_ru(arg):
             return "Канада" if arg == 'Canada' else arg
 
         # Test with Russian locale
-        with mock.patch('builtins.gettext_countries', mock_gettext_countries_ru):
+        with mock.patch('picard.script.functions.gettext_countries', mock_gettext_countries_ru):
             self.assertScriptResultEquals("$countryname(ca)", "Canada", context)
             self.assertScriptResultEquals("$countryname(ca,)", "Canada", context)
             self.assertScriptResultEquals("$countryname(ca, )", "Канада", context)
@@ -1995,7 +1988,7 @@ def mock_gettext_countries_ru(arg):
             self.assertScriptResultEquals("$countryname(fr,yes)", "France", context)
 
         # Reset locale to English for remaining tests
-        with mock.patch('builtins.gettext_countries', mock_gettext_countries_en):
+        with mock.patch('picard.script.functions.gettext_countries', mock_gettext_countries_en):
             self.assertScriptResultEquals("$countryname(ca,)", "Canada", context)
             self.assertScriptResultEquals("$countryname(ca,yes)", "Canada", context)
             self.assertScriptResultEquals("$countryname(ca)", "Canada", context)
diff --git a/test/test_utils.py b/test/test_utils.py
index e95d66cf62..f4e425fac8 100644
--- a/test/test_utils.py
+++ b/test/test_utils.py
@@ -30,7 +30,6 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
 
-import builtins
 from collections import namedtuple
 from collections.abc import Iterator
 from locale import strxfrm as system_strxfrm
@@ -55,6 +54,7 @@
     IS_MACOS,
     IS_WIN,
 )
+from picard.i18n import _
 from picard.util import (
     IgnoreUpdatesContext,
     album_artist_from_path,
@@ -84,11 +84,6 @@
 )
 
 
-# ensure _() is defined
-if '_' not in builtins.__dict__:
-    builtins.__dict__['_'] = lambda a: a
-
-
 class ReplaceWin32IncompatTest(PicardTestCase):
 
     @unittest.skipUnless(IS_WIN, "windows test")

From 2cf93232106e940e53ebc6a3edd552f178e4b926 Mon Sep 17 00:00:00 2001
From: Laurent Monin <github@norz.org>
Date: Sun, 21 Apr 2024 23:08:18 +0200
Subject: [PATCH 2/8] Remove obsolete comment

---
 picard/ui/mainwindow.py | 2 --
 1 file changed, 2 deletions(-)

diff --git a/picard/ui/mainwindow.py b/picard/ui/mainwindow.py
index d97f221a24..64f72e0224 100644
--- a/picard/ui/mainwindow.py
+++ b/picard/ui/mainwindow.py
@@ -461,8 +461,6 @@ def isdict(obj):
             return hasattr(obj, 'keys') and hasattr(obj, '__getitem__')
 
         echo = kwargs.get('echo', log.debug)
-        # _ is defined using builtins.__dict__, so setting it as default named argument
-        # value doesn't work as expected
         translate = kwargs.get('translate', _)
         timeout = kwargs.get('timeout', 0)
         history = kwargs.get('history', log.history_info)

From 2aebd616b4321e05566c115b65f8003e941fd508 Mon Sep 17 00:00:00 2001
From: Laurent Monin <github@norz.org>
Date: Sun, 21 Apr 2024 23:08:40 +0200
Subject: [PATCH 3/8] Remove builtins declarations for checkers

---
 .pylintrc | 3 +--
 setup.cfg | 1 -
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/.pylintrc b/.pylintrc
index a3287f247c..b5dcbc3b04 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -283,8 +283,7 @@ min-similarity-lines=4
 
 # List of additional names supposed to be defined in builtins. Remember that
 # you should avoid defining new builtins when possible.
-additional-builtins=_, N_, ngettext, gettext_attributes, pgettext_attributes,
-                    gettext_constants, gettext_countries
+additional-builtins=
 
 # Tells whether unused global variables should be treated as a violation.
 allow-global-unused-variables=yes
diff --git a/setup.cfg b/setup.cfg
index e59062f07a..85f0faf659 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -7,7 +7,6 @@
 # E501: line too long (xx > 79 characters)
 # W503: line break occurred before a binary operator
 ignore = E127,E128,E129,E226,E241,E501,W503
-builtins = _,N_,ngettext,gettext_attributes,pgettext_attributes,gettext_constants,gettext_countries
 exclude = ui_*.py,picard/resources.py
 
 [coverage:run]

From fc87e6cba20ea89472e61026ae0999e2f710a667 Mon Sep 17 00:00:00 2001
From: Laurent Monin <github@norz.org>
Date: Sun, 21 Apr 2024 23:46:19 +0200
Subject: [PATCH 4/8] i18n: _gettext() -> gettext(), gettext -> module_gettext

It will let do:
from picard.i18n import gettext
or
from picard.i18n import gettext as _
---
 picard/i18n.py | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/picard/i18n.py b/picard/i18n.py
index 6e7ca55d64..5c045f2234 100644
--- a/picard/i18n.py
+++ b/picard/i18n.py
@@ -21,7 +21,7 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
-import gettext
+import gettext as module_gettext
 import locale
 import os
 
@@ -112,10 +112,10 @@ def _try_locales(language):
 def _load_translation(domain, localedir, language):
     try:
         _logger("Loading gettext translation for %s, localedir=%r, language=%r", domain, localedir, language)
-        return gettext.translation(domain, localedir, languages=[language])
+        return module_gettext.translation(domain, localedir, languages=[language])
     except OSError as e:
         _logger(e)
-        return gettext.NullTranslations()
+        return module_gettext.NullTranslations()
 
 
 def _log_lang_env_vars():
@@ -177,21 +177,21 @@ def setup_gettext(localedir, ui_language=None, logger=None):
     _logger(_translation)
 
 
-def _get_translation(key: str) -> gettext.NullTranslations:
+def _get_translation(key: str) -> module_gettext.NullTranslations:
     try:
         return _translation[key]
     except KeyError:
-        return gettext.NullTranslations()
+        return module_gettext.NullTranslations()
 
 
-def _gettext(message: str) -> str:
+def gettext(message: str) -> str:
     """Translate the messsage using the current translator."""
     return _get_translation('main').gettext(message)
 
 
 def _(message: str) -> str:
     """Alias for gettext"""
-    return _gettext(message)
+    return gettext(message)
 
 
 def N_(message: str) -> str:

From 10d2992253eae283dd1a5d0f9f11c1dafccd93a2 Mon Sep 17 00:00:00 2001
From: Laurent Monin <github@norz.org>
Date: Sun, 21 Apr 2024 23:47:32 +0200
Subject: [PATCH 5/8] import _ -> import gettext as _

---
 picard/album.py                                 | 2 +-
 picard/browser/addrelease.py                    | 2 +-
 picard/cluster.py                               | 2 +-
 picard/config_upgrade.py                        | 2 +-
 picard/const/scripts.py                         | 2 +-
 picard/coverart/providers/caa.py                | 2 +-
 picard/coverart/utils.py                        | 2 +-
 picard/file.py                                  | 2 +-
 picard/oauth.py                                 | 2 +-
 picard/pluginmanager.py                         | 2 +-
 picard/releasegroup.py                          | 2 +-
 picard/script/__init__.py                       | 2 +-
 picard/script/functions.py                      | 2 +-
 picard/script/serializer.py                     | 2 +-
 picard/tagger.py                                | 2 +-
 picard/track.py                                 | 2 +-
 picard/ui/aboutdialog.py                        | 2 +-
 picard/ui/caa_types_selector.py                 | 2 +-
 picard/ui/cdlookup.py                           | 2 +-
 picard/ui/collectionmenu.py                     | 2 +-
 picard/ui/colors.py                             | 2 +-
 picard/ui/coverartbox.py                        | 2 +-
 picard/ui/edittagdialog.py                      | 2 +-
 picard/ui/filebrowser.py                        | 2 +-
 picard/ui/infodialog.py                         | 2 +-
 picard/ui/infostatus.py                         | 2 +-
 picard/ui/itemviews.py                          | 2 +-
 picard/ui/logview.py                            | 2 +-
 picard/ui/mainwindow.py                         | 2 +-
 picard/ui/metadatabox.py                        | 2 +-
 picard/ui/newuserdialog.py                      | 2 +-
 picard/ui/options/__init__.py                   | 2 +-
 picard/ui/options/cover.py                      | 2 +-
 picard/ui/options/dialog.py                     | 2 +-
 picard/ui/options/fingerprinting.py             | 2 +-
 picard/ui/options/general.py                    | 2 +-
 picard/ui/options/genres.py                     | 2 +-
 picard/ui/options/interface.py                  | 2 +-
 picard/ui/options/interface_colors.py           | 2 +-
 picard/ui/options/interface_toolbar.py          | 2 +-
 picard/ui/options/maintenance.py                | 2 +-
 picard/ui/options/metadata.py                   | 2 +-
 picard/ui/options/plugins.py                    | 2 +-
 picard/ui/options/profiles.py                   | 2 +-
 picard/ui/options/releases.py                   | 2 +-
 picard/ui/options/renaming.py                   | 2 +-
 picard/ui/options/renaming_compat.py            | 2 +-
 picard/ui/options/scripting.py                  | 2 +-
 picard/ui/passworddialog.py                     | 2 +-
 picard/ui/playertoolbar.py                      | 2 +-
 picard/ui/pluginupdatedialog.py                 | 2 +-
 picard/ui/savewarningdialog.py                  | 2 +-
 picard/ui/scripteditor.py                       | 2 +-
 picard/ui/searchdialog/__init__.py              | 2 +-
 picard/ui/searchdialog/album.py                 | 2 +-
 picard/ui/searchdialog/artist.py                | 2 +-
 picard/ui/searchdialog/track.py                 | 2 +-
 picard/ui/tagsfromfilenames.py                  | 2 +-
 picard/ui/ui_aboutdialog.py                     | 2 +-
 picard/ui/ui_cdlookup.py                        | 2 +-
 picard/ui/ui_edittagdialog.py                   | 2 +-
 picard/ui/ui_exception_script_selector.py       | 2 +-
 picard/ui/ui_infodialog.py                      | 2 +-
 picard/ui/ui_infostatus.py                      | 2 +-
 picard/ui/ui_multi_locale_selector.py           | 2 +-
 picard/ui/ui_options.py                         | 2 +-
 picard/ui/ui_options_advanced.py                | 2 +-
 picard/ui/ui_options_attached_profiles.py       | 2 +-
 picard/ui/ui_options_cdlookup.py                | 2 +-
 picard/ui/ui_options_cdlookup_select.py         | 2 +-
 picard/ui/ui_options_cover.py                   | 2 +-
 picard/ui/ui_options_fingerprinting.py          | 2 +-
 picard/ui/ui_options_general.py                 | 2 +-
 picard/ui/ui_options_genres.py                  | 2 +-
 picard/ui/ui_options_interface.py               | 2 +-
 picard/ui/ui_options_interface_colors.py        | 2 +-
 picard/ui/ui_options_interface_toolbar.py       | 2 +-
 picard/ui/ui_options_interface_top_tags.py      | 2 +-
 picard/ui/ui_options_maintenance.py             | 2 +-
 picard/ui/ui_options_matching.py                | 2 +-
 picard/ui/ui_options_metadata.py                | 2 +-
 picard/ui/ui_options_network.py                 | 2 +-
 picard/ui/ui_options_plugins.py                 | 2 +-
 picard/ui/ui_options_profiles.py                | 2 +-
 picard/ui/ui_options_ratings.py                 | 2 +-
 picard/ui/ui_options_releases.py                | 2 +-
 picard/ui/ui_options_renaming.py                | 2 +-
 picard/ui/ui_options_renaming_compat.py         | 2 +-
 picard/ui/ui_options_script.py                  | 2 +-
 picard/ui/ui_options_tags.py                    | 2 +-
 picard/ui/ui_options_tags_compatibility_aac.py  | 2 +-
 picard/ui/ui_options_tags_compatibility_ac3.py  | 2 +-
 picard/ui/ui_options_tags_compatibility_id3.py  | 2 +-
 picard/ui/ui_options_tags_compatibility_wave.py | 2 +-
 picard/ui/ui_passworddialog.py                  | 2 +-
 picard/ui/ui_provider_options_caa.py            | 2 +-
 picard/ui/ui_provider_options_local.py          | 2 +-
 picard/ui/ui_scripteditor.py                    | 2 +-
 picard/ui/ui_scripteditor_details.py            | 2 +-
 picard/ui/ui_scripting_documentation_dialog.py  | 2 +-
 picard/ui/ui_tagsfromfilenames.py               | 2 +-
 picard/ui/ui_widget_taglisteditor.py            | 2 +-
 picard/ui/ui_win_compat_dialog.py               | 2 +-
 picard/ui/util.py                               | 2 +-
 picard/ui/widgets/profilelistwidget.py          | 2 +-
 picard/ui/widgets/scriptdocumentation.py        | 2 +-
 picard/ui/widgets/scriptlistwidget.py           | 2 +-
 picard/ui/widgets/scripttextedit.py             | 2 +-
 picard/ui/widgets/tristatesortheaderview.py     | 2 +-
 picard/util/__init__.py                         | 2 +-
 picard/util/bytes2human.py                      | 2 +-
 picard/util/checkupdate.py                      | 2 +-
 picard/util/tags.py                             | 2 +-
 picard/util/time.py                             | 2 +-
 picard/util/versions.py                         | 2 +-
 picard/util/webbrowser2.py                      | 2 +-
 setup.py                                        | 2 +-
 test/test_i18n.py                               | 2 +-
 test/test_utils.py                              | 2 +-
 119 files changed, 119 insertions(+), 119 deletions(-)

diff --git a/picard/album.py b/picard/album.py
index 8421fa4961..e8a5a60c28 100644
--- a/picard/album.py
+++ b/picard/album.py
@@ -61,7 +61,7 @@
 from picard.file import File
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.mbjson import (
     medium_to_metadata,
diff --git a/picard/browser/addrelease.py b/picard/browser/addrelease.py
index c33728d214..690f921e77 100644
--- a/picard/browser/addrelease.py
+++ b/picard/browser/addrelease.py
@@ -28,7 +28,7 @@
 from PyQt6.QtCore import QCoreApplication
 
 from picard import log
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.util import format_time
 from picard.util.mbserver import build_submission_url
 from picard.util.webbrowser2 import open
diff --git a/picard/cluster.py b/picard/cluster.py
index b3e1c3fdab..b4eccae5f6 100644
--- a/picard/cluster.py
+++ b/picard/cluster.py
@@ -48,7 +48,7 @@
 from picard.file import File
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.metadata import (
     Metadata,
diff --git a/picard/config_upgrade.py b/picard/config_upgrade.py
index 8337a9a59e..1dfbf92378 100644
--- a/picard/config_upgrade.py
+++ b/picard/config_upgrade.py
@@ -53,7 +53,7 @@
 )
 from picard.const.sys import IS_FROZEN
 from picard.i18n import (
-    _,
+    gettext as _,
     gettext_constants,
 )
 from picard.util import unique_numbered_title
diff --git a/picard/const/scripts.py b/picard/const/scripts.py
index 359b63292d..00fb6c3696 100644
--- a/picard/const/scripts.py
+++ b/picard/const/scripts.py
@@ -22,7 +22,7 @@
 
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 
 
diff --git a/picard/coverart/providers/caa.py b/picard/coverart/providers/caa.py
index d32b8466e9..810c3a6207 100644
--- a/picard/coverart/providers/caa.py
+++ b/picard/coverart/providers/caa.py
@@ -61,7 +61,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.webservice import ratecontrol
 
diff --git a/picard/coverart/utils.py b/picard/coverart/utils.py
index c6a08027f1..eb8cd61271 100644
--- a/picard/coverart/utils.py
+++ b/picard/coverart/utils.py
@@ -27,7 +27,7 @@
 from picard.const import MB_ATTRIBUTES
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     pgettext_attributes,
 )
 
diff --git a/picard/file.py b/picard/file.py
index 5739158c91..d0bd33fad1 100644
--- a/picard/file.py
+++ b/picard/file.py
@@ -73,7 +73,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.metadata import (
     Metadata,
diff --git a/picard/oauth.py b/picard/oauth.py
index d9f1a80d1e..444f918f88 100644
--- a/picard/oauth.py
+++ b/picard/oauth.py
@@ -36,7 +36,7 @@
     MUSICBRAINZ_OAUTH_CLIENT_ID,
     MUSICBRAINZ_OAUTH_CLIENT_SECRET,
 )
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.util import (
     build_qurl,
     load_json,
diff --git a/picard/pluginmanager.py b/picard/pluginmanager.py
index 05ab484218..ee9ea0e608 100644
--- a/picard/pluginmanager.py
+++ b/picard/pluginmanager.py
@@ -46,7 +46,7 @@
 from picard.const.sys import IS_FROZEN
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.plugin import (
     _PLUGIN_MODULE_PREFIX,
diff --git a/picard/releasegroup.py b/picard/releasegroup.py
index 07be7f1ddd..d78b8058f7 100644
--- a/picard/releasegroup.py
+++ b/picard/releasegroup.py
@@ -34,7 +34,7 @@
 from picard.dataobj import DataObject
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     pgettext_attributes,
 )
 from picard.mbjson import (
diff --git a/picard/script/__init__.py b/picard/script/__init__.py
index 7a6cd75bb5..b33c731f8f 100644
--- a/picard/script/__init__.py
+++ b/picard/script/__init__.py
@@ -43,7 +43,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.script.functions import (  # noqa: F401 # pylint: disable=unused-import
     register_script_function,
diff --git a/picard/script/functions.py b/picard/script/functions.py
index 0a1c52c003..f656e8feb6 100644
--- a/picard/script/functions.py
+++ b/picard/script/functions.py
@@ -47,7 +47,7 @@
 from picard.const.countries import RELEASE_COUNTRIES
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     gettext_countries,
 )
 from picard.metadata import MULTI_VALUED_JOINER
diff --git a/picard/script/serializer.py b/picard/script/serializer.py
index 2e81d9762f..e3cc7bab9e 100644
--- a/picard/script/serializer.py
+++ b/picard/script/serializer.py
@@ -45,7 +45,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.util import make_filename_from_title
 
diff --git a/picard/tagger.py b/picard/tagger.py
index 326328fc08..2dbd98df46 100644
--- a/picard/tagger.py
+++ b/picard/tagger.py
@@ -112,7 +112,7 @@
 from picard.formats import open_ as open_file
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     setup_gettext,
 )
 from picard.pluginmanager import (
diff --git a/picard/track.py b/picard/track.py
index 0e3c6bcd88..837c4ae2b8 100644
--- a/picard/track.py
+++ b/picard/track.py
@@ -60,7 +60,7 @@
     run_file_post_addition_to_track_processors,
     run_file_post_removal_from_track_processors,
 )
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.mbjson import recording_to_metadata
 from picard.metadata import (
     Metadata,
diff --git a/picard/ui/aboutdialog.py b/picard/ui/aboutdialog.py
index fbbe802779..444d796297 100644
--- a/picard/ui/aboutdialog.py
+++ b/picard/ui/aboutdialog.py
@@ -31,7 +31,7 @@
 
 from picard.const import PICARD_URLS
 from picard.formats import supported_extensions
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.util import versions
 
 from picard.ui import (
diff --git a/picard/ui/caa_types_selector.py b/picard/ui/caa_types_selector.py
index b1c860a679..6f613b1c7f 100644
--- a/picard/ui/caa_types_selector.py
+++ b/picard/ui/caa_types_selector.py
@@ -39,7 +39,7 @@
 
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 
 from picard.ui import PicardDialog
diff --git a/picard/ui/cdlookup.py b/picard/ui/cdlookup.py
index b14061c134..beae54def8 100644
--- a/picard/ui/cdlookup.py
+++ b/picard/ui/cdlookup.py
@@ -37,7 +37,7 @@
     Option,
     get_config,
 )
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.mbjson import (
     artist_credit_from_node,
     label_info_from_node,
diff --git a/picard/ui/collectionmenu.py b/picard/ui/collectionmenu.py
index b59ebf0cb7..d7d25448f6 100644
--- a/picard/ui/collectionmenu.py
+++ b/picard/ui/collectionmenu.py
@@ -34,7 +34,7 @@
     user_collections,
 )
 from picard.i18n import (
-    _,
+    gettext as _,
     ngettext,
 )
 from picard.util import strxfrm
diff --git a/picard/ui/colors.py b/picard/ui/colors.py
index de6184f9c2..1f0cfeba71 100644
--- a/picard/ui/colors.py
+++ b/picard/ui/colors.py
@@ -27,7 +27,7 @@
 from picard.config import get_config
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 
 from picard.ui.theme import theme
diff --git a/picard/ui/coverartbox.py b/picard/ui/coverartbox.py
index 70a9e30451..863e37bc4d 100644
--- a/picard/ui/coverartbox.py
+++ b/picard/ui/coverartbox.py
@@ -55,7 +55,7 @@
     CoverArtImageIOError,
 )
 from picard.file import File
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.track import Track
 from picard.util import (
     imageinfo,
diff --git a/picard/ui/edittagdialog.py b/picard/ui/edittagdialog.py
index 5e0531211f..767d79f955 100644
--- a/picard/ui/edittagdialog.py
+++ b/picard/ui/edittagdialog.py
@@ -39,7 +39,7 @@
     RELEASE_STATUS,
 )
 from picard.const.countries import RELEASE_COUNTRIES
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.util.tags import TAG_NAMES
 
 from picard.ui import PicardDialog
diff --git a/picard/ui/filebrowser.py b/picard/ui/filebrowser.py
index 27ec6abc2f..f16d6107b1 100644
--- a/picard/ui/filebrowser.py
+++ b/picard/ui/filebrowser.py
@@ -46,7 +46,7 @@
 )
 from picard.const.sys import IS_MACOS
 from picard.formats import supported_formats
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.util import find_existing_path
 
 
diff --git a/picard/ui/infodialog.py b/picard/ui/infodialog.py
index 2be3c720a4..67d1ca98d4 100644
--- a/picard/ui/infodialog.py
+++ b/picard/ui/infodialog.py
@@ -48,7 +48,7 @@
 from picard.coverart.image import CoverArtImageIOError
 from picard.file import File
 from picard.i18n import (
-    _,
+    gettext as _,
     ngettext,
 )
 from picard.track import Track
diff --git a/picard/ui/infostatus.py b/picard/ui/infostatus.py
index fdba9c49ec..ba8f3d6b8c 100644
--- a/picard/ui/infostatus.py
+++ b/picard/ui/infostatus.py
@@ -30,7 +30,7 @@
     QtWidgets,
 )
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.util import icontheme
 from picard.util.time import get_timestamp
 
diff --git a/picard/ui/itemviews.py b/picard/ui/itemviews.py
index 3cabb7f136..ae63b103e1 100644
--- a/picard/ui/itemviews.py
+++ b/picard/ui/itemviews.py
@@ -77,7 +77,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.plugin import ExtensionPoint
 from picard.track import (
diff --git a/picard/ui/logview.py b/picard/ui/logview.py
index 67226b131b..91a52f12b1 100644
--- a/picard/ui/logview.py
+++ b/picard/ui/logview.py
@@ -44,7 +44,7 @@
     get_config,
 )
 from picard.debug_opts import DebugOpt
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.util import (
     reconnect,
     wildcards_to_regex_pattern,
diff --git a/picard/ui/mainwindow.py b/picard/ui/mainwindow.py
index 64f72e0224..88e240d3a6 100644
--- a/picard/ui/mainwindow.py
+++ b/picard/ui/mainwindow.py
@@ -86,7 +86,7 @@
 from picard.formats import supported_formats
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     ngettext,
 )
 from picard.plugin import ExtensionPoint
diff --git a/picard/ui/metadatabox.py b/picard/ui/metadatabox.py
index 0b416d0541..51120bf130 100644
--- a/picard/ui/metadatabox.py
+++ b/picard/ui/metadatabox.py
@@ -53,7 +53,7 @@
 )
 from picard.file import File
 from picard.i18n import (
-    _,
+    gettext as _,
     ngettext,
 )
 from picard.metadata import MULTI_VALUED_JOINER
diff --git a/picard/ui/newuserdialog.py b/picard/ui/newuserdialog.py
index 073de61c9f..2d832785f7 100644
--- a/picard/ui/newuserdialog.py
+++ b/picard/ui/newuserdialog.py
@@ -27,7 +27,7 @@
 )
 
 from picard.const import PICARD_URLS
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 class NewUserDialog():
diff --git a/picard/ui/options/__init__.py b/picard/ui/options/__init__.py
index 43c806c4cd..f9e8ff7265 100644
--- a/picard/ui/options/__init__.py
+++ b/picard/ui/options/__init__.py
@@ -29,7 +29,7 @@
 
 from picard import log
 from picard.config import get_config
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.plugin import ExtensionPoint
 
 
diff --git a/picard/ui/options/cover.py b/picard/ui/options/cover.py
index a4806ace0e..ec89a28a56 100644
--- a/picard/ui/options/cover.py
+++ b/picard/ui/options/cover.py
@@ -37,7 +37,7 @@
 from picard.coverart.providers import cover_art_providers
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 
 from picard.ui.checkbox_list_item import CheckboxListItem
diff --git a/picard/ui/options/dialog.py b/picard/ui/options/dialog.py
index 6ace11ce1b..b2b9bb7ba2 100644
--- a/picard/ui/options/dialog.py
+++ b/picard/ui/options/dialog.py
@@ -48,7 +48,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.profile import UserProfileGroups
 from picard.util import restore_method
diff --git a/picard/ui/options/fingerprinting.py b/picard/ui/options/fingerprinting.py
index 39886ab080..29f0da6c95 100644
--- a/picard/ui/options/fingerprinting.py
+++ b/picard/ui/options/fingerprinting.py
@@ -42,7 +42,7 @@
 from picard.const import DEFAULT_FPCALC_THREADS
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.util import webbrowser2
 
diff --git a/picard/ui/options/general.py b/picard/ui/options/general.py
index 446ca04a27..f1bcdf4eac 100644
--- a/picard/ui/options/general.py
+++ b/picard/ui/options/general.py
@@ -43,7 +43,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     gettext_constants,
 )
 from picard.util.mbserver import is_official_server
diff --git a/picard/ui/options/genres.py b/picard/ui/options/genres.py
index 81bed888fe..a2b8183651 100644
--- a/picard/ui/options/genres.py
+++ b/picard/ui/options/genres.py
@@ -36,7 +36,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.track import TagGenreFilter
 
diff --git a/picard/ui/options/interface.py b/picard/ui/options/interface.py
index e8a586bb88..d9c23f47c2 100644
--- a/picard/ui/options/interface.py
+++ b/picard/ui/options/interface.py
@@ -46,7 +46,7 @@
 from picard.const.sys import IS_MACOS
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     gettext_constants,
 )
 from picard.util import strxfrm
diff --git a/picard/ui/options/interface_colors.py b/picard/ui/options/interface_colors.py
index 2360f15f7d..d5e9745b47 100644
--- a/picard/ui/options/interface_colors.py
+++ b/picard/ui/options/interface_colors.py
@@ -32,7 +32,7 @@
 from picard.const.sys import IS_MACOS
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 
 from picard.ui.colors import (
diff --git a/picard/ui/options/interface_toolbar.py b/picard/ui/options/interface_toolbar.py
index 1bd841a245..082a984320 100644
--- a/picard/ui/options/interface_toolbar.py
+++ b/picard/ui/options/interface_toolbar.py
@@ -42,7 +42,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.util import icontheme
 
diff --git a/picard/ui/options/maintenance.py b/picard/ui/options/maintenance.py
index 162be31721..3986ffafb5 100644
--- a/picard/ui/options/maintenance.py
+++ b/picard/ui/options/maintenance.py
@@ -39,7 +39,7 @@
 from picard.config_upgrade import upgrade_config
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.util import open_local_path
 
diff --git a/picard/ui/options/metadata.py b/picard/ui/options/metadata.py
index b63f195c4e..78090a7fa9 100644
--- a/picard/ui/options/metadata.py
+++ b/picard/ui/options/metadata.py
@@ -46,7 +46,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     gettext_constants,
 )
 
diff --git a/picard/ui/options/plugins.py b/picard/ui/options/plugins.py
index 568dbd79ce..537599f252 100644
--- a/picard/ui/options/plugins.py
+++ b/picard/ui/options/plugins.py
@@ -56,7 +56,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.util import (
     icontheme,
diff --git a/picard/ui/options/profiles.py b/picard/ui/options/profiles.py
index e7400fc4ce..63bc7d78f5 100644
--- a/picard/ui/options/profiles.py
+++ b/picard/ui/options/profiles.py
@@ -41,7 +41,7 @@
 from picard.const import DEFAULT_COPY_TEXT
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     gettext_constants,
 )
 from picard.profile import UserProfileGroups
diff --git a/picard/ui/options/releases.py b/picard/ui/options/releases.py
index df2149f045..4de2b24034 100644
--- a/picard/ui/options/releases.py
+++ b/picard/ui/options/releases.py
@@ -45,7 +45,7 @@
 from picard.const.sys import IS_WIN
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     gettext_countries,
     pgettext_attributes,
 )
diff --git a/picard/ui/options/renaming.py b/picard/ui/options/renaming.py
index 5058ed3208..d4688b1322 100644
--- a/picard/ui/options/renaming.py
+++ b/picard/ui/options/renaming.py
@@ -46,7 +46,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.script import ScriptParser
 
diff --git a/picard/ui/options/renaming_compat.py b/picard/ui/options/renaming_compat.py
index 87801d0064..b4c3a851e7 100644
--- a/picard/ui/options/renaming_compat.py
+++ b/picard/ui/options/renaming_compat.py
@@ -50,7 +50,7 @@
 from picard.const.sys import IS_WIN
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.util import system_supports_long_paths
 
diff --git a/picard/ui/options/scripting.py b/picard/ui/options/scripting.py
index f30b8920cb..08cf393810 100644
--- a/picard/ui/options/scripting.py
+++ b/picard/ui/options/scripting.py
@@ -42,7 +42,7 @@
 from picard.const.sys import IS_MACOS
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.script import ScriptParser
 from picard.script.serializer import (
diff --git a/picard/ui/passworddialog.py b/picard/ui/passworddialog.py
index ec3eb03a75..9f019fa040 100644
--- a/picard/ui/passworddialog.py
+++ b/picard/ui/passworddialog.py
@@ -27,7 +27,7 @@
 
 
 from picard.config import get_config
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 from picard.ui import PicardDialog
 from picard.ui.ui_passworddialog import Ui_PasswordDialog
diff --git a/picard/ui/playertoolbar.py b/picard/ui/playertoolbar.py
index c72ed477ad..d8df2af6b1 100644
--- a/picard/ui/playertoolbar.py
+++ b/picard/ui/playertoolbar.py
@@ -36,7 +36,7 @@
 from picard.const.sys import IS_MACOS
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.util import (
     format_time,
diff --git a/picard/ui/pluginupdatedialog.py b/picard/ui/pluginupdatedialog.py
index f4a7cafb91..6f871f3c1b 100644
--- a/picard/ui/pluginupdatedialog.py
+++ b/picard/ui/pluginupdatedialog.py
@@ -28,7 +28,7 @@
 )
 
 from picard.i18n import (
-    _,
+    gettext as _,
     ngettext,
 )
 
diff --git a/picard/ui/savewarningdialog.py b/picard/ui/savewarningdialog.py
index 60fa9e04d6..eb5a616bca 100644
--- a/picard/ui/savewarningdialog.py
+++ b/picard/ui/savewarningdialog.py
@@ -28,7 +28,7 @@
 
 from picard.config import get_config
 from picard.i18n import (
-    _,
+    gettext as _,
     ngettext,
 )
 
diff --git a/picard/ui/scripteditor.py b/picard/ui/scripteditor.py
index 89ed1cf60e..a5834a95a7 100644
--- a/picard/ui/scripteditor.py
+++ b/picard/ui/scripteditor.py
@@ -51,7 +51,7 @@
 from picard.file import File
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     gettext_constants,
 )
 from picard.metadata import Metadata
diff --git a/picard/ui/searchdialog/__init__.py b/picard/ui/searchdialog/__init__.py
index a70916cd57..7c478c2a3f 100644
--- a/picard/ui/searchdialog/__init__.py
+++ b/picard/ui/searchdialog/__init__.py
@@ -32,7 +32,7 @@
 )
 
 from picard.config import get_config
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.util import (
     icontheme,
     restore_method,
diff --git a/picard/ui/searchdialog/album.py b/picard/ui/searchdialog/album.py
index 06108fd146..a899c66e47 100644
--- a/picard/ui/searchdialog/album.py
+++ b/picard/ui/searchdialog/album.py
@@ -36,7 +36,7 @@
     get_config,
 )
 from picard.const import CAA_URL
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.mbjson import (
     countries_from_node,
     media_formats_from_node,
diff --git a/picard/ui/searchdialog/artist.py b/picard/ui/searchdialog/artist.py
index b1a3f4ca0c..84e652b8ab 100644
--- a/picard/ui/searchdialog/artist.py
+++ b/picard/ui/searchdialog/artist.py
@@ -27,7 +27,7 @@
     Option,
     get_config,
 )
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.mbjson import artist_to_metadata
 from picard.metadata import Metadata
 
diff --git a/picard/ui/searchdialog/track.py b/picard/ui/searchdialog/track.py
index 602004e486..cea1d2d77c 100644
--- a/picard/ui/searchdialog/track.py
+++ b/picard/ui/searchdialog/track.py
@@ -29,7 +29,7 @@
     get_config,
 )
 from picard.file import FILE_COMPARISON_WEIGHTS
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.mbjson import (
     countries_from_node,
     recording_to_metadata,
diff --git a/picard/ui/tagsfromfilenames.py b/picard/ui/tagsfromfilenames.py
index da727b3365..220cf05ff0 100644
--- a/picard/ui/tagsfromfilenames.py
+++ b/picard/ui/tagsfromfilenames.py
@@ -36,7 +36,7 @@
     TextOption,
     get_config,
 )
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.script.parser import normalize_tagname
 from picard.util.tags import display_tag_name
 
diff --git a/picard/ui/ui_aboutdialog.py b/picard/ui/ui_aboutdialog.py
index 0cb512062f..d770af22e2 100644
--- a/picard/ui/ui_aboutdialog.py
+++ b/picard/ui/ui_aboutdialog.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_cdlookup.py b/picard/ui/ui_cdlookup.py
index a97ce35b97..8ebe57e064 100644
--- a/picard/ui/ui_cdlookup.py
+++ b/picard/ui/ui_cdlookup.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_edittagdialog.py b/picard/ui/ui_edittagdialog.py
index 14dd606fe7..eed8722149 100644
--- a/picard/ui/ui_edittagdialog.py
+++ b/picard/ui/ui_edittagdialog.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_exception_script_selector.py b/picard/ui/ui_exception_script_selector.py
index 50a9d6df5a..28c278d93a 100644
--- a/picard/ui/ui_exception_script_selector.py
+++ b/picard/ui/ui_exception_script_selector.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_infodialog.py b/picard/ui/ui_infodialog.py
index 86b9c8c4e4..e4a462de45 100644
--- a/picard/ui/ui_infodialog.py
+++ b/picard/ui/ui_infodialog.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_infostatus.py b/picard/ui/ui_infostatus.py
index 70519b0a35..ab2ce22ae7 100644
--- a/picard/ui/ui_infostatus.py
+++ b/picard/ui/ui_infostatus.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_multi_locale_selector.py b/picard/ui/ui_multi_locale_selector.py
index f971218169..83f87a64b0 100644
--- a/picard/ui/ui_multi_locale_selector.py
+++ b/picard/ui/ui_multi_locale_selector.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options.py b/picard/ui/ui_options.py
index 2a4cbab8b3..d9fc95b7ea 100644
--- a/picard/ui/ui_options.py
+++ b/picard/ui/ui_options.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_advanced.py b/picard/ui/ui_options_advanced.py
index 695c2b94ca..b85c67e1b9 100644
--- a/picard/ui/ui_options_advanced.py
+++ b/picard/ui/ui_options_advanced.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_attached_profiles.py b/picard/ui/ui_options_attached_profiles.py
index fda8e0b9e6..221c1a490b 100644
--- a/picard/ui/ui_options_attached_profiles.py
+++ b/picard/ui/ui_options_attached_profiles.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_cdlookup.py b/picard/ui/ui_options_cdlookup.py
index da021b3545..20fd5814d1 100644
--- a/picard/ui/ui_options_cdlookup.py
+++ b/picard/ui/ui_options_cdlookup.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_cdlookup_select.py b/picard/ui/ui_options_cdlookup_select.py
index 4a74e34381..c2b8cb9d7e 100644
--- a/picard/ui/ui_options_cdlookup_select.py
+++ b/picard/ui/ui_options_cdlookup_select.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_cover.py b/picard/ui/ui_options_cover.py
index 09b2d71e9b..2e25ecd5fc 100644
--- a/picard/ui/ui_options_cover.py
+++ b/picard/ui/ui_options_cover.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_fingerprinting.py b/picard/ui/ui_options_fingerprinting.py
index 0525959cad..9ae0ed53f8 100644
--- a/picard/ui/ui_options_fingerprinting.py
+++ b/picard/ui/ui_options_fingerprinting.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_general.py b/picard/ui/ui_options_general.py
index eb4aba6d83..5eec821978 100644
--- a/picard/ui/ui_options_general.py
+++ b/picard/ui/ui_options_general.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_genres.py b/picard/ui/ui_options_genres.py
index a24741f5e0..8f2badda68 100644
--- a/picard/ui/ui_options_genres.py
+++ b/picard/ui/ui_options_genres.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_interface.py b/picard/ui/ui_options_interface.py
index 3d4a077d84..49c59014ee 100644
--- a/picard/ui/ui_options_interface.py
+++ b/picard/ui/ui_options_interface.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_interface_colors.py b/picard/ui/ui_options_interface_colors.py
index dd45202a0a..5ce3e9ec94 100644
--- a/picard/ui/ui_options_interface_colors.py
+++ b/picard/ui/ui_options_interface_colors.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_interface_toolbar.py b/picard/ui/ui_options_interface_toolbar.py
index 7259328f7f..1f818f2fc9 100644
--- a/picard/ui/ui_options_interface_toolbar.py
+++ b/picard/ui/ui_options_interface_toolbar.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_interface_top_tags.py b/picard/ui/ui_options_interface_top_tags.py
index 8d248f55c8..1521a6a49a 100644
--- a/picard/ui/ui_options_interface_top_tags.py
+++ b/picard/ui/ui_options_interface_top_tags.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_maintenance.py b/picard/ui/ui_options_maintenance.py
index 6bfab728f6..3c5f5e71d6 100644
--- a/picard/ui/ui_options_maintenance.py
+++ b/picard/ui/ui_options_maintenance.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_matching.py b/picard/ui/ui_options_matching.py
index 756ff7db53..1141ac6e65 100644
--- a/picard/ui/ui_options_matching.py
+++ b/picard/ui/ui_options_matching.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_metadata.py b/picard/ui/ui_options_metadata.py
index 442739ac7d..feba096dd0 100644
--- a/picard/ui/ui_options_metadata.py
+++ b/picard/ui/ui_options_metadata.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_network.py b/picard/ui/ui_options_network.py
index 7b7b2cd9aa..befd1a777e 100644
--- a/picard/ui/ui_options_network.py
+++ b/picard/ui/ui_options_network.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_plugins.py b/picard/ui/ui_options_plugins.py
index 0c6e0aa303..6ecf847b2f 100644
--- a/picard/ui/ui_options_plugins.py
+++ b/picard/ui/ui_options_plugins.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_profiles.py b/picard/ui/ui_options_profiles.py
index e6c2b26735..42f3385f6a 100644
--- a/picard/ui/ui_options_profiles.py
+++ b/picard/ui/ui_options_profiles.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_ratings.py b/picard/ui/ui_options_ratings.py
index 559f312c80..192d60aee5 100644
--- a/picard/ui/ui_options_ratings.py
+++ b/picard/ui/ui_options_ratings.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_releases.py b/picard/ui/ui_options_releases.py
index 5d3ab4bf9d..aaa3d20cb8 100644
--- a/picard/ui/ui_options_releases.py
+++ b/picard/ui/ui_options_releases.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_renaming.py b/picard/ui/ui_options_renaming.py
index 98d64d84c0..57094e2ee9 100644
--- a/picard/ui/ui_options_renaming.py
+++ b/picard/ui/ui_options_renaming.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_renaming_compat.py b/picard/ui/ui_options_renaming_compat.py
index 42f3e84134..d592b05bc4 100644
--- a/picard/ui/ui_options_renaming_compat.py
+++ b/picard/ui/ui_options_renaming_compat.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_script.py b/picard/ui/ui_options_script.py
index cf3fb08e76..c85525a302 100644
--- a/picard/ui/ui_options_script.py
+++ b/picard/ui/ui_options_script.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_tags.py b/picard/ui/ui_options_tags.py
index 56cb7e46c3..2b1cc1e44e 100644
--- a/picard/ui/ui_options_tags.py
+++ b/picard/ui/ui_options_tags.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_tags_compatibility_aac.py b/picard/ui/ui_options_tags_compatibility_aac.py
index ae3a6efd2a..32d2ed4270 100644
--- a/picard/ui/ui_options_tags_compatibility_aac.py
+++ b/picard/ui/ui_options_tags_compatibility_aac.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_tags_compatibility_ac3.py b/picard/ui/ui_options_tags_compatibility_ac3.py
index 7d8035a473..ddee75df79 100644
--- a/picard/ui/ui_options_tags_compatibility_ac3.py
+++ b/picard/ui/ui_options_tags_compatibility_ac3.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_tags_compatibility_id3.py b/picard/ui/ui_options_tags_compatibility_id3.py
index 2f34b20ad3..3ec9b55258 100644
--- a/picard/ui/ui_options_tags_compatibility_id3.py
+++ b/picard/ui/ui_options_tags_compatibility_id3.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_options_tags_compatibility_wave.py b/picard/ui/ui_options_tags_compatibility_wave.py
index ef1d8c6bd0..4b484936a0 100644
--- a/picard/ui/ui_options_tags_compatibility_wave.py
+++ b/picard/ui/ui_options_tags_compatibility_wave.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_passworddialog.py b/picard/ui/ui_passworddialog.py
index f9f606f97c..d3423a66ea 100644
--- a/picard/ui/ui_passworddialog.py
+++ b/picard/ui/ui_passworddialog.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_provider_options_caa.py b/picard/ui/ui_provider_options_caa.py
index 65b27c012b..beeeb9a604 100644
--- a/picard/ui/ui_provider_options_caa.py
+++ b/picard/ui/ui_provider_options_caa.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_provider_options_local.py b/picard/ui/ui_provider_options_local.py
index bd06fa9576..065252a7b4 100644
--- a/picard/ui/ui_provider_options_local.py
+++ b/picard/ui/ui_provider_options_local.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_scripteditor.py b/picard/ui/ui_scripteditor.py
index e18d621c37..5b2aba08d1 100644
--- a/picard/ui/ui_scripteditor.py
+++ b/picard/ui/ui_scripteditor.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_scripteditor_details.py b/picard/ui/ui_scripteditor_details.py
index 7fda2553b8..2540682d61 100644
--- a/picard/ui/ui_scripteditor_details.py
+++ b/picard/ui/ui_scripteditor_details.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_scripting_documentation_dialog.py b/picard/ui/ui_scripting_documentation_dialog.py
index 9b95932233..782300c0fc 100644
--- a/picard/ui/ui_scripting_documentation_dialog.py
+++ b/picard/ui/ui_scripting_documentation_dialog.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_tagsfromfilenames.py b/picard/ui/ui_tagsfromfilenames.py
index 91e21ccee5..e6ba5f1a1c 100644
--- a/picard/ui/ui_tagsfromfilenames.py
+++ b/picard/ui/ui_tagsfromfilenames.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_widget_taglisteditor.py b/picard/ui/ui_widget_taglisteditor.py
index 5597d79cc8..f604389eeb 100644
--- a/picard/ui/ui_widget_taglisteditor.py
+++ b/picard/ui/ui_widget_taglisteditor.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/ui_win_compat_dialog.py b/picard/ui/ui_win_compat_dialog.py
index 1c60925c91..6c22c53d00 100644
--- a/picard/ui/ui_win_compat_dialog.py
+++ b/picard/ui/ui_win_compat_dialog.py
@@ -5,7 +5,7 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 from PyQt6 import QtCore, QtGui, QtWidgets
diff --git a/picard/ui/util.py b/picard/ui/util.py
index fcc58361fd..9bd5a4d7ef 100644
--- a/picard/ui/util.py
+++ b/picard/ui/util.py
@@ -40,7 +40,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.util import find_existing_path
 
diff --git a/picard/ui/widgets/profilelistwidget.py b/picard/ui/widgets/profilelistwidget.py
index bec41bd4c8..635924896f 100644
--- a/picard/ui/widgets/profilelistwidget.py
+++ b/picard/ui/widgets/profilelistwidget.py
@@ -32,7 +32,7 @@
 
 from picard.const import DEFAULT_PROFILE_NAME
 from picard.i18n import (
-    _,
+    gettext as _,
     gettext_constants,
 )
 from picard.util import unique_numbered_title
diff --git a/picard/ui/widgets/scriptdocumentation.py b/picard/ui/widgets/scriptdocumentation.py
index 2b6560366a..25be0e596d 100644
--- a/picard/ui/widgets/scriptdocumentation.py
+++ b/picard/ui/widgets/scriptdocumentation.py
@@ -27,7 +27,7 @@
 )
 
 from picard.const import PICARD_URLS
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.script import script_function_documentation_all
 
 from picard.ui import FONT_FAMILY_MONOSPACE
diff --git a/picard/ui/widgets/scriptlistwidget.py b/picard/ui/widgets/scriptlistwidget.py
index de9c07076b..adaf253182 100644
--- a/picard/ui/widgets/scriptlistwidget.py
+++ b/picard/ui/widgets/scriptlistwidget.py
@@ -32,7 +32,7 @@
 
 from picard.const import DEFAULT_SCRIPT_NAME
 from picard.i18n import (
-    _,
+    gettext as _,
     gettext_constants,
 )
 from picard.util import unique_numbered_title
diff --git a/picard/ui/widgets/scripttextedit.py b/picard/ui/widgets/scripttextedit.py
index d5d4667504..ee6960de0d 100644
--- a/picard/ui/widgets/scripttextedit.py
+++ b/picard/ui/widgets/scripttextedit.py
@@ -48,7 +48,7 @@
     get_config,
 )
 from picard.const.sys import IS_MACOS
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.script import (
     ScriptFunctionDocError,
     script_function_documentation,
diff --git a/picard/ui/widgets/tristatesortheaderview.py b/picard/ui/widgets/tristatesortheaderview.py
index 16c2005353..b65321fc51 100644
--- a/picard/ui/widgets/tristatesortheaderview.py
+++ b/picard/ui/widgets/tristatesortheaderview.py
@@ -25,7 +25,7 @@
     QtWidgets,
 )
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 class TristateSortHeaderView(QtWidgets.QHeaderView):
diff --git a/picard/util/__init__.py b/picard/util/__init__.py
index 22290f7d02..94cc2d2abb 100644
--- a/picard/util/__init__.py
+++ b/picard/util/__init__.py
@@ -83,7 +83,7 @@
     IS_WIN,
 )
 from picard.i18n import (
-    _,
+    gettext as _,
     gettext_constants,
 )
 
diff --git a/picard/util/bytes2human.py b/picard/util/bytes2human.py
index 2e67ceb647..31a7b9f75b 100644
--- a/picard/util/bytes2human.py
+++ b/picard/util/bytes2human.py
@@ -34,7 +34,7 @@
 
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 
 
diff --git a/picard/util/checkupdate.py b/picard/util/checkupdate.py
index 33408bfa53..7890cc1a61 100644
--- a/picard/util/checkupdate.py
+++ b/picard/util/checkupdate.py
@@ -37,7 +37,7 @@
 )
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
     gettext_constants,
 )
 from picard.util import webbrowser2
diff --git a/picard/util/tags.py b/picard/util/tags.py
index 47bcbc9915..64bd8d17b0 100644
--- a/picard/util/tags.py
+++ b/picard/util/tags.py
@@ -33,7 +33,7 @@
 
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 
 
diff --git a/picard/util/time.py b/picard/util/time.py
index 5a13a7a6ff..891ae25c86 100644
--- a/picard/util/time.py
+++ b/picard/util/time.py
@@ -23,7 +23,7 @@
 
 from collections import namedtuple
 
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 SECS_IN_DAY = 86400
diff --git a/picard/util/versions.py b/picard/util/versions.py
index 7ea27a9657..55e568cd6d 100644
--- a/picard/util/versions.py
+++ b/picard/util/versions.py
@@ -37,7 +37,7 @@
 from picard.disc import discid_version
 from picard.i18n import (
     N_,
-    _,
+    gettext as _,
 )
 from picard.util.astrcmp import astrcmp_implementation
 
diff --git a/picard/util/webbrowser2.py b/picard/util/webbrowser2.py
index fa661b497d..0b3f74aa28 100644
--- a/picard/util/webbrowser2.py
+++ b/picard/util/webbrowser2.py
@@ -34,7 +34,7 @@
 from PyQt6 import QtWidgets
 
 from picard.const import PICARD_URLS
-from picard.i18n import _
+from picard.i18n import gettext as _
 
 
 def open(url):
diff --git a/setup.py b/setup.py
index ce66c6c025..7e7e7b37c7 100644
--- a/setup.py
+++ b/setup.py
@@ -385,7 +385,7 @@ def compile_ui(uifile, pyfile):
             rc = re.compile(r'\n# WARNING.*?(?=\n\n)', re.MULTILINE | re.DOTALL)
             comment = ("\n# Automatically generated - do not edit.\n"
                        "# Use `python setup.py %s` to update it.\n\n"
-                       "from picard.i18n import _"
+                       "from picard.i18n import gettext as _"
                        % _get_option_name(self))
             for r in list(_translate_re):
                 source = r.sub(r'_(\1)', source)
diff --git a/test/test_i18n.py b/test/test_i18n.py
index a864f588fe..2d4f03c3f8 100644
--- a/test/test_i18n.py
+++ b/test/test_i18n.py
@@ -32,9 +32,9 @@
 
 from picard.i18n import (
     N_,
-    _,
     _try_encodings,
     _try_locales,
+    gettext as _,
     gettext_constants,
     gettext_countries,
     ngettext,
diff --git a/test/test_utils.py b/test/test_utils.py
index f4e425fac8..019726936a 100644
--- a/test/test_utils.py
+++ b/test/test_utils.py
@@ -54,7 +54,7 @@
     IS_MACOS,
     IS_WIN,
 )
-from picard.i18n import _
+from picard.i18n import gettext as _
 from picard.util import (
     IgnoreUpdatesContext,
     album_artist_from_path,

From 5d0c68c9dae0207413ebc811ac4f27d8452931d8 Mon Sep 17 00:00:00 2001
From: Laurent Monin <github@norz.org>
Date: Mon, 22 Apr 2024 10:32:47 +0200
Subject: [PATCH 6/8] Rework setup.py compile_ui to handle Qt6 vs ours
 translation systems

---
 setup.py | 52 +++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 35 insertions(+), 17 deletions(-)

diff --git a/setup.py b/setup.py
index 7e7e7b37c7..5226e60e01 100644
--- a/setup.py
+++ b/setup.py
@@ -65,7 +65,8 @@
 # required for PEP 517
 sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
 
-from picard import (
+
+from picard import (  # noqa: E402
     PICARD_APP_ID,
     PICARD_APP_NAME,
     PICARD_DESKTOP_NAME,
@@ -369,30 +370,47 @@ def finalize_options(self):
 
     def run(self):
         from PyQt6 import uic
+
         _translate_re = (
-            re.compile(
+            (re.compile(r'(\s+_translate = QtCore\.QCoreApplication\.translate)'), r''),
+            (re.compile(
                 r'QtGui\.QApplication.translate\(.*?, (.*?), None, '
-                r'QtGui\.QApplication\.UnicodeUTF8\)'),
-            re.compile(
-                r'\b_translate\(.*?, (.*?)(?:, None)?\)')
+                r'QtGui\.QApplication\.UnicodeUTF8\)'), r'_(\1)'),
+            (re.compile(r'\b_translate\(.*?, (.*?)(?:, None)?\)'), r'_(\1)'),
         )
 
         def compile_ui(uifile, pyfile):
-            log.info("compiling %s -> %s", uifile, pyfile)
             tmp = StringIO()
+            log.info("compiling %s -> %s", uifile, pyfile)
             uic.compileUi(uifile, tmp)
             source = tmp.getvalue()
-            rc = re.compile(r'\n# WARNING.*?(?=\n\n)', re.MULTILINE | re.DOTALL)
-            comment = ("\n# Automatically generated - do not edit.\n"
-                       "# Use `python setup.py %s` to update it.\n\n"
-                       "from picard.i18n import gettext as _"
-                       % _get_option_name(self))
-            for r in list(_translate_re):
-                source = r.sub(r'_(\1)', source)
-                source = rc.sub(comment, source)
-            f = open(pyfile, "w")
-            f.write(source)
-            f.close()
+
+            # replace QT translations stuff by ours
+            for matcher, replacement in _translate_re:
+                source = matcher.sub(replacement, source)
+
+            # replace headers
+            rc = re.compile(r'\n# WARNING.*?(?=\nclass )', re.MULTILINE | re.DOTALL)
+
+            command = _get_option_name(self)
+            new_header = f"""
+# Automatically generated - do not edit.
+# Use `python setup.py {command}` to update it.
+
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
+
+from picard.i18n import gettext as _
+
+"""
+            source = rc.sub(new_header, source)
+
+            # save to final file
+            with open(pyfile, "w") as f:
+                f.write(source)
 
         if self.files:
             for uifile, pyfile in self.files:

From 134cfce668de3de80f8eb20018ee510c7dda8412 Mon Sep 17 00:00:00 2001
From: Laurent Monin <github@norz.org>
Date: Mon, 22 Apr 2024 10:33:41 +0200
Subject: [PATCH 7/8] Regenerate ui_* files

---
 picard/ui/ui_aboutdialog.py                     | 10 ++++++----
 picard/ui/ui_cdlookup.py                        | 10 ++++++----
 picard/ui/ui_edittagdialog.py                   | 10 ++++++----
 picard/ui/ui_exception_script_selector.py       | 10 ++++++----
 picard/ui/ui_infodialog.py                      | 10 ++++++----
 picard/ui/ui_infostatus.py                      | 10 ++++++----
 picard/ui/ui_multi_locale_selector.py           | 10 ++++++----
 picard/ui/ui_options.py                         | 10 ++++++----
 picard/ui/ui_options_advanced.py                | 10 ++++++----
 picard/ui/ui_options_attached_profiles.py       | 10 ++++++----
 picard/ui/ui_options_cdlookup.py                | 10 ++++++----
 picard/ui/ui_options_cdlookup_select.py         | 10 ++++++----
 picard/ui/ui_options_cover.py                   | 10 ++++++----
 picard/ui/ui_options_fingerprinting.py          | 10 ++++++----
 picard/ui/ui_options_general.py                 | 10 ++++++----
 picard/ui/ui_options_genres.py                  | 10 ++++++----
 picard/ui/ui_options_interface.py               | 10 ++++++----
 picard/ui/ui_options_interface_colors.py        | 10 ++++++----
 picard/ui/ui_options_interface_toolbar.py       | 10 ++++++----
 picard/ui/ui_options_interface_top_tags.py      | 10 ++++++----
 picard/ui/ui_options_maintenance.py             | 10 ++++++----
 picard/ui/ui_options_matching.py                | 10 ++++++----
 picard/ui/ui_options_metadata.py                | 10 ++++++----
 picard/ui/ui_options_network.py                 | 10 ++++++----
 picard/ui/ui_options_plugins.py                 | 10 ++++++----
 picard/ui/ui_options_profiles.py                | 10 ++++++----
 picard/ui/ui_options_ratings.py                 | 10 ++++++----
 picard/ui/ui_options_releases.py                | 10 ++++++----
 picard/ui/ui_options_renaming.py                | 10 ++++++----
 picard/ui/ui_options_renaming_compat.py         | 10 ++++++----
 picard/ui/ui_options_script.py                  | 10 ++++++----
 picard/ui/ui_options_tags.py                    | 10 ++++++----
 picard/ui/ui_options_tags_compatibility_aac.py  | 10 ++++++----
 picard/ui/ui_options_tags_compatibility_ac3.py  | 10 ++++++----
 picard/ui/ui_options_tags_compatibility_id3.py  | 10 ++++++----
 picard/ui/ui_options_tags_compatibility_wave.py | 10 ++++++----
 picard/ui/ui_passworddialog.py                  | 10 ++++++----
 picard/ui/ui_provider_options_caa.py            | 10 ++++++----
 picard/ui/ui_provider_options_local.py          | 10 ++++++----
 picard/ui/ui_scripteditor.py                    | 10 ++++++----
 picard/ui/ui_scripteditor_details.py            | 10 ++++++----
 picard/ui/ui_scripting_documentation_dialog.py  | 10 ++++++----
 picard/ui/ui_tagsfromfilenames.py               | 10 ++++++----
 picard/ui/ui_widget_taglisteditor.py            | 10 ++++++----
 picard/ui/ui_win_compat_dialog.py               | 10 ++++++----
 45 files changed, 270 insertions(+), 180 deletions(-)

diff --git a/picard/ui/ui_aboutdialog.py b/picard/ui/ui_aboutdialog.py
index d770af22e2..f8d153545e 100644
--- a/picard/ui/ui_aboutdialog.py
+++ b/picard/ui/ui_aboutdialog.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_AboutDialog(object):
@@ -83,6 +86,5 @@ def setupUi(self, AboutDialog):
         QtCore.QMetaObject.connectSlotsByName(AboutDialog)
 
     def retranslateUi(self, AboutDialog):
-        _translate = QtCore.QCoreApplication.translate
         AboutDialog.setWindowTitle(_("About Picard"))
         self.app_name.setText(_("MusicBrainz Picard"))
diff --git a/picard/ui/ui_cdlookup.py b/picard/ui/ui_cdlookup.py
index 8ebe57e064..0afe731eb4 100644
--- a/picard/ui/ui_cdlookup.py
+++ b/picard/ui/ui_cdlookup.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_Dialog(object):
@@ -85,7 +88,6 @@ def setupUi(self, Dialog):
         Dialog.setTabOrder(self.lookup_button, self.cancel_button)
 
     def retranslateUi(self, Dialog):
-        _translate = QtCore.QCoreApplication.translate
         Dialog.setWindowTitle(_("CD Lookup"))
         self.label.setText(_("The following releases on MusicBrainz match the CD:"))
         self.no_results_label.setText(_("No matching releases found for this disc."))
diff --git a/picard/ui/ui_edittagdialog.py b/picard/ui/ui_edittagdialog.py
index eed8722149..58778666a0 100644
--- a/picard/ui/ui_edittagdialog.py
+++ b/picard/ui/ui_edittagdialog.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_EditTagDialog(object):
@@ -115,7 +118,6 @@ def setupUi(self, EditTagDialog):
         EditTagDialog.setTabOrder(self.remove_value, self.buttonbox)
 
     def retranslateUi(self, EditTagDialog):
-        _translate = QtCore.QCoreApplication.translate
         EditTagDialog.setWindowTitle(_("Edit Tag"))
         self.edit_value.setText(_("Edit value"))
         self.add_value.setText(_("Add value"))
diff --git a/picard/ui/ui_exception_script_selector.py b/picard/ui/ui_exception_script_selector.py
index 28c278d93a..eec0d0c0df 100644
--- a/picard/ui/ui_exception_script_selector.py
+++ b/picard/ui/ui_exception_script_selector.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_ExceptionScriptSelector(object):
@@ -105,7 +108,6 @@ def setupUi(self, ExceptionScriptSelector):
         QtCore.QMetaObject.connectSlotsByName(ExceptionScriptSelector)
 
     def retranslateUi(self, ExceptionScriptSelector):
-        _translate = QtCore.QCoreApplication.translate
         ExceptionScriptSelector.setWindowTitle(_("Exception Language Script Selector"))
         self.label.setText(_("Selected Scripts"))
         self.threshold_label.setText(_("Selected language script match threshold:"))
diff --git a/picard/ui/ui_infodialog.py b/picard/ui/ui_infodialog.py
index e4a462de45..6cccc29007 100644
--- a/picard/ui/ui_infodialog.py
+++ b/picard/ui/ui_infodialog.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_InfoDialog(object):
@@ -81,7 +84,6 @@ def setupUi(self, InfoDialog):
         InfoDialog.setTabOrder(self.tabWidget, self.buttonBox)
 
     def retranslateUi(self, InfoDialog):
-        _translate = QtCore.QCoreApplication.translate
         self.tabWidget.setTabText(self.tabWidget.indexOf(self.info_tab), _("&Info"))
         self.tabWidget.setTabText(self.tabWidget.indexOf(self.error_tab), _("&Error"))
         self.tabWidget.setTabText(self.tabWidget.indexOf(self.artwork_tab), _("A&rtwork"))
diff --git a/picard/ui/ui_infostatus.py b/picard/ui/ui_infostatus.py
index ab2ce22ae7..70be8f63ff 100644
--- a/picard/ui/ui_infostatus.py
+++ b/picard/ui/ui_infostatus.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_InfoStatus(object):
@@ -106,5 +109,4 @@ def setupUi(self, InfoStatus):
         QtCore.QMetaObject.connectSlotsByName(InfoStatus)
 
     def retranslateUi(self, InfoStatus):
-        _translate = QtCore.QCoreApplication.translate
         InfoStatus.setWindowTitle(_("Form"))
diff --git a/picard/ui/ui_multi_locale_selector.py b/picard/ui/ui_multi_locale_selector.py
index 83f87a64b0..5020be7e11 100644
--- a/picard/ui/ui_multi_locale_selector.py
+++ b/picard/ui/ui_multi_locale_selector.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_MultiLocaleSelector(object):
@@ -85,7 +88,6 @@ def setupUi(self, MultiLocaleSelector):
         QtCore.QMetaObject.connectSlotsByName(MultiLocaleSelector)
 
     def retranslateUi(self, MultiLocaleSelector):
-        _translate = QtCore.QCoreApplication.translate
         MultiLocaleSelector.setWindowTitle(_("Locale Selector"))
         self.label.setText(_("Selected Locales"))
         self.move_up.setToolTip(_("Move selected locale up"))
diff --git a/picard/ui/ui_options.py b/picard/ui/ui_options.py
index d9fc95b7ea..c0dd9c0af8 100644
--- a/picard/ui/ui_options.py
+++ b/picard/ui/ui_options.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_Dialog(object):
@@ -50,5 +53,4 @@ def setupUi(self, Dialog):
         QtCore.QMetaObject.connectSlotsByName(Dialog)
 
     def retranslateUi(self, Dialog):
-        _translate = QtCore.QCoreApplication.translate
         Dialog.setWindowTitle(_("Options"))
diff --git a/picard/ui/ui_options_advanced.py b/picard/ui/ui_options_advanced.py
index b85c67e1b9..f64d3f6794 100644
--- a/picard/ui/ui_options_advanced.py
+++ b/picard/ui/ui_options_advanced.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_AdvancedOptionsPage(object):
@@ -138,7 +141,6 @@ def setupUi(self, AdvancedOptionsPage):
         AdvancedOptionsPage.setTabOrder(self.completeness_ignore_videos, self.completeness_ignore_data)
 
     def retranslateUi(self, AdvancedOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.groupBox.setTitle(_("Advanced options"))
         self.label_ignore_regex.setText(_("Ignore file paths matching the following regular expression:"))
         self.label_query_limit.setText(_("Maximum number of entities to return per MusicBrainz query"))
diff --git a/picard/ui/ui_options_attached_profiles.py b/picard/ui/ui_options_attached_profiles.py
index 221c1a490b..b24cc5c969 100644
--- a/picard/ui/ui_options_attached_profiles.py
+++ b/picard/ui/ui_options_attached_profiles.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_AttachedProfilesDialog(object):
@@ -34,5 +37,4 @@ def setupUi(self, AttachedProfilesDialog):
         QtCore.QMetaObject.connectSlotsByName(AttachedProfilesDialog)
 
     def retranslateUi(self, AttachedProfilesDialog):
-        _translate = QtCore.QCoreApplication.translate
         AttachedProfilesDialog.setWindowTitle(_("Profiles Attached to Options"))
diff --git a/picard/ui/ui_options_cdlookup.py b/picard/ui/ui_options_cdlookup.py
index 20fd5814d1..64ea724956 100644
--- a/picard/ui/ui_options_cdlookup.py
+++ b/picard/ui/ui_options_cdlookup.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_CDLookupOptionsPage(object):
@@ -40,6 +43,5 @@ def setupUi(self, CDLookupOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(CDLookupOptionsPage)
 
     def retranslateUi(self, CDLookupOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.rename_files.setTitle(_("CD Lookup"))
         self.label_3.setText(_("CD-ROM device to use for lookups:"))
diff --git a/picard/ui/ui_options_cdlookup_select.py b/picard/ui/ui_options_cdlookup_select.py
index c2b8cb9d7e..68d5bd53eb 100644
--- a/picard/ui/ui_options_cdlookup_select.py
+++ b/picard/ui/ui_options_cdlookup_select.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_CDLookupOptionsPage(object):
@@ -47,6 +50,5 @@ def setupUi(self, CDLookupOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(CDLookupOptionsPage)
 
     def retranslateUi(self, CDLookupOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.rename_files.setTitle(_("CD Lookup"))
         self.cd_lookup_.setText(_("Default CD-ROM drive to use for lookups:"))
diff --git a/picard/ui/ui_options_cover.py b/picard/ui/ui_options_cover.py
index 2e25ecd5fc..6a57428959 100644
--- a/picard/ui/ui_options_cover.py
+++ b/picard/ui/ui_options_cover.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_CoverOptionsPage(object):
@@ -95,7 +98,6 @@ def setupUi(self, CoverOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(CoverOptionsPage)
 
     def retranslateUi(self, CoverOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.save_images_to_tags.setTitle(_("Embed cover images into tags"))
         self.cb_embed_front_only.setText(_("Embed only a single front image"))
         self.save_images_to_files.setTitle(_("Save cover images as separate files"))
diff --git a/picard/ui/ui_options_fingerprinting.py b/picard/ui/ui_options_fingerprinting.py
index 9ae0ed53f8..7978f781aa 100644
--- a/picard/ui/ui_options_fingerprinting.py
+++ b/picard/ui/ui_options_fingerprinting.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_FingerprintingOptionsPage(object):
@@ -97,7 +100,6 @@ def setupUi(self, FingerprintingOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(FingerprintingOptionsPage)
 
     def retranslateUi(self, FingerprintingOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.fingerprinting.setTitle(_("Audio Fingerprinting"))
         self.disable_fingerprinting.setText(_("Do not use audio fingerprinting"))
         self.use_acoustid.setText(_("Use AcoustID"))
diff --git a/picard/ui/ui_options_general.py b/picard/ui/ui_options_general.py
index 5eec821978..2123045cc9 100644
--- a/picard/ui/ui_options_general.py
+++ b/picard/ui/ui_options_general.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_GeneralOptionsPage(object):
@@ -199,7 +202,6 @@ def setupUi(self, GeneralOptionsPage):
         GeneralOptionsPage.setTabOrder(self.update_check_days, self.update_level)
 
     def retranslateUi(self, GeneralOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.groupBox.setTitle(_("MusicBrainz Server"))
         self.label_4.setText(_("You have configured an unofficial MusicBrainz server. By default submissions of releases, recordings and disc IDs will go to the primary database on musicbrainz.org."))
         self.use_server_for_submission.setText(_("Submit data to the configured server"))
diff --git a/picard/ui/ui_options_genres.py b/picard/ui/ui_options_genres.py
index 8f2badda68..9657bac076 100644
--- a/picard/ui/ui_options_genres.py
+++ b/picard/ui/ui_options_genres.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_GenresOptionsPage(object):
@@ -119,7 +122,6 @@ def setupUi(self, GenresOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(GenresOptionsPage)
 
     def retranslateUi(self, GenresOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.use_genres.setTitle(_("Use genres from MusicBrainz"))
         self.only_my_genres.setText(_("Use only my genres"))
         self.artists_genres.setText(_("Fall back on album\'s artists genres if no genres are found for the release or release group"))
diff --git a/picard/ui/ui_options_interface.py b/picard/ui/ui_options_interface.py
index 49c59014ee..4c9c16a1d2 100644
--- a/picard/ui/ui_options_interface.py
+++ b/picard/ui/ui_options_interface.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_InterfaceOptionsPage(object):
@@ -118,7 +121,6 @@ def setupUi(self, InterfaceOptionsPage):
         InterfaceOptionsPage.setTabOrder(self.starting_directory_path, self.starting_directory_browse)
 
     def retranslateUi(self, InterfaceOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.groupBox.setTitle(_("Appearance"))
         self.toolbar_show_labels.setText(_("Show text labels under icons"))
         self.show_menu_icons.setText(_("Show icons in menus"))
diff --git a/picard/ui/ui_options_interface_colors.py b/picard/ui/ui_options_interface_colors.py
index 5ce3e9ec94..eff170bb0d 100644
--- a/picard/ui/ui_options_interface_colors.py
+++ b/picard/ui/ui_options_interface_colors.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_InterfaceColorsOptionsPage(object):
@@ -49,5 +52,4 @@ def setupUi(self, InterfaceColorsOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(InterfaceColorsOptionsPage)
 
     def retranslateUi(self, InterfaceColorsOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.colors.setTitle(_("Colors"))
diff --git a/picard/ui/ui_options_interface_toolbar.py b/picard/ui/ui_options_interface_toolbar.py
index 1f818f2fc9..7902527db5 100644
--- a/picard/ui/ui_options_interface_toolbar.py
+++ b/picard/ui/ui_options_interface_toolbar.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_InterfaceToolbarOptionsPage(object):
@@ -72,7 +75,6 @@ def setupUi(self, InterfaceToolbarOptionsPage):
         InterfaceToolbarOptionsPage.setTabOrder(self.down_button, self.remove_button)
 
     def retranslateUi(self, InterfaceToolbarOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.customize_toolbar_box.setTitle(_("Customize Action Toolbar"))
         self.add_button.setToolTip(_("Add a new button to Toolbar"))
         self.add_button.setText(_("Add Action"))
diff --git a/picard/ui/ui_options_interface_top_tags.py b/picard/ui/ui_options_interface_top_tags.py
index 1521a6a49a..e79d5944ec 100644
--- a/picard/ui/ui_options_interface_top_tags.py
+++ b/picard/ui/ui_options_interface_top_tags.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_InterfaceTopTagsOptionsPage(object):
@@ -37,6 +40,5 @@ def setupUi(self, InterfaceTopTagsOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(InterfaceTopTagsOptionsPage)
 
     def retranslateUi(self, InterfaceTopTagsOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.top_tags_groupBox.setTitle(_("Show the below tags above all other tags in the metadata view"))
 from picard.ui.widgets.taglisteditor import TagListEditor
diff --git a/picard/ui/ui_options_maintenance.py b/picard/ui/ui_options_maintenance.py
index 3c5f5e71d6..0bc5fcde69 100644
--- a/picard/ui/ui_options_maintenance.py
+++ b/picard/ui/ui_options_maintenance.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_MaintenanceOptionsPage(object):
@@ -86,7 +89,6 @@ def setupUi(self, MaintenanceOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(MaintenanceOptionsPage)
 
     def retranslateUi(self, MaintenanceOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.label.setText(_("Configuration File:"))
         self.open_folder_button.setText(_("Open folder"))
         self.load_backup_button.setText(_("Load Backup"))
diff --git a/picard/ui/ui_options_matching.py b/picard/ui/ui_options_matching.py
index 1141ac6e65..a98acdb18c 100644
--- a/picard/ui/ui_options_matching.py
+++ b/picard/ui/ui_options_matching.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_MatchingOptionsPage(object):
@@ -71,7 +74,6 @@ def setupUi(self, MatchingOptionsPage):
         MatchingOptionsPage.setTabOrder(self.cluster_lookup_threshold, self.track_matching_threshold)
 
     def retranslateUi(self, MatchingOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.rename_files.setTitle(_("Thresholds"))
         self.label_6.setText(_("Minimal similarity for matching files to tracks:"))
         self.track_matching_threshold.setSuffix(_(" %"))
diff --git a/picard/ui/ui_options_metadata.py b/picard/ui/ui_options_metadata.py
index feba096dd0..5d98242eec 100644
--- a/picard/ui/ui_options_metadata.py
+++ b/picard/ui/ui_options_metadata.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_MetadataOptionsPage(object):
@@ -129,7 +132,6 @@ def setupUi(self, MetadataOptionsPage):
         MetadataOptionsPage.setTabOrder(self.nat_name, self.nat_name_default)
 
     def retranslateUi(self, MetadataOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.metadata_groupbox.setTitle(_("Metadata"))
         self.translate_artist_names.setText(_("Translate artist names to these locales where possible:"))
         self.select_locales.setText(_("Select…"))
diff --git a/picard/ui/ui_options_network.py b/picard/ui/ui_options_network.py
index befd1a777e..7369aae74e 100644
--- a/picard/ui/ui_options_network.py
+++ b/picard/ui/ui_options_network.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_NetworkOptionsPage(object):
@@ -156,7 +159,6 @@ def setupUi(self, NetworkOptionsPage):
         NetworkOptionsPage.setTabOrder(self.browser_integration_port, self.browser_integration_localhost_only)
 
     def retranslateUi(self, NetworkOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.web_proxy.setTitle(_("Web Proxy"))
         self.proxy_type_http.setText(_("HTTP"))
         self.proxy_type_socks.setText(_("SOCKS"))
diff --git a/picard/ui/ui_options_plugins.py b/picard/ui/ui_options_plugins.py
index 6ecf847b2f..0ec61bfe3e 100644
--- a/picard/ui/ui_options_plugins.py
+++ b/picard/ui/ui_options_plugins.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_PluginsOptionsPage(object):
@@ -131,7 +134,6 @@ def setupUi(self, PluginsOptionsPage):
         PluginsOptionsPage.setTabOrder(self.reload_list_of_plugins, self.scrollArea)
 
     def retranslateUi(self, PluginsOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.groupBox_2.setTitle(_("Plugins"))
         self.plugins.headerItem().setText(0, _("Name"))
         self.plugins.headerItem().setText(1, _("Version"))
diff --git a/picard/ui/ui_options_profiles.py b/picard/ui/ui_options_profiles.py
index 42f3385f6a..ac738285ea 100644
--- a/picard/ui/ui_options_profiles.py
+++ b/picard/ui/ui_options_profiles.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_ProfileEditorDialog(object):
@@ -75,7 +78,6 @@ def setupUi(self, ProfileEditorDialog):
         QtCore.QMetaObject.connectSlotsByName(ProfileEditorDialog)
 
     def retranslateUi(self, ProfileEditorDialog):
-        _translate = QtCore.QCoreApplication.translate
         self.option_profiles_groupbox.setTitle(_("Option Profile(s)"))
         self.move_up_button.setToolTip(_("Move profile up"))
         self.move_down_button.setToolTip(_("Move profile down"))
diff --git a/picard/ui/ui_options_ratings.py b/picard/ui/ui_options_ratings.py
index 192d60aee5..ed2aa1e5fb 100644
--- a/picard/ui/ui_options_ratings.py
+++ b/picard/ui/ui_options_ratings.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_RatingsOptionsPage(object):
@@ -47,7 +50,6 @@ def setupUi(self, RatingsOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(RatingsOptionsPage)
 
     def retranslateUi(self, RatingsOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.enable_ratings.setTitle(_("Enable track ratings"))
         self.label.setText(_("Picard saves the ratings together with an e-mail address identifying the user who did the rating. That way different ratings for different users can be stored in the files. Please specify the e-mail you want to use to save your ratings."))
         self.ignore_tags_2.setText(_("E-mail:"))
diff --git a/picard/ui/ui_options_releases.py b/picard/ui/ui_options_releases.py
index aaa3d20cb8..7e49cb1ff7 100644
--- a/picard/ui/ui_options_releases.py
+++ b/picard/ui/ui_options_releases.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_ReleasesOptionsPage(object):
@@ -110,7 +113,6 @@ def setupUi(self, ReleasesOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(ReleasesOptionsPage)
 
     def retranslateUi(self, ReleasesOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.type_group.setTitle(_("Preferred release types"))
         self.country_group.setTitle(_("Preferred release countries"))
         self.add_countries.setToolTip(_("Add to preferred release countries"))
diff --git a/picard/ui/ui_options_renaming.py b/picard/ui/ui_options_renaming.py
index 57094e2ee9..718931fed7 100644
--- a/picard/ui/ui_options_renaming.py
+++ b/picard/ui/ui_options_renaming.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_RenamingOptionsPage(object):
@@ -150,7 +153,6 @@ def setupUi(self, RenamingOptionsPage):
         RenamingOptionsPage.setTabOrder(self.example_filename_after, self.example_filename_sample_files_button)
 
     def retranslateUi(self, RenamingOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.move_files.setTitle(_("Move files when saving"))
         self.label.setText(_("Destination directory:"))
         self.move_files_to_browse.setText(_("Browse…"))
diff --git a/picard/ui/ui_options_renaming_compat.py b/picard/ui/ui_options_renaming_compat.py
index d592b05bc4..113586cd85 100644
--- a/picard/ui/ui_options_renaming_compat.py
+++ b/picard/ui/ui_options_renaming_compat.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_RenamingCompatOptionsPage(object):
@@ -89,7 +92,6 @@ def setupUi(self, RenamingCompatOptionsPage):
         RenamingCompatOptionsPage.setTabOrder(self.replace_spaces_with_underscores, self.replace_dir_separator)
 
     def retranslateUi(self, RenamingCompatOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.ascii_filenames.setText(_("Replace non-ASCII characters"))
         self.windows_compatibility.setText(_("Windows compatibility"))
         self.btn_windows_compatibility_change.setText(_("Customize…"))
diff --git a/picard/ui/ui_options_script.py b/picard/ui/ui_options_script.py
index c85525a302..050a005850 100644
--- a/picard/ui/ui_options_script.py
+++ b/picard/ui/ui_options_script.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_ScriptingOptionsPage(object):
@@ -119,7 +122,6 @@ def setupUi(self, ScriptingOptionsPage):
         ScriptingOptionsPage.setTabOrder(self.move_down_button, self.remove_button)
 
     def retranslateUi(self, ScriptingOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.enable_tagger_scripts.setTitle(_("Enable Tagger Script(s)"))
         self.label.setText(_("Tagger scripts that have been activated below will be executed automatically for each track of a release loaded from MusicBrainz."))
         self.tagger_script.setPlaceholderText(_("Enter your tagger script here."))
diff --git a/picard/ui/ui_options_tags.py b/picard/ui/ui_options_tags.py
index 2b1cc1e44e..6110e69dee 100644
--- a/picard/ui/ui_options_tags.py
+++ b/picard/ui/ui_options_tags.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_TagsOptionsPage(object):
@@ -71,7 +74,6 @@ def setupUi(self, TagsOptionsPage):
         TagsOptionsPage.setTabOrder(self.remove_ape_from_mp3, self.fix_missing_seekpoints_flac)
 
     def retranslateUi(self, TagsOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.write_tags.setText(_("Write tags to files"))
         self.preserve_timestamps.setText(_("Preserve timestamps of tagged files"))
         self.before_tagging.setTitle(_("Before Tagging"))
diff --git a/picard/ui/ui_options_tags_compatibility_aac.py b/picard/ui/ui_options_tags_compatibility_aac.py
index 32d2ed4270..7a53682beb 100644
--- a/picard/ui/ui_options_tags_compatibility_aac.py
+++ b/picard/ui/ui_options_tags_compatibility_aac.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_TagsCompatibilityOptionsPage(object):
@@ -45,7 +48,6 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(TagsCompatibilityOptionsPage)
 
     def retranslateUi(self, TagsCompatibilityOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.aac_tags.setTitle(_("AAC files"))
         self.info_label.setText(_("Picard can save APEv2 tags to pure AAC files, which by default do not support tagging. APEv2 tags in AAC are supported by some players, but players not supporting AAC files with APEv2 tags can have issues loading and playing those files. To deal with this you can choose whether to save tags to those files."))
         self.aac_save_ape.setText(_("Save APEv2 tags"))
diff --git a/picard/ui/ui_options_tags_compatibility_ac3.py b/picard/ui/ui_options_tags_compatibility_ac3.py
index ddee75df79..984c067926 100644
--- a/picard/ui/ui_options_tags_compatibility_ac3.py
+++ b/picard/ui/ui_options_tags_compatibility_ac3.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_TagsCompatibilityOptionsPage(object):
@@ -45,7 +48,6 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(TagsCompatibilityOptionsPage)
 
     def retranslateUi(self, TagsCompatibilityOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.ac3_files.setTitle(_("AC3 files"))
         self.info_label.setText(_("Picard can save APEv2 tags to pure AC3 files, which by default do not support tagging. APEv2 tags in AC3 are supported by some players, but players not supporting AC3 files with APEv2 tags can have issues loading and playing those files. To deal with this you can choose whether to save tags to those files."))
         self.ac3_save_ape.setText(_("Save APEv2 tags"))
diff --git a/picard/ui/ui_options_tags_compatibility_id3.py b/picard/ui/ui_options_tags_compatibility_id3.py
index 3ec9b55258..414f952091 100644
--- a/picard/ui/ui_options_tags_compatibility_id3.py
+++ b/picard/ui/ui_options_tags_compatibility_id3.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_TagsCompatibilityOptionsPage(object):
@@ -115,7 +118,6 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         TagsCompatibilityOptionsPage.setTabOrder(self.itunes_compatible_grouping, self.write_id3v1)
 
     def retranslateUi(self, TagsCompatibilityOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.tag_compatibility.setTitle(_("ID3"))
         self.id3v2_version.setTitle(_("ID3v2 Version"))
         self.write_id3v24.setText(_("2.4"))
diff --git a/picard/ui/ui_options_tags_compatibility_wave.py b/picard/ui/ui_options_tags_compatibility_wave.py
index 4b484936a0..de53187fcf 100644
--- a/picard/ui/ui_options_tags_compatibility_wave.py
+++ b/picard/ui/ui_options_tags_compatibility_wave.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_TagsCompatibilityOptionsPage(object):
@@ -56,7 +59,6 @@ def setupUi(self, TagsCompatibilityOptionsPage):
         QtCore.QMetaObject.connectSlotsByName(TagsCompatibilityOptionsPage)
 
     def retranslateUi(self, TagsCompatibilityOptionsPage):
-        _translate = QtCore.QCoreApplication.translate
         self.wave_files.setTitle(_("WAVE files"))
         self.label.setText(_("Picard will tag WAVE files using ID3v2 tags. This is not supported by all software. For compatibility with software which does not support ID3v2 tags in WAVE files additional RIFF INFO tags can be written to the files. RIFF INFO has only limited support for tags and character encodings."))
         self.write_wave_riff_info.setText(_("Also include RIFF INFO tags in the files"))
diff --git a/picard/ui/ui_passworddialog.py b/picard/ui/ui_passworddialog.py
index d3423a66ea..5d8ba241d8 100644
--- a/picard/ui/ui_passworddialog.py
+++ b/picard/ui/ui_passworddialog.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_PasswordDialog(object):
@@ -62,7 +65,6 @@ def setupUi(self, PasswordDialog):
         QtCore.QMetaObject.connectSlotsByName(PasswordDialog)
 
     def retranslateUi(self, PasswordDialog):
-        _translate = QtCore.QCoreApplication.translate
         PasswordDialog.setWindowTitle(_("Authentication required"))
         self.label.setText(_("Username:"))
         self.label_2.setText(_("Password:"))
diff --git a/picard/ui/ui_provider_options_caa.py b/picard/ui/ui_provider_options_caa.py
index beeeb9a604..0a6665b47a 100644
--- a/picard/ui/ui_provider_options_caa.py
+++ b/picard/ui/ui_provider_options_caa.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_CaaOptions(object):
@@ -68,7 +71,6 @@ def setupUi(self, CaaOptions):
         CaaOptions.setTabOrder(self.cb_image_size, self.cb_approved_only)
 
     def retranslateUi(self, CaaOptions):
-        _translate = QtCore.QCoreApplication.translate
         CaaOptions.setWindowTitle(_("Form"))
         self.restrict_images_types.setText(_("Download only cover art images matching selected types"))
         self.select_caa_types.setText(_("Select types…"))
diff --git a/picard/ui/ui_provider_options_local.py b/picard/ui/ui_provider_options_local.py
index 065252a7b4..57fbbf20ca 100644
--- a/picard/ui/ui_provider_options_local.py
+++ b/picard/ui/ui_provider_options_local.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_LocalOptions(object):
@@ -52,7 +55,6 @@ def setupUi(self, LocalOptions):
         QtCore.QMetaObject.connectSlotsByName(LocalOptions)
 
     def retranslateUi(self, LocalOptions):
-        _translate = QtCore.QCoreApplication.translate
         LocalOptions.setWindowTitle(_("Form"))
         self.local_cover_regex_label.setText(_("Local cover art files match the following regular expression:"))
         self.local_cover_regex_default.setText(_("Default"))
diff --git a/picard/ui/ui_scripteditor.py b/picard/ui/ui_scripteditor.py
index 5b2aba08d1..a77738fb07 100644
--- a/picard/ui/ui_scripteditor.py
+++ b/picard/ui/ui_scripteditor.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_ScriptEditor(object):
@@ -208,7 +211,6 @@ def setupUi(self, ScriptEditor):
         QtCore.QMetaObject.connectSlotsByName(ScriptEditor)
 
     def retranslateUi(self, ScriptEditor):
-        _translate = QtCore.QCoreApplication.translate
         self.label.setText(_("Selected file naming script:"))
         self.preset_naming_scripts.setToolTip(_("Select the file naming script to load into the editor"))
         self.label_2.setText(_("Title:"))
diff --git a/picard/ui/ui_scripteditor_details.py b/picard/ui/ui_scripteditor_details.py
index 2540682d61..74b4ad3628 100644
--- a/picard/ui/ui_scripteditor_details.py
+++ b/picard/ui/ui_scripteditor_details.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_ScriptDetails(object):
@@ -91,7 +94,6 @@ def setupUi(self, ScriptDetails):
         QtCore.QMetaObject.connectSlotsByName(ScriptDetails)
 
     def retranslateUi(self, ScriptDetails):
-        _translate = QtCore.QCoreApplication.translate
         ScriptDetails.setWindowTitle(_("File Naming Script Metadata"))
         self.script_version.setToolTip(_("Version number of the file naming script."))
         self.label_4.setText(_("Last Updated:"))
diff --git a/picard/ui/ui_scripting_documentation_dialog.py b/picard/ui/ui_scripting_documentation_dialog.py
index 782300c0fc..e1715c18bc 100644
--- a/picard/ui/ui_scripting_documentation_dialog.py
+++ b/picard/ui/ui_scripting_documentation_dialog.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_ScriptingDocumentationDialog(object):
@@ -36,5 +39,4 @@ def setupUi(self, ScriptingDocumentationDialog):
         QtCore.QMetaObject.connectSlotsByName(ScriptingDocumentationDialog)
 
     def retranslateUi(self, ScriptingDocumentationDialog):
-        _translate = QtCore.QCoreApplication.translate
         ScriptingDocumentationDialog.setWindowTitle(_("Scripting Documentation"))
diff --git a/picard/ui/ui_tagsfromfilenames.py b/picard/ui/ui_tagsfromfilenames.py
index e6ba5f1a1c..bd0c7becdc 100644
--- a/picard/ui/ui_tagsfromfilenames.py
+++ b/picard/ui/ui_tagsfromfilenames.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_TagsFromFileNamesDialog(object):
@@ -53,7 +56,6 @@ def setupUi(self, TagsFromFileNamesDialog):
         TagsFromFileNamesDialog.setTabOrder(self.replace_underscores, self.buttonbox)
 
     def retranslateUi(self, TagsFromFileNamesDialog):
-        _translate = QtCore.QCoreApplication.translate
         TagsFromFileNamesDialog.setWindowTitle(_("Convert File Names to Tags"))
         self.replace_underscores.setText(_("Replace underscores with spaces"))
         self.preview.setText(_("&Preview"))
diff --git a/picard/ui/ui_widget_taglisteditor.py b/picard/ui/ui_widget_taglisteditor.py
index f604389eeb..07eb3ae76e 100644
--- a/picard/ui/ui_widget_taglisteditor.py
+++ b/picard/ui/ui_widget_taglisteditor.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_TagListEditor(object):
@@ -68,7 +71,6 @@ def setupUi(self, TagListEditor):
         QtCore.QMetaObject.connectSlotsByName(TagListEditor)
 
     def retranslateUi(self, TagListEditor):
-        _translate = QtCore.QCoreApplication.translate
         TagListEditor.setWindowTitle(_("Form"))
         self.tags_add_btn.setText(_("Add new tag"))
         self.tags_move_up_btn.setToolTip(_("Move tag up"))
diff --git a/picard/ui/ui_win_compat_dialog.py b/picard/ui/ui_win_compat_dialog.py
index 6c22c53d00..0fc9efd81e 100644
--- a/picard/ui/ui_win_compat_dialog.py
+++ b/picard/ui/ui_win_compat_dialog.py
@@ -5,10 +5,13 @@
 # Automatically generated - do not edit.
 # Use `python setup.py build_ui` to update it.
 
-from picard.i18n import gettext as _
-
+from PyQt6 import (
+    QtCore,
+    QtGui,
+    QtWidgets,
+)
 
-from PyQt6 import QtCore, QtGui, QtWidgets
+from picard.i18n import gettext as _
 
 
 class Ui_WinCompatDialog(object):
@@ -191,7 +194,6 @@ def setupUi(self, WinCompatDialog):
         WinCompatDialog.setTabOrder(self.replace_pipe, self.replace_quotationmark)
 
     def retranslateUi(self, WinCompatDialog):
-        _translate = QtCore.QCoreApplication.translate
         WinCompatDialog.setWindowTitle(_("Windows compatibility"))
         self.label_header_character.setText(_("Character"))
         self.label_header_replace.setText(_("Replacement"))

From a0ebf70768d802432c5a778d4fb6267edbcc8a9a Mon Sep 17 00:00:00 2001
From: Laurent Monin <github@norz.org>
Date: Mon, 22 Apr 2024 11:26:12 +0200
Subject: [PATCH 8/8] Get rid of `i18n._get_translation()`, use dict entries
 directly

---
 picard/i18n.py | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/picard/i18n.py b/picard/i18n.py
index 5c045f2234..0717bf30e6 100644
--- a/picard/i18n.py
+++ b/picard/i18n.py
@@ -34,7 +34,14 @@
 
 
 _logger = None
-_translation = dict()
+
+_null_translations = module_gettext.NullTranslations()
+_translation = {
+    'main':  _null_translations,
+    'attributes': _null_translations,
+    'constants': _null_translations,
+    'countries': _null_translations,
+}
 
 
 def set_locale_from_env():
@@ -177,16 +184,9 @@ def setup_gettext(localedir, ui_language=None, logger=None):
     _logger(_translation)
 
 
-def _get_translation(key: str) -> module_gettext.NullTranslations:
-    try:
-        return _translation[key]
-    except KeyError:
-        return module_gettext.NullTranslations()
-
-
 def gettext(message: str) -> str:
     """Translate the messsage using the current translator."""
-    return _get_translation('main').gettext(message)
+    return _translation['main'].gettext(message)
 
 
 def _(message: str) -> str:
@@ -200,20 +200,20 @@ def N_(message: str) -> str:
 
 
 def ngettext(singular: str, plural: str, n: int) -> str:
-    return _get_translation('main').ngettext(singular, plural, n)
+    return _translation['main'].ngettext(singular, plural, n)
 
 
 def pgettext_attributes(context: str, message: str) -> str:
-    return _get_translation('attributes').pgettext(context, message)
+    return _translation['attributes'].pgettext(context, message)
 
 
 def gettext_attributes(message: str) -> str:
-    return _get_translation('attributes').gettext(message)
+    return _translation['attributes'].gettext(message)
 
 
 def gettext_countries(message: str) -> str:
-    return _get_translation('countries').gettext(message)
+    return _translation['countries'].gettext(message)
 
 
 def gettext_constants(message: str) -> str:
-    return _get_translation('constants').gettext(message)
+    return _translation['constants'].gettext(message)