Skip to content

feat: translations #662

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9222c75
feat: implement Translator class
Computerdores Dec 22, 2024
96f9163
feat: add translate_with_setter and implement formatting of translations
Computerdores Dec 22, 2024
de57225
feat: extend PanelModal to allow for translation
Computerdores Dec 23, 2024
9ab681f
feat: extend ProgressWidget to allow for translation
Computerdores Dec 23, 2024
c857eb4
feat: translation in ts_qt.py
Computerdores Dec 23, 2024
bf5d18a
debug: set default lang to DE and show "Not Translated" when replacin…
Computerdores Dec 23, 2024
a38847c
add translation todos
Computerdores Dec 23, 2024
03b2e84
feat: translate modals
Computerdores Dec 23, 2024
c76b6ed
Merge branch 'main' into feat/translations
Computerdores Dec 23, 2024
e2c1440
feat: translate more stuff
Computerdores Dec 23, 2024
2f79458
fix: UI test wasn't comparing to translated strings
Computerdores Dec 23, 2024
05ee989
feat: translations for most of the remaining stuff
Computerdores Dec 23, 2024
399e4eb
fix: replace debug changes with simpler one
Computerdores Dec 23, 2024
2889cf7
uncomment debug change
Computerdores Dec 23, 2024
a555286
fix: missing parameter in call
Computerdores Dec 23, 2024
ba43c42
fix: various review feedback
Computerdores Dec 24, 2024
68fcce1
fix: don't translate json migration discrepancies list
Computerdores Dec 24, 2024
a688cad
fix: typo
Computerdores Dec 24, 2024
f37833d
fix: various PR feedback
Computerdores Dec 24, 2024
cf48d6a
fix: correctly read non-ascii characters
Computerdores Dec 25, 2024
0f44af9
fix: add missing new line at eof
Computerdores Dec 29, 2024
d594e84
fix: comment out line of debug code
Computerdores Dec 29, 2024
465bc41
fix: address latest review comment
Computerdores Dec 29, 2024
cc4b6df
fix: KeyError that occurred when formatting translations
Computerdores Dec 29, 2024
73010cc
fix: regression of d594e84
Computerdores Dec 30, 2024
cdc5bf1
fix: add newline to en.json
CyanVoxel Dec 31, 2024
39562e9
fix: organize en.json, fix typo
CyanVoxel Dec 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 115 additions & 31 deletions tagstudio/resources/translations/en.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,40 @@
{
"app.git": "Git Commit",
"app.pre_release": "Pre-Release",
"app.title": "{base_title} - Library '{library_dir}'",
"drop_import.description": "The following files have filenames already exist in the library",
"drop_import.duplicates_choice.plural": "The following {count} files have filenames that already exist in the library.",
"drop_import.duplicates_choice.singular": "The following file has a filename that already exists in the library.",
"drop_import.progress.label.initial": "Importing New Files...",
"drop_import.progress.label.plural": "Importing New Files...\n{count} Files Imported.{suffix}",
"drop_import.progress.label.singular": "Importing New Files...\n1 File imported.{suffix}",
"drop_import.progress.window_title": "Import Files",
"drop_import.title": "Conflicting File(s)",
"edit.tag_manager": "Manage Tags",
"entries.duplicate.merge.label": "Merging Duplicate Entries",
"entries.duplicate.merge.label": "Merging Duplicate Entries...",
"entries.duplicate.merge": "Merge Duplicate Entries",
"entries.duplicate.refresh": "Refresh Duplicate Entries",
"entries.duplicates.description": "Duplicate entries are defined as multiple entries which point to the same file on disk. Merging these will combine the tags and metadata from all duplicates into a single consolidated entry. These are not to be confused with \"duplicate files\", which are duplicates of your files themselves outside of TagStudio.",
"entries.mirror.confirmation": "Are you sure you want to mirror the following %{len(self.lib.dupe_files)} Entries?",
"entries.mirror.label": "Mirroring 1/%{count} Entries...",
"entries.mirror.confirmation": "Are you sure you want to mirror the following {count} Entries?",
"entries.mirror.label": "Mirroring {idx}/{total} Entries...",
"entries.mirror.title": "Mirroring Entries",
"entries.mirror": "Mirror",
"entries.mirror.window_title": "Mirror Entries",
"entries.mirror": "&Mirror",
"entries.tags": "Tags",
"entries.unlinked.delete.confirm": "Are you sure you want to delete the following %{len(self.lib.missing_files)} entries?",
"entries.unlinked.delete.deleting_count": "Deleting %{x[0]+1}/{len(self.lib.missing_files)} Unlinked Entries",
"entries.unlinked.delete_alt": "De&lete Unlinked Entries",
"entries.unlinked.delete.confirm": "Are you sure you want to delete the following {count} entries?",
"entries.unlinked.delete.deleting_count": "Deleting {idx}/{count} Unlinked Entries",
"entries.unlinked.delete.deleting": "Deleting Entries",
"entries.unlinked.delete": "Delete Unlinked Entries",
"entries.unlinked.description": "Each library entry is linked to a file in one of your directories. If a file linked to an entry is moved or deleted outside of TagStudio, it is then considered unlinked. Unlinked entries may be automatically relinked via searching your directories or deleted if desired.",
"entries.unlinked.refresh_all": "Refresh All",
"entries.unlinked.relink.attempting": "Attempting to Relink %{x[0]+1}/%{len(self.lib.missing_files)} Entries, %{self.fixed} Successfully Relinked",
"entries.unlinked.relink.manual": "Manual Relink",
"entries.unlinked.description": "Each library entry is linked to a file in one of your directories. If a file linked to an entry is moved or deleted outside of TagStudio, it is then considered unlinked.<br><br>Unlinked entries may be automatically relinked via searching your directories or deleted if desired.",
"entries.unlinked.missing_count.none": "Unlinked Entries: N/A",
"entries.unlinked.missing_count.some": "Unlinked Entries: {count}",
"entries.unlinked.refresh_all": "&Refresh All",
"entries.unlinked.relink.attempting": "Attempting to Relink {idx}/{missing_count} Entries, {fixed_count} Successfully Relinked",
"entries.unlinked.relink.manual": "&Manual Relink",
"entries.unlinked.relink.title": "Relinking Entries",
"entries.unlinked.scanning": "Scanning Library for Unlinked Entries...",
"entries.unlinked.search_and_relink": "Search && Relink",
"entries.unlinked.search_and_relink": "&Search && Relink",
"entries.unlinked.title": "Fix Unlinked Entries",
"field.copy": "Copy Field",
"field.edit": "Edit Field",
Expand All @@ -30,21 +43,22 @@
"file.date_created": "Date Created",
"file.date_modified": "Date Modified",
"file.dimensions": "Dimensions",
"file.duplicates.description": "TagStudio supports importing DupeGuru results to manage duplicate files.",
"file.duplicates.dupeguru.advice": "After mirroring, you're free to use DupeGuru to delete the unwanted files. Afterwards, use TagStudio's \"Fix Unlinked Entries\" feature in the Tools menu in order to delete the unlinked Entries.",
"file.duplicates.dupeguru.file_extension": "DupeGuru Files (*.dupeguru)",
"file.duplicates.dupeguru.load_file": "Load DupeGuru File",
"file.duplicates.dupeguru.load_file": "&Load DupeGuru File",
"file.duplicates.dupeguru.no_file": "No DupeGuru File Selected",
"file.duplicates.dupeguru.open_file": "Open DupeGuru Results File",
"file.duplicates.fix": "Fix Duplicate Files",
"file.duplicates.matches_uninitialized": "Duplicate File Matches: N/A",
"file.duplicates.matches": "Duplicate File Matches: %{count}",
"file.duplicates.mirror_entries": "Mirror Entries",
"file.duplicates.matches": "Duplicate File Matches: {count}",
"file.duplicates.mirror_entries": "&Mirror Entries",
"file.duplicates.mirror.description": "Mirror the Entry data across each duplicate match set, combining all data while not removing or duplicating fields. This operation will not delete any files or data.",
"file.duration": "Length",
"file.not_found": "File Not Found",
"file.open_file_with": "Open file with",
"file.open_file": "Open file",
"file.open_location.generic": "Show file in explorer",
"file.open_location.generic": "Show file in file explorer",
"file.open_location.mac": "Reveal in Finder",
"file.open_location.windows": "Show in File Explorer",
"folders_to_tags.close_all": "Close All",
Expand All @@ -53,80 +67,150 @@
"folders_to_tags.open_all": "Open All",
"folders_to_tags.title": "Create Tags From Folders",
"generic.add": "Add",
"generic.apply_alt": "&Apply",
"generic.apply": "Apply",
"generic.cancel_alt": "&Cancel",
"generic.cancel": "Cancel",
"generic.close": "Close",
"generic.continue": "Continue",
"generic.copy": "Copy",
"generic.cut": "Cut",
"generic.delete_alt": "&Delete",
"generic.delete": "Delete",
"generic.done_alt": "&Done",
"generic.done": "Done",
"generic.edit_alt": "&Edit",
"generic.edit": "Edit",
"generic.filename": "Filename",
"generic.navigation.back": "Back",
"generic.navigation.next": "Next",
"generic.overwrite_alt": "&Overwrite",
"generic.overwrite": "Overwrite",
"generic.paste": "Paste",
"generic.recent_libraries": "Recent Libraries",
"generic.rename_alt": "&Rename",
"generic.rename": "Rename",
"generic.save": "Save",
"generic.skip_alt": "&Skip",
"generic.skip": "Skip",
"help.visit_github": "Visit GitHub Repository",
"home.search_entries": "Search Entries",
"home.search_library": "Search Library",
"home.search_tags": "Search Tags",
"home.search": "Search",
"home.thumbnail_size.extra_large": "Extra Large Thumbnails",
"home.thumbnail_size.large": "Large Thumbnails",
"home.thumbnail_size.medium": "Medium Thumbnails",
"home.thumbnail_size.mini": "Mini Thumbnails",
"home.thumbnail_size.small": "Small Thumbnails",
"home.thumbnail_size": "Thumbnail Size",
"ignore_list.add_extension": "Add Extension",
"ignore_list.add_extension": "&Add Extension",
"ignore_list.mode.exclude": "Exclude",
"ignore_list.mode.include": "Include",
"ignore_list.mode.label": "List Mode",
"ignore_list.mode.label": "List Mode:",
"ignore_list.title": "File Extensions",
"json_migration.checking_for_parity": "Checking for Parity...",
"json_migration.creating_database_tables": "Creating SQL Database Tables...",
"json_migration.description": "<br>Start and preview the results of the library migration process. The converted library will <i>not</i> be used unless you click \"Finish Migration\". <br><br>Library data should either have matching values or feature a \"Matched\" label. Values that do not match will be displayed in red and feature a \"<b>(!)</b>\" symbol next to them.<br><center><i>This process may take up to several minutes for larger libraries.</i></center>",
"json_migration.discrepancies_found.description": "Discrepancies were found between the original and converted library formats. Please review and choose to whether continue with the migration or to cancel.",
"json_migration.discrepancies_found": "Library Discrepancies Found",
"json_migration.finish_migration": "Finish Migration",
"json_migration.heading.aliases": "Aliases:",
"json_migration.heading.colors": "Colors:",
"json_migration.heading.differ": "Discrepancy",
"json_migration.heading.entires": "Entries:",
"json_migration.heading.extension_list_type": "Extension List Type:",
"json_migration.heading.fields": "Fields:",
"json_migration.heading.file_extension_list": "File Extension List:",
"json_migration.heading.match": "Matched",
"json_migration.heading.parent_tags": "Parent Tags:",
"json_migration.heading.paths": "Paths:",
"json_migration.heading.shorthands": "Shorthands:",
"json_migration.heading.tags": "Tags:",
"json_migration.info.description": "Library save files created with TagStudio versions <b>9.4 and below</b> will need to be migrated to the new <b>v9.5+</b> format.<br><h2>What you need to know:</h2><ul><li>Your existing library save file will <b><i>NOT</i></b> be deleted</li><li>Your personal files will <b><i>NOT</i></b> be deleted, moved, or modified</li><li>The new v9.5+ save format can not be opened in earlier versions of TagStudio</li></ul>",
"json_migration.migrating_files_entries": "Migrating {entries:,d} File Entries...",
"json_migration.migration_complete_with_discrepancies": "Migration Complete, Discrepancies Found",
"json_migration.migration_complete": "Migration Complete!",
"json_migration.start_and_preview": "Start and Preview",
"json_migration.title.new_lib": "<h2>v9.5+ Library</h2>",
"json_migration.title.old_lib": "<h2>v9.4 Library</h2>",
"json_migration.title": "Save Format Migration: \"{path}\"",
"landing.open_create_library": "Open/Create Library {shortcut}",
"library.field.add": "Add Field",
"library.field.confirm_remove": "Are you sure you want to remove this \"%{self.lib.get_field_attr(field, \"name\")}\" field?",
"library.field.confirm_remove": "Are you sure you want to remove this \"{name}\" field?",
"library.field.mixed_data": "Mixed Data",
"library.field.remove": "Remove Field",
"library.missing": "Library Location is Missing",
"library.name": "Library",
"library.refresh.scanning_preparing": "Scanning Directories for New Files...\nPreparing...",
"library.refresh.scanning": "Scanning Directories for New Files...\n%{x + 1} File%{\"s\" if x + 1 != 1 else \"\"} Searched, %{len(self.lib.files_not_in_library)} New Files Found",
"library.refresh.scanning.plural": "Scanning Directories for New Files...\n{searched_count} Files Searched, {found_count} New Files Found",
"library.refresh.scanning.singular": "Scanning Directories for New Files...\n{searched_count} File Searched, {found_count} New Files Found",
"library.refresh.title": "Refreshing Directories",
"library.scan_library.title": "Scanning Library",
"macros.running.dialog.new_entries": "Running Configured Macros on %{x + 1}/%{len(new_ids)} New Entries",
"macros.running.dialog.new_entries": "Running Configured Macros on {count}/{total} New Entries",
"macros.running.dialog.title": "Running Macros on New Entries",
"media_player.autoplay": "Autoplay",
"menu.edit.ignore_list": "Ignore Files and Folders",
"menu.edit.manage_file_extensions": "Manage File Extensions",
"menu.edit.manage_tags": "Manage Tags",
"menu.edit.new_tag": "New &Tag",
"menu.edit": "Edit",
"menu.file.close_library": "&Close Library",
"menu.file.new_library": "New Library",
"menu.file.open_create_library": "Open/Create Library",
"menu.file.open_create_library": "&Open/Create Library",
"menu.file.open_library": "Open Library",
"menu.file.refresh_directories": "&Refresh Directories",
"menu.file.save_backup": "&Save Library Backup",
"menu.file.save_library": "Save Library",
"menu.file": "File",
"menu.help": "Help",
"menu.macros": "Macros",
"menu.file": "&File",
"menu.help": "&Help",
"menu.macros.folders_to_tags": "Folders to Tags",
"menu.macros": "&Macros",
"menu.select": "Select",
"menu.tools": "Tools",
"menu.view": "View",
"menu.tools.fix_duplicate_files": "Fix Duplicate &Files",
"menu.tools.fix_unlinked_entries": "Fix &Unlinked Entries",
"menu.tools": "&Tools",
"menu.view": "&View",
"menu.window": "Window",
"preview.no_selection": "No Items Selected",
"select.all": "Select All",
"select.clear": "Clear Selection",
"settings.open_library_on_start": "Open Library on Start",
"settings.show_filenames_in_grid": "Show Filenames in Grid",
"settings.show_recent_libraries": "Show Recent Libraries",
"splash.opening_library": "Opening Library",
"status.library_backup_success": "Library Backup Saved at:",
"splash.opening_library": "Opening Library \"{library_path}\"...",
"status.library_backup_in_progress": "Saving Library Backup...",
"status.library_backup_success": "Library Backup Saved at: \"{path}\" ({time_span})",
"status.library_closed": "Library Closed ({time_span})",
"status.library_closing": "Closing Library...",
"status.library_save_success": "Library Saved and Closed!",
"status.library_search_query": "Searching Library for",
"status.results_found": "{results.total_count} Results Found",
"status.library_search_query": "Searching Library...",
"status.results_found": "{count} Results Found ({time_span})",
"status.results": "Results",
"tag_manager.title": "Library Tags",
"tag.add_to_search": "Add to Search",
"tag.add.plural": "Add Tags",
"tag.add": "Add Tag",
"tag.aliases": "Aliases",
"tag.color": "Color",
"tag.confirm_delete": "Are you sure you want to delete the tag \"{tag_name}\"?",
"tag.create": "Create Tag",
"tag.edit": "Edit Tag",
"tag.name": "Name",
"tag.new": "New Tag",
"tag.parent_tags.add": "Add Parent Tag(s)",
"tag.parent_tags.description": "This tag can be treated as a substitute for any of these Parent Tags in searches.",
"tag.parent_tags": "Parent Tags",
"tag.remove": "Remove Tag",
"tag.search_for_tag": "Search for Tag",
"tag.shorthand": "Shorthand",
"tag.tag_name_required": "Tag Name (Required)",
"view.size.0": "Mini",
"view.size.1": "Small",
"view.size.2": "Medium",
"view.size.3": "Large",
"view.size.4": "Extra Large"
"view.size.4": "Extra Large",
"window.message.error_opening_library": "Error opening library.",
"window.title.error": "Error",
"window.title.open_create_library": "Open/Create Library"
}
34 changes: 8 additions & 26 deletions tagstudio/src/qt/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from src.qt.pagination import Pagination
from src.qt.widgets.landing import LandingWidget

