Sun Position: update HDRI mode shader for Metal compatibility
[blender-addons.git] / ui_translate / update_svn.py
blob18f36eb1db990219eda724bac80c516d5e93878a
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 if "bpy" in locals():
4 import importlib
5 importlib.reload(settings)
6 importlib.reload(utils_i18n)
7 importlib.reload(utils_languages_menu)
8 else:
9 import bpy
10 from bpy.types import Operator
11 from bpy.props import (
12 BoolProperty,
13 EnumProperty,
15 from . import settings
16 from bl_i18n_utils import utils as utils_i18n
17 from bl_i18n_utils import utils_languages_menu
19 import concurrent.futures
20 import io
21 import os
22 import shutil
23 import subprocess
24 import tempfile
27 # Operators ###################################################################
29 def i18n_updatetranslation_svn_branches_callback(pot, lng, settings):
30 if not lng['use']:
31 return
32 if os.path.isfile(lng['po_path']):
33 po = utils_i18n.I18nMessages(uid=lng['uid'], kind='PO', src=lng['po_path'], settings=settings)
34 po.update(pot)
35 else:
36 po = pot
37 po.write(kind="PO", dest=lng['po_path'])
38 print("{} PO written!".format(lng['uid']))
41 class UI_OT_i18n_updatetranslation_svn_branches(Operator):
42 """Update i18n svn's branches (po files)"""
43 bl_idname = "ui.i18n_updatetranslation_svn_branches"
44 bl_label = "Update I18n Branches"
46 use_skip_pot_gen: BoolProperty(
47 name="Skip POT",
48 description="Skip POT file generation",
49 default=False,
52 def execute(self, context):
53 if not hasattr(self, "settings"):
54 self.settings = settings.settings
55 i18n_sett = context.window_manager.i18n_update_svn_settings
56 self.settings.FILE_NAME_POT = i18n_sett.pot_path
58 context.window_manager.progress_begin(0, len(i18n_sett.langs) + 1)
59 context.window_manager.progress_update(0)
60 if not self.use_skip_pot_gen:
61 env = os.environ.copy()
62 env["ASAN_OPTIONS"] = "exitcode=0:" + os.environ.get("ASAN_OPTIONS", "")
63 # Generate base pot from RNA messages (we use another blender instance here, to be able to perfectly
64 # control our environment (factory startup, specific addons enabled/disabled...)).
65 # However, we need to export current user settings about this addon!
66 cmmd = (
67 bpy.app.binary_path,
68 "--background",
69 "--factory-startup",
70 "--python",
71 os.path.join(os.path.dirname(utils_i18n.__file__), "bl_extract_messages.py"),
72 "--",
73 "--settings",
74 self.settings.to_json(),
76 # Not working (UI is not refreshed...).
77 #self.report({'INFO'}, "Extracting messages, this will take some time...")
78 context.window_manager.progress_update(1)
79 ret = subprocess.run(cmmd, env=env)
80 if ret.returncode != 0:
81 self.report({'ERROR'}, "Message extraction process failed!")
82 context.window_manager.progress_end()
83 return {'CANCELLED'}
85 # Now we should have a valid POT file, we have to merge it in all languages po's...
86 with concurrent.futures.ProcessPoolExecutor() as exctr:
87 pot = utils_i18n.I18nMessages(kind='PO', src=self.settings.FILE_NAME_POT, settings=self.settings)
88 num_langs = len(i18n_sett.langs)
89 for progress, _ in enumerate(exctr.map(i18n_updatetranslation_svn_branches_callback,
90 (pot,) * num_langs,
91 [dict(lng.items()) for lng in i18n_sett.langs],
92 (self.settings,) * num_langs,
93 chunksize=4)):
94 context.window_manager.progress_update(progress + 2)
95 context.window_manager.progress_end()
96 return {'FINISHED'}
98 def invoke(self, context, event):
99 wm = context.window_manager
100 return wm.invoke_props_dialog(self)
103 def i18n_cleanuptranslation_svn_branches_callback(lng, settings):
104 if not lng['use']:
105 print("Skipping {} language ({}).".format(lng['name'], lng['uid']))
106 return
107 po = utils_i18n.I18nMessages(uid=lng['uid'], kind='PO', src=lng['po_path'], settings=settings)
108 errs = po.check(fix=True)
109 cleanedup_commented = po.clean_commented()
110 po.write(kind="PO", dest=lng['po_path'])
111 print("Processing {} language ({}).\n"
112 "Cleaned up {} commented messages.\n".format(lng['name'], lng['uid'], cleanedup_commented) +
113 ("Errors in this po, solved as best as possible!\n\t" + "\n\t".join(errs) if errs else "") + "\n")
116 class UI_OT_i18n_cleanuptranslation_svn_branches(Operator):
117 """Clean up i18n svn's branches (po files)"""
118 bl_idname = "ui.i18n_cleanuptranslation_svn_branches"
119 bl_label = "Clean up I18n Branches"
121 def execute(self, context):
122 if not hasattr(self, "settings"):
123 self.settings = settings.settings
124 i18n_sett = context.window_manager.i18n_update_svn_settings
125 # 'DEFAULT' and en_US are always valid, fully-translated "languages"!
126 stats = {"DEFAULT": 1.0, "en_US": 1.0}
128 context.window_manager.progress_begin(0, len(i18n_sett.langs) + 1)
129 context.window_manager.progress_update(0)
130 with concurrent.futures.ProcessPoolExecutor() as exctr:
131 num_langs = len(i18n_sett.langs)
132 for progress, _ in enumerate(exctr.map(i18n_cleanuptranslation_svn_branches_callback,
133 [dict(lng.items()) for lng in i18n_sett.langs],
134 (self.settings,) * num_langs,
135 chunksize=4)):
136 context.window_manager.progress_update(progress + 1)
138 context.window_manager.progress_end()
140 return {'FINISHED'}
143 def i18n_updatetranslation_svn_trunk_callback(lng, settings):
144 reports = []
145 if lng['uid'] in settings.IMPORT_LANGUAGES_SKIP:
146 reports.append("Skipping {} language ({}), edit settings if you want to enable it.".format(lng['name'], lng['uid']))
147 return lng['uid'], 0.0, reports
148 if not lng['use']:
149 reports.append("Skipping {} language ({}).".format(lng['name'], lng['uid']))
150 return lng['uid'], 0.0, reports
151 po = utils_i18n.I18nMessages(uid=lng['uid'], kind='PO', src=lng['po_path'], settings=settings)
152 errs = po.check(fix=True)
153 reports.append("Processing {} language ({}).\n"
154 "Cleaned up {} commented messages.\n".format(lng['name'], lng['uid'], po.clean_commented()) +
155 ("Errors in this po, solved as best as possible!\n\t" + "\n\t".join(errs) if errs else ""))
156 if lng['uid'] in settings.IMPORT_LANGUAGES_RTL:
157 po.write(kind="PO", dest=lng['po_path_trunk'][:-3] + "_raw.po")
158 po.rtl_process()
159 po.write(kind="PO", dest=lng['po_path_trunk'])
160 po.write(kind="PO_COMPACT", dest=lng['po_path_git'])
161 ret = po.write(kind="MO", dest=lng['mo_path_trunk'])
162 if (ret.stdout):
163 reports.append(ret.stdout.decode().rstrip("\n"))
164 if (ret.stderr):
165 stderr_str = ret.stderr.decode().rstrip("\n")
166 if ret.returncode != 0:
167 reports.append("ERROR: " + stderr_str)
168 else:
169 reports.append(stderr_str)
170 po.update_info()
171 return lng['uid'], po.nbr_trans_msgs / po.nbr_msgs, reports
174 class UI_OT_i18n_updatetranslation_svn_trunk(Operator):
175 """Update i18n svn's branches (po files)"""
176 bl_idname = "ui.i18n_updatetranslation_svn_trunk"
177 bl_label = "Update I18n Trunk"
179 def execute(self, context):
180 if not hasattr(self, "settings"):
181 self.settings = settings.settings
182 i18n_sett = context.window_manager.i18n_update_svn_settings
183 # 'DEFAULT' and en_US are always valid, fully-translated "languages"!
184 stats = {"DEFAULT": 1.0, "en_US": 1.0}
186 context.window_manager.progress_begin(0, len(i18n_sett.langs) + 1)
187 context.window_manager.progress_update(0)
188 with concurrent.futures.ProcessPoolExecutor() as exctr:
189 num_langs = len(i18n_sett.langs)
190 for progress, (lng_uid, stats_val, reports) in enumerate(exctr.map(i18n_updatetranslation_svn_trunk_callback,
191 [dict(lng.items()) for lng in i18n_sett.langs],
192 (self.settings,) * num_langs,
193 chunksize=4)):
194 context.window_manager.progress_update(progress + 1)
195 stats[lng_uid] = stats_val
196 print("".join(reports) + "\n")
198 # Copy pot file from branches to trunk.
199 shutil.copy2(self.settings.FILE_NAME_POT, self.settings.TRUNK_PO_DIR)
201 print("Generating languages' menu...")
202 context.window_manager.progress_update(progress + 2)
203 # First complete our statistics by checking po files we did not touch this time!
204 po_to_uid = {os.path.basename(lng.po_path): lng.uid for lng in i18n_sett.langs}
205 for po_path in os.listdir(self.settings.TRUNK_PO_DIR):
206 uid = po_to_uid.get(po_path, None)
207 po_path = os.path.join(self.settings.TRUNK_PO_DIR, po_path)
208 if uid and uid not in stats:
209 po = utils_i18n.I18nMessages(uid=uid, kind='PO', src=po_path, settings=self.settings)
210 stats[uid] = po.nbr_trans_msgs / po.nbr_msgs if po.nbr_msgs > 0 else 0
211 utils_languages_menu.gen_menu_file(stats, self.settings)
212 context.window_manager.progress_end()
214 return {'FINISHED'}
217 class UI_OT_i18n_updatetranslation_svn_statistics(Operator):
218 """Create or extend a 'i18n_info.txt' Text datablock"""
219 """(it will contain statistics and checks about current branches and/or trunk)"""
220 bl_idname = "ui.i18n_updatetranslation_svn_statistics"
221 bl_label = "Update I18n Statistics"
223 use_branches: BoolProperty(
224 name="Check Branches",
225 description="Check po files in branches",
226 default=True,
229 use_trunk: BoolProperty(
230 name="Check Trunk",
231 description="Check po files in trunk",
232 default=False,
235 report_name = "i18n_info.txt"
237 def execute(self, context):
238 if not hasattr(self, "settings"):
239 self.settings = settings.settings
240 i18n_sett = context.window_manager.i18n_update_svn_settings
242 buff = io.StringIO()
243 lst = []
244 if self.use_branches:
245 lst += [(lng, lng.po_path) for lng in i18n_sett.langs]
246 if self.use_trunk:
247 lst += [(lng, lng.po_path_trunk) for lng in i18n_sett.langs
248 if lng.uid not in self.settings.IMPORT_LANGUAGES_SKIP]
250 context.window_manager.progress_begin(0, len(lst))
251 context.window_manager.progress_update(0)
252 for progress, (lng, path) in enumerate(lst):
253 context.window_manager.progress_update(progress + 1)
254 if not lng.use:
255 print("Skipping {} language ({}).".format(lng.name, lng.uid))
256 continue
257 buff.write("Processing {} language ({}, {}).\n".format(lng.name, lng.uid, path))
258 po = utils_i18n.I18nMessages(uid=lng.uid, kind='PO', src=path, settings=self.settings)
259 po.print_info(prefix=" ", output=buff.write)
260 errs = po.check(fix=False)
261 if errs:
262 buff.write(" WARNING! Po contains following errors:\n")
263 buff.write(" " + "\n ".join(errs))
264 buff.write("\n")
265 buff.write("\n\n")
267 text = None
268 if self.report_name not in bpy.data.texts:
269 text = bpy.data.texts.new(self.report_name)
270 else:
271 text = bpy.data.texts[self.report_name]
272 data = text.as_string()
273 data = data + "\n" + buff.getvalue()
274 text.from_string(data)
275 self.report({'INFO'}, "Info written to {} text datablock!".format(self.report_name))
276 context.window_manager.progress_end()
278 return {'FINISHED'}
280 def invoke(self, context, event):
281 wm = context.window_manager
282 return wm.invoke_props_dialog(self)
285 classes = (
286 UI_OT_i18n_updatetranslation_svn_branches,
287 UI_OT_i18n_cleanuptranslation_svn_branches,
288 UI_OT_i18n_updatetranslation_svn_trunk,
289 UI_OT_i18n_updatetranslation_svn_statistics,