"
+ # + Translations["entries.unlinked.description.ambiguous"]
+ )
self.unlinked_desc_widget.setObjectName("unlinkedDescriptionLabel")
self.unlinked_desc_widget.setWordWrap(True)
self.unlinked_desc_widget.setStyleSheet("text-align:left;")
@@ -53,35 +55,24 @@ def __init__(self, library: Library, driver: QtDriver):
self.dupe_count_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.refresh_unlinked_button = QPushButton(Translations["entries.generic.refresh_alt"])
- self.refresh_unlinked_button.clicked.connect(self.refresh_unlinked)
+ self.refresh_unlinked_button.clicked.connect(self.driver.sync_library_callback)
self.merge_class = MergeDuplicateEntriesProgress(self.lib, self.driver)
- self.relink_class = RelinkUnlinkedEntriesProgress(self.tracker)
-
- self.search_button = QPushButton(Translations["entries.unlinked.search_and_relink"])
- self.relink_class.done.connect(
- # refresh the grid
- lambda: (
- self.driver.update_browsing_state(),
- self.refresh_unlinked(),
- )
- )
- self.search_button.clicked.connect(self.relink_class.repair_entries)
self.manual_button = QPushButton(Translations["entries.unlinked.relink.manual"])
self.manual_button.setHidden(True)
self.remove_button = QPushButton(Translations["entries.unlinked.remove_alt"])
- self.remove_modal = RemoveUnlinkedEntriesModal(self.driver, self.tracker)
+ self.remove_modal = RemoveUnlinkedEntriesModal(self.driver, self.sync_engine)
self.remove_modal.done.connect(
lambda: (
- self.set_unlinked_count(),
- # refresh the grid
self.driver.update_browsing_state(),
- self.refresh_unlinked(),
+ self._sync_ui_from_tracker(),
)
)
- self.remove_button.clicked.connect(self.remove_modal.show)
+ self.remove_button.clicked.connect(
+ lambda: (self.remove_modal.refresh_list(), self.remove_modal.show())
+ )
self.button_container = QWidget()
self.button_layout = QHBoxLayout(self.button_container)
@@ -96,7 +87,6 @@ def __init__(self, library: Library, driver: QtDriver):
self.root_layout.addWidget(self.unlinked_count_label)
self.root_layout.addWidget(self.unlinked_desc_widget)
self.root_layout.addWidget(self.refresh_unlinked_button)
- self.root_layout.addWidget(self.search_button)
self.root_layout.addWidget(self.manual_button)
self.root_layout.addWidget(self.remove_button)
self.root_layout.addStretch(1)
@@ -105,46 +95,22 @@ def __init__(self, library: Library, driver: QtDriver):
self.update_unlinked_count()
- def refresh_unlinked(self):
- pw = ProgressWidget(
- cancel_button_text=None,
- minimum=0,
- maximum=self.lib.entries_count,
- )
- pw.setWindowTitle(Translations["library.scan_library.title"])
- pw.update_label(Translations["entries.unlinked.scanning"])
-
- def update_driver_widgets():
- if (
- hasattr(self.driver, "library_info_window")
- and self.driver.library_info_window.isVisible()
- ):
- self.driver.library_info_window.update_cleanup()
-
- pw.from_iterable_function(
- self.tracker.refresh_unlinked_files,
- None,
- self.set_unlinked_count,
- self.update_unlinked_count,
- self.remove_modal.refresh_list,
- update_driver_widgets,
- )
+ def _sync_ui_from_tracker(self) -> None:
+ """Refresh the UI from the tracker's current state, without rescanning the library."""
+ self.set_unlinked_count()
+ self.update_unlinked_count()
+ self.remove_modal.refresh_list()
def set_unlinked_count(self):
"""Sets the unlinked_entries_count in the Library to the tracker's value."""
- self.lib.unlinked_entries_count = self.tracker.unlinked_entries_count
+ self.lib.unlinked_entries_count = self.sync_engine.unlinked_entries_count
def update_unlinked_count(self):
"""Updates the UI to reflect the Library's current unlinked_entries_count."""
- # Indicates that the library is new compared to the last update.
- # NOTE: Make sure set_unlinked_count() is called before this!
- if self.tracker.unlinked_entries_count > 0 and self.lib.unlinked_entries_count < 0:
- self.tracker.reset()
-
count: int = self.lib.unlinked_entries_count
+ syncing = self.driver.file_scan_lock # Disabled while a sync is running
- self.search_button.setDisabled(count < 1)
- self.remove_button.setDisabled(count < 1)
+ self.remove_button.setDisabled(count < 1 or syncing)
count_text: str = Translations.format(
"entries.unlinked.unlinked_count", count=count if count >= 0 else "—"
diff --git a/src/tagstudio/qt/mixed/remove_unlinked_modal.py b/src/tagstudio/qt/mixed/remove_unlinked_modal.py
index d34fa02b9..38faa86e7 100644
--- a/src/tagstudio/qt/mixed/remove_unlinked_modal.py
+++ b/src/tagstudio/qt/mixed/remove_unlinked_modal.py
@@ -9,7 +9,7 @@
from PySide6.QtGui import QStandardItem, QStandardItemModel
from PySide6.QtWidgets import QHBoxLayout, QLabel, QListView, QPushButton, QVBoxLayout, QWidget
-from tagstudio.core.library.alchemy.registries.unlinked_registry import UnlinkedRegistry
+from tagstudio.core.library.sync import LibrarySyncEngine
from tagstudio.i18n.translations import Translations
from tagstudio.qt.controllers.progress_bar import ProgressWidget
from tagstudio.qt.utils.custom_runnable import CustomRunnable
@@ -18,11 +18,11 @@
from tagstudio.qt.qt_driver import QtDriver
-# TODO: Split to use MVC guidelines.
+# TODO: Split to use MVC guidelines or completely redo.
class RemoveUnlinkedEntriesModal(QWidget):
done = Signal()
- def __init__(self, driver: QtDriver, tracker: UnlinkedRegistry):
+ def __init__(self, driver: QtDriver, tracker: LibrarySyncEngine):
super().__init__()
self.driver = driver
self.tracker = tracker
diff --git a/src/tagstudio/qt/qt_driver.py b/src/tagstudio/qt/qt_driver.py
index 57ba1877e..bcc0907ae 100644
--- a/src/tagstudio/qt/qt_driver.py
+++ b/src/tagstudio/qt/qt_driver.py
@@ -17,10 +17,11 @@
import time
from argparse import Namespace
from collections import OrderedDict
+from collections.abc import Callable, Iterator
from functools import partial
from pathlib import Path
from queue import Queue
-from typing import TypeVar
+from typing import Literal, TypeVar
from warnings import catch_warnings
import structlog
@@ -47,7 +48,7 @@
from tagstudio.core.library.alchemy.library import Library, LibraryStatus
from tagstudio.core.library.alchemy.models import Entry
from tagstudio.core.library.ignore import Ignore
-from tagstudio.core.library.refresh import RefreshTracker
+from tagstudio.core.library.sync import LibrarySyncEngine
from tagstudio.core.media_types import MediaTypes
from tagstudio.core.query_lang.file_groups import SEARCH
from tagstudio.core.query_lang.util import ParsingError
@@ -67,7 +68,6 @@
from tagstudio.qt.controllers.library_info_window import LibraryInfoWindow
from tagstudio.qt.controllers.main_window import MainWindow
from tagstudio.qt.controllers.modal import Modal
-from tagstudio.qt.controllers.progress_bar import ProgressWidget
from tagstudio.qt.controllers.splash import SplashScreen
from tagstudio.qt.controllers.tag_search_panel import TagSearchPanel
from tagstudio.qt.controllers.update_available_message_box import UpdateAvailableMessageBox
@@ -104,6 +104,9 @@
from signal import SIGINT, SIGQUIT, SIGTERM, signal # pyright: ignore
logger = structlog.get_logger(__name__)
+T = TypeVar("T")
+# Used to track the context state of the banner widget.
+_BannerContext = Literal["new_files", "unlinked", "relinked", "sync_disabled", "sync_finished"]
def clamp(value, lower_bound, upper_bound):
@@ -128,9 +131,6 @@ def run(self):
pass
-T = TypeVar("T")
-
-
# Ex. User visits | A ->[B] |
# | A B ->[C]|
# | A [B]<- C |
@@ -192,13 +192,17 @@ class QtDriver(DriverMixin, QObject):
def __init__(self, args: Namespace):
super().__init__()
- # prevent recursive badges update when multiple items selected
- self.badge_update_lock = False
self.lib = Library()
+ self.sync_engine = LibrarySyncEngine(self.lib)
self.rm: ResourceManager = ResourceManager()
self.args = args
self.frame_content: list[int] = [] # List of Entry IDs for the current query
+ self.badge_update_lock = False
+ self.file_scan_lock: bool = False # Prevent multiple file scanning operations at once
self._selected: OrderedDict[int, None] = OrderedDict()
+ self._sync_session_id: int = 0 # Prevent current sync from affecting subsequent libraries.
+ self._sync_disabled_notice_shown: bool = False
+ self._banner_context: _BannerContext | None = None
self.pages_count = 0
self.scrollbar_pos = 0
@@ -454,9 +458,9 @@ def set_open_last_loaded_on_startup(checked: bool):
set_open_last_loaded_on_startup
)
- # Refresh Directories
- self.main_window.menu_bar.refresh_dir_action.triggered.connect(
- lambda: self.call_if_library_open(self.add_new_files_callback)
+ # Sync Library
+ self.main_window.menu_bar.sync_library_action.triggered.connect(
+ lambda: self.call_if_library_open(self.sync_library_callback)
)
# Close Library
@@ -552,13 +556,8 @@ def on_increase_thumbnail_size_action():
# region Tools Menu ===========================================================
- def create_fix_unlinked_entries_modal():
- if not hasattr(self, "unlinked_modal"):
- self.unlinked_modal = FixUnlinkedEntriesModal(self.lib, self)
- self.unlinked_modal.show()
-
self.main_window.menu_bar.fix_unlinked_entries_action.triggered.connect(
- create_fix_unlinked_entries_modal
+ self.open_fix_unlinked_entries_modal
)
def create_ignored_entries_modal():
@@ -577,7 +576,7 @@ def create_dupe_files_modal():
self.main_window.menu_bar.fix_dupe_files_action.triggered.connect(create_dupe_files_modal)
- # TODO: Move this to a settings screen.
+ # TODO: Make this accessible somewhere more sensible too, like "Library Information"
self.main_window.menu_bar.clear_thumb_cache_action.triggered.connect(
lambda: unwrap(self.cache_manager).clear_cache()
)
@@ -638,6 +637,7 @@ def on_visible_changed(entry_id: int | None):
self.init_library_window()
self.migration_modal: JsonMigrationModal | None = None
+ self.main_window.banner.request_extra_duration()
path_result = self.evaluate_path(str(self.args.open).lstrip().rstrip())
if path_result.success and path_result.library_path:
self.open_library(path_result.library_path)
@@ -678,6 +678,9 @@ def init_library_window(self):
# adj_font_size = math.floor(12 * self.main_window.devicePixelRatio())
def _update_browsing_state():
+ # Clear any banner asking for a manual refresh of the view
+ if self._banner_context == "new_files":
+ self._clear_notice()
try:
self.update_browsing_state(
BrowsingState.from_search_query(self.main_window.search_field.text())
@@ -725,9 +728,11 @@ def _update_browsing_state():
self.main_window.back_button.clicked.connect(lambda: self.navigation_callback(-1))
self.main_window.forward_button.clicked.connect(lambda: self.navigation_callback(1))
- # NOTE: Putting this early will result in a white non-responsive
- # window until everything is loaded. Consider adding a splash screen
- # or implementing some clever loading tricks.
+ # Banner
+ self.main_window.banner.notice_action_clicked.connect(self._on_notice_action_clicked)
+ self.main_window.banner.cancel_requested.connect(self._on_sync_cancel_requested)
+
+ # NOTE: Putting this too early will result in a non-responsive white window on start.
self.main_window.show()
self.main_window.activateWindow()
self.main_window.toggle_landing_page(enabled=True)
@@ -784,8 +789,14 @@ def close_library(self, is_shutdown: bool = False):
if not self.lib.library_dir:
logger.info("No Library to Close")
return
-
logger.info("Closing Library...")
+
+ self.sync_engine.cancelled = True
+ self.file_scan_lock = False
+ self._new_sync_session() # Invalidate any sync still active for the old library
+ self._banner_context = None
+ self.main_window.banner.hide_banner(force=True)
+
self.main_window.status_bar.showMessage(Translations["status.library_closing"])
start_time = time.time()
@@ -800,6 +811,7 @@ def close_library(self, is_shutdown: bool = False):
self.__reset_navigation()
self.lib.close()
+ self.sync_engine.reset()
self.cache_manager = None
self.thumb_job_queue.queue.clear()
@@ -827,7 +839,7 @@ def close_library(self, is_shutdown: bool = False):
try:
self.main_window.menu_bar.save_library_backup_action.setEnabled(False)
self.main_window.menu_bar.close_library_action.setEnabled(False)
- self.main_window.menu_bar.refresh_dir_action.setEnabled(False)
+ self.main_window.menu_bar.sync_library_action.setEnabled(False)
self.main_window.menu_bar.tag_manager_action.setEnabled(False)
self.main_window.menu_bar.color_manager_action.setEnabled(False)
self.main_window.menu_bar.field_template_manager_action.setEnabled(False)
@@ -1067,82 +1079,278 @@ def delete_file_confirmation(self, count: int, filename: Path | None = None) ->
return msg.exec()
- def add_new_files_callback(self):
- """Run when user initiates adding new files to the Library."""
- tracker = RefreshTracker(self.lib)
-
- pw = ProgressWidget(
- cancel_button_text=None,
- minimum=0,
- maximum=0,
- )
- pw.setWindowTitle(Translations["library.refresh.title"])
- pw.update_label(Translations["library.refresh.scanning_preparing"])
- pw.show()
-
- iterator = FunctionIterator(lambda lib=self.lib.library_dir: tracker.refresh_dir(lib))
- iterator.value.connect(
- lambda x: (
- pw.update_progress(x + 1),
- pw.update_label(
- Translations.format(
- "library.refresh.scanning.plural"
- if x + 1 != 1
- else "library.refresh.scanning.singular",
- searched_count=f"{x + 1:n}",
- found_count=f"{tracker.files_count:n}",
- )
+ def _run_sync_step(
+ self,
+ generator: Callable[[], Iterator[T]],
+ on_progress: Callable[[T], None],
+ on_done: Callable[[], None],
+ ) -> None:
+ """Run a generator function on a background thread with signals for progress and completion.
+
+ Args:
+ generator (Callable[[], Iterator[T]]): Zero-argument callable returning the
+ generator to iterate.
+ on_progress (Callable[[T], None]): Called on the main thread with each yielded value.
+ on_done (Callable[[], None]): Called on the main thread once `generator` is finished.
+ """
+ iterator = FunctionIterator(generator)
+ iterator.value.connect(on_progress)
+ runnable = CustomRunnable(iterator.run)
+ runnable.done.connect(on_done)
+ QThreadPool.globalInstance().start(runnable)
+
+ def sync_library_callback(self):
+ """Run when syncing a Library is initiated."""
+ if self.file_scan_lock:
+ logger.info("[QtDriver] Sync already in progress, ignoring request")
+ return
+ self.file_scan_lock = True
+ session_id = self._new_sync_session()
+ # Disable the "Fix Unlinked Entries" modal's relink/remove actions during the sync
+ if hasattr(self, "unlinked_modal") and self.unlinked_modal.isVisible():
+ self.unlinked_modal.update_unlinked_count()
+
+ engine = self.sync_engine
+ library_dir = unwrap(self.lib.library_dir)
+ self.main_window.banner.show_progress(
+ Translations["library.sync.preparing"], phase="preparing"
+ )
+
+ def on_progress(progress: tuple[int, int]) -> None:
+ if engine.cancelled:
+ return
+ searched_count, found_count = progress
+ if searched_count < 0:
+ # Scan finished, duplicate entry merging/relinking is running before the next yield
+ self.main_window.banner.show_progress(
+ Translations["library.sync.repairing"], phase="repairing"
+ )
+ return
+ self.main_window.banner.show_progress(
+ Translations.format(
+ "library.sync.scanning",
+ searched_count=f"{searched_count + 1:n}",
+ found_count=f"{found_count:n}",
),
+ phase="scanning",
)
- )
- r = CustomRunnable(iterator.run)
- r.done.connect(
- lambda: (
- pw.hide(),
- pw.deleteLater(),
- self.add_new_files_runnable(tracker),
+
+ def _start_scan() -> None:
+ self._run_sync_step(
+ lambda lib=library_dir: engine.sync_dir(lib),
+ on_progress,
+ lambda: self.save_new_entries_runnable(engine, session_id=session_id),
)
- )
- QThreadPool.globalInstance().start(r)
- def add_new_files_runnable(self, tracker: RefreshTracker):
- """Adds any known new files to the library and run default macros on them.
+ self.main_window.banner.call_when_open(_start_scan)
- Threaded method.
+ def _finish_sync(
+ self,
+ new_count: int = 0,
+ unlinked_count: int = 0,
+ relinked_count: int = 0,
+ session_id: int = 0,
+ ):
+ """Reset the banner once the sync is completed.
+
+ Args:
+ new_count (int): New files count.
+ unlinked_count (int): Unlinked entries count.
+ relinked_count (int): Automatically relinked files count.
+ session_id (int): The sync_session_id this sync started with.
"""
- files_count = tracker.files_count
+ if self._is_sync_stale(session_id):
+ return
- iterator = FunctionIterator(tracker.save_new_files)
- pw = ProgressWidget(
- cancel_button_text=None,
- minimum=0,
- maximum=0,
- )
- pw.setWindowTitle(Translations["entries.running.dialog.title"])
- pw.update_label(
- Translations.format("entries.running.dialog.new_entries", total=f"{files_count:n}")
- )
- pw.show()
+ self.file_scan_lock = False
+ self.lib.unlinked_entries_count = unlinked_count
+ if hasattr(self, "unlinked_modal") and self.unlinked_modal.isVisible():
+ self.unlinked_modal.update_unlinked_count()
+ self.unlinked_modal.remove_modal.refresh_list()
+ if hasattr(self, "library_info_window") and self.library_info_window.isVisible():
+ self.library_info_window.update_cleanup()
- iterator.value.connect(
- lambda _count: (
- pw.update_label(
- Translations.format(
- "entries.running.dialog.new_entries", total=f"{files_count:n}"
- )
+ if self.sync_engine.cancelled:
+ return
+
+ # Show fleeting count of any new files added with button to refresh view
+ if new_count:
+ text = Translations.format(
+ "library.sync.new_files_banner.plural"
+ if new_count != 1
+ else "library.sync.new_files_banner.singular",
+ count=f"{new_count:n}",
+ )
+ text += self._count_suffix(relinked_count, "library.sync.relinked_suffix")
+ if relinked_count:
+ text += self._count_suffix(unlinked_count, "library.sync.remaining_unlinked_suffix")
+ self._show_notice("new_files", text, Translations["entries.generic.refresh_alt"])
+ # Show persistent count of any remaining unlinked files and button to manually review
+ elif unlinked_count:
+ text = Translations.format(
+ "library.sync.unlinked_banner.plural"
+ if unlinked_count != 1
+ else "library.sync.unlinked_banner.singular",
+ count=f"{unlinked_count:n}",
+ )
+ text += self._count_suffix(relinked_count, "library.sync.relinked_suffix")
+ self._show_notice("unlinked", text, Translations["entries.unlinked.review"])
+ # Show fleeting notice number of entries automatically relinked
+ elif relinked_count:
+ text = Translations.format(
+ "library.sync.relinked_banner.plural"
+ if relinked_count != 1
+ else "library.sync.relinked_banner.singular",
+ count=f"{relinked_count:n}",
+ )
+ text += self._count_suffix(unlinked_count, "library.sync.remaining_unlinked_suffix")
+ self._show_notice("relinked", text, Translations["entries.generic.refresh_alt"])
+ # Show a fleeting "Library Synced" message
+ else:
+ self._show_notice("sync_finished", Translations["library.sync.complete"])
+
+ def _count_suffix(self, count: int, key: str) -> str:
+ """Build a count suffix suffix, or "" if count is 0."""
+ if not count:
+ return ""
+ return " " + Translations.format(key, count=f"{count:n}")
+
+ def _new_sync_session(self) -> int:
+ """Increment the sync session, invalidating any active sync's callbacks."""
+ self._sync_session_id += 1
+ return self._sync_session_id
+
+ def _is_sync_stale(self, session_id: int) -> bool:
+ """Whether `session_id` belongs to an older sync session and should be invalidated."""
+ return session_id != self._sync_session_id
+
+ def _show_notice(
+ self, context: _BannerContext, message: str, button_text: str | None = None
+ ) -> None:
+ """Show a "notice" banner and keep track of its context type.
+
+ Args:
+ context (_BannerContext): The subtype of banner notice.
+ Used to keep track of the context state currently used for the banner.
+ This could be for a startup message, sync progress, an entry relink prompt, etc.
+ message (str): The notice message text.
+ button_text (str): The action button text.
+ """
+ self._banner_context = context
+ if button_text is not None:
+ self.main_window.banner.show_notice(message, button_text)
+ else:
+ self.main_window.banner.show_fleeting_notice(message)
+
+ def _clear_notice(self, force: bool = False) -> None:
+ self._banner_context = None
+ self.main_window.banner.hide_banner(force=force)
+
+ def _on_notice_action_clicked(self) -> None:
+ if self._banner_context == "unlinked":
+ self._on_unlinked_banner_review()
+ elif self._banner_context == "sync_disabled":
+ self._on_sync_disabled_open_settings()
+ else: # "new_files" or "relinked"
+ self._on_new_files_banner_refresh()
+
+ def _on_new_files_banner_refresh(self):
+ self.update_browsing_state()
+ # If there are still unlinked entries after the automatic relinking step, show a notice.
+ if self.lib.unlinked_entries_count > 0:
+ count = self.lib.unlinked_entries_count
+ text = Translations.format(
+ "library.sync.unlinked_banner.plural"
+ if count != 1
+ else "library.sync.unlinked_banner.singular",
+ count=f"{count:n}",
+ )
+ self._show_notice("unlinked", text, Translations["entries.unlinked.review"])
+ else:
+ self._clear_notice(force=True)
+
+ def _on_unlinked_banner_review(self):
+ self._clear_notice(force=True)
+ self.open_fix_unlinked_entries_modal()
+
+ def _on_sync_disabled_open_settings(self):
+ self._clear_notice(force=True)
+ self.open_settings_modal()
+
+ def _on_sync_cancel_requested(self):
+ """Stop the in-progress sync at its next opportunity."""
+ self.sync_engine.cancelled = True
+ logger.info("[QtDriver] Sync cancelled")
+
+ def open_fix_unlinked_entries_modal(self):
+ if not hasattr(self, "unlinked_modal"):
+ self.unlinked_modal = FixUnlinkedEntriesModal(self.lib, self)
+ self.unlinked_modal.show()
+
+ def sync_entry_stats_runnable(
+ self,
+ engine: LibrarySyncEngine,
+ new_count: int = 0,
+ unlinked_count: int = 0,
+ relinked_count: int = 0,
+ session_id: int = 0,
+ ):
+ """Refresh cached stat() data for files already known to the library.
+
+ Threaded method.
+ """
+ if self._is_sync_stale(session_id):
+ return
+ restat_count = engine.restat_count
+
+ def on_progress(idx: int) -> None:
+ if engine.cancelled:
+ return
+ self.main_window.banner.show_progress(
+ Translations.format(
+ "library.sync.updating.label", idx=f"{idx:n}", total=f"{restat_count:n}"
),
+ idx,
+ restat_count,
+ phase="updating",
)
+
+ on_progress(0)
+ self._run_sync_step(
+ engine.sync_entry_stats,
+ on_progress,
+ lambda: self._finish_sync(new_count, unlinked_count, relinked_count, session_id),
)
- r = CustomRunnable(iterator.run)
- r.done.connect(
- lambda: (
- pw.hide(),
- pw.deleteLater(),
- # refresh the library only when new items are added
- files_count and self.update_browsing_state(),
+
+ def save_new_entries_runnable(self, engine: LibrarySyncEngine, session_id: int = 0):
+ """Adds any known new files to the library and run default macros on them.
+
+ Threaded method.
+ """
+ if self._is_sync_stale(session_id):
+ return
+ new_count = engine.new_file_count
+ unlinked_count = engine.unlinked_entries_count
+ relinked_count = engine.relinked_entries_count
+
+ def on_progress(idx: int) -> None:
+ if engine.cancelled:
+ return
+ self.main_window.banner.show_progress(
+ Translations.format("entries.running.dialog.new_entries", total=f"{new_count:n}"),
+ idx,
+ new_count,
+ phase="new_entries",
)
+
+ on_progress(0)
+ self._run_sync_step(
+ engine.save_new_entries,
+ on_progress,
+ lambda: self.sync_entry_stats_runnable(
+ engine, new_count, unlinked_count, relinked_count, session_id
+ ),
)
- QThreadPool.globalInstance().start(r)
def new_file_macros_runnable(self, new_ids):
"""Threaded method that runs macros on a set of Entry IDs."""
@@ -1640,7 +1848,7 @@ def open_library(self, path: Path) -> None:
f"[Config] Thumbnail Cache Size: {format_size(cache_size)}",
)
- # Migration is required
+ # JSON Migration is required
if open_status.json_migration_req:
self.migration_modal = JsonMigrationModal(path)
self.migration_modal.migration_finished.connect(
@@ -1666,7 +1874,19 @@ def _init_library(self, path: Path, open_status: LibraryStatus):
self.__reset_navigation()
if self.settings.scan_files_on_open:
- self.add_new_files_callback()
+ self.sync_library_callback()
+ elif not self._sync_disabled_notice_shown:
+ self._sync_disabled_notice_shown = True
+ # Show that the setting for opening a library on start is turned off,
+ # with a prompt to open the settings to change that (encouraged but not required).
+ self._show_notice(
+ "sync_disabled",
+ Translations.format(
+ "library.sync.disabled_notice",
+ sync_setting=Translations["settings.scan_files_on_open"],
+ ),
+ Translations["library.sync.open_settings"],
+ )
if self.settings.show_filepath == ShowFilepathOption.SHOW_FULL_PATHS:
library_dir_display = self.lib.library_dir
@@ -1688,7 +1908,7 @@ def _init_library(self, path: Path, open_status: LibraryStatus):
self.set_select_actions_visibility()
self.main_window.menu_bar.save_library_backup_action.setEnabled(True)
self.main_window.menu_bar.close_library_action.setEnabled(True)
- self.main_window.menu_bar.refresh_dir_action.setEnabled(True)
+ self.main_window.menu_bar.sync_library_action.setEnabled(True)
self.main_window.menu_bar.tag_manager_action.setEnabled(True)
self.main_window.menu_bar.color_manager_action.setEnabled(True)
self.main_window.menu_bar.field_template_manager_action.setEnabled(True)
diff --git a/src/tagstudio/qt/views/banner_view.py b/src/tagstudio/qt/views/banner_view.py
new file mode 100644
index 000000000..aff8003b0
--- /dev/null
+++ b/src/tagstudio/qt/views/banner_view.py
@@ -0,0 +1,47 @@
+# SPDX-FileCopyrightText: (c) TagStudio Contributors
+# SPDX-License-Identifier: GPL-3.0-only
+
+
+from PySide6.QtWidgets import QHBoxLayout, QPushButton, QVBoxLayout
+
+from tagstudio.i18n.translations import Translations
+from tagstudio.qt.controllers.rounded_progress_bar import RoundedProgressBar
+from tagstudio.qt.controllers.stable_label import StableLabel
+
+
+class BannerView(QVBoxLayout):
+ PROGRESS_BAR_HEIGHT = 4
+
+ def __init__(self) -> None:
+ super().__init__()
+ self.setContentsMargins(0, 0, 0, 0)
+ self.setSpacing(0)
+
+ content_row = QHBoxLayout()
+ content_row.setContentsMargins(6, 6, 6, 2)
+ content_row.setSpacing(8)
+
+ self.close_button = QPushButton("×")
+ self.close_button.setObjectName("bannerCloseButton")
+ self.close_button.setFixedSize(24, 24)
+ content_row.addWidget(self.close_button)
+
+ content_row.addStretch(1)
+
+ self.label = StableLabel()
+ content_row.addWidget(self.label)
+
+ self.action_button = QPushButton(Translations["entries.generic.refresh_alt"])
+ self.action_button.setObjectName("bannerActionButton")
+ content_row.addWidget(self.action_button)
+
+ content_row.addStretch(1)
+ self.addLayout(content_row, 1)
+
+ self.progress_bar = RoundedProgressBar()
+ self.progress_bar.setFixedHeight(self.PROGRESS_BAR_HEIGHT)
+
+ policy = self.progress_bar.sizePolicy()
+ policy.setRetainSizeWhenHidden(True)
+ self.progress_bar.setSizePolicy(policy)
+ self.addWidget(self.progress_bar)
diff --git a/src/tagstudio/qt/views/layouts/thumb_grid_layout.py b/src/tagstudio/qt/views/layouts/thumb_grid_layout.py
index a7c3e8dce..dc1f69191 100644
--- a/src/tagstudio/qt/views/layouts/thumb_grid_layout.py
+++ b/src/tagstudio/qt/views/layouts/thumb_grid_layout.py
@@ -57,8 +57,6 @@ def scroll_to(self, entry_id: int):
self._scroll_to = entry_id
def set_entries(self, entry_ids: list[int]):
- self.scroll_area.verticalScrollBar().setValue(0)
-
self._entry_ids = entry_ids
self._entries.clear()
self._tag_entries.clear()
@@ -211,9 +209,10 @@ def setGeometry(self, arg__1: QRect) -> None:
pass
self._scroll_to = None
- visible_rows = math.ceil((view_height + (offset % height_offset)) / height_offset)
- offset = int(offset / height_offset)
- start = offset * per_row
+ row_offset = offset
+ visible_rows = math.ceil((view_height + (row_offset % height_offset)) / height_offset)
+ row_offset = int(row_offset / height_offset)
+ start = row_offset * per_row
end = start + (visible_rows * per_row)
first_visible = self._entry_ids[start] if 0 <= start < len(self._entry_ids) else None
diff --git a/src/tagstudio/qt/views/styles/stylesheets.py b/src/tagstudio/qt/views/styles/stylesheets.py
index 69d1b0856..417b795b9 100644
--- a/src/tagstudio/qt/views/styles/stylesheets.py
+++ b/src/tagstudio/qt/views/styles/stylesheets.py
@@ -19,6 +19,9 @@
# TODO: There's plenty of good opportunities here to consolidate similar styles.
# Work should be done to more closely use Qt's theming systems rather than override them.
+# Shared with RoundedProgressBar.set_corner_radius() so both use the exact same corner arc.
+BANNER_CORNER_RADIUS = 6
+
def add_button_style() -> str:
"""Style used for tag-like "Add" buttons [+]."""
@@ -557,6 +560,142 @@ def preview_warning_style() -> str:
"""
+def _is_dark_theme() -> bool:
+ return QGuiApplication.styleHints().colorScheme() is Qt.ColorScheme.Dark
+
+
+def get_contrast_text_color(background_color: QColor) -> QColor:
+ """Return plain black or white, whichever reads better against `background_color`."""
+ return QColor(0, 0, 0) if background_color.lightness() > 120 else QColor(255, 255, 255)
+
+
+def _banner_button_hover_style(object_name: str) -> str:
+ """Shared hover/pressed/focus feedback for the banner's accent-tinted buttons."""
+ hover = Palette.accent().darker(140)
+ pressed = Palette.accent().lighter(120)
+ return f"""
+ QPushButton#{object_name}::hover {{
+ background-color: rgba{hover.toTuple()};
+ }}
+ QPushButton#{object_name}::pressed {{
+ background-color: rgba{pressed.toTuple()};
+ }}
+ QPushButton#{object_name}::focus {{
+ outline: none;
+ }}
+ """
+
+
+def banner_close_button_style() -> str:
+ """Style for the banner's close ("X") button in accent-colored notice modes."""
+ accent = Palette.accent().darker(180)
+ text_color = get_contrast_text_color(accent)
+
+ return f"""
+ QPushButton#bannerCloseButton {{
+ font-size: 24pt;
+ padding-bottom: 4px;
+ background: transparent;
+ color: rgba{text_color.toTuple()};
+ border: none;
+ border-radius: 3px;
+ }}
+ {_banner_button_hover_style("bannerCloseButton")}
+ """
+
+
+def banner_action_button_style() -> str:
+ """Style for the banner's action button (Refresh / Review / Open Settings)."""
+ accent = Palette.accent().darker(160)
+ text_color = get_contrast_text_color(accent)
+
+ return f"""
+ QPushButton#bannerActionButton {{
+ background-color: rgba{accent.toTuple()};
+ color: rgba{text_color.toTuple()};
+ border: none;
+ border-radius: 3px;
+ padding: 4px 8px;
+ outline: none;
+ }}
+ {_banner_button_hover_style("bannerActionButton")}
+ """
+
+
+def banner_notice_bg_color() -> QColor:
+ """Fill color for the banner card in "notice" mode."""
+ color = QColor(Palette.accent())
+ color.setAlpha(235)
+ return color
+
+
+def banner_notice_style() -> str:
+ """Label/button rules for the banner's accent-colored "notice" mode."""
+ accent = Palette.accent()
+ text_color = get_contrast_text_color(accent)
+
+ return f"""
+ #banner QLabel {{ color: rgba{text_color.toTuple()}; background: transparent; }}
+ {banner_close_button_style()}
+ {banner_action_button_style()}
+ """
+
+
+def banner_close_button_progress_style() -> str:
+ """Close button style for the progress banner mode."""
+ is_dark = _is_dark_theme()
+ text_color = QColor(255, 255, 255) if is_dark else QColor(0, 0, 0)
+ hover = "rgba(255, 255, 255, 40)" if is_dark else "rgba(0, 0, 0, 40)"
+ pressed = "rgba(255, 255, 255, 70)" if is_dark else "rgba(0, 0, 0, 70)"
+
+ return f"""
+ QPushButton#bannerCloseButton {{
+ font-size: 24pt;
+ padding-bottom: 4px;
+ background: transparent;
+ color: rgba{text_color.toTuple()};
+ border: none;
+ border-radius: 3px;
+ }}
+ QPushButton#bannerCloseButton::hover {{
+ background-color: {hover};
+ }}
+ QPushButton#bannerCloseButton::pressed {{
+ background-color: {pressed};
+ }}
+ QPushButton#bannerCloseButton::focus {{
+ outline: none;
+ }}
+ """
+
+
+def banner_progress_bg_color() -> QColor:
+ """Fill color for the banner card in "progress"/"fleeting_notice" mode."""
+ is_dark = _is_dark_theme()
+ return QColor(
+ ThemePalette.COLOR_BG_DARK.value if is_dark else ThemePalette.COLOR_BG_LIGHT.value
+ )
+
+
+def banner_progress_style() -> str:
+ """Label/button rules for the banner's neutral "progress" mode."""
+ is_dark = _is_dark_theme()
+ text_str = "white" if is_dark else "black"
+
+ return f"""
+ #banner QLabel {{ color: {text_str}; background: transparent; }}
+ {banner_close_button_progress_style()}
+ """
+
+
+def banner_progress_chunk_color() -> QColor:
+ """Fill color for the banner's custom-painted progress bar chunk."""
+ is_dark = _is_dark_theme()
+ chunk = QColor(Palette.accent().lighter(130) if is_dark else Palette.accent().darker(115))
+ chunk.setAlpha(235)
+ return chunk
+
+
def header(string: str, level: int, color: str | None = None) -> str:
"""Wrap a string in HTML header tags.
diff --git a/src/tagstudio/resources/translations/cs.json b/src/tagstudio/resources/translations/cs.json
index b90d8e42f..783b17b60 100644
--- a/src/tagstudio/resources/translations/cs.json
+++ b/src/tagstudio/resources/translations/cs.json
@@ -40,8 +40,6 @@
"entries.duplicates.description": "Duplicitní položky jsou definovány jako více položek, které ukazují na stejný soubor na disku. Jejich sloučením se spojí značky a metadata ze všech duplikátů do jediné konsolidované položky. Nesmí se zaměňovat s „duplicitními soubory“, což jsou duplikáty samotných vašich souborů mimo TagStudio.",
"entries.mirror.confirmation": "Opravdu chcete zrcadlit následujících {count} položek?",
"entries.unlinked.relink.manual": "Znovu propojit ručně",
- "entries.unlinked.relink.title": "Propojuji záznamy",
- "entries.unlinked.scanning": "Skenuji knihovnu pro nepropojené záznamy...",
"entries.unlinked.title": "Opravit nepropojené záznamy",
"field.copy": "Zkopírovat políčko",
"field.edit": "Upravit políčko",
diff --git a/src/tagstudio/resources/translations/de.json b/src/tagstudio/resources/translations/de.json
index 23967904e..af6997d6d 100644
--- a/src/tagstudio/resources/translations/de.json
+++ b/src/tagstudio/resources/translations/de.json
@@ -57,16 +57,11 @@
"entries.remove.plural.confirm": "Sollen die folgenden {count} Einträge gelöscht werden? Es werden keine Dateien auf der Festplatte gelöscht.",
"entries.remove.singular.confirm": "Soll dieser Eintrag von der Bibliothek entfernt werden? Es werden keine Dateien auf der Festplatte gelöscht.",
"entries.running.dialog.new_entries": "Füge {total} neue Dateieinträge hinzu...",
- "entries.running.dialog.title": "Füge neue Dateieinträge hinzu",
"entries.tags": "Tags",
- "entries.unlinked.description": "Jeder Bibliothekseintrag ist mit einer Datei in einem Ihrer Verzeichnisse verknüpft. Wenn eine Datei, die mit einem Eintrag verknüpft ist, außerhalb von TagStudio verschoben oder gelöscht wird, gilt sie als nicht verknüpft.
Nicht verknüpfte Einträge können durch das Durchsuchen Ihrer Verzeichnisse automatisch neu verknüpft, vom Benutzer manuell neu verknüpft oder auf Wunsch gelöscht werden.",
- "entries.unlinked.relink.attempting": "Versuche {index}/{unlinked_count} Einträge neu zu verknüpfen, {fixed_count} bereits erfolgreich neu verknüpft",
+ "entries.unlinked.description": "Jeder Bibliothekseintrag ist mit einer Datei in einem Ihrer Verzeichnisse verknüpft. Wenn eine Datei, die mit einem Eintrag verknüpft ist, außerhalb von TagStudio verschoben oder gelöscht wird, gilt sie als nicht verknüpft.",
"entries.unlinked.relink.manual": "&Manuell Neuverknüpfen",
- "entries.unlinked.relink.title": "Einträge werden neu verknüpft",
"entries.unlinked.remove": "Entferne nicht verknüpfte Einträge",
"entries.unlinked.remove_alt": "Entfer&ne nicht verknüpfte Einträge",
- "entries.unlinked.scanning": "Bibliothek wird nach nicht verknüpften Einträgen durchsucht...",
- "entries.unlinked.search_and_relink": "&Suchen && Neuverknüpfen",
"entries.unlinked.title": "Unverknüpfte Einträge reparieren",
"entries.unlinked.unlinked_count": "Unverknüpfte Einträge: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -180,10 +175,6 @@
"landing.open_create_library": "Bibliothek öffnen/erstellen {shortcut}",
"library.missing": "Dateiort fehlt",
"library.name": "Bibliothek",
- "library.refresh.scanning.plural": "Durchsuche Verzeichnisse nach neuen Dateien...\n{searched_count} Dateien durchsucht, {found_count} neue Dateien gefunden",
- "library.refresh.scanning.singular": "Durchsuche Verzeichnisse nach neuen Dateien...\n{searched_count} Datei durchsucht, {found_count} neue Datei gefunden",
- "library.refresh.scanning_preparing": "Überprüfe Verzeichnisse auf neue Dateien...\nBereite vor...",
- "library.refresh.title": "Verzeichnisse werden aktualisiert",
"library.scan_library.title": "Bibliothek wird scannen",
"library_info.cleanup": "Aufräumen",
"library_info.cleanup.backups": "Bibliotheks-Backups:",
@@ -225,7 +216,6 @@
"menu.file.open_create_library": "Bibli&othek öffnen/erstellen",
"menu.file.open_library": "Bibliothek öffnen",
"menu.file.open_recent_library": "Zuletzt verwendete öffnen",
- "menu.file.refresh_directories": "Ve&rzeichnisse aktualisieren",
"menu.file.save_backup": "Bibliotheksbackup speichern",
"menu.file.save_library": "Bibliothek speichern",
"menu.help": "&Hilfe",
diff --git a/src/tagstudio/resources/translations/el.json b/src/tagstudio/resources/translations/el.json
index 14224d689..5016e837b 100644
--- a/src/tagstudio/resources/translations/el.json
+++ b/src/tagstudio/resources/translations/el.json
@@ -56,16 +56,11 @@
"entries.remove.plural.confirm": "Είστε βέβαιοι ότι θέλετε να αφαιρέσετε αυτές τις {count} εγγραφές από τη βιβλιοθήκη σας; Δεν θα διαγραφεί κανένα αρχείο από τον δίσκο.",
"entries.remove.singular.confirm": "Είστε βέβαιοι ότι θέλετε να αφαιρέσετε αυτή την εγγραφή από τη βιβλιοθήκη σας; Δεν θα διαγραφεί κανένα αρχείο από τον δίσκο.",
"entries.running.dialog.new_entries": "Προσθήκη {total} νέων εγγραφών αρχείων...",
- "entries.running.dialog.title": "Προσθήκη νέων εγγραφών αρχείων",
"entries.tags": "Tags",
- "entries.unlinked.description": "Κάθε εγγραφή της βιβλιοθήκης είναι συνδεδεμένη με ένα αρχείο σε έναν από τους καταλόγους σας. Εάν ένα αρχείο που είναι συνδεδεμένο με μια εγγραφή μετακινηθεί ή διαγραφεί εκτός του TagStudio, τότε θεωρείται αποσυνδεδεμένο.
Οι αποσυνδεδεμένες εγγραφές μπορούν να επανασυνδεθούν αυτόματα μέσω αναζήτησης στους καταλόγους σας ή να διαγραφούν, εάν το επιθυμείτε.",
- "entries.unlinked.relink.attempting": "Προσπάθεια επανασύνδεσης {index}/{unlinked_count} εγγραφών, {fixed_count} επανασυνδέθηκαν επιτυχώς",
+ "entries.unlinked.description": "Κάθε εγγραφή της βιβλιοθήκης είναι συνδεδεμένη με ένα αρχείο σε έναν από τους καταλόγους σας. Εάν ένα αρχείο που είναι συνδεδεμένο με μια εγγραφή μετακινηθεί ή διαγραφεί εκτός του TagStudio, τότε θεωρείται αποσυνδεδεμένο.",
"entries.unlinked.relink.manual": "&Χειροκίνητη επανασύνδεση",
- "entries.unlinked.relink.title": "Επανασύνδεση εγγραφών",
"entries.unlinked.remove": "Αφαίρεση αποσυνδεδεμένων εγγραφών",
"entries.unlinked.remove_alt": "Α&φαίρεση αποσυνδεδεμένων εγγραφών",
- "entries.unlinked.scanning": "Σάρωση βιβλιοθήκης για αποσυνδεδεμένες εγγραφές...",
- "entries.unlinked.search_and_relink": "&Αναζήτηση && Επανασύνδεση",
"entries.unlinked.title": "Διόρθωση αποσυνδεδεμένων εγγραφών",
"entries.unlinked.unlinked_count": "Αποσυνδεδεμένες εγγραφές: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
diff --git a/src/tagstudio/resources/translations/en.json b/src/tagstudio/resources/translations/en.json
index 5f35ae38f..6344844ee 100644
--- a/src/tagstudio/resources/translations/en.json
+++ b/src/tagstudio/resources/translations/en.json
@@ -3,13 +3,13 @@
"about.config_path": "Config Path",
"about.description": "TagStudio is a photo and file organization application with an underlying tag-based system that focuses on giving freedom and flexibility to the user. No proprietary programs or formats, no sea of sidecar files, and no complete upheaval of your filesystem structure.",
"about.documentation": "Documentation",
+ "about.library_version": "Library Format",
"about.module.found": "Found",
"about.modules.title": "Optional Modules",
"about.title": "About TagStudio",
"about.version": "Version",
"about.version.latest": "{built_version} (Latest Release: {latest_version})",
"about.website": "Website",
- "about.library_version": "Library Format",
"app.git": "Git Commit",
"app.nightly": "Nightly",
"app.pre_release": "Pre-Release",
@@ -62,16 +62,14 @@
"entries.remove.plural.confirm": "Are you sure you want to remove these {count} entries from your library? No files on disk will be deleted.",
"entries.remove.singular.confirm": "Are you sure you want to remove this entry from your library? No files on disk will be deleted.",
"entries.running.dialog.new_entries": "Adding {total} New File Entries…",
- "entries.running.dialog.title": "Adding New File Entries",
"entries.tags": "Tags",
- "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.relink.attempting": "Attempting to Relink {index}/{unlinked_count} Entries, {fixed_count} Successfully Relinked",
+ "entries.unlinked.description": "Unlinked entries are file entries that can no longer find their original file on disk. Most entries are automatically relinked during a library sync, however some cases require manual review.",
+ "entries.unlinked.description.ambiguous": "For unlinked entries that have ambiguous matches to multiple files in your library, you may manually choose how they get relinked.",
+ "entries.unlinked.description.deleted": "When you delete files outside of TagStudio, their associated entries become unlinked. You may manually delete any unlinked entries at your own discretion.",
"entries.unlinked.relink.manual": "&Manual Relink",
- "entries.unlinked.relink.title": "Relinking Entries",
- "entries.unlinked.remove": "Remove Unlinked Entries",
- "entries.unlinked.remove_alt": "Remo&ve Unlinked Entries",
- "entries.unlinked.scanning": "Scanning Library for Unlinked Entries…",
- "entries.unlinked.search_and_relink": "&Search && Relink",
+ "entries.unlinked.remove": "Delete Unlinked Entries",
+ "entries.unlinked.remove_alt": "&Delete Unlinked Entries",
+ "entries.unlinked.review": "Manual &Review",
"entries.unlinked.title": "Fix Unlinked Entries",
"entries.unlinked.unlinked_count": "Unlinked Entries: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -121,6 +119,7 @@
"file.open_location.mac": "Reveal in Finder",
"file.open_location.windows": "Show in File Explorer",
"file.path": "File Path",
+ "file.size": "File Size",
"folders_to_tags.close_all": "Close All",
"folders_to_tags.converting": "Converting folders to Tags",
"folders_to_tags.description": "Creates tags based on your folder structure and applies them to your entries.\n The structure below shows all the tags that will be created and what entries they will be applied to.",
@@ -253,11 +252,22 @@
"library_object.slug_required": "ID Slug (Required)",
"library.missing": "Library Location is Missing",
"library.name": "Library",
- "library.refresh.scanning_preparing": "Scanning Directories for New Files…\nPreparing…",
- "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",
+ "library.sync.complete": "Library Synced",
+ "library.sync.disabled_notice": "\"{sync_setting}\" Is Currently Turned Off",
+ "library.sync.new_files_banner.plural": "{count} New Files Found",
+ "library.sync.new_files_banner.singular": "{count} New File Found",
+ "library.sync.open_settings": "Open &Settings",
+ "library.sync.preparing": "Preparing to Sync…",
+ "library.sync.relinked_banner.plural": "{count} Files Automatically Relinked",
+ "library.sync.relinked_banner.singular": "{count} File Automatically Relinked",
+ "library.sync.relinked_suffix": "({count} Automatically Relinked)",
+ "library.sync.remaining_unlinked_suffix": "({count} Still Unlinked)",
+ "library.sync.repairing": "Repairing Entries…",
+ "library.sync.scanning": "Discovering Files… ({found_count} New Out of {searched_count})",
+ "library.sync.unlinked_banner.plural": "{count} Unlinked Entries Found",
+ "library.sync.unlinked_banner.singular": "{count} Unlinked Entry Found",
+ "library.sync.updating.label": "Syncing {idx}/{total} Entries…",
"macros.running.dialog.new_entries": "Running Configured Macros on {count}/{total} New File Entries…",
"macros.running.dialog.title": "Running Macros on New Entries",
"media_player.autoplay": "Autoplay",
@@ -280,9 +290,9 @@
"menu.file.open_create_library": "&Open/Create Library",
"menu.file.open_library": "Open Library",
"menu.file.open_recent_library": "Open Recent",
- "menu.file.refresh_directories": "&Refresh Directories",
"menu.file.save_backup": "&Save Library Backup",
"menu.file.save_library": "Save Library",
+ "menu.file.sync_library": "&Sync Library",
"menu.help": "&Help",
"menu.help.about": "About",
"menu.macros": "&Macros",
@@ -335,10 +345,10 @@
"settings.library": "Library Settings",
"settings.localization": "Localization",
"settings.media": "Media",
- "settings.open_library_on_start": "Open Library on Start",
+ "settings.open_library_on_start": "Open Last Library on Start",
"settings.page_size": "Page Size",
"settings.restart_required": "Please restart TagStudio for changes to take effect.",
- "settings.scan_files_on_open": "Automatically Load New Files",
+ "settings.scan_files_on_open": "Sync Library on Open",
"settings.show_filenames_in_grid": "Show Filenames in Grid",
"settings.show_recent_libraries": "Show Recent Libraries",
"settings.splash.label": "Splash Screen",
diff --git a/src/tagstudio/resources/translations/es.json b/src/tagstudio/resources/translations/es.json
index d9bf5dcb7..cdc6b9989 100644
--- a/src/tagstudio/resources/translations/es.json
+++ b/src/tagstudio/resources/translations/es.json
@@ -60,16 +60,11 @@
"entries.remove.plural.confirm": "¿Está seguro de que desea eliminar estas {count} entradas de su librería? No se eliminará ningún archivo del disco.",
"entries.remove.singular.confirm": "¿Está seguro que quiere eliminar ésta entrada de su librería? Ningún archivo en el disco será eliminado.",
"entries.running.dialog.new_entries": "Añadiendo {total} nuevas entradas de archivos...",
- "entries.running.dialog.title": "Añadiendo las nuevas entradas de archivos",
"entries.tags": "Etiquetas",
- "entries.unlinked.description": "Cada entrada de la biblioteca está vinculada a un archivo en uno de tus directorios. Si un archivo vinculado a una entrada se mueve o se elimina fuera de TagStudio, se considerará desvinculado.
Las entradas no vinculadas se pueden volver a vincular automáticamente mediante una búsqueda en tus directorios, el usuario puede eliminarlas si así lo desea.",
- "entries.unlinked.relink.attempting": "Intentando volver a vincular {index}/{unlinked_count} Entradas, {fixed_count} Reenlazado correctamente",
+ "entries.unlinked.description": "Cada entrada de la biblioteca está vinculada a un archivo en uno de tus directorios. Si un archivo vinculado a una entrada se mueve o se elimina fuera de TagStudio, se considerará desvinculado. ",
"entries.unlinked.relink.manual": "&Reenlace manual",
- "entries.unlinked.relink.title": "Volver a vincular las entradas",
"entries.unlinked.remove": "Eliminar Entradas No Vinculadas",
"entries.unlinked.remove_alt": "Quit&ar entradas desvinculadas",
- "entries.unlinked.scanning": "Buscando entradas no enlazadas en la biblioteca...",
- "entries.unlinked.search_and_relink": "&Buscar && Revincular",
"entries.unlinked.title": "Corregir entradas no vinculadas",
"entries.unlinked.unlinked_count": "Entradas no vinculadas: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -229,10 +224,6 @@
"language.zh_Hant": "Chino (tradicional)",
"library.missing": "Falta la Ubicación de la Biblioteca",
"library.name": "Biblioteca",
- "library.refresh.scanning.plural": "Escaneando directorios en busca de nuevos archivos...\n{searched_count} archivos buscados, {found_count} nuevos archivos encontrados",
- "library.refresh.scanning.singular": "Escaneando directorios en busca de nuevos archivos...\n{searched_count} Archivos buscados, {found_count} Nuevos archivos encontrados",
- "library.refresh.scanning_preparing": "Buscando archivos nuevos en los directorios...\nPreparando...",
- "library.refresh.title": "Refrescando directorios",
"library.scan_library.title": "Escaneando la biblioteca",
"library_info.cleanup": "Limpieza",
"library_info.cleanup.backups": "Reespaldos de la Librería:",
@@ -275,7 +266,6 @@
"menu.file.open_create_library": "&Abrir/Crear biblioteca",
"menu.file.open_library": "Abrir biblioteca",
"menu.file.open_recent_library": "Abrir reciente",
- "menu.file.refresh_directories": "Actualizar directorios",
"menu.file.save_backup": "&Guardar copia de seguridad de la biblioteca",
"menu.file.save_library": "Guardar biblioteca",
"menu.help": "&Ayuda",
diff --git a/src/tagstudio/resources/translations/fi.json b/src/tagstudio/resources/translations/fi.json
index 3acaf7a4a..d00e7c0b1 100644
--- a/src/tagstudio/resources/translations/fi.json
+++ b/src/tagstudio/resources/translations/fi.json
@@ -56,16 +56,11 @@
"entries.remove.plural.confirm": "Haluatko varmasti poistaa nämä {count} merkintää kirjastostasi? Levyllä olevia tiedostoja ei poisteta.",
"entries.remove.singular.confirm": "Haluatko varmasti poistaa tämän merkinnän kirjastostasi? Levyllä olevia tiedostoja ei poisteta.",
"entries.running.dialog.new_entries": "Lisätään {total} uutta tiedosto merkintää...",
- "entries.running.dialog.title": "Lisätään uudet tiedosto merkinnät",
"entries.tags": "Tunnisteet",
- "entries.unlinked.description": "Jokainen kirjastomerkintä on linkitetty tiedostoon jossakin hakemistoistasi. Jos merkintään linkitetty tiedosto siirretään tai poistetaan TagStudion ulkopuolelle, sitä pidetään linkittämättömänä.
Linkittämättömät merkinnät voidaan linkittää automaattisesti uudelleen hakemistojen haun avulla tai poistaa haluttaessa.",
- "entries.unlinked.relink.attempting": "Yritetään linkittää uudelleen {index}/{unlinked_count} merkintää, {fixed_count} uudelleenlinkitys onnistui",
+ "entries.unlinked.description": "Jokainen kirjastomerkintä on linkitetty tiedostoon jossakin hakemistoistasi. Jos merkintään linkitetty tiedosto siirretään tai poistetaan TagStudion ulkopuolelle, sitä pidetään linkittämättömänä.",
"entries.unlinked.relink.manual": "&Manual Relink",
- "entries.unlinked.relink.title": "Uudelleen yhdistetään merkintöjä",
"entries.unlinked.remove": "Poista linkittämättömät merkinnät",
"entries.unlinked.remove_alt": "Remo&ve Unlinked Entries",
- "entries.unlinked.scanning": "Skannataan kirjastosta linkittämättömiä merkintöjä...",
- "entries.unlinked.search_and_relink": "&Search && Relink",
"entries.unlinked.title": "Korjaa linkittämättömät merkinnät",
"entries.unlinked.unlinked_count": "Linkittämättömät merkinnät: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -176,7 +171,6 @@
"landing.open_create_library": "Avaa/Luo kirjasto {shortcut}",
"library.missing": "Kirjaston sijainti puuttuu",
"library.name": "Kirjasto",
- "library.refresh.title": "Virkistetty hakemistot",
"library.scan_library.title": "Skannataan kirjastoa",
"library_info.cleanup": "Puhdistus",
"library_info.cleanup.backups": "Kirjasto varmuuskopiot:",
diff --git a/src/tagstudio/resources/translations/fil.json b/src/tagstudio/resources/translations/fil.json
index c5dda6102..68aa36d7b 100644
--- a/src/tagstudio/resources/translations/fil.json
+++ b/src/tagstudio/resources/translations/fil.json
@@ -47,14 +47,9 @@
"entries.mirror.window_title": "I-mirror ang Mga Entry",
"entries.remove.plural.confirm": "Sigurado ka ba gusto mong burahin ang (mga) sumusunod na {count} entry?",
"entries.running.dialog.new_entries": "Dinadagdag ang {total} Mga Bagong Entry ng File…",
- "entries.running.dialog.title": "Dinadagdag ang Mga Bagong Entry ng File",
"entries.tags": "Mga Tag",
- "entries.unlinked.description": "Ang bawat entry sa library ay naka-link sa isang file sa isa sa iyong mga direktoryo. Kung ang isang file na naka-link sa isang entry ay inilipat o binura sa labas ng TagStudio, ito ay isinasaalang-alang na naka-unlink.
Ang mga naka-unlink na entry ay maaring i-link muli sa pamamagitan ng paghahanap sa iyong mga direktoryo o buburahin kung ninanais.",
- "entries.unlinked.relink.attempting": "Sinusubukang i-link muli ang {index}/{unlinked_count} Mga Entry, {fixed_count} Matagumpay na na-link muli",
+ "entries.unlinked.description": "Ang bawat entry sa library ay naka-link sa isang file sa isa sa iyong mga direktoryo. Kung ang isang file na naka-link sa isang entry ay inilipat o binura sa labas ng TagStudio, ito ay isinasaalang-alang na naka-unlink.",
"entries.unlinked.relink.manual": "&Manwal na Pag-link Muli",
- "entries.unlinked.relink.title": "Nili-link muli ang Mga Entry",
- "entries.unlinked.scanning": "Sina-scan ang Library para sa Mga Naka-unlink na Entry…",
- "entries.unlinked.search_and_relink": "&Maghanap at Mag-link muli",
"entries.unlinked.title": "Ayusin ang Mga Naka-unlink na Entry",
"entries.unlinked.unlinked_count": "Mga Naka-unlink na Entry: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -159,10 +154,6 @@
"landing.open_create_library": "Buksan/Gumawa ng Library {shortcut}",
"library.missing": "Nawawala ang Lokasyon ng Library",
"library.name": "Library",
- "library.refresh.scanning.plural": "Sina-scan ang Direktoryo para sa Mga Bagong File…\n{searched_count} Nahanap na File, {found_count} Nahanap na Bagong FIle",
- "library.refresh.scanning.singular": "Sina-scan ang Direktoryo para sa Mga Bagong File…\n{searched_count} Mga Nahanap na File, {found_count} Nahanap na Bagong FIle",
- "library.refresh.scanning_preparing": "Sina-scan ang Mga Direktoryo para sa Mga Bagong File...\nNaghahanda...",
- "library.refresh.title": "Nire-refresh ang Mga Direktoryo",
"library.scan_library.title": "Sina-scan ang Library",
"library_info.stats.entries": "Mga entry:",
"library_info.stats.fields": "Mga Field:",
@@ -191,7 +182,6 @@
"menu.file.open_create_library": "Magbukas/Gumawa ng Library (&O)",
"menu.file.open_library": "Magbukas ng Library",
"menu.file.open_recent_library": "Magbukas ng Kamakailan",
- "menu.file.refresh_directories": "I-refresh ang mga Direktoryo (&R)",
"menu.file.save_backup": "I-save ang Backup ng Library (&S)",
"menu.file.save_library": "I-save ang Library",
"menu.help": "Tulong",
diff --git a/src/tagstudio/resources/translations/fr.json b/src/tagstudio/resources/translations/fr.json
index e2c7e5270..f142a0019 100644
--- a/src/tagstudio/resources/translations/fr.json
+++ b/src/tagstudio/resources/translations/fr.json
@@ -61,16 +61,11 @@
"entries.remove.plural.confirm": "Êtes-vous sûr de vouloir supprimer les {count} entrées suivantes ? Aucun fichier sur votre disque ne sera supprimée.",
"entries.remove.singular.confirm": "Êtes-vous sûr de vouloir supprimer cette entrée de votre bibliothèque ? Aucun fichier sur le disque ne sera supprimé.",
"entries.running.dialog.new_entries": "Ajout de {total} Nouvelles entrées de fichier...",
- "entries.running.dialog.title": "Ajout de Nouvelles entrées de fichier",
"entries.tags": "Tags",
- "entries.unlinked.description": "Chaque entrée dans la bibliothèque est liée à un fichier dans l'un de vos dossiers. Si un fichier lié à une entrée est déplacé ou supprimé en dehors de TagStudio, il est alors considéré non lié.
Les entrées non liées peuvent être automatiquement reliées via la recherche dans vos dossiers, reliées manuellement par l'utilisateur, ou supprimées si désiré.",
- "entries.unlinked.relink.attempting": "Tentative de Reliage de {index}/{unlinked_count} Entrées, {fixed_count} ont été Reliées avec Succès",
+ "entries.unlinked.description": "Chaque entrée dans la bibliothèque est liée à un fichier dans l'un de vos dossiers. Si un fichier lié à une entrée est déplacé ou supprimé en dehors de TagStudio, il est alors considéré non lié. ",
"entries.unlinked.relink.manual": "&Reliage Manuel",
- "entries.unlinked.relink.title": "Reliage des Entrées",
"entries.unlinked.remove": "Supprimer les entrées non liées",
"entries.unlinked.remove_alt": "Supprim&er les entrées non liées",
- "entries.unlinked.scanning": "Balayage de la Bibliothèque pour trouver des Entrées non Liées...",
- "entries.unlinked.search_and_relink": "&Rechercher && Relier",
"entries.unlinked.title": "Réparation des Entrées non Liées",
"entries.unlinked.unlinked_count": "Entrées non Liées : {count}",
"ffmpeg.missing.status": "{ffmpeg} : {ffmpeg_status} {ffprobe} : {ffprobe_status}",
@@ -230,10 +225,6 @@
"language.zh_Hant": "Chinois (Traditionnelle)",
"library.missing": "Emplacement Manquant",
"library.name": "Bibliothèque",
- "library.refresh.scanning.plural": "Analyse du Répertoire pour de Nouveaux Fichiers...\n{searched_count} Fichiers Trouvées, {found_count} Nouveaux Fichiers",
- "library.refresh.scanning.singular": "Analyse du Répertoire pour de Nouveaux Fichiers...\n{searched_count} Fichier Trouvé, {found_count} Nouveaux Fichiers",
- "library.refresh.scanning_preparing": "Recherche de Nouveaux Fichiers dans les Dossiers...\nPréparation...",
- "library.refresh.title": "Rafraîchissement des Dossiers",
"library.scan_library.title": "Balayage de la Bibliothèque",
"library_info.cleanup": "Nettoyage",
"library_info.cleanup.backups": "Sauvegardes de bibliothèque :",
@@ -276,7 +267,6 @@
"menu.file.open_create_library": "&Ouvrir/Créer une Bibliothèque",
"menu.file.open_library": "Ouvrir la Bibliothèque",
"menu.file.open_recent_library": "Ouvrir la Bibliothèque récente",
- "menu.file.refresh_directories": "&Rafraichir les Répertoires",
"menu.file.save_backup": "&Sauvegarde de la Bibliothèque",
"menu.file.save_library": "Enregistrer la Bibliothèque",
"menu.help": "&Aide",
diff --git a/src/tagstudio/resources/translations/hu.json b/src/tagstudio/resources/translations/hu.json
index 3d445c1b7..fdd8b718e 100644
--- a/src/tagstudio/resources/translations/hu.json
+++ b/src/tagstudio/resources/translations/hu.json
@@ -61,16 +61,11 @@
"entries.remove.plural.confirm": "Biztosan el akarja távolítani ezt a(z) {count} elemet a könyvtárból? A lemezen található fájl nem lesz törölve.",
"entries.remove.singular.confirm": "Biztosan el akarja távolítani ezt az elemet a könyvtárból? A lemezen található fájl nem lesz törölve.",
"entries.running.dialog.new_entries": "{total} új elem felvétele folyamatban…",
- "entries.running.dialog.title": "Új elemek felvétele",
"entries.tags": "Címkék",
- "entries.unlinked.description": "A könyvtár minden eleme egy fájllal van összekapcsolva a számítógépen. Ha egy kapcsolt fájl a TagSudión kívül áthelyezésre vagy törésre kerül, akkor ez a kapcsolat megszakad.
Ezeket a kapcsolat nélküli elemeket a program megpróbálhatja automatikusan megkeresni, de Ön is kézileg újra összekapcsolhatja vagy törölheti őket.",
- "entries.unlinked.relink.attempting": "{unlinked_count}/{index} elem újra összekapcsolásának megkísérlése; {fixed_count} elem sikeresen újra összekapcsolva",
+ "entries.unlinked.description": "A könyvtár minden eleme egy fájllal van összekapcsolva a számítógépen. Ha egy kapcsolt fájl a TagSudión kívül áthelyezésre vagy törésre kerül, akkor ez a kapcsolat megszakad.",
"entries.unlinked.relink.manual": "Új&ra összekapcsolás kézileg",
- "entries.unlinked.relink.title": "Elemek újra összekapcsolása",
"entries.unlinked.remove": "Kapcsolat nélküli elemek eltávolítása",
"entries.unlinked.remove_alt": "&Kapcsolat nélküli elemek eltávolítása",
- "entries.unlinked.scanning": "Kapcsolat nélküli elemek keresése a könyvtárban…",
- "entries.unlinked.search_and_relink": "&Keresés és újra összekapcsolás",
"entries.unlinked.title": "Kapcsolat nélküli elemek javítása",
"entries.unlinked.unlinked_count": "Kapcsolat nélküli elemek: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -233,10 +228,6 @@
"language.zh_Hant": "kínai (hagyományos)",
"library.missing": "Hiányzó hely",
"library.name": "Könyvtár",
- "library.refresh.scanning.plural": "Új fájlok keresése a mappákban…\n{searched_count} fájl megvizsgálva; ebből {found_count} új fájl",
- "library.refresh.scanning.singular": "Új fájlok keresése a mappákban…\n{searched_count} fájl megvizsgálva; ebből {found_count} új fájl",
- "library.refresh.scanning_preparing": "Új fájlok keresése a mappákban…\nElőkészítés…",
- "library.refresh.title": "Könyvtárak frissítése",
"library.scan_library.title": "Könyvtár vizsgálata",
"library_info.cleanup": "Megtisztítás",
"library_info.cleanup.backups": "Könyvtár biztonsági mentései:",
@@ -279,7 +270,6 @@
"menu.file.open_create_library": "Könyvtár meg&nyitása/létrehozása",
"menu.file.open_library": "Könyvtár megnyitása",
"menu.file.open_recent_library": "&Legutóbbi könyvtárak",
- "menu.file.refresh_directories": "Könyvtárak &frissítése",
"menu.file.save_backup": "Biztonsági &mentés létrehozása",
"menu.file.save_library": "Könyvtár &mentése",
"menu.help": "&Súgó",
diff --git a/src/tagstudio/resources/translations/it.json b/src/tagstudio/resources/translations/it.json
index 8e4b632e5..5dfd211aa 100644
--- a/src/tagstudio/resources/translations/it.json
+++ b/src/tagstudio/resources/translations/it.json
@@ -56,16 +56,11 @@
"entries.remove.plural.confirm": "Sei sicuro di voler rimuovere queste {count} voci dalla tua biblioteca? Nessun file su disco verrà eliminato.",
"entries.remove.singular.confirm": "Sei sicuro di voler rimuovere questa voce dalla tua biblioteca? Nessun file su disco verrà eliminato.",
"entries.running.dialog.new_entries": "Aggiundendo {total} Nuove Voci di File...",
- "entries.running.dialog.title": "Aggiungendo Nuove Voci di File",
"entries.tags": "Etichette",
- "entries.unlinked.description": "Ogni voce della biblioteca è collegata ad un file in una delle tue cartelle. Se un file collegato ad una voce viene spostato o eliminito al di fuori di TagStudio, la voce corrispondente viene considerata scollegata.
Le voci scollegate possono essere ricollegate automaticamente attraverso la ricerca nelle tue cartelle oppure cancellate se lo si desidera.",
- "entries.unlinked.relink.attempting": "Tentativo di Ricollegare {index}/{unlinked_count} Voci, {fixed_count} Ricollegate con Successo",
+ "entries.unlinked.description": "Ogni voce della biblioteca è collegata ad un file in una delle tue cartelle. Se un file collegato ad una voce viene spostato o eliminito al di fuori di TagStudio, la voce corrispondente viene considerata scollegata.",
"entries.unlinked.relink.manual": "Ricollegamento &Manuale",
- "entries.unlinked.relink.title": "Ricollegamento Voci",
"entries.unlinked.remove": "Rimuovi Voci non Collegate",
"entries.unlinked.remove_alt": "Rimuo&vi Voci non Collegate",
- "entries.unlinked.scanning": "Scansionando la Biblioteca in cerca di Voci non Collegate...",
- "entries.unlinked.search_and_relink": "&Ricerca && Ricollega",
"entries.unlinked.title": "Correggi Voci non Collegate",
"entries.unlinked.unlinked_count": "Voci non Collegate: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -180,10 +175,6 @@
"landing.open_create_library": "Apri/Crea Biblioteca {shortcut}",
"library.missing": "Manca la Posizione della Biblioteca",
"library.name": "Biblioteca",
- "library.refresh.scanning.plural": "Ricerca di Nuovi File nelle Cartelle...\n{searched_count} Files Cercati, {found_count} Nuovi File Trovati",
- "library.refresh.scanning.singular": "Ricerca di Nuovi File nelle Cartelle...\n{searched_count} File Cercati, {found_count} Nuovi File Trovati",
- "library.refresh.scanning_preparing": "Ricerca di Nuovi File nelle Cartelle...\nPreparazione in corso...",
- "library.refresh.title": "Aggiornamento delle Cartelle",
"library.scan_library.title": "Scansione della Biblioteca",
"library_info.cleanup": "Pulizia",
"library_info.cleanup.backups": "Backup della Biblioteca:",
@@ -225,7 +216,6 @@
"menu.file.open_create_library": "&Apri/Crea Biblioteca",
"menu.file.open_library": "Apri Biblioteca",
"menu.file.open_recent_library": "Apri Recenti",
- "menu.file.refresh_directories": "Aggiorna Cartelle",
"menu.file.save_backup": "&Salva Backup della Biblioteca",
"menu.file.save_library": "Salva Biblioteca",
"menu.help": "&Aiuto",
diff --git a/src/tagstudio/resources/translations/ja.json b/src/tagstudio/resources/translations/ja.json
index 3cbc6b1a9..f65d50274 100644
--- a/src/tagstudio/resources/translations/ja.json
+++ b/src/tagstudio/resources/translations/ja.json
@@ -61,16 +61,11 @@
"entries.remove.plural.confirm": "これら {count} 件のエントリをライブラリから削除しますか? ディスク上のファイルは削除されません。",
"entries.remove.singular.confirm": "このエントリをライブラリから削除しますか? ディスク上のファイルは削除されません。",
"entries.running.dialog.new_entries": "{total} 件の新しいファイル エントリを追加しています…",
- "entries.running.dialog.title": "新しいファイルエントリを追加",
"entries.tags": "タグ",
- "entries.unlinked.description": "ライブラリの各エントリは、ディレクトリ内のファイルにリンクされています。エントリにリンクされたファイルが TagStudio 以外で移動または削除された場合、そのエントリはリンク切れとして扱われます。
リンク切れのエントリは、ディレクトリを検索して自動的に再リンクすることも、必要に応じて削除することもできます。",
- "entries.unlinked.relink.attempting": "{unlinked_count} 件中 {index} 件のエントリを再リンク中、{fixed_count} 件を正常に再リンクしました",
+ "entries.unlinked.description": "ライブラリの各エントリは、ディレクトリ内のファイルにリンクされています。エントリにリンクされたファイルが TagStudio 以外で移動または削除された場合、そのエントリはリンク切れとして扱われます。",
"entries.unlinked.relink.manual": "手動で再リンク(&M)",
- "entries.unlinked.relink.title": "エントリの再リンク",
"entries.unlinked.remove": "リンク切れのエントリを削除",
"entries.unlinked.remove_alt": "リンク切れのエントリを削除(&V)",
- "entries.unlinked.scanning": "リンク切れのエントリをライブラリ内でスキャンしています…",
- "entries.unlinked.search_and_relink": "検索して再リンク(&S)",
"entries.unlinked.title": "リンク切れのエントリを修正",
"entries.unlinked.unlinked_count": "リンク切れのエントリ数: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -233,10 +228,6 @@
"language.zh_Hant": "中国語 (繁体字)",
"library.missing": "ライブラリの場所が見つかりません",
"library.name": "ライブラリ",
- "library.refresh.scanning.plural": "新しいファイルを検索中...\n{searched_count} 件を検索、{found_count} 件の新規ファイルを検出",
- "library.refresh.scanning.singular": "新しいファイルを検索中...\n{searched_count} 件を検索、{found_count} 件の新規ファイルを検出",
- "library.refresh.scanning_preparing": "新しいファイルを検索中...\n準備中…",
- "library.refresh.title": "ディレクトリを更新しています",
"library.scan_library.title": "ライブラリをスキャンしています",
"library_info.cleanup": "クリーンアップ",
"library_info.cleanup.backups": "ライブラリのバックアップ:",
@@ -279,7 +270,6 @@
"menu.file.open_create_library": "ライブラリを開く/作成する(&O)",
"menu.file.open_library": "ライブラリを開く",
"menu.file.open_recent_library": "最近使用したライブラリを開く",
- "menu.file.refresh_directories": "ディレクトリの更新(&R)",
"menu.file.save_backup": "ライブラリ バックアップを保存(&S)",
"menu.file.save_library": "ライブラリを保存",
"menu.help": "ヘルプ(&H)",
diff --git a/src/tagstudio/resources/translations/nb_NO.json b/src/tagstudio/resources/translations/nb_NO.json
index f2d40da72..6d2f306c8 100644
--- a/src/tagstudio/resources/translations/nb_NO.json
+++ b/src/tagstudio/resources/translations/nb_NO.json
@@ -55,14 +55,9 @@
"entries.remove.plural.confirm": "Er du sikker på at du vil slette følgende {count} oppføringer fra biblioteket ditt? Ingen filer på disken vil slettes.",
"entries.remove.singular.confirm": "Er du sikker på at du vil fjerne denne oppføringen fra bibliotek ditt? Ingen filer på disken vil slettes.",
"entries.running.dialog.new_entries": "Legger til {total} Nye Filoppføringer...",
- "entries.running.dialog.title": "Legger til Nye Filoppføringer",
"entries.tags": "Etiketter",
- "entries.unlinked.description": "Hver biblioteksoppføring er koblet til en fil i en av dine mapper. Hvis en fil koblet til en oppføring er flyttet eller slettet utenfor TagStudio, så er den sett på som frakoblet.
Frakoblede oppføringer kan bli automatisk gjenkoblet ved å søke i mappene dine eller slettet om det er ønsket.",
- "entries.unlinked.relink.attempting": "Forsøker å Gjenkoble {index}/{unlinked_count} Oppføringer, {fixed_count} Klart Gjenkoblet",
+ "entries.unlinked.description": "Hver biblioteksoppføring er koblet til en fil i en av dine mapper. Hvis en fil koblet til en oppføring er flyttet eller slettet utenfor TagStudio, så er den sett på som frakoblet.",
"entries.unlinked.relink.manual": "&Manuell Gjenkobling",
- "entries.unlinked.relink.title": "Gjenkobler Oppføringer",
- "entries.unlinked.scanning": "Skanner bibliotek for ulenkede oppføringer …",
- "entries.unlinked.search_and_relink": "&Søk && Gjenkobl",
"entries.unlinked.title": "Fiks ulenkede oppføringer",
"entries.unlinked.unlinked_count": "Frakoblede Oppføringer: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -167,10 +162,6 @@
"landing.open_create_library": "Åpne/Lag nytt Bibliotek {shortcut}",
"library.missing": "Posisjon mangler",
"library.name": "Bibliotek",
- "library.refresh.scanning.plural": "Skanner Mapper for Nye Filer...\n{searched_count} Filer Sjekket, {found_count} Nye Filer Funnet",
- "library.refresh.scanning.singular": "Skanner Mapper for Nye Filer...\n{searched_count} Fil Sjekket, {found_count} Nye Filer Funnet",
- "library.refresh.scanning_preparing": "Skanner Mapper for Nye Filer...\nForbereder...",
- "library.refresh.title": "Oppdaterer Mapper",
"library.scan_library.title": "Skanning av bibliotek",
"library_info.stats.entries": "Oppføringer:",
"library_info.stats.fields": "Felter:",
@@ -199,7 +190,6 @@
"menu.file.open_create_library": "&Åpne/Lag nytt Bibliotek",
"menu.file.open_library": "Åpne Bibliotek",
"menu.file.open_recent_library": "Åpne Nylig",
- "menu.file.refresh_directories": "&Oppdater Mapper",
"menu.file.save_backup": "&Lagre Sikkerhetskopi av Bibliotek",
"menu.file.save_library": "Lagre Bibliotek",
"menu.help": "Hjelp",
diff --git a/src/tagstudio/resources/translations/nl.json b/src/tagstudio/resources/translations/nl.json
index 76f5e5e24..3649bcc04 100644
--- a/src/tagstudio/resources/translations/nl.json
+++ b/src/tagstudio/resources/translations/nl.json
@@ -96,7 +96,6 @@
"json_migration.heading.shorthands": "Afkortingen:",
"json_migration.migration_complete": "Migratie Afgerond!",
"json_migration.title": "Migratie Formaat Opslaan: \"{path}\"",
- "library.refresh.scanning_preparing": "Mappen scannen voor nieuwe bestanden...\nVoorbereiden...",
"library_info.stats.fields": "Velden:",
"library_info.stats.tags": "Labels:",
"menu.delete_selected_files_ambiguous": "Bestand(en) verplaatsen naar {trash_term}",
diff --git a/src/tagstudio/resources/translations/pl.json b/src/tagstudio/resources/translations/pl.json
index 87c794670..5d075629b 100644
--- a/src/tagstudio/resources/translations/pl.json
+++ b/src/tagstudio/resources/translations/pl.json
@@ -47,14 +47,9 @@
"entries.mirror.window_title": "Odzwierciedl wpisy",
"entries.remove.plural.confirm": "Jesteś pewien że chcesz usunąć następujące {count} wpisy?",
"entries.running.dialog.new_entries": "Dodawanie {total} nowych wpisów plików...",
- "entries.running.dialog.title": "Dodawanie nowych wpisów plików",
"entries.tags": "Tagi",
- "entries.unlinked.description": "Każdy wpis w bibliotece jest połączony z plikiem w jednym z twoich katalogów. Jeśli połączony plik jest przeniesiony poza TagStudio albo usunięty to jest uważany za odłączony.
Odłączone wpisy mogą być automatycznie połączone ponownie przez szukanie twoich katalogów, ręczne ponowne łączenie przez użytkownika lub usunięte jeśli zajdzie taka potrzeba.",
- "entries.unlinked.relink.attempting": "Próbowanie ponownego łączenia {index}/{unlinked_count} wpisów, {fixed_count} poprawnie połączono ponownie",
+ "entries.unlinked.description": "Każdy wpis w bibliotece jest połączony z plikiem w jednym z twoich katalogów. Jeśli połączony plik jest przeniesiony poza TagStudio albo usunięty to jest uważany za odłączony.",
"entries.unlinked.relink.manual": "&Ręczne ponowne łączenie",
- "entries.unlinked.relink.title": "Ponowne łączenie wpisów",
- "entries.unlinked.scanning": "Skanowanie biblioteki dla odłączonych wpisów...",
- "entries.unlinked.search_and_relink": "&Wyszukaj && Zalinkuj ponownie",
"entries.unlinked.title": "Napraw odłączone wpisy",
"entries.unlinked.unlinked_count": "Odłączone wpisy: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -157,9 +152,6 @@
"landing.open_create_library": "Otwórz/Stwórz bibliotekę {shortcut}",
"library.missing": "Brak lokalizacji",
"library.name": "Biblioteka",
- "library.refresh.scanning.plural": "Skanowanie folderów w poszukiwaniu nowych plików...\nPrzeszukano {searched_count} plików, Znaleziono {found_count} nowych plików",
- "library.refresh.scanning_preparing": "Skanowanie katalogów w poszukiwaniu nowych plików\nPrzygotowywanie...",
- "library.refresh.title": "Odświeżanie katalogów",
"library.scan_library.title": "Skanowanie biblioteki",
"library_info.stats.entries": "Wpisy:",
"library_info.stats.fields": "Pola:",
@@ -185,7 +177,6 @@
"menu.file.open_create_library": "&Otwórz/Stwórz bibliotekę",
"menu.file.open_library": "Otwórz bibliotekę",
"menu.file.open_recent_library": "Otwórz ostatnie",
- "menu.file.refresh_directories": "Odśwież katalogi",
"menu.file.save_backup": "&Zapisz kopię zapasową biblioteki",
"menu.file.save_library": "Zapisz bibliotekę",
"menu.help": "&Pomoc",
diff --git a/src/tagstudio/resources/translations/pt.json b/src/tagstudio/resources/translations/pt.json
index f8595413e..9a9d1e549 100644
--- a/src/tagstudio/resources/translations/pt.json
+++ b/src/tagstudio/resources/translations/pt.json
@@ -52,15 +52,10 @@
"entries.mirror.window_title": "Espelhar Registos",
"entries.remove.plural.confirm": "Tem certeza que deseja apagar os seguintes {count} registos ?",
"entries.running.dialog.new_entries": "A Adicionar {total} Novos Registos de Ficheiros...",
- "entries.running.dialog.title": "A Adicionar Novos Registos de Ficheiros",
"entries.tags": "Tags",
- "entries.unlinked.description": "Cada registo na biblioteca faz referência à um ficheiro numa das suas pastas. Se um ficheiro referenciado à uma entrada for movido ou apagado fora do TagStudio, ele é depois considerado não-referenciado.
Registos não-referenciados podem ser automaticamente referenciados por pesquisas nos seus diretórios, manualmente pelo utilizador, ou apagado se for desejado.",
- "entries.unlinked.relink.attempting": "A tentar referenciar {index}/{unlinked_count} Registos, {fixed_count} Referenciados com Sucesso",
+ "entries.unlinked.description": "Cada registo na biblioteca faz referência à um ficheiro numa das suas pastas. Se um ficheiro referenciado à uma entrada for movido ou apagado fora do TagStudio, ele é depois considerado não-referenciado.",
"entries.unlinked.relink.manual": "&Referência Manual",
- "entries.unlinked.relink.title": "A Referenciar Registos",
"entries.unlinked.remove_alt": "Remover Entradas sem Conexões",
- "entries.unlinked.scanning": "A escanear biblioteca por registos não referenciados...",
- "entries.unlinked.search_and_relink": "&Pesquisar && Referenciar",
"entries.unlinked.title": "Corrigir Registos Não Referenciados",
"entries.unlinked.unlinked_count": "Registos Não Referenciados: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -163,10 +158,6 @@
"landing.open_create_library": "Abrir/Criar Biblioteca {shortcut}",
"library.missing": "Localização Ausente",
"library.name": "Biblioteca",
- "library.refresh.scanning.plural": "A escanear pastas por Novos Ficheiros ...\n{searched_count} Ficheiros pesquisados, {found_count} Novos Ficheiros",
- "library.refresh.scanning.singular": "A Escanear pastas por novos ficheiros ...\n{searched_count} Ficheiros encontrados, {found_count} Novos Ficheiros",
- "library.refresh.scanning_preparing": "A Escanear Diretórios por Novos Ficheiros...\nPreparando...",
- "library.refresh.title": "A atualizar Pastas",
"library.scan_library.title": "A Escanear Biblioteca",
"library_info.cleanup": "Limpeza",
"library_info.cleanup.dupe_files": "Ficheiros Duplicados:",
@@ -197,7 +188,6 @@
"menu.file.open_create_library": "&Abrir/Criar Biblioteca",
"menu.file.open_library": "Abrir Biblioteca",
"menu.file.open_recent_library": "Abrir Recente",
- "menu.file.refresh_directories": "Atualizar Pastas",
"menu.file.save_backup": "&Gravar Backup da Biblioteca",
"menu.file.save_library": "Gravar Biblioteca",
"menu.help": "&Ajuda",
diff --git a/src/tagstudio/resources/translations/pt_BR.json b/src/tagstudio/resources/translations/pt_BR.json
index 81ff26a1c..383e1c64b 100644
--- a/src/tagstudio/resources/translations/pt_BR.json
+++ b/src/tagstudio/resources/translations/pt_BR.json
@@ -56,16 +56,11 @@
"entries.remove.plural.confirm": "Tem certeza que deseja deletar os seguintes {count} Registros ?",
"entries.remove.singular.confirm": "Você tem certeza que deseja remover esse registro da sua bilbioteca ? Nenhum arquivo no disco será excluído.",
"entries.running.dialog.new_entries": "Adicionando {total} Novos Registros de Arquivos...",
- "entries.running.dialog.title": "Adicionando Novos Registros de Arquivos",
"entries.tags": "Tags",
- "entries.unlinked.description": "Cada registro na biblioteca faz referência à um arquivo em uma de suas pastas. Se um arquivo referenciado à uma entrada for movido ou deletado fora do TagStudio, ele é então considerado não-referenciado.
Registros não-referenciados podem ser automaticamente referenciados por buscas nos seus diretórios, manualmente pelo usuário, ou deletado se for desejado.",
- "entries.unlinked.relink.attempting": "Tentando referenciar {index}/{unlinked_count} Registros, {fixed_count} Referenciados com Sucesso",
+ "entries.unlinked.description": "Cada registro na biblioteca faz referência à um arquivo em uma de suas pastas. Se um arquivo referenciado à uma entrada for movido ou deletado fora do TagStudio, ele é então considerado não-referenciado.",
"entries.unlinked.relink.manual": "&Referência Manual",
- "entries.unlinked.relink.title": "Referenciando Registros",
"entries.unlinked.remove": "Remover Registros Não Vinculados",
"entries.unlinked.remove_alt": "Remover Entradas sem Conexões",
- "entries.unlinked.scanning": "Escaneando bibliotecada em busca de registros não referenciados...",
- "entries.unlinked.search_and_relink": "&Buscar && Referenciar",
"entries.unlinked.title": "Corrigir Registros Não Referenciados",
"entries.unlinked.unlinked_count": "Registros Não Referenciados: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -176,10 +171,6 @@
"landing.open_create_library": "Abrir/Criar Biblioteca {shortcut}",
"library.missing": "Localização Ausente",
"library.name": "Biblioteca",
- "library.refresh.scanning.plural": "Escaneando pastas em busca de novos arquivos ...\n{searched_count} Arquivos encontrados, {found_count} Novos Arquivos",
- "library.refresh.scanning.singular": "Escaneando pastas em busca de novos arquivos ...\n{searched_count} Arquivos encontrados, {found_count} Novos Arquivos",
- "library.refresh.scanning_preparing": "Escaneando Diretórios por Novos Arquivos...\nPreparando...",
- "library.refresh.title": "Atualizando Pastas",
"library.scan_library.title": "Escaneando Biblioteca",
"library_info.cleanup": "Limpeza",
"library_info.cleanup.backups": "Backup de Bibliotecas:",
@@ -221,7 +212,6 @@
"menu.file.open_create_library": "&Abrir/Criar Biblioteca",
"menu.file.open_library": "Abrir Biblioteca",
"menu.file.open_recent_library": "Abrir Recente",
- "menu.file.refresh_directories": "Atualizar Pastas",
"menu.file.save_backup": "&Salvar Backup da Biblioteca",
"menu.file.save_library": "Salvar Biblioteca",
"menu.help": "&Ajuda",
diff --git a/src/tagstudio/resources/translations/qpv.json b/src/tagstudio/resources/translations/qpv.json
index c2bc8a23d..209677673 100644
--- a/src/tagstudio/resources/translations/qpv.json
+++ b/src/tagstudio/resources/translations/qpv.json
@@ -56,16 +56,11 @@
"entries.remove.plural.confirm": "Du kestetsa afto {count} shiruzmakaban we? Nil mlafu na shiruzmabaksu bli kestejena.",
"entries.remove.singular.confirm": "Du kestetsa afto shiruzmakaban long mlafuhuomi we? Nil mlafu na shiruzmabaksu bli kestejena.",
"entries.running.dialog.new_entries": "Nasii {total} neo shiruzmakaban fu mlafu ima...",
- "entries.running.dialog.title": "Nasii neo shiruzmakaban fu mlafu ima",
"entries.tags": "Festaretol",
- "entries.unlinked.description": "Tont shiruzmakaban fu mlafuhuomi tsunagajena na mlafu ine joku mlafukaban fu du. Li mlafu tsunagajena na shiruzmakaban ugokijena os kestejena ekso TagStudio, sit sore kntsunagajena.
Tsunaganaijena shiruzmakaban deki tsunaga gen na suha per mlafukaban fu du os keste li du vil.",
- "entries.unlinked.relink.attempting": "Iskat ima na tsunaga gen {index}/{unlinked_count} shiruzmakaban, {fixed_count} tsunagajena gen",
+ "entries.unlinked.description": "Tont shiruzmakaban fu mlafuhuomi tsunagajena na mlafu ine joku mlafukaban fu du. Li mlafu tsunagajena na shiruzmakaban ugokijena os kestejena ekso TagStudio, sit sore kntsunagajena.",
"entries.unlinked.relink.manual": "&Tsunaga gen mit hant",
- "entries.unlinked.relink.title": "Tsunaga shiruzmakaban gen",
"entries.unlinked.remove": "Keste kntsunagajena shiruzmakaban",
"entries.unlinked.remove_alt": "Keste kntsunagajena shiruzmakaban (&v)",
- "entries.unlinked.scanning": "Taskame mlafuhuomi ima grun kntsunagajena shiruzmakaban...",
- "entries.unlinked.search_and_relink": "&Suha &&Tsunaga gen",
"entries.unlinked.title": "Fiks kntsunagajena shiruzmakaban",
"entries.unlinked.unlinked_count": "Kntsunagajena shiruzmakaban: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -179,10 +174,6 @@
"landing.open_create_library": "Auki/Maha mlafuhuomi {shortcut}",
"library.missing": "Mlafuplas fu mlafuhuomi nai finnajenadan",
"library.name": "Mlafuhuomi",
- "library.refresh.scanning.plural": "Taskame mlafukaban fu neo mlafu ima...\n{searched_count} mlafu suhajenadan, {found_count} neo mlafu finnajenadan",
- "library.refresh.scanning.singular": "Taskame mlafukaban fu neo mlafu ima...\n{searched_count} mlafu suhajenadan, {found_count} neo mlafu finnajenadan",
- "library.refresh.scanning_preparing": "Taskame mlafukaban fu neo mlafu ima...\nGotova ima...",
- "library.refresh.title": "Gengotova al mlafukaban",
"library.scan_library.title": "Taskame mlafuhuomi ima",
"library_info.cleanup": "Parjat",
"library_info.cleanup.backups": "Mverm long mlafuhuomi:",
@@ -217,7 +208,6 @@
"menu.file.open_create_library": "&Auki/maha mlafuhuomi",
"menu.file.open_library": "Auki mlafuhuomi",
"menu.file.open_recent_library": "Auki moloda",
- "menu.file.refresh_directories": "&Gengotova al mlafukaban",
"menu.file.save_backup": "&Ufne mverm fu mlafuhuomi",
"menu.file.save_library": "Ufne mlafuhuomi",
"menu.help": "&Aputsa",
diff --git a/src/tagstudio/resources/translations/ru.json b/src/tagstudio/resources/translations/ru.json
index 573b4e5f7..0084c8215 100644
--- a/src/tagstudio/resources/translations/ru.json
+++ b/src/tagstudio/resources/translations/ru.json
@@ -58,15 +58,10 @@
"entries.remove.plural.confirm": "Вы уверены, что хотите удалить {count} записей? Файлы на диске не будут удалены.",
"entries.remove.singular.confirm": "Вы уверены, что хотите удалить эту запись? Файл на диске не будет удалён.",
"entries.running.dialog.new_entries": "Добавление {total} новых записей...",
- "entries.running.dialog.title": "Добавление новых записей",
"entries.tags": "Теги",
- "entries.unlinked.description": "Каждая запись в библиотеке привязана к файлу, находящегося внутри той или иной папки. Если файл, к которому была привязана запись, был удалён или перемещён без использования TagStudio, то запись становиться \"откреплённой\".
Откреплённые записи могут быть прикреплены обратно автоматически, либо же удалены если в них нет надобности.",
- "entries.unlinked.relink.attempting": "Попытка перепривязать {index}/{unlinked_count} записей, {fixed_count} привязано успешно",
+ "entries.unlinked.description": "Каждая запись в библиотеке привязана к файлу, находящегося внутри той или иной папки. Если файл, к которому была привязана запись, был удалён или перемещён без использования TagStudio, то запись становиться \"откреплённой\".",
"entries.unlinked.relink.manual": "&Ручная привязка",
- "entries.unlinked.relink.title": "Привязка записей",
"entries.unlinked.remove": "Удалить откреплённые записи",
- "entries.unlinked.scanning": "Сканирование библиотеки на наличие откреплённых записей...",
- "entries.unlinked.search_and_relink": "&Поиск и привязка",
"entries.unlinked.title": "Исправить откреплённые записи",
"entries.unlinked.unlinked_count": "Откреплённых записей: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -211,10 +206,6 @@
"language.zh_Hant": "Китайский (традиционный)",
"library.missing": "Отсутствует путь к библиотеке",
"library.name": "Библиотека",
- "library.refresh.scanning.plural": "Сканирование папок на наличие новых файлов...\nПросканировано {searched_count} файлов, найдено {found_count} новых",
- "library.refresh.scanning.singular": "Сканирование папок на наличие новых файлов...\nПросканирован {searched_count} файл, найдено {found_count} новых",
- "library.refresh.scanning_preparing": "Сканирование папок на наличие новых файлов...\nПодготовка...",
- "library.refresh.title": "Обновление папок",
"library.scan_library.title": "Сканирование библиотеки",
"library_info.cleanup.backups": "Резервные копии библиотек:",
"library_info.cleanup.dupe_files": "Файлы-дубликаты:",
@@ -255,7 +246,6 @@
"menu.file.open_create_library": "&Открыть/создать библиотеку",
"menu.file.open_library": "Открыть библиотеку",
"menu.file.open_recent_library": "Открыть последнюю",
- "menu.file.refresh_directories": "Обновить папки",
"menu.file.save_backup": "&Сохранить резервную копию библиотеки",
"menu.file.save_library": "Сохранить библиотеку",
"menu.help": "&Помощь",
diff --git a/src/tagstudio/resources/translations/sv.json b/src/tagstudio/resources/translations/sv.json
index a34c19400..ce69b1042 100644
--- a/src/tagstudio/resources/translations/sv.json
+++ b/src/tagstudio/resources/translations/sv.json
@@ -56,16 +56,11 @@
"entries.remove.plural.confirm": "Är du säker att du vill radera följande {count} poster?",
"entries.remove.singular.confirm": "Är du säker på att du vill ta bort denna post från ditt bibliotek? Inga filer på disken kommer att raderas.",
"entries.running.dialog.new_entries": "Lägger Till {total} Nya Filposter...",
- "entries.running.dialog.title": "Lägger Till Nya Filposter",
"entries.tags": "Etiketter",
"entries.unlinked.description": "Varje post i biblioteket är länkad till en fil i en av dina kataloger. Om en fil länkad till en post är flyttad eller borttagen utanför TagStudio blir den olänkad. Olänkade poster kan automatiskt bli omlänkade genom att söka genom dina kataloger, manuellt omlänkade av användaren eller tas bort om så önskas.",
- "entries.unlinked.relink.attempting": "Försöker att länka om {index}/{unlinked_count} Poster, {fixed_count} Lyckades Länkas Om",
"entries.unlinked.relink.manual": "Länka om manuellt",
- "entries.unlinked.relink.title": "Länkar om poster",
"entries.unlinked.remove": "Ta Bort Olänkade Poster",
"entries.unlinked.remove_alt": "&Ta Bort Olänkade Poster",
- "entries.unlinked.scanning": "Skannar bibliotek efter olänkade poster...",
- "entries.unlinked.search_and_relink": "Sök && Länka om",
"entries.unlinked.title": "Fixa olänkade poster",
"entries.unlinked.unlinked_count": "Olänkade Poster: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -100,8 +95,6 @@
"home.thumbnail_size": "Miniatyrbildsstorlek",
"library.missing": "Platsen saknas",
"library.name": "Bibliotek",
- "library.refresh.scanning_preparing": "Skannar kataloger efter nya filer...\nFörbereder...",
- "library.refresh.title": "Uppdaterar kataloger",
"library.scan_library.title": "Skannar bibliotek",
"macros.running.dialog.title": "Kör makros på nya poster",
"menu.edit": "Redigera",
diff --git a/src/tagstudio/resources/translations/ta.json b/src/tagstudio/resources/translations/ta.json
index 750887723..3ec97a589 100644
--- a/src/tagstudio/resources/translations/ta.json
+++ b/src/tagstudio/resources/translations/ta.json
@@ -56,16 +56,11 @@
"entries.remove.plural.confirm": "இந்த {count} உள்ளீடுகளை உங்கள் நூலகத்திலிருந்து நீக்க விரும்புகிறீர்களா? வட்டில் உள்ள எந்தக் கோப்புகளும் நீக்கப்படாது.",
"entries.remove.singular.confirm": "உங்கள் நூலகத்திலிருந்து இந்தப் பதிவை நிச்சயமாக அகற்ற விரும்புகிறீர்களா? வட்டில் உள்ள கோப்புகள் எதுவும் நீக்கப்படாது.",
"entries.running.dialog.new_entries": "{total} புதிய கோப்பு உள்ளீடுகளைச் சேர்ப்பது ...",
- "entries.running.dialog.title": "புதிய கோப்பு உள்ளீடுகளைச் சேர்ப்பது",
"entries.tags": "குறிச்சொற்கள்",
"entries.unlinked.description": "ஒவ்வொரு நூலக நுழைவும் உங்கள் கோப்பகங்களில் ஒன்றில் ஒரு கோப்போடு இணைக்கப்பட்டுள்ளது. ஒரு நுழைவுடன் இணைக்கப்பட்ட ஒரு கோப்பு முகவரிச்சீட்டுஅறைக்கு வெளியே நகர்த்தப்பட்டால் அல்லது நீக்கப்பட்டால், அது பின்னர் இணைக்கப்படாததாகக் கருதப்படுகிறது.",
- "entries.unlinked.relink.attempting": "{index}/{unlinked_count} உள்ளீடுகளை மீண்டும் இணைக்க முயற்சிக்கிறது, {fixed_count} மீண்டும் இணைக்கப்பட்டது",
"entries.unlinked.relink.manual": "& கையேடு மறுபரிசீலனை",
- "entries.unlinked.relink.title": "உள்ளீடுகள் மீண்டும் இணைக்கப்படுகின்றது",
"entries.unlinked.remove": "இணைக்கப்படாத உள்ளீடுகளை அகற்று",
"entries.unlinked.remove_alt": "இணைக்கப்படாத உள்ளீடுகளை அகற்று&விடு",
- "entries.unlinked.scanning": "இணைக்கப்படாத நுழைவுகளை புத்தககல்லரியில் சோதனை செய்யப்படுகிறது...",
- "entries.unlinked.search_and_relink": "& தேடல் && relink",
"entries.unlinked.title": "இணைக்கப்படாத உள்ளீடுகளைச் சரிசெய்யவும்",
"entries.unlinked.unlinked_count": "இணைக்கப்படாத உள்ளீடுகள்: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -176,10 +171,6 @@
"landing.open_create_library": "நூலகத்தைத் திறக்கவும்/உருவாக்கவும் {shortcut}",
"library.missing": "இடம் காணவில்லை",
"library.name": "நூலகம்",
- "library.refresh.scanning.plural": "புதிய கோப்புகளுக்கான கோப்பகங்களை ச்கேன் செய்தல் ...\n {searched_count} கோப்புகள் தேடப்பட்டன, {found_count} புதிய கோப்புகள் காணப்படுகின்றன",
- "library.refresh.scanning.singular": "புதிய கோப்புகளுக்கான கோப்பகங்களை ச்கேன் செய்தல் ...\n {searched_count} கோப்பு தேடப்பட்டது, {found_count} புதிய கோப்புகள் காணப்படுகின்றன",
- "library.refresh.scanning_preparing": "புதிய கோப்புகளுக்கான அடைவுகள் சோதனை செய்யப்படுகின்றது...\nதயாராகிறது...",
- "library.refresh.title": "கோப்பகங்கள் புதுப்பிக்கப்படுகின்றன",
"library.scan_library.title": "புத்தககல்லரி சோதனை செய்யப்படுகிறது",
"library_info.cleanup": "தூய்மை",
"library_info.cleanup.backups": "நூலக காப்புப்பிரதிகள்:",
@@ -221,7 +212,6 @@
"menu.file.open_create_library": "& நூலகத்தைத் திறக்க/உருவாக்கவும்",
"menu.file.open_library": "திறந்த நூலகம்",
"menu.file.open_recent_library": "அண்மைக் கால திறப்பு",
- "menu.file.refresh_directories": "கோப்பகத்தை புதுப்பிக்கவும்",
"menu.file.save_backup": " நூலக காப்புப்பிரதியை சேமிக்கவும்",
"menu.file.save_library": "நூலகத்தை சேமிக்கவும்",
"menu.help": "உதவி (&h)",
diff --git a/src/tagstudio/resources/translations/tok.json b/src/tagstudio/resources/translations/tok.json
index eaeb15d25..f4894b7ae 100644
--- a/src/tagstudio/resources/translations/tok.json
+++ b/src/tagstudio/resources/translations/tok.json
@@ -55,16 +55,11 @@
"entries.remove.plural.confirm": "mi weka e ijo {count}. ni li pona anu seme? poki lipu pi ilo sina la lipu ala li weka.",
"entries.remove.singular.confirm": "mi weka e ijo ni. ni li pona anu seme? poki lipu pi ilo sina la lipu ala li weka.",
"entries.running.dialog.new_entries": "mi pana e lipu sin {total}...",
- "entries.running.dialog.title": "mi pana e lipu sin",
"entries.tags": "poki",
- "entries.unlinked.description": "ijo ale li jo e ijo lon tomo sina. ona li tawa anu weka lon ilo TagStudio ala la, ona li jo ala e ijo lon.
ijo pi ijo lon li ken alasa lon tomo li ken kama jo e ijo lon. ante la sina ken weka e ona.",
- "entries.unlinked.relink.attempting": "mi o pana e ijo lon tawa ijo {index}/{unlinked_count}. mi pana e ijo lon tawa ijo {fixed_count}",
+ "entries.unlinked.description": "ijo ale li jo e ijo lon tomo sina. ona li tawa anu weka lon ilo TagStudio ala la, ona li jo ala e ijo lon.",
"entries.unlinked.relink.manual": "sina o pana e ijo lon tawa ijo (&M)",
- "entries.unlinked.relink.title": "mi pana e ijo lon tawa ijo",
"entries.unlinked.remove": "o weka e ijo pi ijo lon ala",
"entries.unlinked.remove_alt": "o weka e ijo pi ijo lon ala (&V)",
- "entries.unlinked.scanning": "mi o alasa e ijo pi ijo lon ala...",
- "entries.unlinked.search_and_relink": "o ala&sa o pana e ijo lon tawa ijo",
"entries.unlinked.title": "o pona e ijo pi ijo lon ala",
"entries.unlinked.unlinked_count": "ijo pi ijo lon ala: {count}",
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status} {ffprobe}: {ffprobe_status}",
@@ -176,10 +171,6 @@
"landing.open_create_library": "o open anu pali sin e tomo {shortcut}",
"library.missing": "tomo li lon ala",
"library.name": "tomo",
- "library.refresh.scanning.plural": "mi alasa e lipu sin lon tomo...\nmi alasa e lipu {searched_count}, mi lukin e lipu sin {found_count}",
- "library.refresh.scanning.singular": "mi alasa e lipu sin lon tomo...\nmi alasa e lipu {searched_count}, mi lukin e lipu sin {found_count}",
- "library.refresh.scanning_preparing": "mi alasa e ijo sin lon tomo...\nmi kama pona...",
- "library.refresh.title": "mi kama jo e sin lon tomo",
"library.scan_library.title": "mi o lukin e tomo",
"library_info.cleanup": "jaki",
"library_info.cleanup.backups": "sama awen tomo:",
@@ -219,7 +210,6 @@
"menu.file.open_create_library": "o &open/pali e tomo",
"menu.file.open_library": "o open e tomo",
"menu.file.open_recent_library": "o open e poka",
- "menu.file.refresh_directories": "o lukin sin lon tomo (&R)",
"menu.file.save_backup": "o awen e &sama awen tomo",
"menu.file.save_library": "o awen e sona tomo",
"menu.help": "mi jo e toki seme (&H)",
diff --git a/src/tagstudio/resources/translations/tr.json b/src/tagstudio/resources/translations/tr.json
index fe0c682d5..e187b91bd 100644
--- a/src/tagstudio/resources/translations/tr.json
+++ b/src/tagstudio/resources/translations/tr.json
@@ -46,14 +46,9 @@
"entries.mirror.window_title": "Kayıtları Yansıt",
"entries.remove.plural.confirm": "{count} tane kayıtları silmek istediğinden emin misin?",
"entries.running.dialog.new_entries": "{total} Yeni Dosya Kaydı Ekleniyor...",
- "entries.running.dialog.title": "Yeni Dosya Kayıtları Ekleniyor",
"entries.tags": "Etiketler",
- "entries.unlinked.description": "Kütüphanenizdeki her bir kayıt, dizinlerinizden bir tane dosya ile eşleştirilmektedir. Eğer bir kayıta bağlı dosya TagStudio dışında taşınır veya silinirse, o dosya artık kopmuş olarak sayılır.
Kopmuş kayıtlar dizinlerinizde arama yapılırken otomatik olarak tekrar eşleştirilebilir, manuel olarak sizin tarafınızdan eşleştirilebilir veya isteğiniz üzere silinebilir.",
- "entries.unlinked.relink.attempting": "{index}/{unlinked_count} Kayıt Yeniden Eşleştirilmeye Çalışılıyor, {fixed_count} Başarıyla Yeniden Eşleştirildi",
+ "entries.unlinked.description": "Kütüphanenizdeki her bir kayıt, dizinlerinizden bir tane dosya ile eşleştirilmektedir. Eğer bir kayıta bağlı dosya TagStudio dışında taşınır veya silinirse, o dosya artık kopmuş olarak sayılır.",
"entries.unlinked.relink.manual": "&Manuel Yeniden Eşleştirme",
- "entries.unlinked.relink.title": "Kayıtlar Yeniden Eşleştiriliyor",
- "entries.unlinked.scanning": "Kütüphane, Kopmuş Kayıtlar için Taranıyor...",
- "entries.unlinked.search_and_relink": "&Ara && Yeniden Eşleştir",
"entries.unlinked.title": "Kopmuş Kayıtları Düzelt",
"entries.unlinked.unlinked_count": "Kopmuş Kayıtlar: {count}",
"field.add": "Ek Bilgi Ekle",
@@ -156,10 +151,6 @@
"landing.open_create_library": "Kütüphane Aç/Oluştur {shortcut}",
"library.missing": "Lokasyon bulunamadı",
"library.name": "Kütüphane",
- "library.refresh.scanning.plural": "Yeni Dosyalar İçin Dizinler Taranıyor...\n{searched_count} Dosya Tarandı, {found_count} Yeni Dosya Bulundu",
- "library.refresh.scanning.singular": "Yeni Dosyalar için Dizinler Taranıyor...\n{searched_count} Dosya Tarandı, {found_count} Yeni Dosya Bulundu",
- "library.refresh.scanning_preparing": "Yeni Dosyalar için Dizinler Taranıyor...\nHazırlanıyor...",
- "library.refresh.title": "Dizinler Yenileniyor",
"library.scan_library.title": "Kütüphane Taranıyor",
"library_info.stats.entries": "Kayıtlar:",
"library_info.stats.fields": "Ek Bilgiler:",
@@ -185,7 +176,6 @@
"menu.file.open_create_library": "Kütüphane &Aç/Oluştur",
"menu.file.open_library": "Kütüphane Aç",
"menu.file.open_recent_library": "Son Kullanılanları Aç",
- "menu.file.refresh_directories": "Klasörleri &Yenile",
"menu.file.save_backup": "Kütüphane Yedeğini &Kaydet",
"menu.file.save_library": "Kütüphaneyi Kaydet",
"menu.help": "&Yardım",
diff --git a/src/tagstudio/resources/translations/zh_Hans.json b/src/tagstudio/resources/translations/zh_Hans.json
index acf9f408b..0b0e9c338 100644
--- a/src/tagstudio/resources/translations/zh_Hans.json
+++ b/src/tagstudio/resources/translations/zh_Hans.json
@@ -55,16 +55,11 @@
"entries.mirror.window_title": "项目镜像",
"entries.remove.plural.confirm": "您确定要删除以下 {count} 个项目?",
"entries.running.dialog.new_entries": "正在加入 {total} 个新文件项目...",
- "entries.running.dialog.title": "正在加入新文件项目",
"entries.tags": "标签",
- "entries.unlinked.description": "每个仓库条目都链接到一个目录中的文件。如果链接到某个条目的文件在TagStudio之外被移动或删除,则会被视为未链接。