mirror of
https://github.com/arsenetar/dupeguru.git
synced 2026-01-25 16:11:39 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2dbf8b80ae | ||
|
|
470cd92030 | ||
|
|
111edc3ce5 | ||
|
|
df30a31782 | ||
|
|
91f3a59523 | ||
|
|
3441e51c0e | ||
|
|
a99c40b5d8 | ||
|
|
5b4de58c38 | ||
|
|
cd83b16dbd | ||
|
|
b67db988ab | ||
|
|
7ebea44cb0 |
1
.hgtags
1
.hgtags
@@ -78,3 +78,4 @@ c3d9f91dc9c9d60f370c72bc211f09be3e4fc18d se3.5.0
|
|||||||
e772f1de86744999ffbbe5845554417965b1dfba me6.4.1
|
e772f1de86744999ffbbe5845554417965b1dfba me6.4.1
|
||||||
c8a9a4d355927e509f514308c82306192bc71f92 pe2.6.0
|
c8a9a4d355927e509f514308c82306192bc71f92 pe2.6.0
|
||||||
a618e954f01e4bbdbe9a03e5667a67d62be995a7 me6.4.2
|
a618e954f01e4bbdbe9a03e5667a67d62be995a7 me6.4.2
|
||||||
|
0f18c4498a6c7529bf77207db70aed8a5ec96ee4 se3.6.0
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ from appscript import app, its, k, CommandError, ApplicationNotFoundError
|
|||||||
from . import tunes
|
from . import tunes
|
||||||
|
|
||||||
from cocoa import as_fetch, proxy
|
from cocoa import as_fetch, proxy
|
||||||
from hscommon import io
|
|
||||||
from hscommon.trans import trget
|
from hscommon.trans import trget
|
||||||
from hscommon.path import Path
|
from hscommon.path import Path
|
||||||
from hscommon.util import remove_invalid_xml
|
from hscommon.util import remove_invalid_xml
|
||||||
@@ -78,21 +77,21 @@ def get_itunes_database_path():
|
|||||||
return Path(plistpath)
|
return Path(plistpath)
|
||||||
|
|
||||||
def get_itunes_songs(plistpath):
|
def get_itunes_songs(plistpath):
|
||||||
if not io.exists(plistpath):
|
if not plistpath.exists():
|
||||||
return []
|
return []
|
||||||
s = io.open(plistpath, 'rt', encoding='utf-8').read()
|
s = plistpath.open('rt', encoding='utf-8').read()
|
||||||
# iTunes sometimes produces XML files with invalid characters in it.
|
# iTunes sometimes produces XML files with invalid characters in it.
|
||||||
s = remove_invalid_xml(s, replace_with='')
|
s = remove_invalid_xml(s, replace_with='')
|
||||||
plist = plistlib.readPlistFromBytes(s.encode('utf-8'))
|
plist = plistlib.readPlistFromBytes(s.encode('utf-8'))
|
||||||
result = []
|
result = []
|
||||||
for song_data in plist['Tracks'].values():
|
for song_data in plist['Tracks'].values():
|
||||||
if song_data['Track Type'] != 'File':
|
|
||||||
continue
|
|
||||||
try:
|
try:
|
||||||
|
if song_data['Track Type'] != 'File':
|
||||||
|
continue
|
||||||
song = ITunesSong(song_data)
|
song = ITunesSong(song_data)
|
||||||
except KeyError: # No "Location" or "Track ID" key in track
|
except KeyError: # No "Track Type", "Location" or "Track ID" key in track
|
||||||
continue
|
continue
|
||||||
if io.exists(song.path):
|
if song.path.exists():
|
||||||
result.append(song)
|
result.append(song)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import time
|
|||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from send2trash import send2trash
|
from send2trash import send2trash
|
||||||
from hscommon import io
|
|
||||||
from hscommon.reg import RegistrableApplication
|
from hscommon.reg import RegistrableApplication
|
||||||
from hscommon.notify import Broadcaster
|
from hscommon.notify import Broadcaster
|
||||||
from hscommon.path import Path
|
from hscommon.path import Path
|
||||||
@@ -168,7 +167,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
self.results.perform_on_marked(op, True)
|
self.results.perform_on_marked(op, True)
|
||||||
|
|
||||||
def _do_delete_dupe(self, dupe, link_deleted, use_hardlinks, direct_deletion):
|
def _do_delete_dupe(self, dupe, link_deleted, use_hardlinks, direct_deletion):
|
||||||
if not io.exists(dupe.path):
|
if not dupe.path.exists():
|
||||||
return
|
return
|
||||||
logging.debug("Sending '%s' to trash", dupe.path)
|
logging.debug("Sending '%s' to trash", dupe.path)
|
||||||
str_path = str(dupe.path)
|
str_path = str(dupe.path)
|
||||||
@@ -253,7 +252,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
result = []
|
result = []
|
||||||
for file in files:
|
for file in files:
|
||||||
try:
|
try:
|
||||||
inode = io.stat(file.path).st_ino
|
inode = file.path.stat().st_ino
|
||||||
except OSError:
|
except OSError:
|
||||||
# The file was probably deleted or something
|
# The file was probably deleted or something
|
||||||
continue
|
continue
|
||||||
@@ -324,8 +323,8 @@ class DupeGuru(RegistrableApplication, Broadcaster):
|
|||||||
if dest_type == DestType.Relative:
|
if dest_type == DestType.Relative:
|
||||||
source_base = source_base[location_path:]
|
source_base = source_base[location_path:]
|
||||||
dest_path = dest_path + source_base
|
dest_path = dest_path + source_base
|
||||||
if not io.exists(dest_path):
|
if not dest_path.exists():
|
||||||
io.makedirs(dest_path)
|
dest_path.makedirs()
|
||||||
# Add filename to dest_path. For file move/copy, it's not required, but for folders, yes.
|
# Add filename to dest_path. For file move/copy, it's not required, but for folders, yes.
|
||||||
dest_path = dest_path + source_path[-1]
|
dest_path = dest_path + source_path[-1]
|
||||||
logging.debug("Copy/Move operation from '%s' to '%s'", source_path, dest_path)
|
logging.debug("Copy/Move operation from '%s' to '%s'", source_path, dest_path)
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ from xml.etree import ElementTree as ET
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from jobprogress import job
|
from jobprogress import job
|
||||||
from hscommon import io
|
|
||||||
from hscommon.path import Path
|
from hscommon.path import Path
|
||||||
from hscommon.util import FileOrPath
|
from hscommon.util import FileOrPath
|
||||||
|
|
||||||
@@ -73,9 +72,9 @@ class Directories:
|
|||||||
file.is_ref = state == DirectoryState.Reference
|
file.is_ref = state == DirectoryState.Reference
|
||||||
filepaths.add(file.path)
|
filepaths.add(file.path)
|
||||||
yield file
|
yield file
|
||||||
subpaths = [from_path + name for name in io.listdir(from_path)]
|
subpaths = [from_path + name for name in from_path.listdir()]
|
||||||
# it's possible that a folder (bundle) gets into the file list. in that case, we don't want to recurse into it
|
# it's possible that a folder (bundle) gets into the file list. in that case, we don't want to recurse into it
|
||||||
subfolders = [p for p in subpaths if not io.islink(p) and io.isdir(p) and p not in filepaths]
|
subfolders = [p for p in subpaths if not p.islink() and p.isdir() and p not in filepaths]
|
||||||
for subfolder in subfolders:
|
for subfolder in subfolders:
|
||||||
for file in self._get_files(subfolder, j):
|
for file in self._get_files(subfolder, j):
|
||||||
yield file
|
yield file
|
||||||
@@ -106,7 +105,7 @@ class Directories:
|
|||||||
"""
|
"""
|
||||||
if path in self:
|
if path in self:
|
||||||
raise AlreadyThereError()
|
raise AlreadyThereError()
|
||||||
if not io.exists(path):
|
if not path.exists():
|
||||||
raise InvalidPathError()
|
raise InvalidPathError()
|
||||||
self._dirs = [p for p in self._dirs if p not in path]
|
self._dirs = [p for p in self._dirs if p not in path]
|
||||||
self._dirs.append(path)
|
self._dirs.append(path)
|
||||||
@@ -115,7 +114,7 @@ class Directories:
|
|||||||
def get_subfolders(path):
|
def get_subfolders(path):
|
||||||
"""returns a sorted list of paths corresponding to subfolders in `path`"""
|
"""returns a sorted list of paths corresponding to subfolders in `path`"""
|
||||||
try:
|
try:
|
||||||
names = [name for name in io.listdir(path) if io.isdir(path + name)]
|
names = [name for name in path.listdir() if (path + name).isdir()]
|
||||||
names.sort(key=lambda x:x.lower())
|
names.sort(key=lambda x:x.lower())
|
||||||
return [path + name for name in names]
|
return [path + name for name in names]
|
||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
|
|||||||
25
core/fs.py
25
core/fs.py
@@ -14,7 +14,6 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from hscommon import io
|
|
||||||
from hscommon.util import nonone, get_file_ext
|
from hscommon.util import nonone, get_file_ext
|
||||||
|
|
||||||
NOT_SET = object()
|
NOT_SET = object()
|
||||||
@@ -89,12 +88,12 @@ class File:
|
|||||||
|
|
||||||
def _read_info(self, field):
|
def _read_info(self, field):
|
||||||
if field in ('size', 'mtime'):
|
if field in ('size', 'mtime'):
|
||||||
stats = io.stat(self.path)
|
stats = self.path.stat()
|
||||||
self.size = nonone(stats.st_size, 0)
|
self.size = nonone(stats.st_size, 0)
|
||||||
self.mtime = nonone(stats.st_mtime, 0)
|
self.mtime = nonone(stats.st_mtime, 0)
|
||||||
elif field == 'md5partial':
|
elif field == 'md5partial':
|
||||||
try:
|
try:
|
||||||
fp = io.open(self.path, 'rb')
|
fp = self.path.open('rb')
|
||||||
offset, size = self._get_md5partial_offset_and_size()
|
offset, size = self._get_md5partial_offset_and_size()
|
||||||
fp.seek(offset)
|
fp.seek(offset)
|
||||||
partialdata = fp.read(size)
|
partialdata = fp.read(size)
|
||||||
@@ -105,7 +104,7 @@ class File:
|
|||||||
pass
|
pass
|
||||||
elif field == 'md5':
|
elif field == 'md5':
|
||||||
try:
|
try:
|
||||||
fp = io.open(self.path, 'rb')
|
fp = self.path.open('rb')
|
||||||
md5 = hashlib.md5()
|
md5 = hashlib.md5()
|
||||||
CHUNK_SIZE = 8192
|
CHUNK_SIZE = 8192
|
||||||
filedata = fp.read(CHUNK_SIZE)
|
filedata = fp.read(CHUNK_SIZE)
|
||||||
@@ -130,19 +129,19 @@ class File:
|
|||||||
#--- Public
|
#--- Public
|
||||||
@classmethod
|
@classmethod
|
||||||
def can_handle(cls, path):
|
def can_handle(cls, path):
|
||||||
return not io.islink(path) and io.isfile(path)
|
return not path.islink() and path.isfile()
|
||||||
|
|
||||||
def rename(self, newname):
|
def rename(self, newname):
|
||||||
if newname == self.name:
|
if newname == self.name:
|
||||||
return
|
return
|
||||||
destpath = self.path[:-1] + newname
|
destpath = self.path[:-1] + newname
|
||||||
if io.exists(destpath):
|
if destpath.exists():
|
||||||
raise AlreadyExistsError(newname, self.path[:-1])
|
raise AlreadyExistsError(newname, self.path[:-1])
|
||||||
try:
|
try:
|
||||||
io.rename(self.path, destpath)
|
self.path.rename(destpath)
|
||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
raise OperationError(self)
|
raise OperationError(self)
|
||||||
if not io.exists(destpath):
|
if not destpath.exists():
|
||||||
raise OperationError(self)
|
raise OperationError(self)
|
||||||
self.path = destpath
|
self.path = destpath
|
||||||
|
|
||||||
@@ -180,7 +179,7 @@ class Folder(File):
|
|||||||
if field in {'size', 'mtime'}:
|
if field in {'size', 'mtime'}:
|
||||||
size = sum((f.size for f in self._all_items()), 0)
|
size = sum((f.size for f in self._all_items()), 0)
|
||||||
self.size = size
|
self.size = size
|
||||||
stats = io.stat(self.path)
|
stats = self.path.stat()
|
||||||
self.mtime = nonone(stats.st_mtime, 0)
|
self.mtime = nonone(stats.st_mtime, 0)
|
||||||
elif field in {'md5', 'md5partial'}:
|
elif field in {'md5', 'md5partial'}:
|
||||||
# What's sensitive here is that we must make sure that subfiles'
|
# What's sensitive here is that we must make sure that subfiles'
|
||||||
@@ -199,14 +198,14 @@ class Folder(File):
|
|||||||
@property
|
@property
|
||||||
def subfolders(self):
|
def subfolders(self):
|
||||||
if self._subfolders is None:
|
if self._subfolders is None:
|
||||||
subpaths = [self.path + name for name in io.listdir(self.path)]
|
subpaths = [self.path + name for name in self.path.listdir()]
|
||||||
subfolders = [p for p in subpaths if not io.islink(p) and io.isdir(p)]
|
subfolders = [p for p in subpaths if not p.islink() and p.isdir()]
|
||||||
self._subfolders = [Folder(p) for p in subfolders]
|
self._subfolders = [Folder(p) for p in subfolders]
|
||||||
return self._subfolders
|
return self._subfolders
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def can_handle(cls, path):
|
def can_handle(cls, path):
|
||||||
return not io.islink(path) and io.isdir(path)
|
return not path.islink() and path.isdir()
|
||||||
|
|
||||||
|
|
||||||
def get_file(path, fileclasses=[File]):
|
def get_file(path, fileclasses=[File]):
|
||||||
@@ -225,7 +224,7 @@ def get_files(path, fileclasses=[File]):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
try:
|
try:
|
||||||
paths = [combine_paths(path, name) for name in io.listdir(path)]
|
paths = [combine_paths(path, name) for name in path.listdir()]
|
||||||
result = []
|
result = []
|
||||||
for path in paths:
|
for path in paths:
|
||||||
file = get_file(path, fileclasses=fileclasses)
|
file = get_file(path, fileclasses=fileclasses)
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import re
|
|||||||
import os.path as op
|
import os.path as op
|
||||||
|
|
||||||
from jobprogress import job
|
from jobprogress import job
|
||||||
from hscommon import io
|
|
||||||
from hscommon.util import dedupe, rem_file_ext, get_file_ext
|
from hscommon.util import dedupe, rem_file_ext, get_file_ext
|
||||||
from hscommon.trans import tr
|
from hscommon.trans import tr
|
||||||
|
|
||||||
@@ -129,6 +128,11 @@ class Scanner:
|
|||||||
matches = self._getmatches(files, j)
|
matches = self._getmatches(files, j)
|
||||||
logging.info('Found %d matches' % len(matches))
|
logging.info('Found %d matches' % len(matches))
|
||||||
j.set_progress(100, tr("Removing false matches"))
|
j.set_progress(100, tr("Removing false matches"))
|
||||||
|
# In removing what we call here "false matches", we first want to remove, if we scan by
|
||||||
|
# folders, we want to remove folder matches for which the parent is also in a match (they're
|
||||||
|
# "duplicated duplicates if you will). Then, we also don't want mixed file kinds if the
|
||||||
|
# option isn't enabled, we want matches for which both files exist and, lastly, we don't
|
||||||
|
# want matches with both files as ref.
|
||||||
if self.scan_type == ScanType.Folders and matches:
|
if self.scan_type == ScanType.Folders and matches:
|
||||||
allpath = {m.first.path for m in matches}
|
allpath = {m.first.path for m in matches}
|
||||||
allpath |= {m.second.path for m in matches}
|
allpath |= {m.second.path for m in matches}
|
||||||
@@ -143,7 +147,8 @@ class Scanner:
|
|||||||
matches = [m for m in matches if m.first.path not in toremove or m.second.path not in toremove]
|
matches = [m for m in matches if m.first.path not in toremove or m.second.path not in toremove]
|
||||||
if not self.mix_file_kind:
|
if not self.mix_file_kind:
|
||||||
matches = [m for m in matches if get_file_ext(m.first.name) == get_file_ext(m.second.name)]
|
matches = [m for m in matches if get_file_ext(m.first.name) == get_file_ext(m.second.name)]
|
||||||
matches = [m for m in matches if io.exists(m.first.path) and io.exists(m.second.path)]
|
matches = [m for m in matches if m.first.path.exists() and m.second.path.exists()]
|
||||||
|
matches = [m for m in matches if not (m.first.is_ref and m.second.is_ref)]
|
||||||
if self.ignore_list:
|
if self.ignore_list:
|
||||||
j = j.start_subjob(2)
|
j = j.start_subjob(2)
|
||||||
iter_matches = j.iter_with_progress(matches, tr("Processed %d/%d matches against the ignore list"))
|
iter_matches = j.iter_with_progress(matches, tr("Processed %d/%d matches against the ignore list"))
|
||||||
|
|||||||
@@ -330,18 +330,22 @@ class TestCaseDupeGuruWithResults:
|
|||||||
app = self.app
|
app = self.app
|
||||||
# any other path that isn't a parent or child of the already added path
|
# any other path that isn't a parent or child of the already added path
|
||||||
otherpath = Path(op.dirname(__file__))
|
otherpath = Path(op.dirname(__file__))
|
||||||
eq_(app.add_directory(otherpath), 0)
|
app.add_directory(otherpath)
|
||||||
eq_(len(app.directories), 2)
|
eq_(len(app.directories), 2)
|
||||||
|
|
||||||
def test_addDirectory_already_there(self, do_setup):
|
def test_addDirectory_already_there(self, do_setup):
|
||||||
app = self.app
|
app = self.app
|
||||||
otherpath = Path(op.dirname(__file__))
|
otherpath = Path(op.dirname(__file__))
|
||||||
eq_(app.add_directory(otherpath), 0)
|
app.add_directory(otherpath)
|
||||||
eq_(app.add_directory(otherpath), 1)
|
app.add_directory(otherpath)
|
||||||
|
eq_(len(app.view.messages), 1)
|
||||||
|
assert "already" in app.view.messages[0]
|
||||||
|
|
||||||
def test_addDirectory_does_not_exist(self, do_setup):
|
def test_addDirectory_does_not_exist(self, do_setup):
|
||||||
app = self.app
|
app = self.app
|
||||||
eq_(2,app.add_directory('/does_not_exist'))
|
app.add_directory('/does_not_exist')
|
||||||
|
eq_(len(app.view.messages), 1)
|
||||||
|
assert "exist" in app.view.messages[0]
|
||||||
|
|
||||||
def test_ignore(self, do_setup):
|
def test_ignore(self, do_setup):
|
||||||
app = self.app
|
app = self.app
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ from ..gui.prioritize_dialog import PrioritizeDialog
|
|||||||
class DupeGuruView:
|
class DupeGuruView:
|
||||||
JOB = nulljob
|
JOB = nulljob
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.messages = []
|
||||||
|
|
||||||
def start_job(self, jobid, func, args=()):
|
def start_job(self, jobid, func, args=()):
|
||||||
try:
|
try:
|
||||||
func(self.JOB, *args)
|
func(self.JOB, *args)
|
||||||
@@ -37,7 +40,7 @@ class DupeGuruView:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def show_message(self, msg):
|
def show_message(self, msg):
|
||||||
pass
|
self.messages.append(msg)
|
||||||
|
|
||||||
def ask_yes_no(self, prompt):
|
def ask_yes_no(self, prompt):
|
||||||
return True # always answer yes
|
return True # always answer yes
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
__version__ = '6.4.2'
|
__version__ = '6.5.0'
|
||||||
__appname__ = 'dupeGuru Music Edition'
|
__appname__ = 'dupeGuru Music Edition'
|
||||||
@@ -1,3 +1,15 @@
|
|||||||
|
=== 6.5.0 (2012-08-10)
|
||||||
|
|
||||||
|
* Added "Export to CSV". (#189)
|
||||||
|
* Added "Replace with symlinks" to complement "Replace with hardlinks". [Mac, Linux] (#194)
|
||||||
|
* dupeGuru now tells how many duplicates were affected after each re-prioritization operation. (#204)
|
||||||
|
* Added Longest/Shortest filename criteria in the re-prioritize dialog. (#198)
|
||||||
|
* Fixed result table cells which mistakenly became writable in v3.5.0. [Mac] (#203)
|
||||||
|
* Fixed "Rename Selected" which was broken since v3.5.0. [Mac] (#202)
|
||||||
|
* Fixed a bug where "Reset to Defaults" in the Columns menu wouldn't refresh menu items' marked state.
|
||||||
|
* Improved OGG metadata reading.
|
||||||
|
* Improved Russian localization by Kyrill Detinov.
|
||||||
|
|
||||||
=== 6.4.2 (2012-07-07)
|
=== 6.4.2 (2012-07-07)
|
||||||
|
|
||||||
* Fixed iTunes integration which was broken since iTunes 10.6.3. [Mac]
|
* Fixed iTunes integration which was broken since iTunes 10.6.3. [Mac]
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ Unten befindet sich die Liste aller Menschen, die direkt oder indirekt zu dupeGu
|
|||||||
|
|
||||||
| **Igor Pavlov, Russian localization**
|
| **Igor Pavlov, Russian localization**
|
||||||
|
|
||||||
|
| **Kyrill Detinov, Russian localization**
|
||||||
|
|
||||||
| **Yuri Petrashko, Ukrainian localization**
|
| **Yuri Petrashko, Ukrainian localization**
|
||||||
|
|
||||||
| **Nickolas Pohilets, Ukrainian localization**
|
| **Nickolas Pohilets, Ukrainian localization**
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ Below is the list of people who contributed, directly or indirectly to dupeGuru.
|
|||||||
|
|
||||||
| **Igor Pavlov, Russian localization**
|
| **Igor Pavlov, Russian localization**
|
||||||
|
|
||||||
|
| **Kyrill Detinov, Russian localization**
|
||||||
|
|
||||||
| **Yuri Petrashko, Ukrainian localization**
|
| **Yuri Petrashko, Ukrainian localization**
|
||||||
|
|
||||||
| **Nickolas Pohilets, Ukrainian localization**
|
| **Nickolas Pohilets, Ukrainian localization**
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ Voici la liste des contributeurs de dupeGuru. Merci!
|
|||||||
|
|
||||||
| **Igor Pavlov, localisation russe**
|
| **Igor Pavlov, localisation russe**
|
||||||
|
|
||||||
|
| **Kyrill Detinov, localisation russe**
|
||||||
|
|
||||||
| **Yuri Petrashko, localisation ukrainienne**
|
| **Yuri Petrashko, localisation ukrainienne**
|
||||||
|
|
||||||
| **Nickolas Pohilets, localisation ukrainienne**
|
| **Nickolas Pohilets, localisation ukrainienne**
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
| **Igor Pavlov, Russian localization**
|
| **Igor Pavlov, Russian localization**
|
||||||
|
|
||||||
|
| **Kyrill Detinov, Russian localization**
|
||||||
|
|
||||||
| **Yuri Petrashko, Ukrainian localization**
|
| **Yuri Petrashko, Ukrainian localization**
|
||||||
|
|
||||||
| **Nickolas Pohilets, Ukrainian localization**
|
| **Nickolas Pohilets, Ukrainian localization**
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
| **Igor Pavlov, Russian localization**
|
| **Igor Pavlov, Russian localization**
|
||||||
|
|
||||||
|
| **Kyrill Detinov, Russian localization**
|
||||||
|
|
||||||
| **Yuri Petrashko, Ukrainian localization**
|
| **Yuri Petrashko, Ukrainian localization**
|
||||||
|
|
||||||
| **Nickolas Pohilets, Ukrainian localization**
|
| **Nickolas Pohilets, Ukrainian localization**
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
| **Igor Pavlov, Russian localization**
|
| **Igor Pavlov, Russian localization**
|
||||||
|
|
||||||
|
| **Kyrill Detinov, Russian localization**
|
||||||
|
|
||||||
| **Yuri Petrashko, Ukrainian localization**
|
| **Yuri Petrashko, Ukrainian localization**
|
||||||
|
|
||||||
| **Nickolas Pohilets, Ukrainian localization**
|
| **Nickolas Pohilets, Ukrainian localization**
|
||||||
|
|||||||
@@ -839,7 +839,8 @@ msgstr "Remplacer les fichiers effacés par des liens"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"After having deleted a duplicate, place a link targeting the reference file "
|
"After having deleted a duplicate, place a link targeting the reference file "
|
||||||
"to replace the deleted file."
|
"to replace the deleted file."
|
||||||
msgstr "Après avoir effacé un fichier, remplacer celui-ci par un lien vers le "
|
msgstr ""
|
||||||
|
"Après avoir effacé un fichier, remplacer celui-ci par un lien vers le "
|
||||||
"fichier référence."
|
"fichier référence."
|
||||||
|
|
||||||
#: qt/base/deletion_options.py:45
|
#: qt/base/deletion_options.py:45
|
||||||
|
|||||||
177
locale/ru/LC_MESSAGES/columns.po
Executable file → Normal file
177
locale/ru/LC_MESSAGES/columns.po
Executable file → Normal file
@@ -1,120 +1,121 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Russian translation\n"
|
"Project-Id-Version: dupeGuru\n"
|
||||||
"POT-Creation-Date: \n"
|
"POT-Creation-Date: \n"
|
||||||
"PO-Revision-Date: \n"
|
"PO-Revision-Date: \n"
|
||||||
"Last-Translator: Igor Pavlov <IgorPavlov87@mail.ru>\n"
|
"Last-Translator: Kyrill Detinov <lazy.kent@opensuse.org>\n"
|
||||||
"Language-Team: Igor Pavlov <IgorPavlov87@mail.ru>\n"
|
"Language-Team: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
|
||||||
"X-Poedit-Country: RUSSIAN FEDERATION\n"
|
"X-Poedit-Country: RUSSIAN FEDERATION\n"
|
||||||
"X-Poedit-Language: Russian\n"
|
"X-Poedit-Language: Russian\n"
|
||||||
|
|
||||||
|
#: core_me/result_table.py:28
|
||||||
|
msgid "Album"
|
||||||
|
msgstr "Альбом"
|
||||||
|
|
||||||
|
#: core_me/result_table.py:27
|
||||||
|
msgid "Artist"
|
||||||
|
msgstr "Исполнитель"
|
||||||
|
|
||||||
|
#: core_me/prioritize.py:22 core_me/result_table.py:22
|
||||||
|
msgid "Bitrate"
|
||||||
|
msgstr "Битрейт"
|
||||||
|
|
||||||
|
#: core_me/result_table.py:32
|
||||||
|
msgid "Comment"
|
||||||
|
msgstr "Комментарий"
|
||||||
|
|
||||||
|
#: core_pe/prioritize.py:16 core_pe/result_table.py:22
|
||||||
|
msgid "Dimensions"
|
||||||
|
msgstr "Размеры"
|
||||||
|
|
||||||
|
#: core_me/result_table.py:35 core_pe/result_table.py:25
|
||||||
|
#: core_se/result_table.py:25
|
||||||
|
msgid "Dupe Count"
|
||||||
|
msgstr "Количество дубликатов"
|
||||||
|
|
||||||
|
#: core_me/prioritize.py:16
|
||||||
|
msgid "Duration"
|
||||||
|
msgstr "Продолжительность"
|
||||||
|
|
||||||
|
#: core/gui/problem_table.py:18
|
||||||
|
msgid "Error Message"
|
||||||
|
msgstr "Сообщение об ошибке"
|
||||||
|
|
||||||
#: core/gui/ignore_list_table.py:18 core/gui/ignore_list_table.py:19
|
#: core/gui/ignore_list_table.py:18 core/gui/ignore_list_table.py:19
|
||||||
#: core/gui/problem_table.py:17
|
#: core/gui/problem_table.py:17
|
||||||
msgid "File Path"
|
msgid "File Path"
|
||||||
msgstr "Путь к файлу"
|
msgstr "Путь к файлу"
|
||||||
|
|
||||||
#: core/gui/problem_table.py:18
|
#: core/prioritize.py:88 core_me/result_table.py:18 core_pe/result_table.py:18
|
||||||
msgid "Error Message"
|
#: core_se/result_table.py:18
|
||||||
msgstr "Сообщение об ошибке"
|
msgid "Filename"
|
||||||
|
msgstr "Имя файла"
|
||||||
|
|
||||||
|
#: core/prioritize.py:72 core_me/result_table.py:19 core_pe/result_table.py:19
|
||||||
|
#: core_se/result_table.py:19
|
||||||
|
msgid "Folder"
|
||||||
|
msgstr "Каталог"
|
||||||
|
|
||||||
|
#: core_me/result_table.py:29
|
||||||
|
msgid "Genre"
|
||||||
|
msgstr "Жанр"
|
||||||
|
|
||||||
#: core/prioritize.py:63 core_me/result_table.py:24 core_pe/result_table.py:21
|
#: core/prioritize.py:63 core_me/result_table.py:24 core_pe/result_table.py:21
|
||||||
#: core_se/result_table.py:21
|
#: core_se/result_table.py:21
|
||||||
msgid "Kind"
|
msgid "Kind"
|
||||||
msgstr "Тип"
|
msgstr "Тип"
|
||||||
|
|
||||||
#: core/prioritize.py:72 core_me/result_table.py:19 core_pe/result_table.py:19
|
|
||||||
#: core_se/result_table.py:19
|
|
||||||
msgid "Folder"
|
|
||||||
msgstr "Папка"
|
|
||||||
|
|
||||||
#: core/prioritize.py:88 core_me/result_table.py:18 core_pe/result_table.py:18
|
|
||||||
#: core_se/result_table.py:18
|
|
||||||
msgid "Filename"
|
|
||||||
msgstr "Имя файла"
|
|
||||||
|
|
||||||
#: core/prioritize.py:147
|
|
||||||
msgid "Size"
|
|
||||||
msgstr "Размер"
|
|
||||||
|
|
||||||
#: core/prioritize.py:153 core_me/result_table.py:25
|
|
||||||
#: core_pe/result_table.py:23 core_se/result_table.py:22
|
|
||||||
msgid "Modification"
|
|
||||||
msgstr "Модификация"
|
|
||||||
|
|
||||||
#: core_me/prioritize.py:16
|
|
||||||
msgid "Duration"
|
|
||||||
msgstr "Продолжительность"
|
|
||||||
|
|
||||||
#: core_me/prioritize.py:22 core_me/result_table.py:22
|
|
||||||
msgid "Bitrate"
|
|
||||||
msgstr "Битрейт"
|
|
||||||
|
|
||||||
#: core_me/prioritize.py:28
|
|
||||||
msgid "Samplerate"
|
|
||||||
msgstr "Частота оцифровки"
|
|
||||||
|
|
||||||
#: core_me/result_table.py:20
|
|
||||||
msgid "Size (MB)"
|
|
||||||
msgstr "Размер (Мб)"
|
|
||||||
|
|
||||||
#: core_me/result_table.py:21
|
|
||||||
msgid "Time"
|
|
||||||
msgstr "Время"
|
|
||||||
|
|
||||||
#: core_me/result_table.py:23
|
|
||||||
msgid "Sample Rate"
|
|
||||||
msgstr "Частота"
|
|
||||||
|
|
||||||
#: core_me/result_table.py:26
|
|
||||||
msgid "Title"
|
|
||||||
msgstr "Название"
|
|
||||||
|
|
||||||
#: core_me/result_table.py:27
|
|
||||||
msgid "Artist"
|
|
||||||
msgstr "Артист"
|
|
||||||
|
|
||||||
#: core_me/result_table.py:28
|
|
||||||
msgid "Album"
|
|
||||||
msgstr "Альбом"
|
|
||||||
|
|
||||||
#: core_me/result_table.py:29
|
|
||||||
msgid "Genre"
|
|
||||||
msgstr "Жанр"
|
|
||||||
|
|
||||||
#: core_me/result_table.py:30
|
|
||||||
msgid "Year"
|
|
||||||
msgstr "Год"
|
|
||||||
|
|
||||||
#: core_me/result_table.py:31
|
|
||||||
msgid "Track Number"
|
|
||||||
msgstr "Номер дорожки"
|
|
||||||
|
|
||||||
#: core_me/result_table.py:32
|
|
||||||
msgid "Comment"
|
|
||||||
msgstr "Комментарий"
|
|
||||||
|
|
||||||
#: core_me/result_table.py:33 core_pe/result_table.py:24
|
#: core_me/result_table.py:33 core_pe/result_table.py:24
|
||||||
#: core_se/result_table.py:23
|
#: core_se/result_table.py:23
|
||||||
msgid "Match %"
|
msgid "Match %"
|
||||||
msgstr "Совпадение %"
|
msgstr "Совпадение %"
|
||||||
|
|
||||||
#: core_me/result_table.py:34 core_se/result_table.py:24
|
#: core/prioritize.py:153 core_me/result_table.py:25
|
||||||
msgid "Words Used"
|
#: core_pe/result_table.py:23 core_se/result_table.py:22
|
||||||
msgstr "Слов, используемых"
|
msgid "Modification"
|
||||||
|
msgstr "Время изменения"
|
||||||
|
|
||||||
#: core_me/result_table.py:35 core_pe/result_table.py:25
|
#: core_me/result_table.py:23
|
||||||
#: core_se/result_table.py:25
|
msgid "Sample Rate"
|
||||||
msgid "Dupe Count"
|
msgstr "Частота"
|
||||||
msgstr "Dupe графа"
|
|
||||||
|
|
||||||
#: core_pe/prioritize.py:16 core_pe/result_table.py:22
|
#: core_me/prioritize.py:28
|
||||||
msgid "Dimensions"
|
msgid "Samplerate"
|
||||||
msgstr "Размеры"
|
msgstr "Частота оцифровки"
|
||||||
|
|
||||||
|
#: core/prioritize.py:147
|
||||||
|
msgid "Size"
|
||||||
|
msgstr "Размер"
|
||||||
|
|
||||||
#: core_pe/result_table.py:20 core_se/result_table.py:20
|
#: core_pe/result_table.py:20 core_se/result_table.py:20
|
||||||
msgid "Size (KB)"
|
msgid "Size (KB)"
|
||||||
msgstr "Размер (KB)"
|
msgstr "Размер (КБ)"
|
||||||
|
|
||||||
|
#: core_me/result_table.py:20
|
||||||
|
msgid "Size (MB)"
|
||||||
|
msgstr "Размер (МБ)"
|
||||||
|
|
||||||
|
#: core_me/result_table.py:21
|
||||||
|
msgid "Time"
|
||||||
|
msgstr "Время"
|
||||||
|
|
||||||
|
#: core_me/result_table.py:26
|
||||||
|
msgid "Title"
|
||||||
|
msgstr "Название"
|
||||||
|
|
||||||
|
#: core_me/result_table.py:31
|
||||||
|
msgid "Track Number"
|
||||||
|
msgstr "Номер дорожки"
|
||||||
|
|
||||||
|
#: core_me/result_table.py:34 core_se/result_table.py:24
|
||||||
|
msgid "Words Used"
|
||||||
|
msgstr "Использованные слова"
|
||||||
|
|
||||||
|
#: core_me/result_table.py:30
|
||||||
|
msgid "Year"
|
||||||
|
msgstr "Год"
|
||||||
|
|||||||
280
locale/ru/LC_MESSAGES/core.po
Executable file → Normal file
280
locale/ru/LC_MESSAGES/core.po
Executable file → Normal file
@@ -1,37 +1,28 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Russian translation\n"
|
"Project-Id-Version: dupeGuru\n"
|
||||||
"POT-Creation-Date: \n"
|
"POT-Creation-Date: \n"
|
||||||
"PO-Revision-Date: \n"
|
"PO-Revision-Date: \n"
|
||||||
"Last-Translator: Igor Pavlov <IgorPavlov87@mail.ru>\n"
|
"Last-Translator: Kyrill Detinov <lazy.kent@opensuse.org>\n"
|
||||||
"Language-Team: Igor Pavlov <IgorPavlov87@mail.ru>\n"
|
"Language-Team: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Poedit-Country: RUSSIAN FEDERATION\n"
|
"Language: ru_RU\n"
|
||||||
"X-Poedit-Language: Russian\n"
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
|
||||||
|
|
||||||
#: core/app.py:97
|
#: core/results.py:120
|
||||||
msgid "will only be able to delete, move or copy 10 duplicates at once"
|
msgid " filter: %s"
|
||||||
msgstr ""
|
msgstr "фильтр: %s"
|
||||||
"сможете только для удаления, перемещения или копирования 10 копий сразу"
|
|
||||||
|
|
||||||
#: core/app.py:273
|
#: core/results.py:113
|
||||||
msgid ""
|
msgid "%d / %d (%s / %s) duplicates marked."
|
||||||
"You cannot delete, move or copy more than 10 duplicates at once in demo "
|
msgstr "%d / %d (%s / %s) дубликатов отмечено."
|
||||||
"mode."
|
|
||||||
msgstr ""
|
|
||||||
"Вы не можете удалять, перемещать или копировать более 10 дубликатов сразу в "
|
|
||||||
"демонстрационном режиме."
|
|
||||||
|
|
||||||
#: core/app.py:543
|
#: core/engine.py:196 core/engine.py:223
|
||||||
msgid "Collecting files to scan"
|
msgid "%d matches found"
|
||||||
msgstr "Сбор файлов для сканирования"
|
msgstr "%d совпадений найдено"
|
||||||
|
|
||||||
#: core/app.py:554
|
|
||||||
msgid "The selected directories contain no scannable file."
|
|
||||||
msgstr "Выбранных директорий не содержат сканируемых файлов."
|
|
||||||
|
|
||||||
#: core/app.py:593
|
#: core/app.py:593
|
||||||
msgid "%s (%d discarded)"
|
msgid "%s (%d discarded)"
|
||||||
@@ -39,31 +30,56 @@ msgstr "%s. (%d отменено)"
|
|||||||
|
|
||||||
#: core/engine.py:178 core/engine.py:215
|
#: core/engine.py:178 core/engine.py:215
|
||||||
msgid "0 matches found"
|
msgid "0 matches found"
|
||||||
msgstr "0 сопоставлений найдено"
|
msgstr "0 совпадений найдено"
|
||||||
|
|
||||||
#: core/engine.py:196 core/engine.py:223
|
#: core/app.py:244
|
||||||
msgid "%d matches found"
|
msgid "All marked files were copied sucessfully."
|
||||||
msgstr "%d сопоставлений найдено"
|
msgstr "Все отмеченные файлы были скопированы успешно."
|
||||||
|
|
||||||
#: core/engine.py:208 core/scanner.py:80
|
#: core/app.py:245
|
||||||
msgid "Read size of %d/%d files"
|
msgid "All marked files were moved sucessfully."
|
||||||
msgstr "Реалний размер %d/%d файлов"
|
msgstr "Все отмеченные файлы были перемещены успешно."
|
||||||
|
|
||||||
#: core/engine.py:360
|
#: core/app.py:246
|
||||||
msgid "Grouped %d/%d matches"
|
msgid "All marked files were sucessfully sent to Trash."
|
||||||
msgstr "Группировка %d/%d совпадений"
|
msgstr "Все отмеченные файлы были успешно отправлены в Корзину."
|
||||||
|
|
||||||
#: core/prioritize.py:68
|
#: core/app.py:293
|
||||||
msgid "None"
|
msgid ""
|
||||||
msgstr "Ни один"
|
"All selected %d matches are going to be ignored in all subsequent scans. "
|
||||||
|
"Continue?"
|
||||||
|
msgstr ""
|
||||||
|
"Все выбранные %d совпадений будут игнорироваться при всех последующих "
|
||||||
|
"проверках. Продолжить?"
|
||||||
|
|
||||||
|
#: core_pe/matchblock.py:60
|
||||||
|
msgid "Analyzed %d/%d pictures"
|
||||||
|
msgstr "Анализируется %d/%d изображений"
|
||||||
|
|
||||||
|
#: core/app.py:543
|
||||||
|
msgid "Collecting files to scan"
|
||||||
|
msgstr "Сбор файлов для сканирования"
|
||||||
|
|
||||||
|
#: core/gui/ignore_list_dialog.py:24
|
||||||
|
msgid "Do you really want to remove all %d items from the ignore list?"
|
||||||
|
msgstr ""
|
||||||
|
"Вы действительно хотите удалить все элементы %d из списка игнорирования?"
|
||||||
|
|
||||||
|
#: core/prioritize.py:97
|
||||||
|
msgid "Doesn't end with number"
|
||||||
|
msgstr "Не заканчивается номером"
|
||||||
|
|
||||||
|
#: core/scanner.py:171
|
||||||
|
msgid "Doing group prioritization"
|
||||||
|
msgstr "Выполняется приоритезация групп"
|
||||||
|
|
||||||
#: core/prioritize.py:96
|
#: core/prioritize.py:96
|
||||||
msgid "Ends with number"
|
msgid "Ends with number"
|
||||||
msgstr "Заканчивается номером"
|
msgstr "Заканчивается номером"
|
||||||
|
|
||||||
#: core/prioritize.py:97
|
#: core/engine.py:360
|
||||||
msgid "Doesn't end with number"
|
msgid "Grouped %d/%d matches"
|
||||||
msgstr "Не заканчивается с номером"
|
msgstr "Группировка %d/%d совпадений"
|
||||||
|
|
||||||
#: core/prioritize.py:132
|
#: core/prioritize.py:132
|
||||||
msgid "Highest"
|
msgid "Highest"
|
||||||
@@ -71,59 +87,95 @@ msgstr "Наивысший"
|
|||||||
|
|
||||||
#: core/prioritize.py:132
|
#: core/prioritize.py:132
|
||||||
msgid "Lowest"
|
msgid "Lowest"
|
||||||
msgstr "Самая низкая"
|
msgstr "Самый низкий"
|
||||||
|
|
||||||
#: core/prioritize.py:159
|
#: core/prioritize.py:159
|
||||||
msgid "Newest"
|
msgid "Newest"
|
||||||
msgstr "Новейший"
|
msgstr "Новейший"
|
||||||
|
|
||||||
|
#: core/app.py:231
|
||||||
|
msgid "No duplicates found."
|
||||||
|
msgstr "Дубликаты не найдены."
|
||||||
|
|
||||||
|
#: core/prioritize.py:68
|
||||||
|
msgid "None"
|
||||||
|
msgstr "Ни один"
|
||||||
|
|
||||||
#: core/prioritize.py:159
|
#: core/prioritize.py:159
|
||||||
msgid "Oldest"
|
msgid "Oldest"
|
||||||
msgstr "Старейшие"
|
msgstr "Старейшие"
|
||||||
|
|
||||||
#: core/results.py:113
|
# Not sure.
|
||||||
msgid "%d / %d (%s / %s) duplicates marked."
|
|
||||||
msgstr "%d / %d (%s / %s) дубликаты обозначены."
|
|
||||||
|
|
||||||
#: core/results.py:120
|
|
||||||
msgid " filter: %s"
|
|
||||||
msgstr "филтр. %s"
|
|
||||||
|
|
||||||
#: core/scanner.py:100
|
|
||||||
msgid "Read metadata of %d/%d files"
|
|
||||||
msgstr "Прочитано метаданных %d/%d файлов"
|
|
||||||
|
|
||||||
#: core/scanner.py:131
|
|
||||||
msgid "Removing false matches"
|
|
||||||
msgstr "Удаление ложных совпадениях"
|
|
||||||
|
|
||||||
#: core/scanner.py:149
|
|
||||||
msgid "Processed %d/%d matches against the ignore list"
|
|
||||||
msgstr "Обработано %d/%d матчей против игнор-лист"
|
|
||||||
|
|
||||||
#: core/scanner.py:171
|
|
||||||
msgid "Doing group prioritization"
|
|
||||||
msgstr "Делая группы приоритетов"
|
|
||||||
|
|
||||||
#: core_pe/matchblock.py:60
|
|
||||||
msgid "Analyzed %d/%d pictures"
|
|
||||||
msgstr "Анализируется %d/%d фотографии"
|
|
||||||
|
|
||||||
#: core_pe/matchblock.py:152
|
#: core_pe/matchblock.py:152
|
||||||
msgid "Performed %d/%d chunk matches"
|
msgid "Performed %d/%d chunk matches"
|
||||||
msgstr "Исполняет %d/%d совпадениях кусоков"
|
msgstr "Выполнено %d/%d совпадений блоков"
|
||||||
|
|
||||||
#: core_pe/matchblock.py:157
|
#: core_pe/matchblock.py:157
|
||||||
msgid "Preparing for matching"
|
msgid "Preparing for matching"
|
||||||
msgstr "Подготовка для сравнения"
|
msgstr "Подготовка для сравнения"
|
||||||
|
|
||||||
#: core_pe/matchblock.py:192
|
# Not sure.
|
||||||
msgid "Verified %d/%d matches"
|
#: core/scanner.py:149
|
||||||
msgstr "Проверенные %d/%d совпадениях"
|
msgid "Processed %d/%d matches against the ignore list"
|
||||||
|
msgstr "Обработано %d/%d совпадений используя список игнорирования"
|
||||||
|
|
||||||
#: core_pe/matchexif.py:21
|
#: core_pe/matchexif.py:21
|
||||||
msgid "Read EXIF of %d/%d pictures"
|
msgid "Read EXIF of %d/%d pictures"
|
||||||
msgstr "Прочитано EXIF %d/%d из фотографии"
|
msgstr "Прочитана EXIF-информация %d/%d фотографий"
|
||||||
|
|
||||||
|
#: core/scanner.py:100
|
||||||
|
msgid "Read metadata of %d/%d files"
|
||||||
|
msgstr "Прочитаны метаданные %d/%d файлов"
|
||||||
|
|
||||||
|
#: core/engine.py:208 core/scanner.py:80
|
||||||
|
msgid "Read size of %d/%d files"
|
||||||
|
msgstr "Подсчитан размер %d/%d файлов"
|
||||||
|
|
||||||
|
#: core/scanner.py:131
|
||||||
|
msgid "Removing false matches"
|
||||||
|
msgstr "Удаление ложных совпадений"
|
||||||
|
|
||||||
|
#: core/app.py:354
|
||||||
|
msgid "Select a directory to {} marked files to"
|
||||||
|
msgstr "Выберите каталог {} для отмеченных файлов"
|
||||||
|
|
||||||
|
#: core/app.py:554
|
||||||
|
msgid "The selected directories contain no scannable file."
|
||||||
|
msgstr "Выбранные каталоги не содержат файлов для сканирования."
|
||||||
|
|
||||||
|
#: core_pe/matchblock.py:192
|
||||||
|
msgid "Verified %d/%d matches"
|
||||||
|
msgstr "Проверено %d/%d совпадений"
|
||||||
|
|
||||||
|
#: core/app.py:492 core/app.py:503
|
||||||
|
msgid "You are about to remove %d files from results. Continue?"
|
||||||
|
msgstr "Вы собираетесь удалить %d файлов из результата поиска. Продолжить?"
|
||||||
|
|
||||||
|
#: core/app.py:273
|
||||||
|
msgid ""
|
||||||
|
"You cannot delete, move or copy more than 10 duplicates at once in demo "
|
||||||
|
"mode."
|
||||||
|
msgstr ""
|
||||||
|
"Вы не можете удалять, перемещать или копировать более 10 дубликатов за один "
|
||||||
|
"раз в демонстрационном режиме."
|
||||||
|
|
||||||
|
#: core/app.py:405
|
||||||
|
msgid "You have no custom command set up. Set it up in your preferences."
|
||||||
|
msgstr "Вы не создали пользовательскую команду. Задайте её в настройках."
|
||||||
|
|
||||||
|
#: core/app.py:353
|
||||||
|
msgid "copy"
|
||||||
|
msgstr "копирование"
|
||||||
|
|
||||||
|
#: core/app.py:353
|
||||||
|
msgid "move"
|
||||||
|
msgstr "перемещение"
|
||||||
|
|
||||||
|
#: core/app.py:97
|
||||||
|
msgid "will only be able to delete, move or copy 10 duplicates at once"
|
||||||
|
msgstr ""
|
||||||
|
"вы сможете удалить, переместить или скопировать только 10 дубликатов за один"
|
||||||
|
" раз"
|
||||||
|
|
||||||
#: core/app.py:38
|
#: core/app.py:38
|
||||||
msgid "There are no marked duplicates. Nothing has been done."
|
msgid "There are no marked duplicates. Nothing has been done."
|
||||||
@@ -133,72 +185,6 @@ msgstr ""
|
|||||||
msgid "There are no selected duplicates. Nothing has been done."
|
msgid "There are no selected duplicates. Nothing has been done."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: core/app.py:231
|
|
||||||
msgid "No duplicates found."
|
|
||||||
msgstr "Дубликаты не найдены."
|
|
||||||
|
|
||||||
#: core/app.py:244
|
|
||||||
msgid "All marked files were copied sucessfully."
|
|
||||||
msgstr "Все выбранные файлы были скопированы успешно."
|
|
||||||
|
|
||||||
#: core/app.py:245
|
|
||||||
msgid "All marked files were moved sucessfully."
|
|
||||||
msgstr "Все выбранные файлы были перемещены успешно."
|
|
||||||
|
|
||||||
#: core/app.py:246
|
|
||||||
msgid "All marked files were sucessfully sent to Trash."
|
|
||||||
msgstr "Все выбранные файлы были успешно отправлены в корзину."
|
|
||||||
|
|
||||||
#: core/app.py:293
|
|
||||||
msgid ""
|
|
||||||
"All selected %d matches are going to be ignored in all subsequent scans. "
|
|
||||||
"Continue?"
|
|
||||||
msgstr ""
|
|
||||||
"Все выбранные %d матчей будут игнорироваться во всех последующих проверок. "
|
|
||||||
"Продолжить?"
|
|
||||||
|
|
||||||
#: core/gui/ignore_list_dialog.py:24
|
|
||||||
msgid "Do you really want to remove all %d items from the ignore list?"
|
|
||||||
msgstr "Вы действительно хотите удалить все элементы %d из черного списка?"
|
|
||||||
|
|
||||||
#: core/app.py:405
|
|
||||||
msgid "You have no custom command set up. Set it up in your preferences."
|
|
||||||
msgstr ""
|
|
||||||
"У вас нет пользовательской команды создали. Установите его в ваших "
|
|
||||||
"предпочтениях."
|
|
||||||
|
|
||||||
#: core/app.py:492 core/app.py:503
|
|
||||||
msgid "You are about to remove %d files from results. Continue?"
|
|
||||||
msgstr "Вы собираетесь удалить файлы %d из результата поиска. Продолжить?"
|
|
||||||
|
|
||||||
#: core/app.py:353
|
|
||||||
msgid "copy"
|
|
||||||
msgstr "копия"
|
|
||||||
|
|
||||||
#: core/app.py:353
|
|
||||||
msgid "move"
|
|
||||||
msgstr "перемещение"
|
|
||||||
|
|
||||||
#: core/app.py:354
|
|
||||||
msgid "Select a directory to {} marked files to"
|
|
||||||
msgstr "Выберите каталог на {} отмеченные файлы"
|
|
||||||
|
|
||||||
#: core/gui/deletion_options.py:21
|
|
||||||
msgid "You are sending {} file(s) to the Trash."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: core/prioritize.py:98
|
|
||||||
msgid "Longest"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: core/prioritize.py:99
|
|
||||||
msgid "Shortest"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: core/app.py:523
|
|
||||||
msgid "{} duplicate groups were changed by the re-prioritization."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: core/app.py:284
|
#: core/app.py:284
|
||||||
msgid "'{}' already is in the list."
|
msgid "'{}' already is in the list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -210,3 +196,19 @@ msgstr ""
|
|||||||
#: core/app.py:380
|
#: core/app.py:380
|
||||||
msgid "Select a destination for your exported CSV"
|
msgid "Select a destination for your exported CSV"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/app.py:523
|
||||||
|
msgid "{} duplicate groups were changed by the re-prioritization."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/gui/deletion_options.py:21
|
||||||
|
msgid "You are sending {} file(s) to the Trash."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/prioritize.py:98
|
||||||
|
msgid "Longest"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: core/prioritize.py:99
|
||||||
|
msgid "Shortest"
|
||||||
|
msgstr ""
|
||||||
|
|||||||
1413
locale/ru/LC_MESSAGES/ui.po
Executable file → Normal file
1413
locale/ru/LC_MESSAGES/ui.po
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,6 @@ jobprogress>=1.0.4
|
|||||||
Send2Trash3k>=1.2.0
|
Send2Trash3k>=1.2.0
|
||||||
sphinx>=1.1.3
|
sphinx>=1.1.3
|
||||||
polib>=0.7.0
|
polib>=0.7.0
|
||||||
hsaudiotag3k>=1.1.2
|
hsaudiotag3k>=1.1.3
|
||||||
pytest>=2.0.0
|
pytest>=2.0.0
|
||||||
pytest-monkeyplus>=1.0.0
|
pytest-monkeyplus>=1.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user