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 #####
25 importlib
.reload(settings
)
26 importlib
.reload(utils_i18n
)
29 from bpy
.types
import Operator
30 from bpy
.props
import (
35 from . import settings
36 from bl_i18n_utils
import utils
as utils_i18n
39 # A global cache for I18nMessages objects, as parsing po files takes a few seconds.
43 def _get_messages(lang
, fname
):
44 if fname
not in PO_CACHE
:
45 PO_CACHE
[fname
] = utils_i18n
.I18nMessages(uid
=lang
, kind
='PO', key
=fname
, src
=fname
, settings
=settings
.settings
)
46 return PO_CACHE
[fname
]
49 class UI_OT_i18n_edittranslation_update_mo(Operator
):
50 """Try to "compile" given po file into relevant blender.mo file"""
51 """(WARNING: it will replace the official mo file in your user dir!)"""
52 bl_idname
= "ui.i18n_edittranslation_update_mo"
53 bl_label
= "Edit Translation Update Mo"
57 description
="Current (translated) language",
58 options
={'SKIP_SAVE'},
61 po_file
: StringProperty(
62 description
="Path to the matching po file",
64 options
={'SKIP_SAVE'},
67 clean_mo
: BoolProperty(
68 description
="Remove all local translation files, to be able to use the system ones again",
72 # /End Operator Arguments
74 def execute(self
, context
):
76 root
= bpy
.utils
.user_resource('DATAFILES', settings
.settings
.MO_PATH_ROOT_RELATIVE
)
79 elif not (self
.lang
and self
.po_file
):
82 mo_dir
= bpy
.utils
.user_resource('DATAFILES', settings
.settings
.MO_PATH_TEMPLATE_RELATIVE
.format(self
.lang
),
84 mo_file
= os
.path
.join(mo_dir
, settings
.settings
.MO_FILE_NAME
)
85 _get_messages(self
.lang
, self
.po_file
).write(kind
='MO', dest
=mo_file
)
87 bpy
.ops
.ui
.reloadtranslation()
91 class UI_OT_i18n_edittranslation(Operator
):
92 """Translate the label and tooltip of the given property"""
93 bl_idname
= "ui.edittranslation"
94 bl_label
= "Edit Translation"
97 but_label
: StringProperty(
98 description
="Label of the control",
99 options
={'SKIP_SAVE'},
102 rna_label
: StringProperty(
103 description
="RNA-defined label of the control, if any",
104 options
={'SKIP_SAVE'},
107 enum_label
: StringProperty(
108 description
="Label of the enum item of the control, if any",
109 options
={'SKIP_SAVE'},
112 but_tip
: StringProperty(
113 description
="Tip of the control",
114 options
={'SKIP_SAVE'},
117 rna_tip
: StringProperty(
118 description
="RNA-defined tip of the control, if any",
119 options
={'SKIP_SAVE'},
122 enum_tip
: StringProperty(
123 description
="Tip of the enum item of the control, if any",
124 options
={'SKIP_SAVE'},
127 rna_struct
: StringProperty(
128 description
="Identifier of the RNA struct, if any",
129 options
={'SKIP_SAVE'},
132 rna_prop
: StringProperty(
133 description
="Identifier of the RNA property, if any",
134 options
={'SKIP_SAVE'},
137 rna_enum
: StringProperty(
138 description
="Identifier of the RNA enum item, if any",
139 options
={'SKIP_SAVE'},
142 rna_ctxt
: StringProperty(
143 description
="RNA context for label",
144 options
={'SKIP_SAVE'},
147 lang
: StringProperty(
148 description
="Current (translated) language",
149 options
={'SKIP_SAVE'},
152 po_file
: StringProperty(
153 description
="Path to the matching po file",
155 options
={'SKIP_SAVE'},
159 org_but_label
: StringProperty(
160 description
="Original label of the control",
161 options
={'SKIP_SAVE'},
164 org_rna_label
: StringProperty(
165 description
="Original RNA-defined label of the control, if any",
166 options
={'SKIP_SAVE'},
169 org_enum_label
: StringProperty(
170 description
="Original label of the enum item of the control, if any",
171 options
={'SKIP_SAVE'},
174 org_but_tip
: StringProperty(
175 description
="Original tip of the control",
176 options
={'SKIP_SAVE'},
179 org_rna_tip
: StringProperty(
180 description
="Original RNA-defined tip of the control, if any", options
={'SKIP_SAVE'}
183 org_enum_tip
: StringProperty(
184 description
="Original tip of the enum item of the control, if any",
185 options
={'SKIP_SAVE'},
189 ('FUZZY', "Fuzzy", "Message is marked as fuzzy in po file"),
190 ('ERROR', "Error", "Some error occurred with this message"),
193 but_label_flags
: EnumProperty(
194 description
="Flags about the label of the button",
196 options
={'SKIP_SAVE', 'ENUM_FLAG'},
199 rna_label_flags
: EnumProperty(
200 description
="Flags about the RNA-defined label of the button",
202 options
={'SKIP_SAVE', 'ENUM_FLAG'},
205 enum_label_flags
: EnumProperty(
206 description
="Flags about the RNA enum item label of the button",
208 options
={'SKIP_SAVE', 'ENUM_FLAG'},
211 but_tip_flags
: EnumProperty(
212 description
="Flags about the tip of the button",
214 options
={'SKIP_SAVE', 'ENUM_FLAG'},
217 rna_tip_flags
: EnumProperty(
218 description
="Flags about the RNA-defined tip of the button",
220 options
={'SKIP_SAVE', 'ENUM_FLAG'},
223 enum_tip_flags
: EnumProperty(
224 description
="Flags about the RNA enum item tip of the button",
226 options
={'SKIP_SAVE', 'ENUM_FLAG'},
229 stats_str
: StringProperty(
230 description
="Stats from opened po", options
={'SKIP_SAVE'})
232 update_po
: BoolProperty(
233 description
="Update po file, try to rebuild mo file, and refresh Blender's UI",
235 options
={'SKIP_SAVE'},
238 update_mo
: BoolProperty(
239 description
="Try to rebuild mo file, and refresh Blender's UI",
241 options
={'SKIP_SAVE'},
244 clean_mo
: BoolProperty(
245 description
="Remove all local translation files, to be able to use the system ones again",
247 options
={'SKIP_SAVE'},
249 # /End Operator Arguments
251 def execute(self
, context
):
252 if not hasattr(self
, "msgmap"):
253 self
.report('ERROR', "invoke() needs to be called before execute()")
256 msgs
= _get_messages(self
.lang
, self
.po_file
)
258 for mmap
in self
.msgmap
.values():
259 if 'ERROR' in getattr(self
, mmap
["msg_flags"]):
262 if k
not in done_keys
and len(k
) == 1:
264 msgs
.msgs
[k
].msgstr
= getattr(self
, mmap
["msgstr"])
265 msgs
.msgs
[k
].is_fuzzy
= 'FUZZY' in getattr(self
, mmap
["msg_flags"])
269 # Try to overwrite .po file, may fail if there are no permissions.
271 msgs
.write(kind
='PO', dest
=self
.po_file
)
272 except Exception as e
:
273 self
.report('ERROR', "Could not write to po file ({})".format(str(e
)))
274 # Always invalidate reverse messages cache afterward!
275 msgs
.invalidate_reverse_cache()
277 lang
= os
.path
.splitext(os
.path
.basename(self
.po_file
))[0]
278 bpy
.ops
.ui
.i18n_edittranslation_update_mo(po_file
=self
.po_file
, lang
=lang
)
280 bpy
.ops
.ui
.i18n_edittranslation_update_mo(clean_mo
=True)
283 def invoke(self
, context
, event
):
286 "msgstr": "but_label", "msgid": "org_but_label", "msg_flags": "but_label_flags", "key": set()},
288 "msgstr": "rna_label", "msgid": "org_rna_label", "msg_flags": "rna_label_flags", "key": set()},
290 "msgstr": "enum_label", "msgid": "org_enum_label", "msg_flags": "enum_label_flags", "key": set()},
292 "msgstr": "but_tip", "msgid": "org_but_tip", "msg_flags": "but_tip_flags", "key": set()},
294 "msgstr": "rna_tip", "msgid": "org_rna_tip", "msg_flags": "rna_tip_flags", "key": set()},
296 "msgstr": "enum_tip", "msgid": "org_enum_tip", "msg_flags": "enum_tip_flags", "key": set()},
299 msgs
= _get_messages(self
.lang
, self
.po_file
)
300 msgs
.find_best_messages_matches(self
, self
.msgmap
, self
.rna_ctxt
, self
.rna_struct
, self
.rna_prop
, self
.rna_enum
)
302 self
.stats_str
= "{}: {} messages, {} translated.".format(os
.path
.basename(self
.po_file
), msgs
.nbr_msgs
,
305 for mmap
in self
.msgmap
.values():
306 k
= tuple(mmap
["key"])
311 setattr(self
, mmap
["msgstr"], msgs
.msgs
[k
].msgstr
)
312 setattr(self
, mmap
["msgid"], msgid
)
313 if msgs
.msgs
[k
].is_fuzzy
:
314 setattr(self
, mmap
["msg_flags"], {'FUZZY'})
316 setattr(self
, mmap
["msgid"],
317 "ERROR: Button label “{}” matches several messages in po file ({})!"
318 "".format(self
.but_label
, k
))
319 setattr(self
, mmap
["msg_flags"], {'ERROR'})
321 setattr(self
, mmap
["msgstr"], "")
322 setattr(self
, mmap
["msgid"], "")
324 wm
= context
.window_manager
325 return wm
.invoke_props_dialog(self
, width
=600)
327 def draw(self
, context
):
329 layout
.label(text
=self
.stats_str
)
330 src
, _a
, _b
= bpy
.utils
.make_rna_paths(self
.rna_struct
, self
.rna_prop
, self
.rna_enum
)
332 layout
.label(text
=" RNA Path: bpy.types." + src
)
334 layout
.label(text
=" RNA Context: " + self
.rna_ctxt
)
336 if self
.org_but_label
or self
.org_rna_label
or self
.org_enum_label
:
337 # XXX Can't use box, labels are not enough readable in them :/
339 box
.label(text
="Labels:")
340 split
= box
.split(factor
=0.15)
341 col1
= split
.column()
342 col2
= split
.column()
343 if self
.org_but_label
:
344 col1
.label(text
="Button Label:")
347 if 'ERROR' in self
.but_label_flags
:
350 col1
.prop_enum(self
, "but_label_flags", 'FUZZY', text
="Fuzzy")
351 col2
.prop(self
, "but_label", text
="")
352 row
.prop(self
, "org_but_label", text
="")
353 if self
.org_rna_label
:
354 col1
.label(text
="RNA Label:")
357 if 'ERROR' in self
.rna_label_flags
:
360 col1
.prop_enum(self
, "rna_label_flags", 'FUZZY', text
="Fuzzy")
361 col2
.prop(self
, "rna_label", text
="")
362 row
.prop(self
, "org_rna_label", text
="")
363 if self
.org_enum_label
:
364 col1
.label(text
="Enum Item Label:")
367 if 'ERROR' in self
.enum_label_flags
:
370 col1
.prop_enum(self
, "enum_label_flags", 'FUZZY', text
="Fuzzy")
371 col2
.prop(self
, "enum_label", text
="")
372 row
.prop(self
, "org_enum_label", text
="")
374 if self
.org_but_tip
or self
.org_rna_tip
or self
.org_enum_tip
:
375 # XXX Can't use box, labels are not enough readable in them :/
377 box
.label(text
="Tool Tips:")
378 split
= box
.split(factor
=0.15)
379 col1
= split
.column()
380 col2
= split
.column()
382 col1
.label(text
="Button Tip:")
385 if 'ERROR' in self
.but_tip_flags
:
388 col1
.prop_enum(self
, "but_tip_flags", 'FUZZY', text
="Fuzzy")
389 col2
.prop(self
, "but_tip", text
="")
390 row
.prop(self
, "org_but_tip", text
="")
392 col1
.label(text
="RNA Tip:")
395 if 'ERROR' in self
.rna_tip_flags
:
398 col1
.prop_enum(self
, "rna_tip_flags", 'FUZZY', text
="Fuzzy")
399 col2
.prop(self
, "rna_tip", text
="")
400 row
.prop(self
, "org_rna_tip", text
="")
401 if self
.org_enum_tip
:
402 col1
.label(text
="Enum Item Tip:")
405 if 'ERROR' in self
.enum_tip_flags
:
408 col1
.prop_enum(self
, "enum_tip_flags", 'FUZZY', text
="Fuzzy")
409 col2
.prop(self
, "enum_tip", text
="")
410 row
.prop(self
, "org_enum_tip", text
="")
413 row
.prop(self
, "update_po", text
="Save to PO File", toggle
=True)
414 row
.prop(self
, "update_mo", text
="Rebuild MO File", toggle
=True)
415 row
.prop(self
, "clean_mo", text
="Erase Local MO files", toggle
=True)
419 UI_OT_i18n_edittranslation_update_mo
,
420 UI_OT_i18n_edittranslation
,