remove '.' from descriptions
[blender-addons.git] / ui_translate / edit_translation.py
blobb486df3785374e6ff56b68d6dcb883d4cffe9f6a
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 #####
19 # <pep8 compliant>
21 if "bpy" in locals():
22 import imp
23 imp.reload(settings)
24 imp.reload(utils_i18n)
25 else:
26 import bpy
27 from bpy.props import (BoolProperty,
28 CollectionProperty,
29 EnumProperty,
30 FloatProperty,
31 FloatVectorProperty,
32 IntProperty,
33 PointerProperty,
34 StringProperty,
36 from . import settings
37 from bl_i18n_utils import utils as utils_i18n
40 import os
41 import shutil
44 # A global cache for I18nMessages objects, as parsing po files takes a few seconds.
45 PO_CACHE = {}
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"
60 # "Parameters"
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):
71 if self.clean_mo:
72 root = bpy.utils.user_resource('DATAFILES', settings.settings.MO_PATH_ROOT_RELATIVE)
73 if root:
74 shutil.rmtree(root)
75 elif not (self.lang and self.po_file):
76 return {'CANCELLED'}
77 else:
78 mo_dir = bpy.utils.user_resource('DATAFILES', settings.settings.MO_PATH_TEMPLATE_RELATIVE.format(self.lang),
79 create=True)
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()
84 return {'FINISHED'}
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"
92 # "Parameters"
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'})
107 # Found in po file.
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!")
146 return {'CANCELLED'}
148 msgs = _get_messages(self.lang, self.po_file)
149 done_keys = set()
150 for mmap in self.msgmap.values():
151 if 'ERROR' in getattr(self, mmap["msg_flags"]):
152 continue
153 k = mmap["key"]
154 # print(k)
155 if k not in done_keys and len(k) == 1:
156 k = tuple(k)[0]
157 msgs.msgs[k].msgstr = getattr(self, mmap["msgstr"])
158 msgs.msgs[k].is_fuzzy = 'FUZZY' in getattr(self, mmap["msg_flags"])
159 done_keys.add(k)
161 if self.update_po:
162 # Try to overwrite po file, may fail if we have no good rights...
163 try:
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()
169 if self.update_mo:
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)
172 elif self.clean_mo:
173 bpy.ops.ui.i18n_edittranslation_update_mo(clean_mo=True)
174 return {'FINISHED'}
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)
193 msgs.update_info()
194 self.stats_str = "{}: {} messages, {} translated.".format(os.path.basename(self.po_file), msgs.nbr_msgs,
195 msgs.nbr_trans_msgs)
197 for mmap in self.msgmap.values():
198 k = tuple(mmap["key"])
199 if k:
200 if len(k) == 1:
201 k = k[0]
202 ctxt, msgid = k
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'})
207 else:
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'})
212 else:
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):
220 layout = self.layout
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)
223 if src:
224 layout.label(text=" RNA Path: bpy.types." + src)
225 if self.rna_ctxt:
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 :/
230 box = layout.box()
231 #box = layout
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:")
238 row = col2.row()
239 row.enabled = False
240 if 'ERROR' in self.but_label_flags:
241 row.alert = True
242 else:
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:")
248 row = col2.row()
249 row.enabled = False
250 if 'ERROR' in self.rna_label_flags:
251 row.alert = True
252 else:
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:")
258 row = col2.row()
259 row.enabled = False
260 if 'ERROR' in self.enum_label_flags:
261 row.alert = True
262 else:
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 :/
269 box = layout.box()
270 #box = layout
271 box.label(text="Tool Tips:")
272 split = box.split(percentage=0.15)
273 col1 = split.column()
274 col2 = split.column()
275 if self.org_but_tip:
276 col1.label(text="Button Tip:")
277 row = col2.row()
278 row.enabled = False
279 if 'ERROR' in self.but_tip_flags:
280 row.alert = True
281 else:
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="")
285 if self.org_rna_tip:
286 col1.label(text="RNA Tip:")
287 row = col2.row()
288 row.enabled = False
289 if 'ERROR' in self.rna_tip_flags:
290 row.alert = True
291 else:
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:")
297 row = col2.row()
298 row.enabled = False
299 if 'ERROR' in self.enum_tip_flags:
300 row.alert = True
301 else:
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="")
306 row = layout.row()
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)