1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2026-01-25 08:01:39 +00:00

Compare commits

..

11 Commits

Author SHA1 Message Date
Virgil Dupras
2dbf8b80ae Updated hsaudiotag version req. 2012-08-10 10:30:50 -04:00
Virgil Dupras
470cd92030 me v6.5.0 2012-08-10 10:23:35 -04:00
Virgil Dupras
111edc3ce5 Fixed a bug causing groups with more than one ref file in it to appear (which looks weird and messes with selection).
Contents scans already weeded them out, bu t they were still possible with name-based scans. Now, the Scanner removes them all.
2012-08-09 11:16:06 -04:00
Virgil Dupras
df30a31782 Refactoring: Began to phase out to the use of hscommon.io in favor of Path methods. 2012-08-09 10:53:24 -04:00
Virgil Dupras
91f3a59523 Fixed add_directory() test which were broken. 2012-08-09 10:22:04 -04:00
Virgil Dupras
3441e51c0e [#200 state:fixed] Fixed a KeyError wihle parsing iTunes XML. 2012-08-09 10:01:44 -04:00
Virgil Dupras
a99c40b5d8 Updated PO files from POTs. 2012-08-09 09:58:14 -04:00
Virgil Dupras
5b4de58c38 Oops, I had forgot one of the credits file. 2012-08-08 16:53:08 -04:00
Virgil Dupras
cd83b16dbd Added Kyrill Detinov to credits for russian loc improvements. 2012-08-08 16:39:17 -04:00
Virgil Dupras
b67db988ab Improvement to the Russian loc by Kyrill Detinov. 2012-08-08 16:32:14 -04:00
Virgil Dupras
7ebea44cb0 Added tag se3.6.0 for changeset 0f18c4498a6c 2012-08-08 11:27:04 -04:00
21 changed files with 1025 additions and 959 deletions

View File

@@ -78,3 +78,4 @@ c3d9f91dc9c9d60f370c72bc211f09be3e4fc18d se3.5.0
e772f1de86744999ffbbe5845554417965b1dfba me6.4.1
c8a9a4d355927e509f514308c82306192bc71f92 pe2.6.0
a618e954f01e4bbdbe9a03e5667a67d62be995a7 me6.4.2
0f18c4498a6c7529bf77207db70aed8a5ec96ee4 se3.6.0

View File

@@ -14,7 +14,6 @@ from appscript import app, its, k, CommandError, ApplicationNotFoundError
from . import tunes
from cocoa import as_fetch, proxy
from hscommon import io
from hscommon.trans import trget
from hscommon.path import Path
from hscommon.util import remove_invalid_xml
@@ -78,21 +77,21 @@ def get_itunes_database_path():
return Path(plistpath)
def get_itunes_songs(plistpath):
if not io.exists(plistpath):
if not plistpath.exists():
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.
s = remove_invalid_xml(s, replace_with='')
plist = plistlib.readPlistFromBytes(s.encode('utf-8'))
result = []
for song_data in plist['Tracks'].values():
if song_data['Track Type'] != 'File':
continue
try:
if song_data['Track Type'] != 'File':
continue
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
if io.exists(song.path):
if song.path.exists():
result.append(song)
return result

View File

@@ -15,7 +15,6 @@ import time
import shutil
from send2trash import send2trash
from hscommon import io
from hscommon.reg import RegistrableApplication
from hscommon.notify import Broadcaster
from hscommon.path import Path
@@ -168,7 +167,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
self.results.perform_on_marked(op, True)
def _do_delete_dupe(self, dupe, link_deleted, use_hardlinks, direct_deletion):
if not io.exists(dupe.path):
if not dupe.path.exists():
return
logging.debug("Sending '%s' to trash", dupe.path)
str_path = str(dupe.path)
@@ -253,7 +252,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
result = []
for file in files:
try:
inode = io.stat(file.path).st_ino
inode = file.path.stat().st_ino
except OSError:
# The file was probably deleted or something
continue
@@ -324,8 +323,8 @@ class DupeGuru(RegistrableApplication, Broadcaster):
if dest_type == DestType.Relative:
source_base = source_base[location_path:]
dest_path = dest_path + source_base
if not io.exists(dest_path):
io.makedirs(dest_path)
if not dest_path.exists():
dest_path.makedirs()
# Add filename to dest_path. For file move/copy, it's not required, but for folders, yes.
dest_path = dest_path + source_path[-1]
logging.debug("Copy/Move operation from '%s' to '%s'", source_path, dest_path)

View File

@@ -10,7 +10,6 @@ from xml.etree import ElementTree as ET
import logging
from jobprogress import job
from hscommon import io
from hscommon.path import Path
from hscommon.util import FileOrPath
@@ -73,9 +72,9 @@ class Directories:
file.is_ref = state == DirectoryState.Reference
filepaths.add(file.path)
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
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 file in self._get_files(subfolder, j):
yield file
@@ -106,7 +105,7 @@ class Directories:
"""
if path in self:
raise AlreadyThereError()
if not io.exists(path):
if not path.exists():
raise InvalidPathError()
self._dirs = [p for p in self._dirs if p not in path]
self._dirs.append(path)
@@ -115,7 +114,7 @@ class Directories:
def get_subfolders(path):
"""returns a sorted list of paths corresponding to subfolders in `path`"""
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())
return [path + name for name in names]
except EnvironmentError:

View File

@@ -14,7 +14,6 @@
import hashlib
import logging
from hscommon import io
from hscommon.util import nonone, get_file_ext
NOT_SET = object()
@@ -89,12 +88,12 @@ class File:
def _read_info(self, field):
if field in ('size', 'mtime'):
stats = io.stat(self.path)
stats = self.path.stat()
self.size = nonone(stats.st_size, 0)
self.mtime = nonone(stats.st_mtime, 0)
elif field == 'md5partial':
try:
fp = io.open(self.path, 'rb')
fp = self.path.open('rb')
offset, size = self._get_md5partial_offset_and_size()
fp.seek(offset)
partialdata = fp.read(size)
@@ -105,7 +104,7 @@ class File:
pass
elif field == 'md5':
try:
fp = io.open(self.path, 'rb')
fp = self.path.open('rb')
md5 = hashlib.md5()
CHUNK_SIZE = 8192
filedata = fp.read(CHUNK_SIZE)
@@ -130,19 +129,19 @@ class File:
#--- Public
@classmethod
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):
if newname == self.name:
return
destpath = self.path[:-1] + newname
if io.exists(destpath):
if destpath.exists():
raise AlreadyExistsError(newname, self.path[:-1])
try:
io.rename(self.path, destpath)
self.path.rename(destpath)
except EnvironmentError:
raise OperationError(self)
if not io.exists(destpath):
if not destpath.exists():
raise OperationError(self)
self.path = destpath
@@ -180,7 +179,7 @@ class Folder(File):
if field in {'size', 'mtime'}:
size = sum((f.size for f in self._all_items()), 0)
self.size = size
stats = io.stat(self.path)
stats = self.path.stat()
self.mtime = nonone(stats.st_mtime, 0)
elif field in {'md5', 'md5partial'}:
# What's sensitive here is that we must make sure that subfiles'
@@ -199,14 +198,14 @@ class Folder(File):
@property
def subfolders(self):
if self._subfolders is None:
subpaths = [self.path + name for name in io.listdir(self.path)]
subfolders = [p for p in subpaths if not io.islink(p) and io.isdir(p)]
subpaths = [self.path + name for name in self.path.listdir()]
subfolders = [p for p in subpaths if not p.islink() and p.isdir()]
self._subfolders = [Folder(p) for p in subfolders]
return self._subfolders
@classmethod
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]):
@@ -225,7 +224,7 @@ def get_files(path, fileclasses=[File]):
raise
try:
paths = [combine_paths(path, name) for name in io.listdir(path)]
paths = [combine_paths(path, name) for name in path.listdir()]
result = []
for path in paths:
file = get_file(path, fileclasses=fileclasses)

View File

@@ -11,7 +11,6 @@ import re
import os.path as op
from jobprogress import job
from hscommon import io
from hscommon.util import dedupe, rem_file_ext, get_file_ext
from hscommon.trans import tr
@@ -129,6 +128,11 @@ class Scanner:
matches = self._getmatches(files, j)
logging.info('Found %d matches' % len(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:
allpath = {m.first.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]
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 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:
j = j.start_subjob(2)
iter_matches = j.iter_with_progress(matches, tr("Processed %d/%d matches against the ignore list"))

View File

@@ -330,18 +330,22 @@ class TestCaseDupeGuruWithResults:
app = self.app
# any other path that isn't a parent or child of the already added path
otherpath = Path(op.dirname(__file__))
eq_(app.add_directory(otherpath), 0)
app.add_directory(otherpath)
eq_(len(app.directories), 2)
def test_addDirectory_already_there(self, do_setup):
app = self.app
otherpath = Path(op.dirname(__file__))
eq_(app.add_directory(otherpath), 0)
eq_(app.add_directory(otherpath), 1)
app.add_directory(otherpath)
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):
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):
app = self.app

View File

@@ -24,6 +24,9 @@ from ..gui.prioritize_dialog import PrioritizeDialog
class DupeGuruView:
JOB = nulljob
def __init__(self):
self.messages = []
def start_job(self, jobid, func, args=()):
try:
func(self.JOB, *args)
@@ -37,7 +40,7 @@ class DupeGuruView:
pass
def show_message(self, msg):
pass
self.messages.append(msg)
def ask_yes_no(self, prompt):
return True # always answer yes

View File

@@ -1,2 +1,2 @@
__version__ = '6.4.2'
__version__ = '6.5.0'
__appname__ = 'dupeGuru Music Edition'

View File

@@ -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)
* Fixed iTunes integration which was broken since iTunes 10.6.3. [Mac]

View File

@@ -18,6 +18,8 @@ Unten befindet sich die Liste aller Menschen, die direkt oder indirekt zu dupeGu
| **Igor Pavlov, Russian localization**
| **Kyrill Detinov, Russian localization**
| **Yuri Petrashko, Ukrainian localization**
| **Nickolas Pohilets, Ukrainian localization**

View File

@@ -20,6 +20,8 @@ Below is the list of people who contributed, directly or indirectly to dupeGuru.
| **Igor Pavlov, Russian localization**
| **Kyrill Detinov, Russian localization**
| **Yuri Petrashko, Ukrainian localization**
| **Nickolas Pohilets, Ukrainian localization**

View File

@@ -19,6 +19,8 @@ Voici la liste des contributeurs de dupeGuru. Merci!
| **Igor Pavlov, localisation russe**
| **Kyrill Detinov, localisation russe**
| **Yuri Petrashko, localisation ukrainienne**
| **Nickolas Pohilets, localisation ukrainienne**

View File

@@ -20,6 +20,8 @@
| **Igor Pavlov, Russian localization**
| **Kyrill Detinov, Russian localization**
| **Yuri Petrashko, Ukrainian localization**
| **Nickolas Pohilets, Ukrainian localization**

View File

@@ -20,6 +20,8 @@
| **Igor Pavlov, Russian localization**
| **Kyrill Detinov, Russian localization**
| **Yuri Petrashko, Ukrainian localization**
| **Nickolas Pohilets, Ukrainian localization**

View File

@@ -20,6 +20,8 @@
| **Igor Pavlov, Russian localization**
| **Kyrill Detinov, Russian localization**
| **Yuri Petrashko, Ukrainian localization**
| **Nickolas Pohilets, Ukrainian localization**

View File

@@ -839,7 +839,8 @@ msgstr "Remplacer les fichiers effacés par des liens"
msgid ""
"After having deleted a duplicate, place a link targeting the reference 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."
#: qt/base/deletion_options.py:45

177
locale/ru/LC_MESSAGES/columns.po Executable file → Normal file
View File

@@ -1,120 +1,121 @@
#
msgid ""
msgstr ""
"Project-Id-Version: Russian translation\n"
"Project-Id-Version: dupeGuru\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: Igor Pavlov <IgorPavlov87@mail.ru>\n"
"Language-Team: Igor Pavlov <IgorPavlov87@mail.ru>\n"
"Last-Translator: Kyrill Detinov <lazy.kent@opensuse.org>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\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-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/problem_table.py:17
msgid "File Path"
msgstr "Путь к файлу"
#: core/gui/problem_table.py:18
msgid "Error Message"
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: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_se/result_table.py:21
msgid "Kind"
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_se/result_table.py:23
msgid "Match %"
msgstr "Совпадение %"
#: core_me/result_table.py:34 core_se/result_table.py:24
msgid "Words Used"
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/result_table.py:35 core_pe/result_table.py:25
#: core_se/result_table.py:25
msgid "Dupe Count"
msgstr "Dupe графа"
#: core_me/result_table.py:23
msgid "Sample Rate"
msgstr "Частота"
#: core_pe/prioritize.py:16 core_pe/result_table.py:22
msgid "Dimensions"
msgstr "Размеры"
#: core_me/prioritize.py:28
msgid "Samplerate"
msgstr "Частота оцифровки"
#: core/prioritize.py:147
msgid "Size"
msgstr "Размер"
#: core_pe/result_table.py:20 core_se/result_table.py:20
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
View File

@@ -1,37 +1,28 @@
#
msgid ""
msgstr ""
"Project-Id-Version: Russian translation\n"
"Project-Id-Version: dupeGuru\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: Igor Pavlov <IgorPavlov87@mail.ru>\n"
"Language-Team: Igor Pavlov <IgorPavlov87@mail.ru>\n"
"Last-Translator: Kyrill Detinov <lazy.kent@opensuse.org>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-Country: RUSSIAN FEDERATION\n"
"X-Poedit-Language: Russian\n"
"Language: ru_RU\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
msgid "will only be able to delete, move or copy 10 duplicates at once"
msgstr ""
"сможете только для удаления, перемещения или копирования 10 копий сразу"
#: core/results.py:120
msgid " filter: %s"
msgstr "фильтр: %s"
#: core/app.py:273
msgid ""
"You cannot delete, move or copy more than 10 duplicates at once in demo "
"mode."
msgstr ""
"Вы не можете удалять, перемещать или копировать более 10 дубликатов сразу в "
"демонстрационном режиме."
#: core/results.py:113
msgid "%d / %d (%s / %s) duplicates marked."
msgstr "%d / %d (%s / %s) дубликатов отмечено."
#: core/app.py:543
msgid "Collecting files to scan"
msgstr "Сбор файлов для сканирования"
#: core/app.py:554
msgid "The selected directories contain no scannable file."
msgstr "Выбранных директорий не содержат сканируемых файлов."
#: core/engine.py:196 core/engine.py:223
msgid "%d matches found"
msgstr "%d совпадений найдено"
#: core/app.py:593
msgid "%s (%d discarded)"
@@ -39,31 +30,56 @@ msgstr "%s. (%d отменено)"
#: core/engine.py:178 core/engine.py:215
msgid "0 matches found"
msgstr "0 сопоставлений найдено"
msgstr "0 совпадений найдено"
#: core/engine.py:196 core/engine.py:223
msgid "%d matches found"
msgstr "%d сопоставлений найдено"
#: core/app.py:244
msgid "All marked files were copied sucessfully."
msgstr "Все отмеченные файлы были скопированы успешно."
#: core/engine.py:208 core/scanner.py:80
msgid "Read size of %d/%d files"
msgstr "Реалний размер %d/%d файлов"
#: core/app.py:245
msgid "All marked files were moved sucessfully."
msgstr "Все отмеченные файлы были перемещены успешно."
#: core/engine.py:360
msgid "Grouped %d/%d matches"
msgstr "Группировка %d/%d совпадений"
#: core/app.py:246
msgid "All marked files were sucessfully sent to Trash."
msgstr "Все отмеченные файлы были успешно отправлены в Корзину."
#: core/prioritize.py:68
msgid "None"
msgstr "Ни один"
#: core/app.py:293
msgid ""
"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
msgid "Ends with number"
msgstr "Заканчивается номером"
#: core/prioritize.py:97
msgid "Doesn't end with number"
msgstr "Не заканчивается с номером"
#: core/engine.py:360
msgid "Grouped %d/%d matches"
msgstr "Группировка %d/%d совпадений"
#: core/prioritize.py:132
msgid "Highest"
@@ -71,59 +87,95 @@ msgstr "Наивысший"
#: core/prioritize.py:132
msgid "Lowest"
msgstr "Самая низкая"
msgstr "Самый низкий"
#: core/prioritize.py:159
msgid "Newest"
msgstr "Новейший"
#: core/app.py:231
msgid "No duplicates found."
msgstr "Дубликаты не найдены."
#: core/prioritize.py:68
msgid "None"
msgstr "Ни один"
#: core/prioritize.py:159
msgid "Oldest"
msgstr "Старейшие"
#: core/results.py:113
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 фотографии"
# Not sure.
#: core_pe/matchblock.py:152
msgid "Performed %d/%d chunk matches"
msgstr "Исполняет %d/%d совпадениях кусоков"
msgstr "Выполнено %d/%d совпадений блоков"
#: core_pe/matchblock.py:157
msgid "Preparing for matching"
msgstr "Подготовка для сравнения"
#: core_pe/matchblock.py:192
msgid "Verified %d/%d matches"
msgstr "Проверенные %d/%d совпадениях"
# Not sure.
#: core/scanner.py:149
msgid "Processed %d/%d matches against the ignore list"
msgstr "Обработано %d/%d совпадений используя список игнорирования"
#: core_pe/matchexif.py:21
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
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."
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
msgid "'{}' already is in the list."
msgstr ""
@@ -210,3 +196,19 @@ msgstr ""
#: core/app.py:380
msgid "Select a destination for your exported CSV"
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

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,6 @@ jobprogress>=1.0.4
Send2Trash3k>=1.2.0
sphinx>=1.1.3
polib>=0.7.0
hsaudiotag3k>=1.1.2
hsaudiotag3k>=1.1.3
pytest>=2.0.0
pytest-monkeyplus>=1.0.0