WebUI: Improve hash copy actions in context menu
[qBittorrent.git] / src / webui / www / tstool.py
blob2166815dcfd2b42ef38e4229797fc02e07aaffad
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
4 # TSTool - script for update qBittorrent WebUI translation files
5 # Copyright (C) 2018 Vladimir Golovnev <glassez@yandex.ru>
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License
9 # as published by the Free Software Foundation; either version 2
10 # of the License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 # In addition, as a special exception, the copyright holders give permission to
22 # link this program with the OpenSSL project's "OpenSSL" library (or with
23 # modified versions of it that use the same license as the "OpenSSL" library),
24 # and distribute the linked executables. You must obey the GNU General Public
25 # License in all respects for all of the code used other than "OpenSSL". If you
26 # modify file(s), you may extend this exception to your version of the file(s),
27 # but you are not obligated to do so. If you do not wish to do so, delete this
28 # exception statement from your version.
30 import argparse
31 import copy
32 import os
33 import os.path
34 import re
35 import sys
36 import xml.etree.ElementTree as ET
38 accepted_exts = [".js", ".html", ".css"]
40 no_obsolete = False
41 www_folder = "."
42 ts_folder = os.path.join(www_folder, "translations")
45 def parseSource(filename, sources):
46 print("Parsing %s..." % (os.path.normpath(filename)))
47 with open(filename, encoding='utf-8', mode='r') as file:
48 regex = re.compile(
49 r"QBT_TR\((([^\)]|\)(?!QBT_TR))+)\)QBT_TR\[CONTEXT=([a-zA-Z_][a-zA-Z0-9_]*)\]")
50 for match in regex.finditer(file.read()):
51 string = match.group(1)
52 context = match.group(3)
54 if context not in sources:
55 sources[context] = set()
56 sources[context].add(string)
59 def processTranslation(filename, sources):
60 print('Processing %s...' % (os.path.normpath(filename)))
62 try:
63 tree = ET.ElementTree(file=filename)
64 except Exception:
65 print('\tFailed to parse %s!' % (os.path.normpath(filename)))
66 return
68 root = tree.getroot()
69 for context in root.findall('context'):
70 context_name = context.find('name').text
71 has_context = context_name in sources
72 if not has_context and no_obsolete:
73 root.remove(context)
74 continue
76 for message in context.findall('message'):
77 for location in message.findall('location'):
78 message.remove(location)
80 source = message.find('source').text
81 translation = message.find('translation')
82 if has_context and source in sources[context_name]:
83 sources[context_name].remove(source)
85 trtype = translation.attrib.get('type')
86 if (trtype == 'obsolete') or (trtype == 'vanished'):
87 del translation.attrib['type'] # i.e. finished
88 else:
89 if no_obsolete or (translation.attrib.get('type', '') == 'unfinished'):
90 context.remove(message)
91 else:
92 translation.attrib['type'] = 'vanished'
94 if not has_context:
95 continue
97 # add new messages for current context
98 for source in sources[context_name]:
99 message = ET.SubElement(context, 'message')
100 ET.SubElement(message, 'source').text = source
101 ET.SubElement(message, 'translation', {'type': 'unfinished'})
102 del sources[context_name]
104 # add messages for new contexts
105 for context_name in sources:
106 context = ET.SubElement(root, 'context')
107 ET.SubElement(context, 'name').text = context_name
109 for source in sources[context_name]:
110 message = ET.SubElement(context, 'message')
111 ET.SubElement(message, 'source').text = source
112 ET.SubElement(message, 'translation', {'type': 'unfinished'})
114 # prettify output xml
115 indent = ' ' * 4
116 root.text = '\n'
117 for context in root.findall('./context'):
118 context.text = '\n' + indent
119 context.tail = '\n'
120 context.find('./name').tail = '\n' + indent
121 messages = context.findall('./message')
122 if len(messages) == 0:
123 continue
125 for message in messages:
126 message.text = '\n' + (indent * 2)
127 message.tail = '\n' + indent
128 elems = message.findall('./')
129 if len(elems) == 0:
130 continue
132 for elem in elems:
133 elem.tail = '\n' + (indent * 2)
134 elems[-1:][0].tail = '\n' + indent
135 messages[-1:][0].tail = '\n'
137 try:
138 with open(filename, mode='wb') as file:
139 file.write(b'<?xml version="1.0" encoding="utf-8"?>\n'
140 b'<!DOCTYPE TS>\n')
141 tree.write(file, encoding='utf-8')
142 except Exception:
143 print('\tFailed to write %s!' % (os.path.normpath(filename)))
146 argp = argparse.ArgumentParser(
147 prog='tstool.py', description='Update qBittorrent WebUI translation files.')
148 argp.add_argument('--no-obsolete', dest='no_obsolete', action='store_true',
149 default=no_obsolete,
150 help='remove obsolete messages (default: mark them as obsolete)')
151 argp.add_argument('--www-folder', dest='www_folder', action='store',
152 default=www_folder,
153 help='folder with WebUI source files (default: "%s")' % (www_folder))
154 argp.add_argument('--ts-folder', dest='ts_folder', action='store',
155 default=ts_folder,
156 help='folder with WebUI translation files (default: "%s")' % (ts_folder))
158 args = argp.parse_args()
159 no_obsolete = args.no_obsolete
160 www_folder = args.www_folder
161 ts_folder = args.ts_folder
163 print("Processing source files...")
164 nfiles = 0
165 source_ts = {}
166 for root, dirs, files in os.walk(www_folder):
167 for file in files:
168 if os.path.splitext(file)[-1] in accepted_exts:
169 parseSource(os.path.join(root, file), source_ts)
170 nfiles += 1
172 if nfiles == 0:
173 print("No source files found!")
174 sys.exit()
176 nstrings = sum(len(sublist) for sublist in source_ts)
177 print("Found %d strings within %d contexts." % (nstrings, len(source_ts)))
178 print("")
180 print("Processing translation files...")
181 for entry in os.scandir(ts_folder):
182 if (entry.is_file() and entry.name.startswith('webui_') and entry.name.endswith(".ts")):
183 processTranslation(entry.path, copy.deepcopy(source_ts))
185 print("Done!")