from src.qt.translations import Translations

# Only import for type checking/autocompletion, will not be imported at runtime.
if typing.TYPE_CHECKING:
from src.qt.ts_qt import QtDriver
Expand Down Expand Up @@ -77,6 +79,8 @@ def setupUi(self, MainWindow):
# Thumbnail Size placeholder
self.thumb_size_combobox = QComboBox(self.centralwidget)
self.thumb_size_combobox.setObjectName(u"thumbSizeComboBox")
Translations.translate_with_setter(self.thumb_size_combobox.setPlaceholderText, "home.thumbnail_size")
self.thumb_size_combobox.setCurrentText("")
sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
Expand Down Expand Up @@ -128,7 +132,7 @@ def setupUi(self, MainWindow):
self.horizontalLayout_2 = QHBoxLayout()
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.horizontalLayout_2.setSizeConstraint(QLayout.SetMinimumSize)
self.backButton = QPushButton(self.centralwidget)
self.backButton = QPushButton("<", self.centralwidget)
self.backButton.setObjectName(u"backButton")
self.backButton.setMinimumSize(QSize(0, 32))
self.backButton.setMaximumSize(QSize(32, 16777215))
Expand All @@ -139,7 +143,7 @@ def setupUi(self, MainWindow):

self.horizontalLayout_2.addWidget(self.backButton)

