1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
23 importlib
.reload(settings
)
24 importlib
.reload(utils_i18n
)
25 importlib
.reload(utils_languages_menu
)
28 from bpy
.types
import Operator
29 from bpy
.props
import (
33 from . import settings
34 from bl_i18n_utils
import utils
as utils_i18n
35 from bl_i18n_utils
import utils_languages_menu
37 import concurrent
.futures
45 # Operators ###################################################################
47 def i18n_updatetranslation_svn_branches_callback(pot
, lng
, settings
):
50 if os
.path
.isfile(lng
['po_path']):
51 po
= utils_i18n
.I18nMessages(uid
=lng
['uid'], kind
='PO', src
=lng
['po_path'], settings
=settings
)
55 po
.write(kind
="PO", dest
=lng
['po_path'])
56 print("{} PO written!".format(lng
['uid']))
59 class UI_OT_i18n_updatetranslation_svn_branches(Operator
):
60 """Update i18n svn's branches (po files)"""
61 bl_idname
= "ui.i18n_updatetranslation_svn_branches"
62 bl_label
= "Update I18n Branches"
64 use_skip_pot_gen
: BoolProperty(
66 description
="Skip POT file generation",
70 def execute(self
, context
):
71 if not hasattr(self
, "settings"):
72 self
.settings
= settings
.settings
73 i18n_sett
= context
.window_manager
.i18n_update_svn_settings
74 self
.settings
.FILE_NAME_POT
= i18n_sett
.pot_path
76 context
.window_manager
.progress_begin(0, len(i18n_sett
.langs
) + 1)
77 context
.window_manager
.progress_update(0)
78 if not self
.use_skip_pot_gen
:
79 env
= os
.environ
.copy()
80 env
["ASAN_OPTIONS"] = "exitcode=0:" + os
.environ
.get("ASAN_OPTIONS", "")
81 # Generate base pot from RNA messages (we use another blender instance here, to be able to perfectly
82 # control our environment (factory startup, specific addons enabled/disabled...)).
83 # However, we need to export current user settings about this addon!
89 os
.path
.join(os
.path
.dirname(utils_i18n
.__file
__), "bl_extract_messages.py"),
92 self
.settings
.to_json(),
94 # Not working (UI is not refreshed...).
95 #self.report({'INFO'}, "Extracting messages, this will take some time...")
96 context
.window_manager
.progress_update(1)
97 ret
= subprocess
.run(cmmd
, env
=env
)
98 if ret
.returncode
!= 0:
99 self
.report({'ERROR'}, "Message extraction process failed!")
100 context
.window_manager
.progress_end()
103 # Now we should have a valid POT file, we have to merge it in all languages po's...
104 with concurrent
.futures
.ProcessPoolExecutor() as exctr
:
105 pot
= utils_i18n
.I18nMessages(kind
='PO', src
=self
.settings
.FILE_NAME_POT
, settings
=self
.settings
)
106 num_langs
= len(i18n_sett
.langs
)
107 for progress
, _
in enumerate(exctr
.map(i18n_updatetranslation_svn_branches_callback
,
109 [dict(lng
.items()) for lng
in i18n_sett
.langs
],
110 (self
.settings
,) * num_langs
,
112 context
.window_manager
.progress_update(progress
+ 2)
113 context
.window_manager
.progress_end()
116 def invoke(self
, context
, event
):
117 wm
= context
.window_manager
118 return wm
.invoke_props_dialog(self
)
121 def i18n_cleanuptranslation_svn_branches_callback(lng
, settings
):
123 print("Skipping {} language ({}).".format(lng
['name'], lng
['uid']))
125 po
= utils_i18n
.I18nMessages(uid
=lng
['uid'], kind
='PO', src
=lng
['po_path'], settings
=settings
)
126 errs
= po
.check(fix
=True)
127 cleanedup_commented
= po
.clean_commented()
128 po
.write(kind
="PO", dest
=lng
['po_path'])
129 print("Processing {} language ({}).\n"
130 "Cleaned up {} commented messages.\n".format(lng
['name'], lng
['uid'], cleanedup_commented
) +
131 ("Errors in this po, solved as best as possible!\n\t" + "\n\t".join(errs
) if errs
else "") + "\n")
134 class UI_OT_i18n_cleanuptranslation_svn_branches(Operator
):
135 """Clean up i18n svn's branches (po files)"""
136 bl_idname
= "ui.i18n_cleanuptranslation_svn_branches"
137 bl_label
= "Clean up I18n Branches"
139 def execute(self
, context
):
140 if not hasattr(self
, "settings"):
141 self
.settings
= settings
.settings
142 i18n_sett
= context
.window_manager
.i18n_update_svn_settings
143 # 'DEFAULT' and en_US are always valid, fully-translated "languages"!
144 stats
= {"DEFAULT": 1.0, "en_US": 1.0}
146 context
.window_manager
.progress_begin(0, len(i18n_sett
.langs
) + 1)
147 context
.window_manager
.progress_update(0)
148 with concurrent
.futures
.ProcessPoolExecutor() as exctr
:
149 num_langs
= len(i18n_sett
.langs
)
150 for progress
, _
in enumerate(exctr
.map(i18n_cleanuptranslation_svn_branches_callback
,
151 [dict(lng
.items()) for lng
in i18n_sett
.langs
],
152 (self
.settings
,) * num_langs
,
154 context
.window_manager
.progress_update(progress
+ 1)
156 context
.window_manager
.progress_end()
161 def i18n_updatetranslation_svn_trunk_callback(lng
, settings
):
162 if lng
['uid'] in settings
.IMPORT_LANGUAGES_SKIP
:
163 print("Skipping {} language ({}), edit settings if you want to enable it.\n".format(lng
['name'], lng
['uid']))
164 return lng
['uid'], 0.0
166 print("Skipping {} language ({}).\n".format(lng
['name'], lng
['uid']))
167 return lng
['uid'], 0.0
168 po
= utils_i18n
.I18nMessages(uid
=lng
['uid'], kind
='PO', src
=lng
['po_path'], settings
=settings
)
169 errs
= po
.check(fix
=True)
170 print("Processing {} language ({}).\n"
171 "Cleaned up {} commented messages.\n".format(lng
['name'], lng
['uid'], po
.clean_commented()) +
172 ("Errors in this po, solved as best as possible!\n\t" + "\n\t".join(errs
) if errs
else "") + "\n")
173 if lng
['uid'] in settings
.IMPORT_LANGUAGES_RTL
:
174 po
.write(kind
="PO", dest
=lng
['po_path_trunk'][:-3] + "_raw.po")
176 po
.write(kind
="PO", dest
=lng
['po_path_trunk'])
177 po
.write(kind
="PO_COMPACT", dest
=lng
['po_path_git'])
178 po
.write(kind
="MO", dest
=lng
['mo_path_trunk'])
180 return lng
['uid'], po
.nbr_trans_msgs
/ po
.nbr_msgs
183 class UI_OT_i18n_updatetranslation_svn_trunk(Operator
):
184 """Update i18n svn's branches (po files)"""
185 bl_idname
= "ui.i18n_updatetranslation_svn_trunk"
186 bl_label
= "Update I18n Trunk"
188 def execute(self
, context
):
189 if not hasattr(self
, "settings"):
190 self
.settings
= settings
.settings
191 i18n_sett
= context
.window_manager
.i18n_update_svn_settings
192 # 'DEFAULT' and en_US are always valid, fully-translated "languages"!
193 stats
= {"DEFAULT": 1.0, "en_US": 1.0}
195 context
.window_manager
.progress_begin(0, len(i18n_sett
.langs
) + 1)
196 context
.window_manager
.progress_update(0)
197 with concurrent
.futures
.ProcessPoolExecutor() as exctr
:
198 num_langs
= len(i18n_sett
.langs
)
199 for progress
, (lng_uid
, stats_val
) in enumerate(exctr
.map(i18n_updatetranslation_svn_trunk_callback
,
200 [dict(lng
.items()) for lng
in i18n_sett
.langs
],
201 (self
.settings
,) * num_langs
,
203 context
.window_manager
.progress_update(progress
+ 1)
204 stats
[lng_uid
] = stats_val
206 # Copy pot file from branches to trunk.
207 shutil
.copy2(self
.settings
.FILE_NAME_POT
, self
.settings
.TRUNK_PO_DIR
)
209 print("Generating languages' menu...")
210 context
.window_manager
.progress_update(progress
+ 2)
211 # First complete our statistics by checking po files we did not touch this time!
212 po_to_uid
= {os
.path
.basename(lng
.po_path
): lng
.uid
for lng
in i18n_sett
.langs
}
213 for po_path
in os
.listdir(self
.settings
.TRUNK_PO_DIR
):
214 uid
= po_to_uid
.get(po_path
, None)
215 po_path
= os
.path
.join(self
.settings
.TRUNK_PO_DIR
, po_path
)
216 if uid
and uid
not in stats
:
217 po
= utils_i18n
.I18nMessages(uid
=uid
, kind
='PO', src
=po_path
, settings
=self
.settings
)
218 stats
[uid
] = po
.nbr_trans_msgs
/ po
.nbr_msgs
if po
.nbr_msgs
> 0 else 0
219 utils_languages_menu
.gen_menu_file(stats
, self
.settings
)
220 context
.window_manager
.progress_end()
225 class UI_OT_i18n_updatetranslation_svn_statistics(Operator
):
226 """Create or extend a 'i18n_info.txt' Text datablock"""
227 """(it will contain statistics and checks about current branches and/or trunk)"""
228 bl_idname
= "ui.i18n_updatetranslation_svn_statistics"
229 bl_label
= "Update I18n Statistics"
231 use_branches
: BoolProperty(
232 name
="Check Branches",
233 description
="Check po files in branches",
237 use_trunk
: BoolProperty(
239 description
="Check po files in trunk",
243 report_name
= "i18n_info.txt"
245 def execute(self
, context
):
246 if not hasattr(self
, "settings"):
247 self
.settings
= settings
.settings
248 i18n_sett
= context
.window_manager
.i18n_update_svn_settings
252 if self
.use_branches
:
253 lst
+= [(lng
, lng
.po_path
) for lng
in i18n_sett
.langs
]
255 lst
+= [(lng
, lng
.po_path_trunk
) for lng
in i18n_sett
.langs
256 if lng
.uid
not in self
.settings
.IMPORT_LANGUAGES_SKIP
]
258 context
.window_manager
.progress_begin(0, len(lst
))
259 context
.window_manager
.progress_update(0)
260 for progress
, (lng
, path
) in enumerate(lst
):
261 context
.window_manager
.progress_update(progress
+ 1)
263 print("Skipping {} language ({}).".format(lng
.name
, lng
.uid
))
265 buff
.write("Processing {} language ({}, {}).\n".format(lng
.name
, lng
.uid
, path
))
266 po
= utils_i18n
.I18nMessages(uid
=lng
.uid
, kind
='PO', src
=path
, settings
=self
.settings
)
267 po
.print_info(prefix
=" ", output
=buff
.write
)
268 errs
= po
.check(fix
=False)
270 buff
.write(" WARNING! Po contains following errors:\n")
271 buff
.write(" " + "\n ".join(errs
))
276 if self
.report_name
not in bpy
.data
.texts
:
277 text
= bpy
.data
.texts
.new(self
.report_name
)
279 text
= bpy
.data
.texts
[self
.report_name
]
280 data
= text
.as_string()
281 data
= data
+ "\n" + buff
.getvalue()
282 text
.from_string(data
)
283 self
.report({'INFO'}, "Info written to {} text datablock!".format(self
.report_name
))
284 context
.window_manager
.progress_end()
288 def invoke(self
, context
, event
):
289 wm
= context
.window_manager
290 return wm
.invoke_props_dialog(self
)
294 UI_OT_i18n_updatetranslation_svn_branches
,
295 UI_OT_i18n_cleanuptranslation_svn_branches
,
296 UI_OT_i18n_updatetranslation_svn_trunk
,
297 UI_OT_i18n_updatetranslation_svn_statistics
,