mirror of
https://github.com/TagStudioDev/TagStudio.git
synced 2026-01-30 14:50:47 +00:00
Compare commits
12 Commits
readme-upd
...
pillow-bum
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08a10ef288 | ||
|
|
6397b228eb | ||
|
|
4d882a7156 | ||
|
|
4c0cb1648f | ||
|
|
0529925cd1 | ||
|
|
5dcad418f7 | ||
|
|
615978e5a6 | ||
|
|
e833473c5b | ||
|
|
c9f5347182 | ||
|
|
db7b126725 | ||
|
|
26803b0d42 | ||
|
|
d86a9bfb7b |
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -4,7 +4,8 @@
|
||||
^^^ Summarize the changes done and why they were done above.
|
||||
|
||||
By submitting this pull request, you certify that you have read the
|
||||
[CONTRIBUTING.md](https://github.com/TagStudioDev/TagStudio/blob/main/CONTRIBUTING.md).
|
||||
[Contributing](https://docs.tagstud.io/contributing) page on our documentation site,
|
||||
or in the project's [CONTRIBUTING.md](https://github.com/TagStudioDev/TagStudio/blob/main/docs/contributing.md) file.
|
||||
|
||||
IMPORTANT FOR FEATURES: Please verify that a feature request or some other form
|
||||
of communication with maintainers was already conducted in terms of approving.
|
||||
|
||||
32
.github/workflows/pytest.yaml
vendored
32
.github/workflows/pytest.yaml
vendored
@@ -4,21 +4,24 @@ name: pytest
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
pytest:
|
||||
name: Run pytest
|
||||
pytest-linux:
|
||||
name: Run pytest (Linux)
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
- &checkout
|
||||
name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
- &setup-python
|
||||
name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: pip
|
||||
|
||||
- name: Install Python dependencies
|
||||
- &install-dependencies
|
||||
name: Install Python dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade uv
|
||||
uv pip install --system .[pytest]
|
||||
@@ -52,10 +55,27 @@ jobs:
|
||||
name: coverage
|
||||
path: coverage.xml
|
||||
|
||||
pytest-windows:
|
||||
name: Run pytest (Windows)
|
||||
runs-on: windows-2025
|
||||
|
||||
steps:
|
||||
- *checkout
|
||||
- *setup-python
|
||||
- *install-dependencies
|
||||
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
choco install ripgrep
|
||||
|
||||
- name: Execute pytest
|
||||
run: |
|
||||
pytest
|
||||
|
||||
coverage:
|
||||
name: Check coverage
|
||||
runs-on: ubuntu-latest
|
||||
needs: pytest
|
||||
needs: pytest-linux
|
||||
|
||||
steps:
|
||||
- name: Fetch coverage
|
||||
|
||||
12
flake.lock
generated
12
flake.lock
generated
@@ -7,11 +7,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1756770412,
|
||||
"narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=",
|
||||
"lastModified": 1763759067,
|
||||
"narHash": "sha256-LlLt2Jo/gMNYAwOgdRQBrsRoOz7BPRkzvNaI/fzXi2Q=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "4524271976b625a4a605beefd893f270620fd751",
|
||||
"rev": "2cccadc7357c0ba201788ae99c4dfa90728ef5e0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -22,11 +22,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1757487488,
|
||||
"narHash": "sha256-zwE/e7CuPJUWKdvvTCB7iunV4E/+G0lKfv4kk/5Izdg=",
|
||||
"lastModified": 1763835633,
|
||||
"narHash": "sha256-HzxeGVID5MChuCPESuC0dlQL1/scDKu+MmzoVBJxulM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ab0f3607a6c7486ea22229b92ed2d355f1482ee0",
|
||||
"rev": "050e09e091117c3d7328c7b2b7b577492c43c134",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
qt6,
|
||||
ripgrep,
|
||||
stdenv,
|
||||
wrapGAppsHook,
|
||||
wrapGAppsHook3,
|
||||
|
||||
pillow-jxl-plugin,
|
||||
|
||||
@@ -30,7 +30,7 @@ python3Packages.buildPythonApplication {
|
||||
# Should be unnecessary once PR is pulled.
|
||||
# PR: https://github.com/NixOS/nixpkgs/pull/271037
|
||||
# Issue: https://github.com/NixOS/nixpkgs/issues/149812
|
||||
wrapGAppsHook
|
||||
wrapGAppsHook3
|
||||
];
|
||||
buildInputs = [
|
||||
qt6.qtbase
|
||||
@@ -70,7 +70,7 @@ python3Packages.buildPythonApplication {
|
||||
"\${qtWrapperArgs[@]}"
|
||||
];
|
||||
|
||||
pythonRemoveDeps = lib.optional (!withJXLSupport) [ "pillow_jxl" ];
|
||||
pythonRemoveDeps = lib.optional (!withJXLSupport) "pillow_jxl";
|
||||
pythonRelaxDeps = [
|
||||
"numpy"
|
||||
"pillow"
|
||||
@@ -96,7 +96,6 @@ python3Packages.buildPythonApplication {
|
||||
numpy
|
||||
opencv-python
|
||||
pillow
|
||||
pillow-avif-plugin
|
||||
pillow-heif
|
||||
py7zr
|
||||
pydantic
|
||||
|
||||
@@ -51,7 +51,7 @@ let
|
||||
# Should be unnecessary once PR is pulled.
|
||||
# PR: https://github.com/NixOS/nixpkgs/pull/271037
|
||||
# Issue: https://github.com/NixOS/nixpkgs/issues/149812
|
||||
wrapGAppsHook
|
||||
wrapGAppsHook3
|
||||
];
|
||||
buildInputs = with pkgs.qt6; [
|
||||
qtbase
|
||||
@@ -87,7 +87,7 @@ pkgs.mkShellNoCC {
|
||||
env = {
|
||||
QT_QPA_PLATFORM = "wayland;xcb";
|
||||
|
||||
UV_NO_SYNC = "1";
|
||||
UV_NO_SYNC = 1;
|
||||
UV_PYTHON_DOWNLOADS = "never";
|
||||
};
|
||||
|
||||
@@ -111,7 +111,8 @@ pkgs.mkShellNoCC {
|
||||
fi
|
||||
|
||||
source "''${venv}"/bin/activate
|
||||
PYTHONPATH=${pythonPath}''${PYTHONPATH:+:}''${PYTHONPATH:-}
|
||||
PYTHONPATH=${pythonPath}''${PYTHONPATH:+:''${PYTHONPATH}}
|
||||
export PYTHONPATH
|
||||
|
||||
if [ ! -f "''${venv}"/pyproject.toml ] || ! diff --brief pyproject.toml "''${venv}"/pyproject.toml >/dev/null; then
|
||||
printf '%s\n' 'Installing dependencies, pyproject.toml changed...' >&2
|
||||
|
||||
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
|
||||
[project]
|
||||
name = "TagStudio"
|
||||
description = "A User-Focused Photo & File Management System."
|
||||
version = "9.5.5"
|
||||
version = "9.5.6"
|
||||
license = "GPL-3.0-only"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12,<3.13"
|
||||
@@ -16,8 +16,7 @@ dependencies = [
|
||||
"mutagen~=1.47",
|
||||
"numpy~=2.2",
|
||||
"opencv_python~=4.11",
|
||||
"Pillow>=10.2,<=11",
|
||||
"pillow-avif-plugin~=1.5",
|
||||
"Pillow>=10.2,<12",
|
||||
"pillow-heif~=0.22",
|
||||
"pillow-jxl-plugin~=1.3",
|
||||
"py7zr==1.0.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Licensed under the GPL-3.0 License.
|
||||
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio
|
||||
|
||||
VERSION: str = "9.5.5" # Major.Minor.Patch
|
||||
VERSION: str = "9.5.6" # Major.Minor.Patch
|
||||
VERSION_BRANCH: str = "" # Usually "" or "Pre-Release"
|
||||
|
||||
# The folder & file names where TagStudio keeps its data relative to a library.
|
||||
|
||||
@@ -146,7 +146,7 @@ class SQLBoolExpressionBuilder(BaseVisitor[ColumnElement[bool]]):
|
||||
def __separate_tags(
|
||||
self, terms: list[AST], only_single: bool = True
|
||||
) -> tuple[list[int], list[ColumnElement[bool]]]:
|
||||
tag_ids: list[int] = []
|
||||
tag_ids: set[int] = set()
|
||||
bool_expressions: list[ColumnElement[bool]] = []
|
||||
|
||||
for term in terms:
|
||||
@@ -154,7 +154,7 @@ class SQLBoolExpressionBuilder(BaseVisitor[ColumnElement[bool]]):
|
||||
match term.type:
|
||||
case ConstraintType.TagID:
|
||||
try:
|
||||
tag_ids.append(int(term.value))
|
||||
tag_ids.add(int(term.value))
|
||||
except ValueError:
|
||||
logger.error(
|
||||
"[SQLBoolExpressionBuilder] Could not cast value to an int Tag ID",
|
||||
@@ -164,10 +164,10 @@ class SQLBoolExpressionBuilder(BaseVisitor[ColumnElement[bool]]):
|
||||
case ConstraintType.Tag:
|
||||
ids = self.__get_tag_ids(term.value)
|
||||
if not only_single:
|
||||
tag_ids.extend(ids)
|
||||
tag_ids.update(ids)
|
||||
continue
|
||||
elif len(ids) == 1:
|
||||
tag_ids.append(ids[0])
|
||||
tag_ids.add(ids[0])
|
||||
continue
|
||||
case ConstraintType.FileType:
|
||||
pass
|
||||
@@ -179,7 +179,7 @@ class SQLBoolExpressionBuilder(BaseVisitor[ColumnElement[bool]]):
|
||||
raise NotImplementedError(f"Unhandled constraint: '{term.type}'")
|
||||
|
||||
bool_expressions.append(self.visit(term))
|
||||
return tag_ids, bool_expressions
|
||||
return list(tag_ids), bool_expressions
|
||||
|
||||
def __entry_has_all_tags(self, tag_ids: list[int]) -> ColumnElement[bool]:
|
||||
"""Returns Binary Expression that is true if the Entry has all provided tag ids."""
|
||||
|
||||
@@ -17,6 +17,7 @@ from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.core.library.alchemy.models import Entry
|
||||
from tagstudio.core.library.ignore import PATH_GLOB_FLAGS, Ignore, ignore_to_glob
|
||||
from tagstudio.core.utils.silent_subprocess import silent_run # pyright: ignore
|
||||
from tagstudio.core.utils.types import unwrap
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -30,24 +31,27 @@ class RefreshTracker:
|
||||
def files_count(self) -> int:
|
||||
return len(self.files_not_in_library)
|
||||
|
||||
def save_new_files(self):
|
||||
def save_new_files(self) -> Iterator[int]:
|
||||
"""Save the list of files that are not in the library."""
|
||||
if self.files_not_in_library:
|
||||
batch_size = 200
|
||||
|
||||
index = 0
|
||||
while index < len(self.files_not_in_library):
|
||||
yield index
|
||||
end = min(len(self.files_not_in_library), index + batch_size)
|
||||
entries = [
|
||||
Entry(
|
||||
path=entry_path,
|
||||
folder=self.library.folder, # pyright: ignore[reportArgumentType]
|
||||
folder=unwrap(self.library.folder),
|
||||
fields=[],
|
||||
date_added=dt.now(),
|
||||
)
|
||||
for entry_path in self.files_not_in_library
|
||||
for entry_path in self.files_not_in_library[index:end]
|
||||
]
|
||||
self.library.add_entries(entries)
|
||||
|
||||
index = end
|
||||
self.files_not_in_library = []
|
||||
|
||||
yield
|
||||
|
||||
def refresh_dir(self, library_dir: Path, force_internal_tools: bool = False) -> Iterator[int]:
|
||||
"""Scan a directory for files, and add those relative filenames to internal variables.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from datetime import datetime as dt
|
||||
from warnings import catch_warnings
|
||||
|
||||
import structlog
|
||||
from PySide6.QtCore import Qt, Signal
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QGuiApplication
|
||||
from PySide6.QtWidgets import (
|
||||
QFrame,
|
||||
@@ -22,7 +22,6 @@ from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from tagstudio.core.constants import TAG_ARCHIVED, TAG_FAVORITE
|
||||
from tagstudio.core.enums import Theme
|
||||
from tagstudio.core.library.alchemy.enums import FieldTypeEnum
|
||||
from tagstudio.core.library.alchemy.fields import (
|
||||
@@ -51,9 +50,6 @@ logger = structlog.get_logger(__name__)
|
||||
class FieldContainers(QWidget):
|
||||
"""The Preview Panel Widget."""
|
||||
|
||||
favorite_updated = Signal(bool)
|
||||
archived_updated = Signal(bool)
|
||||
|
||||
def __init__(self, library: Library, driver: "QtDriver"):
|
||||
super().__init__()
|
||||
|
||||
@@ -131,7 +127,7 @@ class FieldContainers(QWidget):
|
||||
container_index += 1
|
||||
container_len += 1
|
||||
if update_badges:
|
||||
self.emit_badge_signals({t.id for t in entry_tags})
|
||||
self.driver.emit_badge_signals({t.id for t in entry_tags})
|
||||
|
||||
# Write field container(s)
|
||||
for index, field in enumerate(entry_fields, start=container_index):
|
||||
@@ -242,7 +238,7 @@ class FieldContainers(QWidget):
|
||||
self.driver.selected,
|
||||
tag_ids=tags,
|
||||
)
|
||||
self.emit_badge_signals(tags, emit_on_absent=False)
|
||||
self.driver.emit_badge_signals(tags, emit_on_absent=False)
|
||||
|
||||
def write_container(self, index: int, field: BaseField, is_mixed: bool = False):
|
||||
"""Update/Create data for a FieldContainer.
|
||||
@@ -493,16 +489,3 @@ class FieldContainers(QWidget):
|
||||
result = remove_mb.exec_()
|
||||
if result == QMessageBox.ButtonRole.ActionRole.value:
|
||||
callback()
|
||||
|
||||
def emit_badge_signals(self, tag_ids: list[int] | set[int], emit_on_absent: bool = True):
|
||||
"""Emit any connected signals for updating badge icons."""
|
||||
logger.info("[emit_badge_signals] Emitting", tag_ids=tag_ids, emit_on_absent=emit_on_absent)
|
||||
if TAG_ARCHIVED in tag_ids:
|
||||
self.archived_updated.emit(True) # noqa: FBT003
|
||||
elif emit_on_absent:
|
||||
self.archived_updated.emit(False) # noqa: FBT003
|
||||
|
||||
if TAG_FAVORITE in tag_ids:
|
||||
self.favorite_updated.emit(True) # noqa: FBT003
|
||||
elif emit_on_absent:
|
||||
self.favorite_updated.emit(False) # noqa: FBT003
|
||||
|
||||
@@ -304,6 +304,7 @@ class TagSearchPanel(PanelWidget):
|
||||
tag_widget.on_edit.disconnect()
|
||||
tag_widget.on_remove.disconnect()
|
||||
tag_widget.bg_button.clicked.disconnect()
|
||||
tag_widget.search_for_tag_action.triggered.disconnect()
|
||||
|
||||
tag_id = tag.id
|
||||
tag_widget.on_edit.connect(lambda t=tag: self.edit_tag(t))
|
||||
|
||||
@@ -19,7 +19,6 @@ from xml.etree.ElementTree import Element
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
import pillow_avif # noqa: F401 # pyright: ignore[reportUnusedImport]
|
||||
import py7zr
|
||||
import py7zr.io
|
||||
import rarfile
|
||||
|
||||
@@ -23,7 +23,7 @@ LANGUAGES = {
|
||||
"French": "fr",
|
||||
"German": "de",
|
||||
"Hungarian": "hu",
|
||||
# "Italian": "it", # Minimal
|
||||
"Italian": "it",
|
||||
"Japanese": "ja",
|
||||
"Norwegian Bokmål": "nb_NO",
|
||||
"Polish": "pl",
|
||||
|
||||
@@ -177,6 +177,9 @@ class QtDriver(DriverMixin, QObject):
|
||||
|
||||
SIGTERM = Signal()
|
||||
|
||||
favorite_updated = Signal(bool)
|
||||
archived_updated = Signal(bool)
|
||||
|
||||
tag_manager_panel: PanelModal | None = None
|
||||
color_manager_panel: TagColorManager | None = None
|
||||
ignore_modal: PanelModal | None = None
|
||||
@@ -357,8 +360,9 @@ class QtDriver(DriverMixin, QObject):
|
||||
self.tag_manager_panel = PanelModal(
|
||||
widget=TagDatabasePanel(self, self.lib),
|
||||
title=Translations["tag_manager.title"],
|
||||
done_callback=lambda checked=False,
|
||||
s=self.selected: self.main_window.preview_panel.set_selection(s, update_preview=False),
|
||||
done_callback=lambda checked=False: (
|
||||
self.main_window.preview_panel.set_selection(self.selected, update_preview=False)
|
||||
),
|
||||
has_save=False,
|
||||
)
|
||||
|
||||
@@ -369,9 +373,9 @@ class QtDriver(DriverMixin, QObject):
|
||||
self.add_tag_modal = TagSearchModal(self.lib, is_tag_chooser=True)
|
||||
self.add_tag_modal.tsp.set_driver(self)
|
||||
self.add_tag_modal.tsp.tag_chosen.connect(
|
||||
lambda t, s=self.selected: (
|
||||
self.add_tags_to_selected_callback(t),
|
||||
self.main_window.preview_panel.set_selection(s),
|
||||
lambda chosen_tag: (
|
||||
self.add_tags_to_selected_callback([chosen_tag]),
|
||||
self.main_window.preview_panel.set_selection(self.selected),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -559,12 +563,12 @@ class QtDriver(DriverMixin, QObject):
|
||||
|
||||
self.main_window.search_field.textChanged.connect(self.update_completions_list)
|
||||
|
||||
self.main_window.preview_panel.field_containers_widget.archived_updated.connect(
|
||||
self.archived_updated.connect(
|
||||
lambda hidden: self.update_badges(
|
||||
{BadgeType.ARCHIVED: hidden}, origin_id=0, add_tags=False
|
||||
)
|
||||
)
|
||||
self.main_window.preview_panel.field_containers_widget.favorite_updated.connect(
|
||||
self.favorite_updated.connect(
|
||||
lambda hidden: self.update_badges(
|
||||
{BadgeType.FAVORITE: hidden}, origin_id=0, add_tags=False
|
||||
)
|
||||
@@ -800,6 +804,19 @@ class QtDriver(DriverMixin, QObject):
|
||||
)
|
||||
)
|
||||
|
||||
def emit_badge_signals(self, tag_ids: list[int] | set[int], emit_on_absent: bool = True):
|
||||
"""Emit any connected signals for updating badge icons."""
|
||||
logger.info("[emit_badge_signals] Emitting", tag_ids=tag_ids, emit_on_absent=emit_on_absent)
|
||||
if TAG_ARCHIVED in tag_ids:
|
||||
self.archived_updated.emit(True) # noqa: FBT003
|
||||
elif emit_on_absent:
|
||||
self.archived_updated.emit(False) # noqa: FBT003
|
||||
|
||||
if TAG_FAVORITE in tag_ids:
|
||||
self.favorite_updated.emit(True) # noqa: FBT003
|
||||
elif emit_on_absent:
|
||||
self.favorite_updated.emit(False) # noqa: FBT003
|
||||
|
||||
def add_tag_action_callback(self):
|
||||
panel = BuildTagPanel(self.lib)
|
||||
self.modal = PanelModal(
|
||||
@@ -848,9 +865,10 @@ class QtDriver(DriverMixin, QObject):
|
||||
self.main_window.preview_panel.set_selection(self.selected)
|
||||
|
||||
def add_tags_to_selected_callback(self, tag_ids: list[int]):
|
||||
selected = self.selected
|
||||
selected: list[int] = self.selected
|
||||
self.main_window.thumb_layout.add_tags(selected, tag_ids)
|
||||
self.lib.add_tags_to_entries(selected, tag_ids)
|
||||
self.emit_badge_signals(tag_ids)
|
||||
|
||||
def delete_files_callback(self, origin_path: str | Path, origin_id: int | None = None):
|
||||
"""Callback to send on or more files to the system trash.
|
||||
@@ -1048,7 +1066,7 @@ class QtDriver(DriverMixin, QObject):
|
||||
pw.show()
|
||||
|
||||
iterator.value.connect(
|
||||
lambda: (
|
||||
lambda _count: (
|
||||
pw.update_label(
|
||||
Translations.format(
|
||||
"entries.running.dialog.new_entries", total=f"{files_count:n}"
|
||||
|
||||
@@ -1,13 +1,354 @@
|
||||
{
|
||||
"about.config_path": "Percorso di Configurazione",
|
||||
"about.description": "TagStudio è un'applicazione di organizzazione dei file e delle foto che utlizza un sistema di etichette focalizzato sul dare libertà e flessibilità all'utente. Niente programmi o formati proprietari, niente mare di file sidecar, e nessun stravolgimento della struttura del tuo sistema di file.",
|
||||
"about.documentation": "Documentazione",
|
||||
"about.license": "Licenza",
|
||||
"about.module.found": "Trovato",
|
||||
"about.title": "Informazioni su TagStudio",
|
||||
"about.website": "Sito web",
|
||||
"app.git": "Git Commit",
|
||||
"app.pre_release": "Pre-rilascio",
|
||||
"app.title": "{base_title} - Biblioteca '{library_dir}'",
|
||||
"color.color_border": "Usa Colore Secondario per il Bordo",
|
||||
"color.confirm_delete": "Sei sicuro di voler eliminare il colore \"{color_name}\"?",
|
||||
"color.delete": "Elimina Etichetta",
|
||||
"color.import_pack": "Importa Pacchetto di Colori",
|
||||
"color.name": "Nome",
|
||||
"color.namespace.delete.prompt": "Sei sicuro di voler eliminare questo spazio dei nomi dei colori? Questo eliminerà TUTTI i colori contenuti nello spazio dei nomi insieme ad esso!",
|
||||
"color.namespace.delete.title": "Elimina Spazio dei Nomi dei Colori",
|
||||
"color.new": "Nuovo Colore",
|
||||
"color.placeholder": "Colore",
|
||||
"color.primary": "Colore Primario",
|
||||
"color.primary_required": "Colore Primario (Obbligatorio)",
|
||||
"color.secondary": "Colore Secondario",
|
||||
"color.title.no_color": "Nessun Colore",
|
||||
"color_manager.title": "Gestisci Colori dei Tag",
|
||||
"dependency.missing.title": "{dependency} Non Trovata",
|
||||
"drop_import.description": "I seguenti file corrispondono a percorsi di file che già esistono nella biblioteca",
|
||||
"drop_import.duplicates_choice.plural": "I seguenti {count} file corrispondono a percorsi di file già esistenti nella biblioteca.",
|
||||
"drop_import.duplicates_choice.singular": "Il seguente file corrisponde ad un percorso di file già esistente nella biblioteca.",
|
||||
"drop_import.progress.label.initial": "Importando Nuovi File...",
|
||||
"drop_import.progress.label.plural": "Importando Nuovi File...\n{count} File Importati.{suffix}",
|
||||
"drop_import.progress.label.singular": "Importando Nuovi File...\n1 File Importato.{suffix}",
|
||||
"drop_import.progress.window_title": "Importa File",
|
||||
"drop_import.title": "File in Conflitto",
|
||||
"edit.color_manager": "Gestisci i Colori delle Etichette",
|
||||
"edit.copy_fields": "Copia Campi",
|
||||
"edit.paste_fields": "Incolla Campi",
|
||||
"edit.tag_manager": "Gestisci Etichette",
|
||||
"entries.duplicate.merge": "Unisci Voci Duplicate",
|
||||
"entries.duplicate.merge.label": "Unendo Voci Duplicate...",
|
||||
"entries.duplicate.refresh": "Ricarica Voci Duplicate",
|
||||
"entries.duplicates.description": "Le voci duplicate sono definite come molteplici voci che puntano allo stesso file sul disco. Unendole verranno combinate le etichette ed i metadati da tutti i duplicati in una singola voce consolidata. Quese non devono essere confuse con i \"file duplicati\", che sono duplicati dei tuoi file stessi al di fuori di TagStudio.",
|
||||
"entries.generic.refresh_alt": "&Ricarica",
|
||||
"entries.generic.remove.removing": "Rimuovendo Voci",
|
||||
"entries.generic.remove.removing_count": "Rimozione di {count} Voci...",
|
||||
"entries.ignored.description": "Le voci dei file sono considerare \"ignorate\" se sono state aggiunte alla biblioteca prima che le regole di ignoranza dell'utente (attraverso il file '.ts_ignore') siano state aggiornate per escluderle. I file ignorati sono tenuti nella biblioteca, per impostazione predefinita, per prevenire perdite accidentali di dati durante l'aggiornamento delle regole di ignoranza.",
|
||||
"entries.ignored.ignored_count": "Voci Ignorate: {count}",
|
||||
"entries.ignored.remove": "Rimuovi Voci Ignorate",
|
||||
"entries.ignored.remove_alt": "Rimuo&vi Voci Ignorate",
|
||||
"entries.ignored.scanning": "Scansione della Biblioteca in cerca di Voci Ignorate...",
|
||||
"entries.ignored.title": "Correggi Voci Ignorate",
|
||||
"entries.mirror": "&Replica",
|
||||
"entries.mirror.confirmation": "Sei sicuro di voler replicare le seguenti {count} voci?",
|
||||
"entries.mirror.label": "Replicazione {idx}/{total} Voci...",
|
||||
"entries.mirror.title": "Replicazione Voci",
|
||||
"entries.mirror.window_title": "Replica Voci",
|
||||
"entries.remove.plural.confirm": "Sei sicuro di voler rimuovere queste <b>{count}</b> 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.<br><br>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.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.description": "FFmpeg e/o FFprobe non sono stati trovati. FFmpeg è necessario per la riproduzione multimediale e per le miniature.",
|
||||
"ffmpeg.missing.status": "{ffmpeg}: {ffmpeg_status}<br>{ffprobe}: {ffprobe_status}",
|
||||
"field.copy": "Copia Campo",
|
||||
"field.edit": "Modifica Campo",
|
||||
"field.paste": "Incolla Campo",
|
||||
"file.date_added": "Data Aggiunta",
|
||||
"file.date_created": "Data di Creazione",
|
||||
"file.date_modified": "Data di Modifica",
|
||||
"file.dimensions": "Dimensioni",
|
||||
"file.duplicates.description": "TagStudio supporta l'importazione di risultati di DupeGuru per gestire file duplicati.",
|
||||
"file.duplicates.dupeguru.advice": "Dopo la replicazione, sei libero di usare DupeGuru per eliminare i file indesiderati. Dopodiché, usa la funzione \"Correggi Voci non Collegate\" di TagStudio nel menu Strumenti per eliminare le voci non collegate.",
|
||||
"file.duplicates.dupeguru.file_extension": "File di DupeGuru (*.dupeguru)",
|
||||
"file.duplicates.dupeguru.load_file": "&Carica File di DupeGuru",
|
||||
"file.duplicates.dupeguru.no_file": "Nessun File DupeGuru Selezionato",
|
||||
"file.duplicates.dupeguru.open_file": "Apri il File dei Risulati di DupeGuru",
|
||||
"file.duplicates.fix": "Corregi File Duplicati",
|
||||
"file.duplicates.matches": "File Duplicati Corrispondenti: {count}",
|
||||
"file.duplicates.matches_uninitialized": "File Duplicati Corrispondenti: N/A",
|
||||
"file.duplicates.mirror_entries": "&Replica Voci",
|
||||
"file.duration": "Lunghezza",
|
||||
"file.not_found": "File Non Trovato",
|
||||
"file.open_file": "Apri file",
|
||||
"file.open_file_with": "Apri file con",
|
||||
"file.open_location.generic": "Mostra file in File Explorer",
|
||||
"file.open_location.mac": "Mostra nel Finder",
|
||||
"file.open_location.windows": "Mostra in File Explorer",
|
||||
"file.path": "Percorso del File",
|
||||
"folders_to_tags.close_all": "Chiudi Tutto",
|
||||
"folders_to_tags.converting": "Conversione delle cartelle in Etichette",
|
||||
"folders_to_tags.description": "Crea Etichette basate sulla struttura delle tue cartelle e le applica alle tue voci.\nLa struttura riportata di seguito mostra tutte le etichette che verranno create ed a che voci verranno applicate.",
|
||||
"folders_to_tags.open_all": "Apri Tutto",
|
||||
"folders_to_tags.title": "Crea Etichette dalle Cartelle",
|
||||
"generic.add": "Aggiungi",
|
||||
"generic.apply": "Applica",
|
||||
"generic.apply_alt": "&Applica",
|
||||
"generic.cancel": "Annulla",
|
||||
"generic.cancel_alt": "&Annulla",
|
||||
"generic.close": "Chiudi",
|
||||
"generic.continue": "Continua",
|
||||
"generic.copy": "Copia",
|
||||
"generic.cut": "Taglia",
|
||||
"generic.delete": "Elimina",
|
||||
"generic.recent_libraries": "Librerias Recenti",
|
||||
"generic.delete_alt": "&Elimina",
|
||||
"generic.done": "Fatto",
|
||||
"generic.done_alt": "&Fatto",
|
||||
"generic.edit": "Modifica",
|
||||
"generic.edit_alt": "&Modifica",
|
||||
"generic.filename": "Nome File",
|
||||
"generic.missing": "Mancante",
|
||||
"generic.navigation.back": "Indietro",
|
||||
"generic.navigation.next": "Prossimo",
|
||||
"generic.no": "No",
|
||||
"generic.none": "Nessuno",
|
||||
"generic.overwrite": "Sovrascrivi",
|
||||
"generic.overwrite_alt": "&Sovrascrivi",
|
||||
"generic.paste": "Incolla",
|
||||
"generic.recent_libraries": "Biblioteche Recenti",
|
||||
"generic.remove": "Rimuovi",
|
||||
"generic.remove_alt": "&RImuovi",
|
||||
"generic.rename": "Rinomina",
|
||||
"generic.rename_alt": "&Rinomina",
|
||||
"generic.reset": "Ripristina",
|
||||
"generic.save": "Salva",
|
||||
"generic.skip": "Salta",
|
||||
"generic.skip_alt": "&Salta",
|
||||
"generic.yes": "Sì",
|
||||
"home.search": "Cerca",
|
||||
"menu.file": "File",
|
||||
"home.search_entries": "Cerca Voci",
|
||||
"home.search_library": "Cerca Biblioteca",
|
||||
"home.search_tags": "Cerca Etichette",
|
||||
"home.thumbnail_size": "Dimensione Miniature",
|
||||
"home.thumbnail_size.extra_large": "Miniature Molto Grandi",
|
||||
"home.thumbnail_size.large": "Miniature Grandi",
|
||||
"home.thumbnail_size.medium": "Miniature Medie",
|
||||
"home.thumbnail_size.mini": "Miniature Mini",
|
||||
"home.thumbnail_size.small": "Miniature Piccole",
|
||||
"ignore.open_file": "Mostra File \"{ts_ignore}\" su Disco",
|
||||
"json_migration.checking_for_parity": "Controllo della Parità...",
|
||||
"json_migration.creating_database_tables": "Creazione Tabelle di Database SQL...",
|
||||
"json_migration.description": "<br>Avvia e visualizza in anteprima i risultati del processo di migrazione della biblioteca. La biblioteca convertita <i>non</i> verrà utilizzata finché non clicchi su \"Completa Migrazione\". <br><br>I dati della biblioteca devono avere valori corrispondenti o presentare un'etichetta \"Corrispondente\". I valori che non corrispondono saranno visualizzati in rosso e contrassegnati con un simbolo \"<b>(!)</b>\" accanto a loro.<br><center><i>Questo processo può richiedere diversi minuti per biblioteche di grandi dimensioni.</i></center>",
|
||||
"json_migration.discrepancies_found": "Discrepanze Riscontrate nella Biblioteca",
|
||||
"json_migration.discrepancies_found.description": "Sono state riscontrate delle discrepanze tra i formati originali e quelli della biblioteca convertita. Si prega di verificare e scegliere se continuare con la migrazione oppure se annullarla.",
|
||||
"json_migration.finish_migration": "Completa Migrazione",
|
||||
"json_migration.heading.aliases": "Alias:",
|
||||
"json_migration.heading.colors": "Colori:",
|
||||
"json_migration.heading.differ": "Discrepanze",
|
||||
"json_migration.heading.extension_list_type": "Tipo di Lista di Entensioni:",
|
||||
"json_migration.heading.file_extension_list": "Elenco Estensioni dei File:",
|
||||
"json_migration.heading.match": "Abbinato",
|
||||
"json_migration.heading.names": "Nomi:",
|
||||
"json_migration.heading.parent_tags": "Etichette Padre:",
|
||||
"json_migration.heading.paths": "Percorsi:",
|
||||
"json_migration.heading.shorthands": "Abbreviazioni:",
|
||||
"json_migration.migrating_files_entries": "Migrando {entries:,d} Voci di File...",
|
||||
"json_migration.migration_complete": "Migrazione Completata!",
|
||||
"json_migration.migration_complete_with_discrepancies": "Migrazione Completata, Discrepanze Rilevate",
|
||||
"json_migration.start_and_preview": "Avvio ed Anteprima",
|
||||
"json_migration.title": "Salva Formato Migrazione: \"{path}\"",
|
||||
"json_migration.title.new_lib": "<h2>v9.5+ Biblioteca</h2>",
|
||||
"json_migration.title.old_lib": "<h2>v9.4 Biblioteca</h2>",
|
||||
"landing.open_create_library": "Apri/Crea Biblioteca {shortcut}",
|
||||
"library.field.add": "Aggiungi Campo",
|
||||
"library.field.confirm_remove": "Sei sicuro di voler rimuovere il campo \"{name}\"?",
|
||||
"library.field.mixed_data": "Dati Misti",
|
||||
"library.field.remove": "Rimuovi Campo",
|
||||
"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:",
|
||||
"library_info.cleanup.dupe_files": "File Duplicati:",
|
||||
"library_info.cleanup.ignored": "Voci Ignorate:",
|
||||
"library_info.cleanup.unlinked": "Voci non Collegate:",
|
||||
"library_info.stats": "Statistiche",
|
||||
"library_info.stats.colors": "Colori Etichette:",
|
||||
"library_info.stats.entries": "Voci:",
|
||||
"library_info.stats.fields": "Campi:",
|
||||
"library_info.stats.macros": "Macro:",
|
||||
"library_info.stats.namespaces": "Spazi dei Nomi:",
|
||||
"library_info.stats.tags": "Etichette:",
|
||||
"library_info.title": "Biblioteca '{library_dir}'",
|
||||
"library_info.version": "Versione del Formato della Biblioteca: {version}",
|
||||
"library_object.name": "Nome",
|
||||
"library_object.name_required": "Nome (Obbligatorio)",
|
||||
"library_object.slug": "ID Slug",
|
||||
"library_object.slug_required": "ID Slug (Obbligatorio)",
|
||||
"macros.running.dialog.new_entries": "Esecuzione delle Macro Configurate su {count}/{total} Nuove Voci di File...",
|
||||
"macros.running.dialog.title": "Esecuzione delle Macro sulle Nuove Voci",
|
||||
"media_player.autoplay": "Riproduzione Automatica",
|
||||
"media_player.loop": "Metti in Loop",
|
||||
"menu.delete_selected_files_ambiguous": "Sposta File nel {trash_term}",
|
||||
"menu.delete_selected_files_plural": "Sposta Files nel {trash_term}",
|
||||
"menu.delete_selected_files_singular": "Sposta il File nel {trash_term}",
|
||||
"menu.edit": "Modifica",
|
||||
"menu.edit.ignore_files": "Ignora File e Cartelle",
|
||||
"menu.edit.manage_tags": "Gestisci Etichette",
|
||||
"menu.edit.new_tag": "Nuova &Etichetta",
|
||||
"menu.file": "&File",
|
||||
"menu.file.clear_recent_libraries": "Cancella Recenti",
|
||||
"menu.file.close_library": "&Chiudi Biblioteca",
|
||||
"menu.file.missing_library.message": "La posizione della biblioteca \"{library}\" non può essere trovata.",
|
||||
"menu.file.missing_library.title": "Biblioteca Mancante",
|
||||
"menu.file.new_library": "Nuova Biblioteca",
|
||||
"menu.file.open_backups_folder": "Apri Cartella dei Backup",
|
||||
"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",
|
||||
"menu.help.about": "Informazioni",
|
||||
"menu.macros": "&Macro",
|
||||
"menu.macros.folders_to_tags": "Cartelle ad Etichette",
|
||||
"menu.select": "Seleziona",
|
||||
"menu.settings": "Impostazioni...",
|
||||
"menu.tools": "&Strumenti",
|
||||
"menu.tools.fix_duplicate_files": "Coreggi File &Duplicati",
|
||||
"menu.tools.fix_ignored_entries": "Correggi Voci &Ignorate",
|
||||
"menu.tools.fix_unlinked_entries": "Correggi Voci &Scollegate",
|
||||
"menu.view": "&Visualizza",
|
||||
"menu.view.decrease_thumbnail_size": "Riduci Dimensione Miniature",
|
||||
"menu.view.increase_thumbnail_size": "Aumenta Dimensione Miniature",
|
||||
"menu.view.library_info": "&Informazioni Biblioteca",
|
||||
"menu.window": "Finestra",
|
||||
"tag.add": "Aggiungi Tag",
|
||||
"namespace.create.description": "Gli spazi dei nomi sono usati da TagStudio per separare gruppi di elementi come etichette e colori in maniera da facilitarne l'esportazione e la condivisione. Gli spazi dei nomi che iniziano con \"tagstudio\" sono riservati per l'uso interno di TagStudio.",
|
||||
"namespace.create.description_color": "I colori delle etichette usano gli spazi dei nomi come gruppi di tavolozze di colori. Tutti i colori personalizzati devono prima essere inseriti in uno spazio dei nomi.",
|
||||
"namespace.create.title": "Crea Spazio dei Nomi",
|
||||
"namespace.new.button": "Nuovo Spazio dei Nomi",
|
||||
"namespace.new.prompt": "Crea un Nuovo Spazio dei Nomi per Iniziare ad Aggiungere Colori Personalizzati!",
|
||||
"preview.ignored": "Ignorato",
|
||||
"preview.multiple_selection": "<b>{count}</b> Elementi Selezionati",
|
||||
"preview.no_selection": "Nessun Elemento Selezionato",
|
||||
"preview.unlinked": "Scollegato",
|
||||
"select.add_tag_to_selected": "Aggiungi Etichetta alla Selezione",
|
||||
"select.all": "Seleziona Tutto",
|
||||
"select.clear": "Cancella Selezione",
|
||||
"select.inverse": "Inverti Selezione",
|
||||
"settings.clear_thumb_cache.title": "Cancella Cache delle Miniature",
|
||||
"settings.dateformat.english": "Inglese",
|
||||
"settings.dateformat.international": "Internazionale",
|
||||
"settings.dateformat.label": "Formato Data",
|
||||
"settings.dateformat.system": "Sistema",
|
||||
"settings.filepath.label": "Visibilità del Percorso del File",
|
||||
"settings.filepath.option.full": "Mostra Percorsi Completi",
|
||||
"settings.filepath.option.name": "Mostra Solo i Nomi dei File",
|
||||
"settings.filepath.option.relative": "Mostra Percorsi Relativi",
|
||||
"settings.generate_thumbs": "Generazione delle Miniature",
|
||||
"settings.global": "Impostazioni Globali",
|
||||
"settings.hourformat.label": "Formato a 24 Ore",
|
||||
"settings.infinite_scroll": "Scorrimento Infinito",
|
||||
"settings.language": "Lingua",
|
||||
"settings.library": "Impostazioni Biblioteca",
|
||||
"settings.open_library_on_start": "Apri Biblioteca all'Avvio",
|
||||
"settings.page_size": "Dimensione Pagina",
|
||||
"settings.restart_required": "Riavvia TagStudio affinchè le modifiche abbiano effetto.",
|
||||
"settings.show_filenames_in_grid": "Mostra Nomi dei File nella Griglia",
|
||||
"settings.show_recent_libraries": "Mostra Biblioteche Recenti",
|
||||
"settings.splash.label": "Schermata Iniziale",
|
||||
"settings.splash.option.classic": "Classico (9.0)",
|
||||
"settings.splash.option.default": "Predefinito",
|
||||
"settings.splash.option.goo_gears": "Open Source (9.4)",
|
||||
"settings.splash.option.ninety_five": "'95 (9.5)",
|
||||
"settings.splash.option.random": "Casuale",
|
||||
"settings.tag_click_action.add_to_search": "Aggiungi Etichette alla Ricerca",
|
||||
"settings.tag_click_action.label": "Azione di Clic sulle Etichette",
|
||||
"settings.tag_click_action.open_edit": "Modifica Etichetta",
|
||||
"settings.tag_click_action.set_search": "Cerca Etichetta",
|
||||
"settings.theme.dark": "Scuro",
|
||||
"settings.theme.label": "Tema:",
|
||||
"settings.theme.light": "Chiaro",
|
||||
"settings.theme.system": "Sistema",
|
||||
"settings.thumb_cache_size.label": "Dimensione Cache delle Miniature",
|
||||
"settings.title": "Impostazioni",
|
||||
"sorting.direction.ascending": "Ascendente",
|
||||
"sorting.direction.descending": "Discendente",
|
||||
"sorting.mode.random": "Casuale",
|
||||
"splash.opening_library": "Aprendo Biblioteca \"{library_path}\"...",
|
||||
"status.deleted_file_plural": "{count} file eliminati!",
|
||||
"status.deleted_file_singular": "1 file eliminato!",
|
||||
"status.deleted_none": "Nessun file eliminato.",
|
||||
"status.deleted_partial_warning": "Solo {count} file sono stati eliminati! Verifica se alcuni dei file sono attualmente mancanti o in uso.",
|
||||
"status.deleting_file": "Eliminano file [{i}/{count}]: \"{path}\"...",
|
||||
"status.library_backup_in_progress": "Salvataggio Backup della Biblioteca...",
|
||||
"status.library_backup_success": "Backup della BIblioteca Salvato in: \"{path}\" ({time_span})",
|
||||
"status.library_closed": "Biblioteca Chiusa ({time_span})",
|
||||
"status.library_closing": "Chiudendo la Biblioteca...",
|
||||
"status.library_save_success": "Biblioteca Salvata e Chiusa!",
|
||||
"status.library_search_query": "Cercando nella Biblioteca...",
|
||||
"status.library_version_expected": "Previsto:",
|
||||
"status.library_version_found": "Trovato:",
|
||||
"status.library_version_mismatch": "Versione della Biblioteca non Corrispondente!",
|
||||
"status.results": "Risultati",
|
||||
"status.results.invalid_syntax": "Sintassi di Ricerca Non Valida:",
|
||||
"status.results_found": "{count} Risultati Trovati ({time_span})",
|
||||
"tag.add": "Aggiungi Etichetta",
|
||||
"tag.add.plural": "Aggiungi Etichette",
|
||||
"tag.add_to_search": "Aggiungi alla Ricerca",
|
||||
"tag.aliases": "Alias",
|
||||
"tag.all_tags": "Tutte le Etichette",
|
||||
"tag.choose_color": "Scegli Colore dell'Etichetta",
|
||||
"tag.color": "Colore",
|
||||
"tag.confirm_delete": "Sei sicuro di voler eliminare l'etichetta \"{tag_name}\"?",
|
||||
"tag.create": "Crea Etichetta",
|
||||
"tag.create_add": "Crea && Aggiungi \"{query}\"",
|
||||
"tag.disambiguation.tooltip": "Usa questa etichetta per la disambiguazione",
|
||||
"tag.edit": "Modifica Etichetta",
|
||||
"tag.is_category": "È Categoria",
|
||||
"tag.name": "Nome",
|
||||
"tag.new": "Nuovo Tag"
|
||||
"tag.new": "Nuova Etichetta",
|
||||
"tag.parent_tags.add": "Aggiungi Etichette Padre",
|
||||
"tag.parent_tags.description": "Questa etichetta può essere considerata come sostitutiva di qualunque di queste Etichette Padre nelle richerche.",
|
||||
"tag.remove": "Rimuovi Etichetta",
|
||||
"tag.search_for_tag": "Cerca Etichetta",
|
||||
"tag.shorthand": "Abbreviazione",
|
||||
"tag.tag_name_required": "Nome Etichetta (Obbligatorio)",
|
||||
"tag.view_limit": "Limite di Visualizzazione:",
|
||||
"tag_manager.title": "Etichette della Biblioteca",
|
||||
"trash.context.ambiguous": "Sposta file(s) in {trash_term}",
|
||||
"trash.context.plural": "Sposta files in {trash_term}",
|
||||
"trash.context.singular": "Sposta file in {trash_term}",
|
||||
"trash.dialog.disambiguation_warning.plural": "Questo li rimuoverà da TagStudio <i>E</i> dal tuo sistema di file!",
|
||||
"trash.dialog.disambiguation_warning.singular": "Questo lo rimuoverà da TagStudio <i>E</i> dal tuo sistema di file!",
|
||||
"trash.dialog.move.confirmation.plural": "Sei sicuro di voler spostare questi {count} file nel {trash_term}?",
|
||||
"trash.dialog.move.confirmation.singular": "Sei sicuro di voler spostare questo file nel {trash_term}?",
|
||||
"trash.dialog.permanent_delete_warning": "<b>ATTENZIONE!</b> Se questo file non può essere spostato nel {trash_term}, verrà <b>eliminato permanentemente!</b>",
|
||||
"trash.dialog.title.plural": "Elimina Files",
|
||||
"trash.dialog.title.singular": "Elimina File",
|
||||
"trash.name.generic": "Spazzatura",
|
||||
"trash.name.windows": "Cestino",
|
||||
"view.size.0": "Mini",
|
||||
"view.size.1": "Piccolo",
|
||||
"view.size.2": "Medio",
|
||||
"view.size.3": "Grande",
|
||||
"view.size.4": "Molto Grande",
|
||||
"window.message.error_opening_library": "Errore nell'apertura della biblioteca.",
|
||||
"window.title.error": "Errore",
|
||||
"window.title.open_create_library": "Apri/Crea Biblioteca"
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# Copyright (C) 2025
|
||||
# Licensed under the GPL-3.0 License.
|
||||
# Created for TagStudio: https://github.com/CyanVoxel/TagStudio
|
||||
|
||||
|
||||
from PySide6.QtCore import SIGNAL
|
||||
from pytestqt.qtbot import QtBot
|
||||
|
||||
from tagstudio.core.library.alchemy.library import Library
|
||||
from tagstudio.qt.mixed.tag_search import TagSearchPanel
|
||||
from tagstudio.qt.mixed.tag_widget import TagWidget
|
||||
from tagstudio.qt.ts_qt import QtDriver
|
||||
|
||||
|
||||
def test_update_tags(qtbot: QtBot, library: Library):
|
||||
@@ -17,3 +18,35 @@ def test_update_tags(qtbot: QtBot, library: Library):
|
||||
|
||||
# When
|
||||
panel.update_tags()
|
||||
|
||||
|
||||
def test_tag_widget_actions_replaced_correctly(qtbot: QtBot, qt_driver: QtDriver, library: Library):
|
||||
panel = TagSearchPanel(library)
|
||||
qtbot.addWidget(panel)
|
||||
panel.driver = qt_driver
|
||||
|
||||
# Set the widget
|
||||
tags = library.tags
|
||||
panel.set_tag_widget(tags[0], 0)
|
||||
tag_widget: TagWidget = panel.scroll_layout.itemAt(0).widget()
|
||||
|
||||
should_replace_actions = {
|
||||
tag_widget: ["on_edit()", "on_remove()"],
|
||||
tag_widget.bg_button: ["clicked()"],
|
||||
tag_widget.search_for_tag_action: ["triggered()"],
|
||||
}
|
||||
|
||||
# Ensure each action has been set
|
||||
ensure_one_receiver_per_action(should_replace_actions)
|
||||
|
||||
# Set the widget again
|
||||
panel.set_tag_widget(tags[0], 0)
|
||||
|
||||
# Ensure each action has been replaced (amount of receivers is still 1)
|
||||
ensure_one_receiver_per_action(should_replace_actions)
|
||||
|
||||
|
||||
def ensure_one_receiver_per_action(should_replace_actions):
|
||||
for action, signal_strings in should_replace_actions.items():
|
||||
for signal_str in signal_strings:
|
||||
assert action.receivers(SIGNAL(signal_str)) == 1
|
||||
|
||||
Reference in New Issue
Block a user