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 #####
24
imp.reload(utils_i18n)
27
from bpy.props import (BoolProperty,
36
from . import settings
37
from bl_i18n_utils import utils as utils_i18n
44
# A global cache for I18nMessages objects, as parsing po files takes a few seconds.
48
def _get_messages(lang, fname):
49
if fname not in PO_CACHE:
50
PO_CACHE[fname] = utils_i18n.I18nMessages(uid=lang, kind='PO', key=fname, src=fname, settings=settings.settings)
51
return PO_CACHE[fname]
54
class UI_OT_i18n_edittranslation_update_mo(bpy.types.Operator):
55
"""Try to "compile" given po file into relevant blender.mo file """ \
56
"""(WARNING: it will replace the official mo file in your user dir!)"""
57
bl_idname = "ui.i18n_edittranslation_update_mo"
58
bl_label = "Edit Translation Update Mo"
61
lang = StringProperty(description="Current (translated) language",
62
options={'SKIP_SAVE'})
63
po_file = StringProperty(description="Path to the matching po file",
64
subtype='FILE_PATH', options={'SKIP_SAVE'})
65
clean_mo = BoolProperty(description="Clean up (remove) all local "
66
"translation files, to be able to use "
67
"all system's ones again",
68
default=False, options={'SKIP_SAVE'})
70
def execute(self, context):
72
root = bpy.utils.user_resource('DATAFILES', settings.settings.MO_PATH_ROOT_RELATIVE)
75
elif not (self.lang and self.po_file):
78
mo_dir = bpy.utils.user_resource('DATAFILES', settings.settings.MO_PATH_TEMPLATE_RELATIVE.format(self.lang),
80
mo_file = os.path.join(mo_dir, settings.settings.MO_FILE_NAME)
81
_get_messages(self.lang, self.po_file).write(kind='MO', dest=mo_file)
83
bpy.ops.ui.reloadtranslation()
87
class UI_OT_i18n_edittranslation(bpy.types.Operator):
88
"""Translate the label and tool tip of the property defined by given 'parameters'"""
89
bl_idname = "ui.edittranslation"
90
bl_label = "Edit Translation"
93
but_label = StringProperty(description="Label of the control", options={'SKIP_SAVE'})
94
rna_label = StringProperty(description="RNA-defined label of the control, if any", options={'SKIP_SAVE'})
95
enum_label = StringProperty(description="Label of the enum item of the control, if any", options={'SKIP_SAVE'})
96
but_tip = StringProperty(description="Tip of the control", options={'SKIP_SAVE'})
97
rna_tip = StringProperty(description="RNA-defined tip of the control, if any", options={'SKIP_SAVE'})
98
enum_tip = StringProperty(description="Tip of the enum item of the control, if any", options={'SKIP_SAVE'})
99
rna_struct = StringProperty(description="Identifier of the RNA struct, if any", options={'SKIP_SAVE'})
100
rna_prop = StringProperty(description="Identifier of the RNA property, if any", options={'SKIP_SAVE'})
101
rna_enum = StringProperty(description="Identifier of the RNA enum item, if any", options={'SKIP_SAVE'})
102
rna_ctxt = StringProperty(description="RNA context for label", options={'SKIP_SAVE'})
104
lang = StringProperty(description="Current (translated) language", options={'SKIP_SAVE'})
105
po_file = StringProperty(description="Path to the matching po file", subtype='FILE_PATH', options={'SKIP_SAVE'})
108
org_but_label = StringProperty(description="Original label of the control", options={'SKIP_SAVE'})
109
org_rna_label = StringProperty(description="Original RNA-defined label of the control, if any",
110
options={'SKIP_SAVE'})
111
org_enum_label = StringProperty(description="Original label of the enum item of the control, if any",
112
options={'SKIP_SAVE'})
113
org_but_tip = StringProperty(description="Original tip of the control", options={'SKIP_SAVE'})
114
org_rna_tip = StringProperty(description="Original RNA-defined tip of the control, if any", options={'SKIP_SAVE'})
115
org_enum_tip = StringProperty(description="Original tip of the enum item of the control, if any",
116
options={'SKIP_SAVE'})
118
flag_items = (('FUZZY', "Fuzzy", "Message is marked as fuzzy in po file"),
119
('ERROR', "Error", "Some error occurred with this message"),
121
but_label_flags = EnumProperty(items=flag_items, description="Flags about the label of the button",
122
options={'SKIP_SAVE', 'ENUM_FLAG'})
123
rna_label_flags = EnumProperty(items=flag_items, description="Flags about the RNA-defined label of the button",
124
options={'SKIP_SAVE', 'ENUM_FLAG'})
125
enum_label_flags = EnumProperty(items=flag_items, description="Flags about the RNA enum item label of the button",
126
options={'SKIP_SAVE', 'ENUM_FLAG'})
127
but_tip_flags = EnumProperty(items=flag_items, description="Flags about the tip of the button",
128
options={'SKIP_SAVE', 'ENUM_FLAG'})
129
rna_tip_flags = EnumProperty(items=flag_items, description="Flags about the RNA-defined tip of the button",
130
options={'SKIP_SAVE', 'ENUM_FLAG'})
131
enum_tip_flags = EnumProperty(items=flag_items, description="Flags about the RNA enum item tip of the button",
132
options={'SKIP_SAVE', 'ENUM_FLAG'})
134
stats_str = StringProperty(description="Stats from opened po", options={'SKIP_SAVE'})
135
update_po = BoolProperty(description="Update po file, try to rebuild mo file, and refresh Blender UI",
136
default=False, options={'SKIP_SAVE'})
137
update_mo = BoolProperty(description="Try to rebuild mo file, and refresh Blender UI",
138
default=False, options={'SKIP_SAVE'})
139
clean_mo = BoolProperty(description="Clean up (remove) all local translation files, to be able to use "
140
"all system's ones again",
141
default=False, options={'SKIP_SAVE'})
143
def execute(self, context):
144
if not hasattr(self, "msgmap"):
145
self.report('ERROR', "Looks like you did not invoke this operator first!")
148
msgs = _get_messages(self.lang, self.po_file)
150
for mmap in self.msgmap.values():
151
if 'ERROR' in getattr(self, mmap["msg_flags"]):
155
if k not in done_keys and len(k) == 1:
157
msgs.msgs[k].msgstr = getattr(self, mmap["msgstr"])
158
msgs.msgs[k].is_fuzzy = 'FUZZY' in getattr(self, mmap["msg_flags"])
162
# Try to overwrite po file, may fail if we have no good rights...
164
msgs.write(kind='PO', dest=self.po_file)
165
except Exception as e:
166
self.report('ERROR', "Could not write to po file ({})".format(str(e)))
167
# Always invalidate reverse messages cache afterward!
168
msgs.invalidate_reverse_cache()
170
lang = os.path.splitext(os.path.basename(self.po_file))[0]
171
bpy.ops.ui.i18n_edittranslation_update_mo(po_file=self.po_file, lang=lang)
173
bpy.ops.ui.i18n_edittranslation_update_mo(clean_mo=True)
176
def invoke(self, context, event):
177
self.msgmap = {"but_label": {"msgstr": "but_label", "msgid": "org_but_label",
178
"msg_flags": "but_label_flags", "key": set()},
179
"rna_label": {"msgstr": "rna_label", "msgid": "org_rna_label",
180
"msg_flags": "rna_label_flags", "key": set()},
181
"enum_label": {"msgstr": "enum_label", "msgid": "org_enum_label",
182
"msg_flags": "enum_label_flags", "key": set()},
183
"but_tip": {"msgstr": "but_tip", "msgid": "org_but_tip",
184
"msg_flags": "but_tip_flags", "key": set()},
185
"rna_tip": {"msgstr": "rna_tip", "msgid": "org_rna_tip",
186
"msg_flags": "rna_tip_flags", "key": set()},
187
"enum_tip": {"msgstr": "enum_tip", "msgid": "org_enum_tip",
188
"msg_flags": "enum_tip_flags", "key": set()},
191
msgs = _get_messages(self.lang, self.po_file)
192
msgs.find_best_messages_matches(self, self.msgmap, self.rna_ctxt, self.rna_struct, self.rna_prop, self.rna_enum)
194
self.stats_str = "{}: {} messages, {} translated.".format(os.path.basename(self.po_file), msgs.nbr_msgs,
197
for mmap in self.msgmap.values():
198
k = tuple(mmap["key"])
203
setattr(self, mmap["msgstr"], msgs.msgs[k].msgstr)
204
setattr(self, mmap["msgid"], msgid)
205
if msgs.msgs[k].is_fuzzy:
206
setattr(self, mmap["msg_flags"], {'FUZZY'})
208
setattr(self, mmap["msgid"],
209
"ERROR: Button label “{}” matches several messages in po file ({})!"
210
"".format(self.but_label, k))
211
setattr(self, mmap["msg_flags"], {'ERROR'})
213
setattr(self, mmap["msgstr"], "")
214
setattr(self, mmap["msgid"], "")
216
wm = context.window_manager
217
return wm.invoke_props_dialog(self, width=600)
219
def draw(self, context):
221
layout.label(text=self.stats_str)
222
src, _a, _b = bpy.utils.make_rna_paths(self.rna_struct, self.rna_prop, self.rna_enum)
224
layout.label(text=" RNA Path: bpy.types." + src)
226
layout.label(text=" RNA Context: " + self.rna_ctxt)
228
if self.org_but_label or self.org_rna_label or self.org_enum_label:
229
# XXX Can't use box, labels are not enough readable in them :/
232
box.label(text="Labels:")
233
split = box.split(percentage=0.15)
234
col1 = split.column()
235
col2 = split.column()
236
if self.org_but_label:
237
col1.label(text="Button Label:")
240
if 'ERROR' in self.but_label_flags:
243
col1.prop_enum(self, "but_label_flags", 'FUZZY', text="Fuzzy")
244
col2.prop(self, "but_label", text="")
245
row.prop(self, "org_but_label", text="")
246
if self.org_rna_label:
247
col1.label(text="RNA Label:")
250
if 'ERROR' in self.rna_label_flags:
253
col1.prop_enum(self, "rna_label_flags", 'FUZZY', text="Fuzzy")
254
col2.prop(self, "rna_label", text="")
255
row.prop(self, "org_rna_label", text="")
256
if self.org_enum_label:
257
col1.label(text="Enum Item Label:")
260
if 'ERROR' in self.enum_label_flags:
263
col1.prop_enum(self, "enum_label_flags", 'FUZZY', text="Fuzzy")
264
col2.prop(self, "enum_label", text="")
265
row.prop(self, "org_enum_label", text="")
267
if self.org_but_tip or self.org_rna_tip or self.org_enum_tip:
268
# XXX Can't use box, labels are not enough readable in them :/
271
box.label(text="Tool Tips:")
272
split = box.split(percentage=0.15)
273
col1 = split.column()
274
col2 = split.column()
276
col1.label(text="Button Tip:")
279
if 'ERROR' in self.but_tip_flags:
282
col1.prop_enum(self, "but_tip_flags", 'FUZZY', text="Fuzzy")
283
col2.prop(self, "but_tip", text="")
284
row.prop(self, "org_but_tip", text="")
286
col1.label(text="RNA Tip:")
289
if 'ERROR' in self.rna_tip_flags:
292
col1.prop_enum(self, "rna_tip_flags", 'FUZZY', text="Fuzzy")
293
col2.prop(self, "rna_tip", text="")
294
row.prop(self, "org_rna_tip", text="")
295
if self.org_enum_tip:
296
col1.label(text="Enum Item Tip:")
299
if 'ERROR' in self.enum_tip_flags:
302
col1.prop_enum(self, "enum_tip_flags", 'FUZZY', text="Fuzzy")
303
col2.prop(self, "enum_tip", text="")
304
row.prop(self, "org_enum_tip", text="")
307
row.prop(self, "update_po", text="Save to PO File", toggle=True)
308
row.prop(self, "update_mo", text="Rebuild MO File", toggle=True)
309
row.prop(self, "clean_mo", text="Erase Local MO files", toggle=True)