37
Usage = """updatets - update all .ts files found in the source directories
44
(c) 2019 FreeCAD Volunteers
57
{"tsname": "App", "workingdir": "./src/App", "tsdir": "Resources/translations"},
58
{"tsname": "Base", "workingdir": "./src/Base", "tsdir": "Resources/translations"},
59
{"tsname": "FreeCAD", "workingdir": "./src/Gui", "tsdir": "Language"},
61
"tsname": "AddonManager",
62
"workingdir": "./src/Mod/AddonManager/",
63
"tsdir": "Resources/translations",
67
"workingdir": "./src/Mod/Arch/",
68
"tsdir": "Resources/translations",
72
"workingdir": "./src/Mod/Assembly/",
73
"tsdir": "Gui/Resources/translations",
77
"workingdir": "./src/Mod/Draft/",
78
"tsdir": "Resources/translations",
82
"workingdir": "./src/Mod/Drawing/",
83
"tsdir": "Gui/Resources/translations",
87
"workingdir": "./src/Mod/Fem/",
88
"tsdir": "Gui/Resources/translations",
91
"tsname": "Inspection",
92
"workingdir": "./src/Mod/Inspection/",
93
"tsdir": "Gui/Resources/translations",
97
"workingdir": "./src/Mod/Material/",
98
"tsdir": "Resources/translations",
102
"workingdir": "./src/Mod/Mesh/",
103
"tsdir": "Gui/Resources/translations",
106
"tsname": "MeshPart",
107
"workingdir": "./src/Mod/MeshPart/",
108
"tsdir": "Gui/Resources/translations",
111
"tsname": "OpenSCAD",
112
"workingdir": "./src/Mod/OpenSCAD/",
113
"tsdir": "Resources/translations",
116
"tsname": "PartDesign",
117
"workingdir": "./src/Mod/PartDesign/",
118
"tsdir": "Gui/Resources/translations",
122
"workingdir": "./src/Mod/Part/",
123
"tsdir": "Gui/Resources/translations",
127
"workingdir": "./src/Mod/CAM/",
128
"tsdir": "Gui/Resources/translations",
132
"workingdir": "./src/Mod/Points/",
133
"tsdir": "Gui/Resources/translations",
136
"tsname": "ReverseEngineering",
137
"workingdir": "./src/Mod/ReverseEngineering/",
138
"tsdir": "Gui/Resources/translations",
142
"workingdir": "./src/Mod/Robot/",
143
"tsdir": "Gui/Resources/translations",
146
"tsname": "Sketcher",
147
"workingdir": "./src/Mod/Sketcher/",
148
"tsdir": "Gui/Resources/translations",
151
"tsname": "Spreadsheet",
152
"workingdir": "./src/Mod/Spreadsheet/",
153
"tsdir": "Gui/Resources/translations",
156
"tsname": "StartPage",
157
"workingdir": "./src/Mod/Start/",
158
"tsdir": "Gui/Resources/translations",
161
"tsname": "TechDraw",
162
"workingdir": "./src/Mod/TechDraw/",
163
"tsdir": "Gui/Resources/translations",
167
"workingdir": "./src/Mod/Test/",
168
"tsdir": "Gui/Resources/translations",
172
"workingdir": "./src/Mod/Tux/",
173
"tsdir": "Resources/translations",
177
"workingdir": "./src/Mod/Web/",
178
"tsdir": "Gui/Resources/translations",
182
"workingdir": "./src/Mod/Help/",
183
"tsdir": "Resources/translations",
189
("CAM", "UtilsArguments.py"),
190
("CAM", "refactored_centroid_post.py"),
191
("CAM", "refactored_grbl_post.py"),
192
("CAM", "refactored_linuxcnc_post.py"),
193
("CAM", "refactored_mach3_mach4_post.py"),
194
("CAM", "refactored_test_post.py"),
204
def find_tools(noobsolete=True):
206
print(Usage + "\nFirst, lets find all necessary tools on your system")
207
global QMAKE, LUPDATE, PYLUPDATE, LCONVERT, QT_VERSION_MAJOR
209
p = subprocess.run(["lupdate", "-version"], check=True, stdout=subprocess.PIPE)
210
lupdate_version = p.stdout.decode()
211
result = re.search(r".* ([456])\.([\d]+)\.([\d]+)", lupdate_version)
213
print(f"Failed to parse version from {lupdate_version}")
214
QT_VERSION_MAJOR = int(result.group(1))
215
QT_VERSION_MINOR = int(result.group(2))
216
QT_VERSION_PATCH = int(result.group(3))
217
QT_VERSION = f"{QT_VERSION_MAJOR}.{QT_VERSION_MINOR}.{QT_VERSION_PATCH}"
218
print(f"Found Qt {QT_VERSION}")
220
if QT_VERSION_MAJOR < 6:
221
if os.system("lupdate -version") == 0:
225
LUPDATE += " -no-obsolete"
226
elif os.system("lupdate-qt5 -version") == 0:
227
LUPDATE = "lupdate-qt5"
229
LUPDATE += " -no-obsolete"
231
raise Exception("Cannot find lupdate")
235
if QT_VERSION_MAJOR < 6:
236
if os.system("qmake -version") == 0:
238
elif os.system("qmake-qt5 -version") == 0:
241
raise Exception("Cannot find qmake")
242
if os.system("pylupdate -version") == 0:
243
PYLUPDATE = "pylupdate"
244
elif os.system("pylupdate6 --version") == 0:
245
PYLUPDATE = "pylupdate6"
247
PYLUPDATE += " -no-obsolete"
248
elif os.system("pylupdate5 -version") == 0:
249
PYLUPDATE = "pylupdate5"
251
PYLUPDATE += " -noobsolete"
252
elif os.system("pyside2-lupdate -version") == 0:
253
PYLUPDATE = "pyside2-lupdate"
255
"Please do not use pyside2-lupdate at the moment, as it shows encoding problems. Please use pylupdate5 or 6 instead."
258
raise Exception("Cannot find pylupdate")
260
QMAKE = "(qmake not needed for Qt 6 and later)"
261
PYLUPDATE = "(pylupdate not needed for Qt 6 and later)"
262
if os.system("lconvert -h") == 0:
263
LCONVERT = "lconvert"
264
if noobsolete and QT_VERSION_MAJOR < 6:
265
LCONVERT += " -no-obsolete"
267
raise Exception("Cannot find lconvert")
269
"\nAll Qt tools have been found!\n",
271
"\t" + LUPDATE + "\n",
272
"\t" + PYLUPDATE + "\n",
273
"\t" + LCONVERT + "\n",
275
print("==============================================\n")
278
def update_translation(entry):
280
global QMAKE, LUPDATE, LCONVERT, QT_VERSION_MAJOR
282
log_redirect = f" 2>> {cur}/tsupdate_stderr.log 1>> {cur}/tsupdate_stdout.log"
283
os.chdir(entry["workingdir"])
284
existingjsons = [f for f in os.listdir(".") if f.endswith(".json")]
285
project_filename = entry["tsname"] + ".pro"
286
tsBasename = os.path.join(entry["tsdir"], entry["tsname"])
288
if QT_VERSION_MAJOR < 6:
289
print("\n\n=============================================")
290
print(f"EXTRACTING STRINGS FOR {entry['tsname']}")
291
print("=============================================", flush=True)
294
f"touch dummy_cpp_file_for_lupdate.cpp"
296
execline.append(f"touch {tsBasename}py.ts")
297
execline.append(f'{PYLUPDATE} `find ./ -name "*.py"` -ts {tsBasename}py.ts {log_redirect}')
298
execline.append(f"{QMAKE} -project -o {project_filename} -r")
299
execline.append(f"{LUPDATE} {project_filename} -ts {tsBasename}.ts {log_redirect}")
301
f"sed 's/<translation.*>.*<\/translation>/<translation type=\"unfinished\"><\/translation>/g' {tsBasename}.ts > {tsBasename}.ts.temp"
303
execline.append(f"mv {tsBasename}.ts.temp {tsBasename}.ts")
305
f"{LCONVERT} -i {tsBasename}py.ts {tsBasename}.ts -o {tsBasename}.ts {log_redirect}"
307
execline.append(f"rm {tsBasename}py.ts")
308
execline.append(f"rm dummy_cpp_file_for_lupdate.cpp")
310
print(f"Executing commands in {entry['workingdir']}:")
311
for line in execline:
316
os.remove(project_filename)
318
for jsonfile in [f for f in os.listdir(".") if f.endswith(".json")]:
319
if not jsonfile in existingjsons:
322
elif QT_VERSION_MAJOR == 6:
348
with open("files_to_translate.txt", "w", encoding="utf-8") as file_list:
349
for root, dirs, files in os.walk("./"):
352
for exclusion in excluded_files:
353
if entry["tsname"] == exclusion[0] and f == exclusion[1]:
355
f" (NOTE: Excluding file {f} because it is in the excluded_files list)"
359
if not skip and pathlib.Path(f).suffix[1:] in extensions:
360
file_list.write(os.path.join(root, f) + "\n")
366
"@files_to_translate.txt",
379
raise RuntimeError("No return result from lupdate")
381
raise RuntimeError("No stdout from lupdate")
382
except Exception as e:
386
print(f"ERROR RUNNING lupdate -- TRANSLATIONS FOR {entry['tsname']} PROBABLY FAILED...")
394
with open(f"{cur}/tsupdate_stdout.log", "a", encoding="utf-8") as f:
396
print(p.stdout, flush=True)
398
with open(f"{cur}/tsupdate_stderr.log", "a", encoding="utf-8") as f:
405
"-drop-translations",
415
"ERROR: unrecognized version of lupdate -- found Qt {QT_VERSION_MAJOR}, we only support 4, 5 and 6"
425
path = os.path.realpath(__file__)
426
path = os.path.dirname(path)
430
print("\n\n\n BEGINNING TRANSLATION EXTRACTION \n\n")
432
for i in directories:
433
if i["tsname"] == mod:
434
print("WARNING - Updating", mod, "ONLY")
435
update_translation(i)
438
for i in directories:
439
update_translation(i)
441
"\nIf updatets.py was run successfully, the next step is to run ./src/Tools/updatecrowdin.py"
443
print("stderr output from lupdate can be found in tsupdate_stderr.log")
444
print("stdout output from lupdate can be found in tsupdate_stdout.log")
447
if __name__ == "__main__":
448
if len(sys.argv[1:]) > 0: