d9e0de646228d5e907145a0e3869cb114b5d02cc
[blender.git] / release / scripts / modules / bl_i18n_utils / settings.py
1 # ***** BEGIN GPL LICENSE BLOCK *****
2 #
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.
7 #
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.
12 #
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.
16 #
17 # ***** END GPL LICENSE BLOCK *****
18
19 # <pep8 compliant>
20
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
23 #     named "setting.py"
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).
26
27 import os.path
28
29
30 ###############################################################################
31 # MISC
32 ###############################################################################
33
34 # The languages defined in Blender.
35 LANGUAGES_CATEGORIES = (
36     # Min completeness level, UI english label.
37     ( 0.95, "Complete"),
38     ( 0.33, "In Progress"),
39     ( -1.0, "Starting"),
40 )
41 LANGUAGES = (
42     # ID, UI english label, ISO code.
43     ( 0, "Default (Default)", "DEFAULT"),
44     ( 1, "English (English)", "en_US"),
45     ( 2, "Japanese (日本語)", "ja_JP"),
46     ( 3, "Dutch (Nederlandse taal)", "nl_NL"),
47     ( 4, "Italian (Italiano)", "it_IT"),
48     ( 5, "German (Deutsch)", "de_DE"),
49     ( 6, "Finnish (Suomi)", "fi_FI"),
50     ( 7, "Swedish (Svenska)", "sv_SE"),
51     ( 8, "French (Français)", "fr_FR"),
52     ( 9, "Spanish (Español)", "es"),
53     (10, "Catalan (Català)", "ca_AD"),
54     (11, "Czech (Český)", "cs_CZ"),
55     (12, "Portuguese (Português)", "pt_PT"),
56     (13, "Simplified Chinese (简体中文)", "zh_CN"),
57     (14, "Traditional Chinese (繁體中文)", "zh_TW"),
58     (15, "Russian (Русский)", "ru_RU"),
59     (16, "Croatian (Hrvatski)", "hr_HR"),
60     (17, "Serbian (Српски)", "sr_RS"),
61     (18, "Ukrainian (Український)", "uk_UA"),
62     (19, "Polish (Polski)", "pl_PL"),
63     (20, "Romanian (Român)", "ro_RO"),
64     # Using the utf8 flipped form of Arabic (العربية).
65     (21, "Arabic (ﺔﻴﺑﺮﻌﻟﺍ)", "ar_EG"),
66     (22, "Bulgarian (Български)", "bg_BG"),
67     (23, "Greek (Ελληνικά)", "el_GR"),
68     (24, "Korean (한국 언어)", "ko_KR"),
69     (25, "Nepali (नेपाली)", "ne_NP"),
70     # Using the utf8 flipped form of Persian (فارسی).
71     (26, "Persian (ﯽﺳﺭﺎﻓ)", "fa_IR"),
72     (27, "Indonesian (Bahasa indonesia)", "id_ID"),
73     (28, "Serbian Latin (Srpski latinica)", "sr_RS@latin"),
74     (29, "Kyrgyz (Кыргыз тили)", "ky_KG"),
75     (30, "Turkish (Türkçe)", "tr_TR"),
76     (31, "Hungarian (Magyar)", "hu_HU"),
77     (32, "Brazilian Portuguese (Português do Brasil)", "pt_BR"),
78     # Using the utf8 flipped form of Hebrew (עִבְרִית)).
79     (33, "Hebrew (תירִבְעִ)", "he_IL"),
80     (34, "Estonian (Eestlane)", "et_EE"),
81     (35, "Esperanto (Esperanto)", "eo"),
82     (36, "Spanish from Spain (Español de España)", "es_ES"),
83     (37, "Amharic (አማርኛ)", "am_ET"),
84     (38, "Uzbek (Oʻzbek)", "uz_UZ"),
85     (39, "Uzbek Cyrillic (Ўзбек)", "uz_UZ@cyrillic"),
86 )
87
88 # Name of language file used by Blender to generate translations' menu.
89 LANGUAGES_FILE = "languages"
90
91 # The min level of completeness for a po file to be imported from /branches
92 # into /trunk, as a percentage. -1 means "import everything".
93 IMPORT_MIN_LEVEL = -1
94
95 # Languages in /branches we do not want to import in /trunk currently...
96 IMPORT_LANGUAGES_SKIP = {'am', 'bg', 'fi', 'el', 'et', 'ko', 'ne', 'pl', 'ro', 'uz', 'uz@cyrillic'}
97
98 # The comment prefix used in generated messages.txt file.
99 MSG_COMMENT_PREFIX = "#~ "
100
101 # The comment prefix used in generated messages.txt file.
102 MSG_CONTEXT_PREFIX = "MSGCTXT:"
103
104 # The default comment prefix used in po's.
105 PO_COMMENT_PREFIX= "# "
106
107 # The comment prefix used to mark sources of msgids, in po's.
108 PO_COMMENT_PREFIX_SOURCE = "#: "
109
110 # The comment prefix used to mark sources of msgids, in po's.
111 PO_COMMENT_PREFIX_SOURCE_CUSTOM = "#. :src: "
112
113 # The comment prefix used to comment entries in po's.
114 PO_COMMENT_PREFIX_MSG= "#~ "
115
116 # The comment prefix used to mark fuzzy msgids, in po's.
117 PO_COMMENT_FUZZY = "#, fuzzy"
118
119 # The prefix used to define context, in po's.
120 PO_MSGCTXT = "msgctxt "
121
122 # The prefix used to define msgid, in po's.
123 PO_MSGID = "msgid "
124
125 # The prefix used to define msgstr, in po's.
126 PO_MSGSTR = "msgstr "
127
128 # The 'header' key of po files.
129 PO_HEADER_KEY = ("", "")
130
131 PO_HEADER_MSGSTR = (
132     "Project-Id-Version: Blender {blender_ver} (r{blender_rev})\\n\n"
133     "Report-Msgid-Bugs-To: \\n\n"
134     "POT-Creation-Date: {time}\\n\n"
135     "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\n"
136     "Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\n"
137     "Language-Team: LANGUAGE <LL@li.org>\\n\n"
138     "Language: {iso}\\n\n"
139     "MIME-Version: 1.0\\n\n"
140     "Content-Type: text/plain; charset=UTF-8\\n\n"
141     "Content-Transfer-Encoding: 8bit\n"
142 )
143 PO_HEADER_COMMENT_COPYRIGHT = (
144     "# Blender's translation file (po format).\n"
145     "# Copyright (C) {year} The Blender Foundation.\n"
146     "# This file is distributed under the same license as the Blender package.\n"
147     "#\n"
148 )
149 PO_HEADER_COMMENT = (
150     "# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n"
151     "#"
152 )
153
154 TEMPLATE_ISO_ID = "__TEMPLATE__"
155
156 # Default context.
157 CONTEXT_DEFAULT = ""
158
159 # Undocumented operator placeholder string.
160 UNDOC_OPS_STR = "(undocumented operator)"
161
162 # The gettext domain.
163 DOMAIN = "blender"
164
165 # Our own "gettext" stuff.
166 # File type (ext) to parse.
167 PYGETTEXT_ALLOWED_EXTS = {".c", ".cpp", ".cxx", ".hpp", ".hxx", ".h"}
168
169 # Max number of contexts into a BLF_I18N_MSGID_MULTI_CTXT macro...
170 PYGETTEXT_MAX_MULTI_CTXT = 16
171
172 # Where to search contexts definitions, relative to SOURCE_DIR (defined below).
173 PYGETTEXT_CONTEXTS_DEFSRC = os.path.join("source", "blender", "blenfont", "BLF_translation.h")
174
175 # Regex to extract contexts defined in BLF_translation.h
176 # XXX Not full-proof, but should be enough here!
177 PYGETTEXT_CONTEXTS = "#define\\s+(BLF_I18NCONTEXT_[A-Z_0-9]+)\\s+\"([^\"]*)\""
178
179 # Keywords' regex.
180 # XXX Most unfortunately, we can't use named backreferences inside character sets,
181 #     which makes the regexes even more twisty... :/
182 _str_base = (
183     # Match void string
184     "(?P<{_}1>[\"'])(?P={_}1)"  # Get opening quote (' or "), and closing immediately.
185     "|"
186     # Or match non-void string
187     "(?P<{_}2>[\"'])"  # Get opening quote (' or ").
188         "(?{capt}(?:"
189             # This one is for crazy things like "hi \\\\\" folks!"...
190             r"(?:(?!<\\)(?:\\\\)*\\(?=(?P={_}2)))|"
191             # The most common case.
192             ".(?!(?P={_}2))"
193         ")+.)"  # Don't forget the last char!
194     "(?P={_}2)"  # And closing quote.
195 )
196 str_clean_re = _str_base.format(_="g", capt="P<clean>")
197 _inbetween_str_re = (
198     # XXX Strings may have comments between their pieces too, not only spaces!
199     r"(?:\s*(?:"
200         # A C comment
201         r"/\*.*(?!\*/).\*/|"
202         # Or a C++ one!
203         r"//[^\n]*\n"
204     # And we are done!
205     r")?)*"
206 )
207 # Here we have to consider two different cases (empty string and other).
208 _str_whole_re = (
209     _str_base.format(_="{_}1_", capt=":") +
210     # Optional loop start, this handles "split" strings...
211     "(?:(?<=[\"'])" + _inbetween_str_re + "(?=[\"'])(?:"
212         + _str_base.format(_="{_}2_", capt=":") +
213     # End of loop.
214     "))*"
215 )
216 _ctxt_re_gen = lambda uid : r"(?P<ctxt_raw{uid}>(?:".format(uid=uid) + \
217                             _str_whole_re.format(_="_ctxt{uid}".format(uid=uid)) + \
218                             r")|(?:[A-Z_0-9]+))"
219 _ctxt_re = _ctxt_re_gen("")
220 _msg_re = r"(?P<msg_raw>" + _str_whole_re.format(_="_msg") + r")"
221 PYGETTEXT_KEYWORDS = (() +
222     tuple((r"{}\(\s*" + _msg_re + r"\s*\)").format(it)
223           for it in ("IFACE_", "TIP_", "N_")) +
224
225     tuple((r"{}\(\s*" + _ctxt_re + r"\s*,\s*" + _msg_re + r"\s*\)").format(it)
226           for it in ("CTX_IFACE_", "CTX_TIP_", "CTX_N_")) + 
227
228     tuple(("{}\\((?:[^\"',]+,){{1,2}}\\s*" + _msg_re + r"\s*(?:\)|,)").format(it)
229           for it in ("BKE_report", "BKE_reportf", "BKE_reports_prepend", "BKE_reports_prependf")) +
230
231     tuple(("{}\\((?:[^\"',]+,){{3}}\\s*" + _msg_re + r"\s*,").format(it)
232           for it in ("BMO_error_raise",)) +
233
234     tuple(("{}\\((?:[^\"',]+,)\\s*" + _msg_re + r"\s*(?:\)|,)").format(it)
235           for it in ("modifier_setError",)) +
236
237     tuple((r"{}\(\s*" + _msg_re + r"\s*,\s*(?:" + \
238            r"\s*,\s*)?(?:".join(_ctxt_re_gen(i) for i in range(PYGETTEXT_MAX_MULTI_CTXT)) + r")?\s*\)").format(it)
239           for it in ("BLF_I18N_MSGID_MULTI_CTXT",))
240 )
241
242 ESCAPE_RE = (
243     (r'((?<!\\)"|(?<!\\)\\(?!\\|"))', r"\\\1"),
244     ('\t', r"\\t"),
245 )
246
247 # Should po parser warn when finding a first letter not capitalized?
248 WARN_MSGID_NOT_CAPITALIZED = True
249
250 # Strings that should not raise above warning!
251 WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
252     "",  # Simplifies things... :p
253     "sin(x) / x",
254     "fBM",
255     "sqrt(x*x+y*y+z*z)",
256     "iTaSC",
257     "bItasc",
258     "px",
259     "mm",
260     "fStop",
261     "sRGB",
262     "iso-8859-15",
263     "utf-8",
264     "ascii",
265     "re",
266     "y",
267     "ac3",
268     "flac",
269     "mkv",
270     "mp2",
271     "mp3",
272     "ogg",
273     "wav",
274     "iTaSC parameters",
275     "vBVH",
276     "rv",
277     "et_EE",
278     "eo",
279     "available with",                # Is part of multi-line msg.
280     "virtual parents",               # Is part of multi-line msg.
281     "description",                   # Addons' field. :/
282     "location",                      # Addons' field. :/
283     "author",                        # Addons' field. :/
284     "in memory to enable editing!",  # Is part of multi-line msg.
285     "iScale",
286     "dx",
287     "p0",
288     "res",
289 }
290 WARN_MSGID_NOT_CAPITALIZED_ALLOWED |= set(lng[2] for lng in LANGUAGES)
291
292 PARSER_CACHE_HASH = 'sha1'
293
294
295 ###############################################################################
296 # PATHS
297 ###############################################################################
298
299 # The tools path, should be OK.
300 TOOLS_DIR = os.path.join(os.path.dirname(__file__))
301
302 # The Python3 executable.You’ll likely have to edit it in your user_settings.py
303 # if you’re under Windows.
304 PYTHON3_EXEC = "python3"
305
306 # The Blender executable!
307 # This is just an example, you’ll most likely have to edit it in your user_settings.py!
308 BLENDER_EXEC = os.path.abspath(os.path.join(TOOLS_DIR, "..", "..", "..", "..", "blender"))
309 # check for blender.bin
310 if not os.path.exists(BLENDER_EXEC):
311     if os.path.exists(BLENDER_EXEC + ".bin"):
312         BLENDER_EXEC = BLENDER_EXEC + ".bin"
313
314 # The xgettext tool. You’ll likely have to edit it in your user_settings.py if you’re under Windows.
315 GETTEXT_XGETTEXT_EXECUTABLE = "xgettext"
316
317 # The gettext msgmerge tool. You’ll likely have to edit it in your user_settings.py if you’re under Windows.
318 GETTEXT_MSGMERGE_EXECUTABLE = "msgmerge"
319
320 # The gettext msgfmt "compiler". You’ll likely have to edit it in your user_settings.py if you’re under Windows.
321 GETTEXT_MSGFMT_EXECUTABLE = "msgfmt"
322
323 # The svn binary... You’ll likely have to edit it in your user_settings.py if you’re under Windows.
324 SVN_EXECUTABLE = "svn"
325
326 # The FriBidi C compiled library (.so under Linux, .dll under windows...).
327 # You’ll likely have to edit it in your user_settings.py if you’re under Windows., e.g. using the included one:
328 #     FRIBIDI_LIB = os.path.join(TOOLS_DIR, "libfribidi.dll")
329 FRIBIDI_LIB = "libfribidi.so.0"
330
331 # The name of the (currently empty) file that must be present in a po's directory to enable rtl-preprocess.
332 RTL_PREPROCESS_FILE = "is_rtl"
333
334 # The Blender source root path.
335 # This is just an example, you’ll most likely have to override it in your user_settings.py!
336 SOURCE_DIR = os.path.abspath(os.path.join(TOOLS_DIR, "..", "..", "..", "..", "..", "..", "blender_msgs"))
337
338 # The bf-translation repository (you'll likely have to override this in your user_settings.py).
339 I18N_DIR = os.path.abspath(os.path.join(TOOLS_DIR, "..", "..", "..", "..", "..", "..", "i18n"))
340
341 # The /branches path (overriden in bf-translation's i18n_override_settings.py).
342 BRANCHES_DIR = os.path.join(I18N_DIR, "branches")
343
344 # The /trunk path (overriden in bf-translation's i18n_override_settings.py).
345 TRUNK_DIR = os.path.join(I18N_DIR, "trunk")
346
347 # The /trunk/po path (overriden in bf-translation's i18n_override_settings.py).
348 TRUNK_PO_DIR = os.path.join(TRUNK_DIR, "po")
349
350 # The /trunk/mo path (overriden in bf-translation's i18n_override_settings.py).
351 TRUNK_MO_DIR = os.path.join(TRUNK_DIR, "locale")
352
353 # The file storing Blender-generated messages.
354 FILE_NAME_MESSAGES = os.path.join(TRUNK_PO_DIR, "messages.txt")
355
356 # The Blender source path to check for i18n macros.
357 POTFILES_SOURCE_DIR = os.path.join(SOURCE_DIR, "source")
358
359 # The "source" file storing which files should be processed by xgettext, used to create FILE_NAME_POTFILES
360 FILE_NAME_SRC_POTFILES = os.path.join(TRUNK_PO_DIR, "_POTFILES.in")
361
362 # The final (generated) file storing which files should be processed by xgettext.
363 FILE_NAME_POTFILES = os.path.join(TRUNK_PO_DIR, "POTFILES.in")
364
365 # The template messages file.
366 FILE_NAME_POT = os.path.join(TRUNK_PO_DIR, ".".join((DOMAIN, "pot")))
367
368 # Other py files that should be searched for ui strings, relative to SOURCE_DIR.
369 # Needed for Cycles, currently...
370 CUSTOM_PY_UI_FILES = [os.path.join("intern", "cycles", "blender", "addon", "ui.py"),]
371
372
373 # A cache storing validated msgids, to avoid re-spellchecking them.
374 SPELL_CACHE = os.path.join("/tmp", ".spell_cache")
375
376
377 # Custom override settings must be one dir above i18n tools itself!
378 import sys
379 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
380 try:
381     from bl_i18n_override_settings import *
382 except ImportError:  # If no i18n_override_settings available, it’s no error!
383     pass
384
385 # Override with custom user settings, if available.
386 try:
387     from user_settings import *
388 except ImportError:  # If no user_settings available, it’s no error!
389     pass