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 tooltip 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)