Vladimir Golovnev
6 years ago
committed by
GitHub
61 changed files with 92642 additions and 178 deletions
@ -1,97 +0,0 @@ |
|||||||
/*
|
|
||||||
* Bittorrent Client using Qt and libtorrent. |
|
||||||
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru> |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or |
|
||||||
* modify it under the terms of the GNU General Public License |
|
||||||
* as published by the Free Software Foundation; either version 2 |
|
||||||
* of the License, or (at your option) any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; if not, write to the Free Software |
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
||||||
* |
|
||||||
* In addition, as a special exception, the copyright holders give permission to |
|
||||||
* link this program with the OpenSSL project's "OpenSSL" library (or with |
|
||||||
* modified versions of it that use the same license as the "OpenSSL" library), |
|
||||||
* and distribute the linked executables. You must obey the GNU General Public |
|
||||||
* License in all respects for all of the code used other than "OpenSSL". If you |
|
||||||
* modify file(s), you may extend this exception to your version of the file(s), |
|
||||||
* but you are not obligated to do so. If you do not wish to do so, delete this |
|
||||||
* exception statement from your version. |
|
||||||
*/ |
|
||||||
|
|
||||||
#ifndef EXTRA_TRANSLATIONS_H |
|
||||||
#define EXTRA_TRANSLATIONS_H |
|
||||||
|
|
||||||
#include <QObject> |
|
||||||
|
|
||||||
// Additional translations for Web UI
|
|
||||||
const char *QBT_WEBUI_TRANSLATIONS[] = { |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Logout"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Exit qBittorrent"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Download Torrents from their URLs or Magnet links"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Only one link per line"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Upload local torrent"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Are you sure you want to delete the selected torrents from the transfer list?"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Global upload rate limit must be greater than 0 or disabled."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Global download rate limit must be greater than 0 or disabled."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Alternative upload rate limit must be greater than 0 or disabled."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Alternative download rate limit must be greater than 0 or disabled."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Maximum active downloads must be greater than -1."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Maximum active uploads must be greater than -1."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Maximum active torrents must be greater than -1."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Maximum number of connections limit must be greater than 0 or disabled."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Maximum number of connections per torrent limit must be greater than 0 or disabled."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Maximum number of upload slots per torrent limit must be greater than 0 or disabled."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Unable to save program preferences, qBittorrent is probably unreachable."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "The port used for incoming connections must be between 1 and 65535."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "The port used for the Web UI must be between 1 and 65535."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Save"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "qBittorrent client is not reachable"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "qBittorrent has been shutdown."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Unable to log in, qBittorrent is probably unreachable."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Invalid Username or Password."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Username"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Password"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Login"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Original authors"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Apply"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Add"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Save files to location:"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Cookie:"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Type folder here"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "More information"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Information about certificates"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Save Files to"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "IRC: #qbittorrent on Freenode"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Invalid category name:\nPlease do not use any special characters in the category name."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Unknown"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Hard Disk"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Share ratio limit must be between 0 and 9998."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Seeding time limit must be between 0 and 525600 minutes."), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Set location"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Limit upload rate"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Limit download rate"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Rename torrent"), |
|
||||||
QT_TRANSLATE_NOOP("HttpServer", "Unable to create category") |
|
||||||
}; |
|
||||||
|
|
||||||
const struct { const char *source; const char *comment; } QBT_WEBUI_COMMENTED_TRANSLATIONS[] = { |
|
||||||
QT_TRANSLATE_NOOP3("HttpServer", "Other...", "Save Files to: Watch Folder / Default Folder / Other..."), |
|
||||||
QT_TRANSLATE_NOOP3("HttpServer", "Monday", "Schedule the use of alternative rate limits on ..."), |
|
||||||
QT_TRANSLATE_NOOP3("HttpServer", "Tuesday", "Schedule the use of alternative rate limits on ..."), |
|
||||||
QT_TRANSLATE_NOOP3("HttpServer", "Wednesday", "Schedule the use of alternative rate limits on ..."), |
|
||||||
QT_TRANSLATE_NOOP3("HttpServer", "Thursday", "Schedule the use of alternative rate limits on ..."), |
|
||||||
QT_TRANSLATE_NOOP3("HttpServer", "Friday", "Schedule the use of alternative rate limits on ..."), |
|
||||||
QT_TRANSLATE_NOOP3("HttpServer", "Saturday", "Schedule the use of alternative rate limits on ..."), |
|
||||||
QT_TRANSLATE_NOOP3("HttpServer", "Sunday", "Schedule the use of alternative rate limits on ..."), |
|
||||||
QT_TRANSLATE_NOOP3("HttpServer", "Upload Torrents", "Upload torrent files to qBittorent using WebUI") |
|
||||||
}; |
|
||||||
|
|
||||||
#endif // EXTRA_TRANSLATIONS_H
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,181 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
# -*- coding: utf-8 -*- |
||||||
|
|
||||||
|
# TSTool - script for update qBittorrent WebUI translation files |
||||||
|
# Copyright (C) 2018 Vladimir Golovnev <glassez@yandex.ru> |
||||||
|
# |
||||||
|
# This program is free software; you can redistribute it and/or |
||||||
|
# modify it under the terms of the GNU General Public License |
||||||
|
# as published by the Free Software Foundation; either version 2 |
||||||
|
# of the License, or (at your option) any later version. |
||||||
|
# |
||||||
|
# This program is distributed in the hope that it will be useful, |
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
# GNU General Public License for more details. |
||||||
|
# |
||||||
|
# You should have received a copy of the GNU General Public License |
||||||
|
# along with this program; if not, write to the Free Software |
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
# |
||||||
|
# In addition, as a special exception, the copyright holders give permission to |
||||||
|
# link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
# modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
# and distribute the linked executables. You must obey the GNU General Public |
||||||
|
# License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
# modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
# but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
# exception statement from your version. |
||||||
|
|
||||||
|
import argparse |
||||||
|
import copy |
||||||
|
import os |
||||||
|
import os.path |
||||||
|
import re |
||||||
|
import sys |
||||||
|
import xml.etree.ElementTree as ET |
||||||
|
|
||||||
|
accepted_exts = [".js", ".html", ".css"] |
||||||
|
|
||||||
|
no_obsolete = False |
||||||
|
www_folder = "." |
||||||
|
ts_folder = os.path.join(www_folder, "translations") |
||||||
|
|
||||||
|
def parseSource(filename, sources): |
||||||
|
print("Parsing %s..." % (os.path.normpath(filename))) |
||||||
|
with open(filename, encoding = 'utf-8', mode = 'r') as file: |
||||||
|
regex = re.compile( |
||||||
|
r"QBT_TR\((([^\)]|\)(?!QBT_TR))+)\)QBT_TR\[CONTEXT=([a-zA-Z_][a-zA-Z0-9_]*)\]") |
||||||
|
for match in regex.finditer(file.read()): |
||||||
|
string = match.group(1) |
||||||
|
context = match.group(3) |
||||||
|
|
||||||
|
if context not in sources: |
||||||
|
sources[context] = set() |
||||||
|
sources[context].add(string) |
||||||
|
|
||||||
|
def processTranslation(filename, sources): |
||||||
|
print('Processing %s...' % (os.path.normpath(filename))) |
||||||
|
|
||||||
|
try: |
||||||
|
tree = ET.ElementTree(file = filename) |
||||||
|
except Exception: |
||||||
|
print('\tFailed to parse %s!' % (os.path.normpath(filename))) |
||||||
|
return |
||||||
|
|
||||||
|
root = tree.getroot() |
||||||
|
for context in root.findall('context'): |
||||||
|
context_name = context.find('name').text |
||||||
|
has_context = context_name in sources |
||||||
|
if not has_context and no_obsolete: |
||||||
|
root.remove(context) |
||||||
|
continue |
||||||
|
|
||||||
|
for message in context.findall('message'): |
||||||
|
for location in message.findall('location'): |
||||||
|
message.remove(location) |
||||||
|
|
||||||
|
source = message.find('source').text |
||||||
|
translation = message.find('translation') |
||||||
|
if has_context and source in sources[context_name]: |
||||||
|
sources[context_name].remove(source) |
||||||
|
|
||||||
|
trtype = translation.attrib.get('type') |
||||||
|
if (trtype == 'obsolete') or (trtype == 'vanished'): |
||||||
|
del translation.attrib['type'] # i.e. finished |
||||||
|
else: |
||||||
|
if no_obsolete or (translation.attrib.get('type', '') == 'unfinished'): |
||||||
|
context.remove(message) |
||||||
|
else: |
||||||
|
translation.attrib['type'] = 'vanished' |
||||||
|
|
||||||
|
if not has_context: |
||||||
|
continue |
||||||
|
|
||||||
|
# add new messages for current context |
||||||
|
for source in sources[context_name]: |
||||||
|
message = ET.SubElement(context, 'message') |
||||||
|
ET.SubElement(message, 'source').text = source |
||||||
|
ET.SubElement(message, 'translation', {'type': 'unfinished'}) |
||||||
|
del sources[context_name] |
||||||
|
|
||||||
|
# add messages for new contexts |
||||||
|
for context_name in sources: |
||||||
|
context = ET.SubElement(root, 'context') |
||||||
|
ET.SubElement(context, 'name').text = context_name |
||||||
|
|
||||||
|
for source in sources[context_name]: |
||||||
|
message = ET.SubElement(context, 'message') |
||||||
|
ET.SubElement(message, 'source').text = source |
||||||
|
ET.SubElement(message, 'translation', {'type': 'unfinished'}) |
||||||
|
|
||||||
|
# prettify output xml |
||||||
|
indent = ' ' * 4 |
||||||
|
root.text = '\n' |
||||||
|
for context in root.findall('./context'): |
||||||
|
context.text = '\n' + indent |
||||||
|
context.tail = '\n' |
||||||
|
context.find('./name').tail = '\n' + indent |
||||||
|
messages = context.findall('./message') |
||||||
|
if len(messages) == 0: continue |
||||||
|
|
||||||
|
for message in messages: |
||||||
|
message.text = '\n' + (indent * 2) |
||||||
|
message.tail = '\n' + indent |
||||||
|
elems = message.findall('./') |
||||||
|
if len(elems) == 0: continue |
||||||
|
|
||||||
|
for elem in elems: |
||||||
|
elem.tail = '\n' + (indent * 2) |
||||||
|
elems[-1:][0].tail = '\n' + indent |
||||||
|
messages[-1:][0].tail = '\n' |
||||||
|
|
||||||
|
try: |
||||||
|
with open(filename, mode = 'wb') as file: |
||||||
|
file.write(b'<?xml version="1.0" encoding="utf-8"?>\n' |
||||||
|
b'<!DOCTYPE TS>\n') |
||||||
|
tree.write(file, encoding = 'utf-8') |
||||||
|
except Exception: |
||||||
|
print('\tFailed to write %s!' % (os.path.normpath(filename))) |
||||||
|
|
||||||
|
argp = argparse.ArgumentParser( |
||||||
|
prog = 'tstool.py', description = 'Update qBittorrent WebUI translation files.') |
||||||
|
argp.add_argument('--no-obsolete', dest = 'no_obsolete', action = 'store_true', |
||||||
|
default = no_obsolete, |
||||||
|
help = 'remove obsolete messages (default: mark them as obsolete)') |
||||||
|
argp.add_argument('--www-folder', dest = 'www_folder', action = 'store', |
||||||
|
default = www_folder, |
||||||
|
help = 'folder with WebUI source files (default: "%s")' % (www_folder)) |
||||||
|
argp.add_argument('--ts-folder', dest = 'ts_folder', action = 'store', |
||||||
|
default = ts_folder, |
||||||
|
help = 'folder with WebUI translation files (default: "%s")' % (ts_folder)) |
||||||
|
|
||||||
|
args = argp.parse_args() |
||||||
|
no_obsolete = args.no_obsolete |
||||||
|
www_folder = args.www_folder |
||||||
|
ts_folder = args.ts_folder |
||||||
|
|
||||||
|
print("Processing source files...") |
||||||
|
nfiles = 0 |
||||||
|
source_ts = {} |
||||||
|
for root, dirs, files in os.walk(www_folder): |
||||||
|
for file in files: |
||||||
|
if os.path.splitext(file)[-1] in accepted_exts: |
||||||
|
parseSource(os.path.join(root, file), source_ts) |
||||||
|
nfiles += 1 |
||||||
|
|
||||||
|
if nfiles == 0: |
||||||
|
print("No source files found!") |
||||||
|
sys.exit() |
||||||
|
|
||||||
|
nstrings = sum(len(sublist) for sublist in source_ts) |
||||||
|
print("Found %d strings within %d contexts." % (nstrings, len(source_ts))) |
||||||
|
print("") |
||||||
|
|
||||||
|
print("Processing translation files...") |
||||||
|
for entry in os.scandir(ts_folder): |
||||||
|
if (entry.is_file() and entry.name.startswith('webui_') |
||||||
|
and entry.name.endswith(".ts")): |
||||||
|
processTranslation(entry.path, copy.deepcopy(source_ts)) |
||||||
|
|
||||||
|
print("Done!") |
Loading…
Reference in new issue