OLD | NEW |
1 # ***** BEGIN GPL LICENSE BLOCK ***** | 1 # ***** BEGIN GPL LICENSE BLOCK ***** |
2 # | 2 # |
3 # This program is free software; you can redistribute it and/or | 3 # This program is free software; you can redistribute it and/or |
4 # modify it under the terms of the GNU General Public License | 4 # modify it under the terms of the GNU General Public License |
5 # as published by the Free Software Foundation; either version 2 | 5 # as published by the Free Software Foundation; either version 2 |
6 # of the License, or (at your option) any later version. | 6 # of the License, or (at your option) any later version. |
7 # | 7 # |
8 # This program is distributed in the hope that it will be useful, | 8 # This program is distributed in the hope that it will be useful, |
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 # GNU General Public License for more details. | 11 # GNU General Public License for more details. |
12 # | 12 # |
13 # You should have received a copy of the GNU General Public License | 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, | 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. | 15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 # | 16 # |
17 # ***** END GPL LICENSE BLOCK ***** | 17 # ***** END GPL LICENSE BLOCK ***** |
18 | 18 |
19 # <pep8 compliant> | 19 # <pep8 compliant> |
20 | 20 |
21 # Global settings used by all scripts in this dir. | 21 # Global settings used by all scripts in this dir. |
22 # XXX Before any use of the tools in this dir, please make a copy of this file | 22 # XXX Before any use of the tools in this dir, please make a copy of this file |
23 # named "setting.py" | 23 # named "setting.py" |
24 # XXX This is a template, most values should be OK, but some you’ll have to | 24 # XXX This is a template, most values should be OK, but some you’ll have to |
25 # edit (most probably, BLENDER_EXEC and SOURCE_DIR). | 25 # edit (most probably, BLENDER_EXEC and SOURCE_DIR). |
26 | 26 |
| 27 import os.path |
27 | 28 |
28 import json | |
29 import os | |
30 import sys | |
31 | |
32 import bpy | |
33 | 29 |
34 ############################################################################### | 30 ############################################################################### |
35 # MISC | 31 # MISC |
36 ############################################################################### | 32 ############################################################################### |
37 | 33 |
38 # The languages defined in Blender. | 34 # The languages defined in Blender. |
39 LANGUAGES_CATEGORIES = ( | 35 LANGUAGES_CATEGORIES = ( |
40 # Min completeness level, UI english label. | 36 # Min completeness level, UI english label. |
41 ( 0.95, "Complete"), | 37 ( 0.95, "Complete"), |
42 ( 0.33, "In Progress"), | 38 ( 0.33, "In Progress"), |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 (33, "Hebrew (תירִבְעִ)", "he_IL"), | 79 (33, "Hebrew (תירִבְעִ)", "he_IL"), |
84 (34, "Estonian (Eestlane)", "et_EE"), | 80 (34, "Estonian (Eestlane)", "et_EE"), |
85 (35, "Esperanto (Esperanto)", "eo"), | 81 (35, "Esperanto (Esperanto)", "eo"), |
86 (36, "Spanish from Spain (Español de España)", "es_ES"), | 82 (36, "Spanish from Spain (Español de España)", "es_ES"), |
87 (37, "Amharic (አማርኛ)", "am_ET"), | 83 (37, "Amharic (አማርኛ)", "am_ET"), |
88 (38, "Uzbek (Oʻzbek)", "uz_UZ"), | 84 (38, "Uzbek (Oʻzbek)", "uz_UZ"), |
89 (39, "Uzbek Cyrillic (Ўзбек)", "uz_UZ@cyrillic"), | 85 (39, "Uzbek Cyrillic (Ўзбек)", "uz_UZ@cyrillic"), |
90 (40, "Hindi (मानक हिन्दी)", "hi_IN"), | 86 (40, "Hindi (मानक हिन्दी)", "hi_IN"), |
91 ) | 87 ) |
92 | 88 |
93 # Default context, in py! | |
94 DEFAULT_CONTEXT = bpy.app.translations.contexts.default | |
95 | |
96 # Name of language file used by Blender to generate translations' menu. | 89 # Name of language file used by Blender to generate translations' menu. |
97 LANGUAGES_FILE = "languages" | 90 LANGUAGES_FILE = "languages" |
98 | 91 |
99 # The min level of completeness for a po file to be imported from /branches into
/trunk, as a percentage. | 92 # The min level of completeness for a po file to be imported from /branches |
100 IMPORT_MIN_LEVEL = 0.0 | 93 # into /trunk, as a percentage. -1 means "import everything". |
| 94 IMPORT_MIN_LEVEL = -1 |
101 | 95 |
102 # Languages in /branches we do not want to import in /trunk currently... | 96 # Languages in /branches we do not want to import in /trunk currently... |
103 IMPORT_LANGUAGES_SKIP = { | 97 IMPORT_LANGUAGES_SKIP = {'am', 'bg', 'fi', 'el', 'et', 'ne', 'pl', 'ro', 'uz', '
uz@cyrillic'} |
104 'am_ET', 'bg_BG', 'fi_FI', 'el_GR', 'et_EE', 'ne_NP', 'pl_PL', 'ro_RO', 'uz_
UZ', 'uz_UZ@cyrillic', | |
105 } | |
106 | |
107 # Languages that need RTL pre-processing. | |
108 IMPORT_LANGUAGES_RTL = { | |
109 'ar_EG', 'fa_IR', 'he_IL', | |
110 } | |
111 | 98 |
112 # The comment prefix used in generated messages.txt file. | 99 # The comment prefix used in generated messages.txt file. |
113 MSG_COMMENT_PREFIX = "#~ " | 100 MSG_COMMENT_PREFIX = "#~ " |
114 | 101 |
115 # The comment prefix used in generated messages.txt file. | 102 # The comment prefix used in generated messages.txt file. |
116 MSG_CONTEXT_PREFIX = "MSGCTXT:" | 103 MSG_CONTEXT_PREFIX = "MSGCTXT:" |
117 | 104 |
118 # The default comment prefix used in po's. | 105 # The default comment prefix used in po's. |
119 PO_COMMENT_PREFIX= "# " | 106 PO_COMMENT_PREFIX= "# " |
120 | 107 |
121 # The comment prefix used to mark sources of msgids, in po's. | 108 # The comment prefix used to mark sources of msgids, in po's. |
122 PO_COMMENT_PREFIX_SOURCE = "#: " | 109 PO_COMMENT_PREFIX_SOURCE = "#: " |
123 | 110 |
124 # The comment prefix used to mark sources of msgids, in po's. | 111 # The comment prefix used to mark sources of msgids, in po's. |
125 PO_COMMENT_PREFIX_SOURCE_CUSTOM = "#. :src: " | 112 PO_COMMENT_PREFIX_SOURCE_CUSTOM = "#. :src: " |
126 | 113 |
127 # The general "generated" comment prefix, in po's. | |
128 PO_COMMENT_PREFIX_GENERATED = "#. " | |
129 | |
130 # The comment prefix used to comment entries in po's. | 114 # The comment prefix used to comment entries in po's. |
131 PO_COMMENT_PREFIX_MSG= "#~ " | 115 PO_COMMENT_PREFIX_MSG= "#~ " |
132 | 116 |
133 # The comment prefix used to mark fuzzy msgids, in po's. | 117 # The comment prefix used to mark fuzzy msgids, in po's. |
134 PO_COMMENT_FUZZY = "#, fuzzy" | 118 PO_COMMENT_FUZZY = "#, fuzzy" |
135 | 119 |
136 # The prefix used to define context, in po's. | 120 # The prefix used to define context, in po's. |
137 PO_MSGCTXT = "msgctxt " | 121 PO_MSGCTXT = "msgctxt " |
138 | 122 |
139 # The prefix used to define msgid, in po's. | 123 # The prefix used to define msgid, in po's. |
140 PO_MSGID = "msgid " | 124 PO_MSGID = "msgid " |
141 | 125 |
142 # The prefix used to define msgstr, in po's. | 126 # The prefix used to define msgstr, in po's. |
143 PO_MSGSTR = "msgstr " | 127 PO_MSGSTR = "msgstr " |
144 | 128 |
145 # The 'header' key of po files. | 129 # The 'header' key of po files. |
146 PO_HEADER_KEY = (DEFAULT_CONTEXT, "") | 130 PO_HEADER_KEY = ("", "") |
147 | 131 |
148 PO_HEADER_MSGSTR = ( | 132 PO_HEADER_MSGSTR = ( |
149 "Project-Id-Version: {blender_ver} (r{blender_rev})\\n\n" | 133 "Project-Id-Version: Blender {blender_ver} (r{blender_rev})\\n\n" |
150 "Report-Msgid-Bugs-To: \\n\n" | 134 "Report-Msgid-Bugs-To: \\n\n" |
151 "POT-Creation-Date: {time}\\n\n" | 135 "POT-Creation-Date: {time}\\n\n" |
152 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\n" | 136 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\n" |
153 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\n" | 137 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\n" |
154 "Language-Team: LANGUAGE <LL@li.org>\\n\n" | 138 "Language-Team: LANGUAGE <LL@li.org>\\n\n" |
155 "Language: {uid}\\n\n" | 139 "Language: {iso}\\n\n" |
156 "MIME-Version: 1.0\\n\n" | 140 "MIME-Version: 1.0\\n\n" |
157 "Content-Type: text/plain; charset=UTF-8\\n\n" | 141 "Content-Type: text/plain; charset=UTF-8\\n\n" |
158 "Content-Transfer-Encoding: 8bit\n" | 142 "Content-Transfer-Encoding: 8bit\n" |
159 ) | 143 ) |
160 PO_HEADER_COMMENT_COPYRIGHT = ( | 144 PO_HEADER_COMMENT_COPYRIGHT = ( |
161 "# Blender's translation file (po format).\n" | 145 "# Blender's translation file (po format).\n" |
162 "# Copyright (C) {year} The Blender Foundation.\n" | 146 "# Copyright (C) {year} The Blender Foundation.\n" |
163 "# This file is distributed under the same license as the Blender package.\n
" | 147 "# This file is distributed under the same license as the Blender package.\n
" |
164 "#\n" | 148 "#\n" |
165 ) | 149 ) |
166 PO_HEADER_COMMENT = ( | 150 PO_HEADER_COMMENT = ( |
167 "# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n" | 151 "# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n" |
168 "#" | 152 "#" |
169 ) | 153 ) |
170 | 154 |
171 TEMPLATE_ISO_ID = "__TEMPLATE__" | 155 TEMPLATE_ISO_ID = "__TEMPLATE__" |
172 | 156 |
173 # Num buttons report their label with a trailing ': '... | 157 # Default context. |
174 NUM_BUTTON_SUFFIX = ": " | 158 CONTEXT_DEFAULT = "" |
175 | 159 |
176 # Undocumented operator placeholder string. | 160 # Undocumented operator placeholder string. |
177 UNDOC_OPS_STR = "(undocumented operator)" | 161 UNDOC_OPS_STR = "(undocumented operator)" |
178 | 162 |
179 # The gettext domain. | 163 # The gettext domain. |
180 DOMAIN = "blender" | 164 DOMAIN = "blender" |
181 | 165 |
182 # Our own "gettext" stuff. | 166 # Our own "gettext" stuff. |
183 # File type (ext) to parse. | 167 # File type (ext) to parse. |
184 PYGETTEXT_ALLOWED_EXTS = {".c", ".cpp", ".cxx", ".hpp", ".hxx", ".h"} | 168 PYGETTEXT_ALLOWED_EXTS = {".c", ".cpp", ".cxx", ".hpp", ".hxx", ".h"} |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 for it in ("BMO_error_raise",)) + | 234 for it in ("BMO_error_raise",)) + |
251 | 235 |
252 tuple(("{}\\((?:[^\"',]+,)\\s*" + _msg_re + r"\s*(?:\)|,)").format(it) | 236 tuple(("{}\\((?:[^\"',]+,)\\s*" + _msg_re + r"\s*(?:\)|,)").format(it) |
253 for it in ("modifier_setError",)) + | 237 for it in ("modifier_setError",)) + |
254 | 238 |
255 tuple((r"{}\(\s*" + _msg_re + r"\s*,\s*(?:" + \ | 239 tuple((r"{}\(\s*" + _msg_re + r"\s*,\s*(?:" + \ |
256 r"\s*,\s*)?(?:".join(_ctxt_re_gen(i) for i in range(PYGETTEXT_MAX_MUL
TI_CTXT)) + r")?\s*\)").format(it) | 240 r"\s*,\s*)?(?:".join(_ctxt_re_gen(i) for i in range(PYGETTEXT_MAX_MUL
TI_CTXT)) + r")?\s*\)").format(it) |
257 for it in ("BLF_I18N_MSGID_MULTI_CTXT",)) | 241 for it in ("BLF_I18N_MSGID_MULTI_CTXT",)) |
258 ) | 242 ) |
259 | 243 |
| 244 ESCAPE_RE = ( |
| 245 (r'((?<!\\)"|(?<!\\)\\(?!\\|"))', r"\\\1"), |
| 246 ('\t', r"\\t"), |
| 247 ) |
| 248 |
260 # Should po parser warn when finding a first letter not capitalized? | 249 # Should po parser warn when finding a first letter not capitalized? |
261 WARN_MSGID_NOT_CAPITALIZED = True | 250 WARN_MSGID_NOT_CAPITALIZED = True |
262 | 251 |
263 # Strings that should not raise above warning! | 252 # Strings that should not raise above warning! |
264 WARN_MSGID_NOT_CAPITALIZED_ALLOWED = { | 253 WARN_MSGID_NOT_CAPITALIZED_ALLOWED = { |
265 "", # Simplifies things... :p | 254 "", # Simplifies things... :p |
266 "sin(x) / x", | 255 "sin(x) / x", |
267 "fBM", | 256 "fBM", |
268 "sqrt(x*x+y*y+z*z)", | 257 "sqrt(x*x+y*y+z*z)", |
269 "iTaSC", | 258 "iTaSC", |
(...skipping 25 matching lines...) Expand all Loading... |
295 "location", # Addons' field. :/ | 284 "location", # Addons' field. :/ |
296 "author", # Addons' field. :/ | 285 "author", # Addons' field. :/ |
297 "in memory to enable editing!", # Is part of multi-line msg. | 286 "in memory to enable editing!", # Is part of multi-line msg. |
298 "iScale", | 287 "iScale", |
299 "dx", | 288 "dx", |
300 "p0", | 289 "p0", |
301 "res", | 290 "res", |
302 } | 291 } |
303 WARN_MSGID_NOT_CAPITALIZED_ALLOWED |= set(lng[2] for lng in LANGUAGES) | 292 WARN_MSGID_NOT_CAPITALIZED_ALLOWED |= set(lng[2] for lng in LANGUAGES) |
304 | 293 |
305 WARN_MSGID_END_POINT_ALLOWED = { | |
306 "Numpad .", | |
307 "Circle|Alt .", | |
308 "Temp. Diff.", | |
309 "Float Neg. Exp.", | |
310 } | |
311 | |
312 PARSER_CACHE_HASH = 'sha1' | 294 PARSER_CACHE_HASH = 'sha1' |
313 | 295 |
314 PARSER_TEMPLATE_ID = "__POT__" | |
315 PARSER_PY_ID = "__PY__" | |
316 | |
317 PARSER_PY_MARKER_BEGIN = "\n# ##### BEGIN AUTOGENERATED I18N SECTION #####\n" | |
318 PARSER_PY_MARKER_END = "\n# ##### END AUTOGENERATED I18N SECTION #####\n" | |
319 | |
320 PARSER_MAX_FILE_SIZE = 2**24 # in bytes, i.e. 16 Mb. | |
321 | 296 |
322 ############################################################################### | 297 ############################################################################### |
323 # PATHS | 298 # PATHS |
324 ############################################################################### | 299 ############################################################################### |
325 | 300 |
| 301 # The tools path, should be OK. |
| 302 TOOLS_DIR = os.path.join(os.path.dirname(__file__)) |
| 303 |
326 # The Python3 executable.You’ll likely have to edit it in your user_settings.py | 304 # The Python3 executable.You’ll likely have to edit it in your user_settings.py |
327 # if you’re under Windows. | 305 # if you’re under Windows. |
328 PYTHON3_EXEC = "python3" | 306 PYTHON3_EXEC = "python3" |
329 | 307 |
330 # The Blender executable! | 308 # The Blender executable! |
331 # This is just an example, you’ll have to edit it in your user_settings.py! | 309 # This is just an example, you’ll most likely have to edit it in your user_setti
ngs.py! |
332 BLENDER_EXEC = os.path.abspath(os.path.join("foo", "bar", "blender")) | 310 BLENDER_EXEC = os.path.abspath(os.path.join(TOOLS_DIR, "..", "..", "..", "..", "
blender")) |
333 # check for blender.bin | 311 # check for blender.bin |
334 if not os.path.exists(BLENDER_EXEC): | 312 if not os.path.exists(BLENDER_EXEC): |
335 if os.path.exists(BLENDER_EXEC + ".bin"): | 313 if os.path.exists(BLENDER_EXEC + ".bin"): |
336 BLENDER_EXEC = BLENDER_EXEC + ".bin" | 314 BLENDER_EXEC = BLENDER_EXEC + ".bin" |
337 | 315 |
| 316 # The xgettext tool. You’ll likely have to edit it in your user_settings.py if y
ou’re under Windows. |
| 317 GETTEXT_XGETTEXT_EXECUTABLE = "xgettext" |
| 318 |
| 319 # The gettext msgmerge tool. You’ll likely have to edit it in your user_settings
.py if you’re under Windows. |
| 320 GETTEXT_MSGMERGE_EXECUTABLE = "msgmerge" |
| 321 |
338 # The gettext msgfmt "compiler". You’ll likely have to edit it in your user_sett
ings.py if you’re under Windows. | 322 # The gettext msgfmt "compiler". You’ll likely have to edit it in your user_sett
ings.py if you’re under Windows. |
339 GETTEXT_MSGFMT_EXECUTABLE = "msgfmt" | 323 GETTEXT_MSGFMT_EXECUTABLE = "msgfmt" |
340 | 324 |
| 325 # The svn binary... You’ll likely have to edit it in your user_settings.py if yo
u’re under Windows. |
| 326 SVN_EXECUTABLE = "svn" |
| 327 |
341 # The FriBidi C compiled library (.so under Linux, .dll under windows...). | 328 # The FriBidi C compiled library (.so under Linux, .dll under windows...). |
342 # You’ll likely have to edit it in your user_settings.py if you’re under Windows
., e.g. using the included one: | 329 # You’ll likely have to edit it in your user_settings.py if you’re under Windows
., e.g. using the included one: |
343 # FRIBIDI_LIB = os.path.join(TOOLS_DIR, "libfribidi.dll") | 330 # FRIBIDI_LIB = os.path.join(TOOLS_DIR, "libfribidi.dll") |
344 FRIBIDI_LIB = "libfribidi.so.0" | 331 FRIBIDI_LIB = "libfribidi.so.0" |
345 | 332 |
346 # The name of the (currently empty) file that must be present in a po's director
y to enable rtl-preprocess. | 333 # The name of the (currently empty) file that must be present in a po's director
y to enable rtl-preprocess. |
347 RTL_PREPROCESS_FILE = "is_rtl" | 334 RTL_PREPROCESS_FILE = "is_rtl" |
348 | 335 |
349 # The Blender source root path. | 336 # The Blender source root path. |
350 # This is just an example, you’ll have to override it in your user_settings.py! | 337 # This is just an example, you’ll most likely have to override it in your user_s
ettings.py! |
351 SOURCE_DIR = os.path.abspath(os.path.join("blender")) | 338 SOURCE_DIR = os.path.abspath(os.path.join(TOOLS_DIR, "..", "..", "..", "..", "..
", "..", "blender_msgs")) |
352 | 339 |
353 # The bf-translation repository (you'll have to override this in your user_setti
ngs.py). | 340 # The bf-translation repository (you'll likely have to override this in your use
r_settings.py). |
354 I18N_DIR = os.path.abspath(os.path.join("i18n")) | 341 I18N_DIR = os.path.abspath(os.path.join(TOOLS_DIR, "..", "..", "..", "..", "..",
"..", "i18n")) |
355 | 342 |
356 # The /branches path (relative to I18N_DIR). | 343 # The /branches path (overriden in bf-translation's i18n_override_settings.py). |
357 REL_BRANCHES_DIR = os.path.join("branches") | 344 BRANCHES_DIR = os.path.join(I18N_DIR, "branches") |
358 | 345 |
359 # The /trunk path (relative to I18N_DIR). | 346 # The /trunk path (overriden in bf-translation's i18n_override_settings.py). |
360 REL_TRUNK_DIR = os.path.join("trunk") | 347 TRUNK_DIR = os.path.join(I18N_DIR, "trunk") |
361 | 348 |
362 # The /trunk/po path (relative to I18N_DIR). | 349 # The /trunk/po path (overriden in bf-translation's i18n_override_settings.py). |
363 REL_TRUNK_PO_DIR = os.path.join(REL_TRUNK_DIR, "po") | 350 TRUNK_PO_DIR = os.path.join(TRUNK_DIR, "po") |
364 | 351 |
365 # The /trunk/mo path (relative to I18N_DIR). | 352 # The /trunk/mo path (overriden in bf-translation's i18n_override_settings.py). |
366 REL_TRUNK_MO_DIR = os.path.join(REL_TRUNK_DIR, "locale") | 353 TRUNK_MO_DIR = os.path.join(TRUNK_DIR, "locale") |
367 | 354 |
368 # The Blender source path to check for i18n macros (relative to SOURCE_DIR). | 355 # The file storing Blender-generated messages. |
369 REL_POTFILES_SOURCE_DIR = os.path.join("source") | 356 FILE_NAME_MESSAGES = os.path.join(TRUNK_PO_DIR, "messages.txt") |
370 | 357 |
371 # The template messages file (relative to I18N_DIR). | 358 # The Blender source path to check for i18n macros. |
372 REL_FILE_NAME_POT = os.path.join(REL_BRANCHES_DIR, DOMAIN + ".pot") | 359 POTFILES_SOURCE_DIR = os.path.join(SOURCE_DIR, "source") |
373 | 360 |
374 # Mo root datapath. | 361 # The "source" file storing which files should be processed by xgettext, used to
create FILE_NAME_POTFILES |
375 REL_MO_PATH_ROOT = os.path.join(REL_TRUNK_DIR, "locale") | 362 FILE_NAME_SRC_POTFILES = os.path.join(TRUNK_PO_DIR, "_POTFILES.in") |
376 | 363 |
377 # Mo path generator for a given language. | 364 # The final (generated) file storing which files should be processed by xgettext
. |
378 REL_MO_PATH_TEMPLATE = os.path.join(REL_MO_PATH_ROOT, "{}", "LC_MESSAGES") | 365 FILE_NAME_POTFILES = os.path.join(TRUNK_PO_DIR, "POTFILES.in") |
379 | 366 |
380 # Mo path generator for a given language (relative to any "locale" dir). | 367 # The template messages file. |
381 MO_PATH_ROOT_RELATIVE = os.path.join("locale") | 368 FILE_NAME_POT = os.path.join(TRUNK_PO_DIR, ".".join((DOMAIN, "pot"))) |
382 MO_PATH_TEMPLATE_RELATIVE = os.path.join(MO_PATH_ROOT_RELATIVE, "{}", "LC_MESSAG
ES") | |
383 | 369 |
384 # Mo file name. | 370 # Other py files that should be searched for ui strings, relative to SOURCE_DIR. |
385 MO_FILE_NAME = DOMAIN + ".mo" | 371 # Needed for Cycles, currently... |
386 | 372 CUSTOM_PY_UI_FILES = [ |
387 # Where to search for py files that may contain ui strings (relative to SOURCE_D
IR). | |
388 REL_CUSTOM_PY_UI_FILES = [ | |
389 os.path.join("release", "scripts", "startup", "bl_ui"), | |
390 os.path.join("intern", "cycles", "blender", "addon", "ui.py"), | 373 os.path.join("intern", "cycles", "blender", "addon", "ui.py"), |
391 os.path.join("release", "scripts", "modules", "rna_prop_ui.py"), | 374 os.path.join("release", "scripts", "modules", "rna_prop_ui.py"), |
392 ] | 375 ] |
393 | 376 |
394 # An optional text file listing files to force include/exclude from py_xgettext
process. | |
395 SRC_POTFILES = "" | |
396 | 377 |
397 # A cache storing validated msgids, to avoid re-spellchecking them. | 378 # A cache storing validated msgids, to avoid re-spellchecking them. |
398 SPELL_CACHE = os.path.join("/tmp", ".spell_cache") | 379 SPELL_CACHE = os.path.join("/tmp", ".spell_cache") |
399 | 380 |
400 # Threshold defining whether a new msgid is similar enough with an old one to re
use its translation... | |
401 SIMILAR_MSGID_THRESHOLD = 0.75 | |
402 | |
403 # Additional import paths to add to sys.path (';' separated)... | |
404 INTERN_PY_SYS_PATHS = "" | |
405 | 381 |
406 # Custom override settings must be one dir above i18n tools itself! | 382 # Custom override settings must be one dir above i18n tools itself! |
| 383 import sys |
407 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) | 384 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) |
408 try: | 385 try: |
409 from bl_i18n_override_settings import * | 386 from bl_i18n_override_settings import * |
410 except ImportError: # If no i18n_override_settings available, it’s no error! | 387 except ImportError: # If no i18n_override_settings available, it’s no error! |
411 pass | 388 pass |
412 | 389 |
413 # Override with custom user settings, if available. | 390 # Override with custom user settings, if available. |
414 try: | 391 try: |
415 from user_settings import * | 392 from user_settings import * |
416 except ImportError: # If no user_settings available, it’s no error! | 393 except ImportError: # If no user_settings available, it’s no error! |
417 pass | 394 pass |
418 | |
419 | |
420 for p in set(INTERN_PY_SYS_PATHS.split(";")): | |
421 if p: | |
422 sys.path.append(p) | |
423 | |
424 | |
425 # The settings class itself! | |
426 def _do_get(ref, path): | |
427 return os.path.normpath(os.path.join(ref, path)) | |
428 | |
429 def _do_set(ref, path): | |
430 path = os.path.normpath(path) | |
431 # If given path is absolute, make it relative to current ref one (else we co
nsider it is already the case!) | |
432 if os.path.isabs(path): | |
433 return os.path.relpath(path, ref) | |
434 else: | |
435 return path | |
436 | |
437 def _gen_get_set_path(ref, name): | |
438 def _get(self): | |
439 return _do_get(getattr(self, ref), getattr(self, name)) | |
440 def _set(self, value): | |
441 setattr(self, name, _do_set(getattr(self, ref), value)) | |
442 return _get, _set | |
443 | |
444 def _gen_get_set_paths(ref, name): | |
445 def _get(self): | |
446 return [_do_get(getattr(self, ref), p) for p in getattr(self, name)] | |
447 def _set(self, value): | |
448 setattr(self, name, [_do_set(getattr(self, ref), p) for p in value]) | |
449 return _get, _set | |
450 | |
451 class I18nSettings: | |
452 """ | |
453 Class allowing persistence of our settings! | |
454 Saved in JSon format, so settings should be JSon'able objects! | |
455 """ | |
456 _settings = None | |
457 | |
458 def __new__(cls, *args, **kwargs): | |
459 # Addon preferences are singleton by definition, so is this class! | |
460 if not I18nSettings._settings: | |
461 cls._settings = super(I18nSettings, cls).__new__(cls) | |
462 cls._settings.__dict__ = {uid: data for uid, data in globals().items
() if not uid.startswith("_")} | |
463 return I18nSettings._settings | |
464 | |
465 def from_json(self, string): | |
466 data = dict(json.loads(string)) | |
467 # Special case... :/ | |
468 if "INTERN_PY_SYS_PATHS" in data: | |
469 self.PY_SYS_PATHS = data["INTERN_PY_SYS_PATHS"] | |
470 self.__dict__.update(data) | |
471 | |
472 def to_json(self): | |
473 # Only save the diff from default i18n_settings! | |
474 glob = globals() | |
475 export_dict = {uid: val for uid, val in self.__dict__.items() if glob.ge
t(uid) != val} | |
476 return json.dumps(export_dict) | |
477 | |
478 def load(self, fname, reset=False): | |
479 if reset: | |
480 self.__dict__ = {uid: data for uid, data in globals().items() if not
uid.startswith("_")} | |
481 if isinstance(fname, str): | |
482 if not os.path.isfile(fname): | |
483 return | |
484 with open(fname) as f: | |
485 self.from_json(f.read()) | |
486 # Else assume fname is already a file(like) object! | |
487 else: | |
488 self.from_json(fname.read()) | |
489 | |
490 def save(self, fname): | |
491 if isinstance(fname, str): | |
492 with open(fname, 'w') as f: | |
493 f.write(self.to_json()) | |
494 # Else assume fname is already a file(like) object! | |
495 else: | |
496 fname.write(self.to_json()) | |
497 | |
498 BRANCHES_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_BRANCHES_DIR"))
) | |
499 TRUNK_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_TRUNK_DIR"))) | |
500 TRUNK_PO_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_TRUNK_PO_DIR"))
) | |
501 TRUNK_MO_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_TRUNK_MO_DIR"))
) | |
502 POTFILES_SOURCE_DIR = property(*(_gen_get_set_path("SOURCE_DIR", "REL_POTFIL
ES_SOURCE_DIR"))) | |
503 FILE_NAME_POT = property(*(_gen_get_set_path("I18N_DIR", "REL_FILE_NAME_POT"
))) | |
504 MO_PATH_ROOT = property(*(_gen_get_set_path("I18N_DIR", "REL_MO_PATH_ROOT"))
) | |
505 MO_PATH_TEMPLATE = property(*(_gen_get_set_path("I18N_DIR", "REL_MO_PATH_TEM
PLATE"))) | |
506 CUSTOM_PY_UI_FILES = property(*(_gen_get_set_paths("SOURCE_DIR", "REL_CUSTOM
_PY_UI_FILES"))) | |
507 | |
508 def _get_py_sys_paths(self): | |
509 return self.INTERN_PY_SYS_PATHS | |
510 def _set_py_sys_paths(self, val): | |
511 old_paths = set(self.INTERN_PY_SYS_PATHS.split(";")) - {""} | |
512 new_paths = set(val.split(";")) - {""} | |
513 for p in old_paths - new_paths: | |
514 if p in sys.path: | |
515 sys.path.remove(p) | |
516 for p in new_paths - old_paths: | |
517 sys.path.append(p) | |
518 self.INTERN_PY_SYS_PATHS = val | |
519 PY_SYS_PATHS = property(_get_py_sys_paths, _set_py_sys_paths) | |
OLD | NEW |