self.forwardButton = QPushButton(self.centralwidget)
self.forwardButton = QPushButton(">", self.centralwidget)
self.forwardButton.setObjectName(u"forwardButton")
self.forwardButton.setMinimumSize(QSize(0, 32))
self.forwardButton.setMaximumSize(QSize(32, 16777215))
Expand All @@ -152,6 +156,7 @@ def setupUi(self, MainWindow):
self.horizontalLayout_2.addWidget(self.forwardButton)

self.searchField = QLineEdit(self.centralwidget)
Translations.translate_with_setter(self.searchField.setPlaceholderText, "home.search_entries")
self.searchField.setObjectName(u"searchField")
self.searchField.setMinimumSize(QSize(0, 32))
font2 = QFont()
Expand All @@ -167,6 +172,7 @@ def setupUi(self, MainWindow):
self.horizontalLayout_2.addWidget(self.searchField)

self.searchButton = QPushButton(self.centralwidget)
Translations.translate_qobject(self.searchButton, "home.search")
self.searchButton.setObjectName(u"searchButton")
self.searchButton.setMinimumSize(QSize(0, 32))
self.searchButton.setFont(font2)
Expand All @@ -186,33 +192,9 @@ def setupUi(self, MainWindow):
self.statusbar.setSizePolicy(sizePolicy1)
MainWindow.setStatusBar(self.statusbar)

self.retranslateUi(MainWindow)

QMetaObject.connectSlotsByName(MainWindow)
# setupUi

def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate(
"MainWindow", u"MainWindow", None))
# Navigation buttons
self.backButton.setText(
QCoreApplication.translate("MainWindow", u"<", None))
self.forwardButton.setText(
QCoreApplication.translate("MainWindow", u">", None))

# Search field
self.searchField.setPlaceholderText(
QCoreApplication.translate("MainWindow", u"Search Entries", None))
self.searchButton.setText(
QCoreApplication.translate("MainWindow", u"Search", None))

self.thumb_size_combobox.setCurrentText("")

# Thumbnail size selector
self.thumb_size_combobox.setPlaceholderText(
QCoreApplication.translate("MainWindow", u"Thumbnail Size", None))
# retranslateUi

def moveEvent(self, event) -> None:
# time.sleep(0.02) # sleep for 20ms
pass
Expand Down
Loading
Loading