2023-08-16 00:20:26 +10:00
|
|
|
|
# SPDX-FileCopyrightText: 2012-2023 Blender Authors
|
2023-06-15 13:09:04 +10:00
|
|
|
|
#
|
2022-02-11 09:07:11 +11:00
|
|
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2024-05-28 13:42:16 +10:00
|
|
|
|
# Global settings used by all scripts in this directory.
|
|
|
|
|
# XXX Before any use of the tools in this directory, please make a copy of this file
|
2012-07-02 19:51:06 +00:00
|
|
|
|
# named "setting.py"
|
|
|
|
|
# XXX This is a template, most values should be OK, but some you’ll have to
|
|
|
|
|
# edit (most probably, BLENDER_EXEC and SOURCE_DIR).
|
|
|
|
|
|
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
import sys
|
2020-05-05 18:04:22 +02:00
|
|
|
|
import types
|
2013-02-24 08:50:55 +00:00
|
|
|
|
|
2024-08-09 17:48:01 +02:00
|
|
|
|
# Only do soft-dependency on `bpy` module, not real strong need for it currently.
|
2020-12-04 15:08:11 +01:00
|
|
|
|
try:
|
|
|
|
|
import bpy
|
|
|
|
|
except ModuleNotFoundError:
|
|
|
|
|
bpy = None
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
# MISC
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
2012-10-22 14:17:30 +00:00
|
|
|
|
# The languages defined in Blender.
|
|
|
|
|
LANGUAGES = (
|
2023-09-05 10:49:20 +10:00
|
|
|
|
# ID, UI English label, ISO code.
|
2025-06-11 13:11:40 +02:00
|
|
|
|
(0, "Automatic", "DEFAULT"),
|
|
|
|
|
(1, "English (US)", "en_US"),
|
|
|
|
|
(2, "Japanese - 日本語", "ja_JP"),
|
|
|
|
|
(3, "Dutch - Nederlands", "nl_NL"),
|
|
|
|
|
(4, "Italian - Italiano", "it_IT"),
|
|
|
|
|
(5, "German - Deutsch", "de_DE"),
|
|
|
|
|
(6, "Finnish - Suomi", "fi_FI"),
|
|
|
|
|
(7, "Swedish - Svenska", "sv_SE"),
|
|
|
|
|
(8, "French - Français", "fr_FR"),
|
|
|
|
|
(9, "Spanish - Español", "es"),
|
|
|
|
|
(10, "Catalan - Català", "ca_AD"),
|
|
|
|
|
(11, "Czech - Čeština", "cs_CZ"),
|
|
|
|
|
(12, "Portuguese (Portugal) - Português europeu", "pt_PT"),
|
|
|
|
|
(13, "Chinese (Simplified) - 简体中文", "zh_HANS"),
|
|
|
|
|
(14, "Chinese (Traditional) - 繁體中文", "zh_HANT"),
|
|
|
|
|
(15, "Russian - Русский", "ru_RU"),
|
|
|
|
|
(16, "Croatian - Hrvatski", "hr_HR"),
|
|
|
|
|
(17, "Serbian (Cyrillic) - Српски", "sr_RS"),
|
|
|
|
|
(18, "Ukrainian - Українська", "uk_UA"),
|
|
|
|
|
(19, "Polish - Polski", "pl_PL"),
|
|
|
|
|
(20, "Romanian - Român", "ro_RO"),
|
2012-10-22 14:17:30 +00:00
|
|
|
|
# Using the utf8 flipped form of Arabic (العربية).
|
2025-06-11 13:11:40 +02:00
|
|
|
|
(21, "Arabic - ﺔﻴﺑﺮﻌﻟﺍ", "ar_EG"),
|
|
|
|
|
(22, "Bulgarian - Български", "bg_BG"),
|
|
|
|
|
(23, "Greek - Ελληνικά", "el_GR"),
|
|
|
|
|
(24, "Korean - 한국어", "ko_KR"),
|
|
|
|
|
(25, "Nepali - नेपाली", "ne_NP"),
|
2012-10-22 14:17:30 +00:00
|
|
|
|
# Using the utf8 flipped form of Persian (فارسی).
|
2025-06-11 13:11:40 +02:00
|
|
|
|
(26, "Persian - ﯽﺳﺭﺎﻓ", "fa_IR"),
|
|
|
|
|
(27, "Indonesian - Bahasa indonesia", "id_ID"),
|
|
|
|
|
(28, "Serbian (Latin) - Srpski latinica", "sr_RS@latin"),
|
|
|
|
|
(29, "Kyrgyz - Кыргыз тили", "ky_KG"),
|
|
|
|
|
(30, "Turkish - Türkçe", "tr_TR"),
|
|
|
|
|
(31, "Hungarian - Magyar", "hu_HU"),
|
|
|
|
|
(32, "Portuguese (Brazil) - Português brasileiro", "pt_BR"),
|
2012-10-22 14:17:30 +00:00
|
|
|
|
# Using the utf8 flipped form of Hebrew (עִבְרִית)).
|
2025-06-11 13:11:40 +02:00
|
|
|
|
(33, "Hebrew - תירִבְעִ", "he_IL"),
|
|
|
|
|
(34, "Estonian - Eesti keel", "et_EE"),
|
|
|
|
|
(35, "Esperanto - Esperanto", "eo"),
|
2023-09-15 12:55:33 +02:00
|
|
|
|
# 36 is free, used to be 'Spanish from Spain' (`es_ES`).
|
2025-06-11 13:11:40 +02:00
|
|
|
|
(37, "Amharic - አማርኛ", "am_ET"),
|
|
|
|
|
(38, "Uzbek (Latin) - Oʻzbek", "uz_UZ@latin"),
|
|
|
|
|
(39, "Uzbek (Cyrillic) - Ўзбек", "uz_UZ@cyrillic"),
|
|
|
|
|
(40, "Hindi - हिन्दी", "hi_IN"),
|
|
|
|
|
(41, "Vietnamese - Tiếng Việt", "vi_VN"),
|
|
|
|
|
(42, "Basque - Euskara", "eu_EU"),
|
|
|
|
|
(43, "Hausa - Hausa", "ha"),
|
|
|
|
|
(44, "Kazakh - Қазақша", "kk_KZ"),
|
|
|
|
|
(45, "Abkhaz - Аԥсуа бызшәа", "ab"),
|
|
|
|
|
(46, "Thai - ภาษาไทย", "th_TH"),
|
|
|
|
|
(47, "Slovak - Slovenčina", "sk_SK"),
|
|
|
|
|
(48, "Georgian - ქართული", "ka"),
|
|
|
|
|
(49, "Tamil - தமிழ்", "ta"),
|
|
|
|
|
(50, "Khmer - ខ្មែរ", "km"),
|
|
|
|
|
(51, "Swahili - Kiswahili", "sw"),
|
|
|
|
|
(52, "Belarusian - беларуску", "be"),
|
|
|
|
|
(53, "Danish - Dansk", "da"),
|
|
|
|
|
(54, "Slovenian - Slovenščina", "sl"),
|
2024-09-16 12:22:18 +02:00
|
|
|
|
# Using the utf8 flipped form of Urdu (اُردُو).
|
2025-06-11 13:11:40 +02:00
|
|
|
|
(55, "Urdu - وُدرُا", "ur"),
|
|
|
|
|
(56, "Lithuanian - Lietuviškai", "lt"),
|
|
|
|
|
(57, "English (UK)", "en_GB"),
|
2012-10-22 14:17:30 +00:00
|
|
|
|
)
|
|
|
|
|
|
2024-08-09 17:48:01 +02:00
|
|
|
|
# Default context, in py (keep in sync with `BLT_translation.hh`)!
|
2020-12-04 15:08:11 +01:00
|
|
|
|
if bpy is not None:
|
2022-09-14 16:18:59 +10:00
|
|
|
|
assert bpy.app.translations.contexts.default == "*"
|
2020-12-04 15:08:11 +01:00
|
|
|
|
DEFAULT_CONTEXT = "*"
|
2013-02-24 08:50:55 +00:00
|
|
|
|
|
2012-10-22 14:17:30 +00:00
|
|
|
|
# Name of language file used by Blender to generate translations' menu.
|
|
|
|
|
LANGUAGES_FILE = "languages"
|
|
|
|
|
|
2025-04-26 00:48:04 +00:00
|
|
|
|
# The minimum level of completeness for a `.po` file to be imported from
|
2023-09-17 09:01:43 +10:00
|
|
|
|
# the working repository to the Blender one, as a percentage.
|
2013-02-24 08:50:55 +00:00
|
|
|
|
IMPORT_MIN_LEVEL = 0.0
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2023-09-15 16:50:25 +02:00
|
|
|
|
# Languages in the working repository that should not be imported in the Blender one currently...
|
2013-02-24 08:50:55 +00:00
|
|
|
|
IMPORT_LANGUAGES_SKIP = {
|
2024-10-20 18:19:37 +02:00
|
|
|
|
'am_ET', 'et_EE', 'uz_UZ@latin', 'uz_UZ@cyrillic', 'kk_KZ',
|
2013-02-24 08:50:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Languages that need RTL pre-processing.
|
|
|
|
|
IMPORT_LANGUAGES_RTL = {
|
2024-09-16 12:22:18 +02:00
|
|
|
|
'ar_EG', 'fa_IR', 'he_IL', 'ur',
|
2013-02-24 08:50:55 +00:00
|
|
|
|
}
|
2012-10-20 08:52:54 +00:00
|
|
|
|
|
2023-09-03 21:35:03 +10:00
|
|
|
|
# The comment prefix used in generated `messages.txt` file.
|
2013-01-12 16:49:06 +00:00
|
|
|
|
MSG_COMMENT_PREFIX = "#~ "
|
|
|
|
|
|
2023-09-03 21:35:03 +10:00
|
|
|
|
# The comment prefix used in generated `messages.txt` file.
|
2013-01-12 16:49:06 +00:00
|
|
|
|
MSG_CONTEXT_PREFIX = "MSGCTXT:"
|
|
|
|
|
|
|
|
|
|
# The default comment prefix used in po's.
|
2017-06-12 13:35:00 +10:00
|
|
|
|
PO_COMMENT_PREFIX = "# "
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
|
|
|
|
# The comment prefix used to mark sources of msgids, in po's.
|
2013-01-12 16:49:06 +00:00
|
|
|
|
PO_COMMENT_PREFIX_SOURCE = "#: "
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2013-01-12 16:49:06 +00:00
|
|
|
|
# The comment prefix used to mark sources of msgids, in po's.
|
|
|
|
|
PO_COMMENT_PREFIX_SOURCE_CUSTOM = "#. :src: "
|
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
# The general "generated" comment prefix, in po's.
|
|
|
|
|
PO_COMMENT_PREFIX_GENERATED = "#. "
|
|
|
|
|
|
2013-01-12 16:49:06 +00:00
|
|
|
|
# The comment prefix used to comment entries in po's.
|
2017-06-12 13:35:00 +10:00
|
|
|
|
PO_COMMENT_PREFIX_MSG = "#~ "
|
2013-01-12 16:49:06 +00:00
|
|
|
|
|
|
|
|
|
# The comment prefix used to mark fuzzy msgids, in po's.
|
|
|
|
|
PO_COMMENT_FUZZY = "#, fuzzy"
|
|
|
|
|
|
|
|
|
|
# The prefix used to define context, in po's.
|
|
|
|
|
PO_MSGCTXT = "msgctxt "
|
|
|
|
|
|
|
|
|
|
# The prefix used to define msgid, in po's.
|
|
|
|
|
PO_MSGID = "msgid "
|
|
|
|
|
|
|
|
|
|
# The prefix used to define msgstr, in po's.
|
|
|
|
|
PO_MSGSTR = "msgstr "
|
|
|
|
|
|
|
|
|
|
# The 'header' key of po files.
|
2013-02-24 08:50:55 +00:00
|
|
|
|
PO_HEADER_KEY = (DEFAULT_CONTEXT, "")
|
2013-01-12 16:49:06 +00:00
|
|
|
|
|
|
|
|
|
PO_HEADER_MSGSTR = (
|
2013-11-04 18:26:56 +00:00
|
|
|
|
"Project-Id-Version: {blender_ver} ({blender_hash})\\n\n"
|
2013-01-12 16:49:06 +00:00
|
|
|
|
"Report-Msgid-Bugs-To: \\n\n"
|
|
|
|
|
"POT-Creation-Date: {time}\\n\n"
|
|
|
|
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\n"
|
|
|
|
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\n"
|
|
|
|
|
"Language-Team: LANGUAGE <LL@li.org>\\n\n"
|
2013-02-24 08:50:55 +00:00
|
|
|
|
"Language: {uid}\\n\n"
|
2013-01-12 16:49:06 +00:00
|
|
|
|
"MIME-Version: 1.0\\n\n"
|
|
|
|
|
"Content-Type: text/plain; charset=UTF-8\\n\n"
|
|
|
|
|
"Content-Transfer-Encoding: 8bit\n"
|
|
|
|
|
)
|
|
|
|
|
PO_HEADER_COMMENT_COPYRIGHT = (
|
|
|
|
|
"# Blender's translation file (po format).\n"
|
2023-08-16 00:20:26 +10:00
|
|
|
|
"# Copyright (C) {year} The Blender Authors.\n"
|
2013-01-12 16:49:06 +00:00
|
|
|
|
"# This file is distributed under the same license as the Blender package.\n"
|
|
|
|
|
"#\n"
|
|
|
|
|
)
|
|
|
|
|
PO_HEADER_COMMENT = (
|
|
|
|
|
"# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n"
|
|
|
|
|
"#"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
TEMPLATE_ISO_ID = "__TEMPLATE__"
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
# Num buttons report their label with a trailing ': '...
|
|
|
|
|
NUM_BUTTON_SUFFIX = ": "
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
|
|
|
|
# Undocumented operator placeholder string.
|
|
|
|
|
UNDOC_OPS_STR = "(undocumented operator)"
|
|
|
|
|
|
|
|
|
|
# The gettext domain.
|
|
|
|
|
DOMAIN = "blender"
|
|
|
|
|
|
|
|
|
|
# Our own "gettext" stuff.
|
|
|
|
|
# File type (ext) to parse.
|
2021-11-02 17:00:23 +01:00
|
|
|
|
PYGETTEXT_ALLOWED_EXTS = {".c", ".cc", ".cpp", ".cxx", ".hh", ".hpp", ".hxx", ".h"}
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2015-08-25 21:12:36 +02:00
|
|
|
|
# Max number of contexts into a BLT_I18N_MSGID_MULTI_CTXT macro...
|
2012-11-23 15:35:16 +00:00
|
|
|
|
PYGETTEXT_MAX_MULTI_CTXT = 16
|
|
|
|
|
|
2012-07-02 19:51:06 +00:00
|
|
|
|
# Where to search contexts definitions, relative to SOURCE_DIR (defined below).
|
2015-08-25 21:12:36 +02:00
|
|
|
|
PYGETTEXT_CONTEXTS_DEFSRC = os.path.join("source", "blender", "blentranslation", "BLT_translation.h")
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2015-08-25 21:12:36 +02:00
|
|
|
|
# Regex to extract contexts defined in BLT_translation.h
|
2012-07-02 19:51:06 +00:00
|
|
|
|
# XXX Not full-proof, but should be enough here!
|
2015-08-25 21:12:36 +02:00
|
|
|
|
PYGETTEXT_CONTEXTS = "#define\\s+(BLT_I18NCONTEXT_[A-Z_0-9]+)\\s+\"([^\"]*)\""
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2022-04-20 15:39:36 +10:00
|
|
|
|
# autopep8: off
|
|
|
|
|
|
2012-07-02 19:51:06 +00:00
|
|
|
|
# Keywords' regex.
|
2023-09-05 10:49:20 +10:00
|
|
|
|
# XXX Most unfortunately, we can't use named back-references inside character sets,
|
|
|
|
|
# which makes the REGEXES even more twisty... :/
|
2012-07-03 01:11:59 +00:00
|
|
|
|
_str_base = (
|
|
|
|
|
# Match void string
|
|
|
|
|
"(?P<{_}1>[\"'])(?P={_}1)" # Get opening quote (' or "), and closing immediately.
|
|
|
|
|
"|"
|
|
|
|
|
# Or match non-void string
|
|
|
|
|
"(?P<{_}2>[\"'])" # Get opening quote (' or ").
|
|
|
|
|
"(?{capt}(?:"
|
|
|
|
|
# This one is for crazy things like "hi \\\\\" folks!"...
|
|
|
|
|
r"(?:(?!<\\)(?:\\\\)*\\(?=(?P={_}2)))|"
|
|
|
|
|
# The most common case.
|
|
|
|
|
".(?!(?P={_}2))"
|
2023-05-18 17:44:54 +02:00
|
|
|
|
")*.)" # Don't forget the last char!
|
2012-07-03 01:11:59 +00:00
|
|
|
|
"(?P={_}2)" # And closing quote.
|
|
|
|
|
)
|
|
|
|
|
str_clean_re = _str_base.format(_="g", capt="P<clean>")
|
2013-01-12 16:49:06 +00:00
|
|
|
|
_inbetween_str_re = (
|
|
|
|
|
# XXX Strings may have comments between their pieces too, not only spaces!
|
|
|
|
|
r"(?:\s*(?:"
|
|
|
|
|
# A C comment
|
|
|
|
|
r"/\*.*(?!\*/).\*/|"
|
|
|
|
|
# Or a C++ one!
|
2024-05-27 14:48:09 +02:00
|
|
|
|
r"//[^\n]*\n|"
|
|
|
|
|
# Or some #defined value (like `BLI_STR_UTF8_BLACK_RIGHT_POINTING_SMALL_TRIANGLE`)
|
|
|
|
|
# NOTE: This should be avoided at all cost, as it will simply make translation lookup fail.
|
|
|
|
|
r"[ a-zA-Z0-9_]*"
|
2013-01-12 16:49:06 +00:00
|
|
|
|
# And we are done!
|
|
|
|
|
r")?)*"
|
|
|
|
|
)
|
2012-07-03 01:11:59 +00:00
|
|
|
|
# Here we have to consider two different cases (empty string and other).
|
|
|
|
|
_str_whole_re = (
|
|
|
|
|
_str_base.format(_="{_}1_", capt=":") +
|
|
|
|
|
# Optional loop start, this handles "split" strings...
|
2013-01-12 16:49:06 +00:00
|
|
|
|
"(?:(?<=[\"'])" + _inbetween_str_re + "(?=[\"'])(?:"
|
2012-07-03 01:11:59 +00:00
|
|
|
|
+ _str_base.format(_="{_}2_", capt=":") +
|
|
|
|
|
# End of loop.
|
|
|
|
|
"))*"
|
|
|
|
|
)
|
2025-01-21 23:30:55 +11:00
|
|
|
|
_ctxt_re_gen = lambda uid: (
|
|
|
|
|
r"(?P<ctxt_raw{uid}>(?:".format(uid=uid) +
|
|
|
|
|
_str_whole_re.format(_="_ctxt{uid}".format(uid=uid)) +
|
|
|
|
|
r")|(?:[A-Z_0-9]+))"
|
|
|
|
|
)
|
2012-11-23 15:35:16 +00:00
|
|
|
|
_ctxt_re = _ctxt_re_gen("")
|
2012-07-02 19:51:06 +00:00
|
|
|
|
_msg_re = r"(?P<msg_raw>" + _str_whole_re.format(_="_msg") + r")"
|
|
|
|
|
PYGETTEXT_KEYWORDS = (() +
|
|
|
|
|
tuple((r"{}\(\s*" + _msg_re + r"\s*\)").format(it)
|
2024-01-11 19:49:03 +01:00
|
|
|
|
for it in ("IFACE_", "TIP_", "RPT_", "DATA_", "N_")) +
|
2012-10-27 11:12:09 +00:00
|
|
|
|
|
2012-07-29 12:07:06 +00:00
|
|
|
|
tuple((r"{}\(\s*" + _ctxt_re + r"\s*,\s*" + _msg_re + r"\s*\)").format(it)
|
2024-01-11 19:49:03 +01:00
|
|
|
|
for it in ("CTX_IFACE_", "CTX_TIP_", "CTX_RPT_", "CTX_DATA_", "CTX_N_")) +
|
2012-10-27 11:12:09 +00:00
|
|
|
|
|
2012-10-26 17:32:50 +00:00
|
|
|
|
tuple(("{}\\((?:[^\"',]+,){{1,2}}\\s*" + _msg_re + r"\s*(?:\)|,)").format(it)
|
2013-02-19 15:47:30 +00:00
|
|
|
|
for it in ("BKE_report", "BKE_reportf", "BKE_reports_prepend", "BKE_reports_prependf",
|
2024-01-11 19:49:03 +01:00
|
|
|
|
"CTX_wm_operator_poll_msg_set", "WM_report", "WM_reportf",
|
|
|
|
|
"UI_but_disable")) +
|
2012-10-27 11:12:09 +00:00
|
|
|
|
|
2023-12-19 18:41:09 +01:00
|
|
|
|
# bmesh operator errors
|
2013-02-17 14:00:40 +00:00
|
|
|
|
tuple(("{}\\((?:[^\"',]+,){{3}}\\s*" + _msg_re + r"\s*\)").format(it)
|
2012-10-27 11:12:09 +00:00
|
|
|
|
for it in ("BMO_error_raise",)) +
|
|
|
|
|
|
2023-12-19 18:41:09 +01:00
|
|
|
|
# Modifier errors
|
2022-07-14 18:46:52 +02:00
|
|
|
|
tuple(("{}\\((?:[^\"',]+,){{2}}\\s*" + _msg_re + r"\s*(?:\)|,)").format(it)
|
2021-11-10 10:46:49 -06:00
|
|
|
|
for it in ("BKE_modifier_set_error",)) +
|
2012-11-23 15:35:16 +00:00
|
|
|
|
|
2024-09-02 20:13:31 +02:00
|
|
|
|
# Compositor and EEVEE messages.
|
|
|
|
|
# Ends either with `)` (function call close), or `,` when there are extra formatting parameters.
|
|
|
|
|
tuple((r"{}\(\s*" + _msg_re + r"\s*(?:\)|,)").format(it)
|
|
|
|
|
for it in ("set_info_message", "info_append_i18n")) +
|
2023-12-19 18:41:09 +01:00
|
|
|
|
|
2022-07-15 11:41:13 +02:00
|
|
|
|
# This one is a tad more risky, but in practice would not expect a name/uid string parameter
|
|
|
|
|
# (the second one in those functions) to ever have a comma in it, so think this is fine.
|
|
|
|
|
tuple(("{}\\((?:[^,]+,){{2}}\\s*" + _msg_re + r"\s*(?:\)|,)").format(it)
|
|
|
|
|
for it in ("modifier_subpanel_register", "gpencil_modifier_subpanel_register")) +
|
|
|
|
|
|
2023-09-05 10:49:20 +10:00
|
|
|
|
# Node socket declarations: context-less names.
|
2023-05-18 17:44:54 +02:00
|
|
|
|
tuple((r"\.{}<decl::.*?>\(\s*" + _msg_re + r"(?:,[^),]+)*\s*\)"
|
|
|
|
|
r"(?![^;]*\.translation_context\()").format(it)
|
2023-04-23 16:16:55 +02:00
|
|
|
|
for it in ("add_input", "add_output")) +
|
|
|
|
|
|
|
|
|
|
# Node socket declarations: names with contexts
|
|
|
|
|
tuple((r"\.{}<decl::.*?>\(\s*" + _msg_re + r"[^;]*\.translation_context\(\s*" + _ctxt_re + r"\s*\)").format(it)
|
|
|
|
|
for it in ("add_input", "add_output")) +
|
|
|
|
|
|
|
|
|
|
# Node socket declarations: description and error messages
|
|
|
|
|
tuple((r"\.{}\(\s*" + _msg_re + r"\s*\)").format(it)
|
|
|
|
|
for it in ("description", "error_message_add")) +
|
|
|
|
|
|
2023-10-12 17:51:37 +02:00
|
|
|
|
# Node socket labels from declarations: context-less names
|
|
|
|
|
tuple((r"\.{}\(\s*" + _msg_re +
|
|
|
|
|
r"\s*\)(?![^;]*\.translation_context\()[^;]*;").format(it)
|
|
|
|
|
for it in ("short_label",)) +
|
|
|
|
|
|
|
|
|
|
# Node socket labels from declarations: names with contexts
|
|
|
|
|
tuple((r"\.{}\(\s*" + _msg_re + r"[^;]*\.translation_context\(\s*" +
|
|
|
|
|
_ctxt_re + r"\s*\)").format(it)
|
|
|
|
|
for it in ("short_label",)) +
|
|
|
|
|
|
|
|
|
|
# Dynamic node socket labels
|
2023-05-15 18:42:11 +02:00
|
|
|
|
tuple((r"{}\(\s*[^,]+,\s*" + _msg_re + r"\s*\)").format(it)
|
|
|
|
|
for it in ("node_sock_label",)) +
|
|
|
|
|
|
2023-09-27 19:27:44 +02:00
|
|
|
|
# Node panel declarations
|
|
|
|
|
tuple((r"\.{}\(\s*" + _msg_re + r"\s*\)").format(it)
|
|
|
|
|
for it in ("add_panel",)) +
|
|
|
|
|
|
2023-04-23 16:16:55 +02:00
|
|
|
|
# Geometry Nodes field inputs
|
|
|
|
|
((r"FieldInput\(CPPType::get<.*?>\(\),\s*" + _msg_re + r"\s*\)"),) +
|
|
|
|
|
|
2023-12-19 18:41:09 +01:00
|
|
|
|
# bUnitDef unit names
|
|
|
|
|
((r"/\*name_display\*/\s*" + _msg_re + r"\s*,"),) +
|
2022-04-22 15:37:16 +02:00
|
|
|
|
|
2013-03-28 19:33:14 +00:00
|
|
|
|
tuple((r"{}\(\s*" + _msg_re + r"\s*,\s*(?:" +
|
2024-06-24 18:45:07 +02:00
|
|
|
|
r"\s*,\s*)?(?:".join(_ctxt_re_gen(i) for i in range(PYGETTEXT_MAX_MULTI_CTXT)) + r")?\s*,?\s*\)").format(it)
|
2015-08-25 21:12:36 +02:00
|
|
|
|
for it in ("BLT_I18N_MSGID_MULTI_CTXT",))
|
2012-07-02 19:51:06 +00:00
|
|
|
|
)
|
2012-07-07 14:28:49 +00:00
|
|
|
|
|
2022-04-20 15:39:36 +10:00
|
|
|
|
# autopep8: on
|
|
|
|
|
|
|
|
|
|
|
2013-10-19 14:28:32 +00:00
|
|
|
|
# Check printf mismatches between msgid and msgstr.
|
|
|
|
|
CHECK_PRINTF_FORMAT = (
|
2018-09-03 16:49:08 +02:00
|
|
|
|
r"(?!<%)(?:%%)*%" # Beginning, with handling for crazy things like '%%%%%s'
|
2013-10-19 14:28:32 +00:00
|
|
|
|
r"[-+#0]?" # Flags (note: do not add the ' ' (space) flag here, generates too much false positives!)
|
|
|
|
|
r"(?:\*|[0-9]+)?" # Width
|
|
|
|
|
r"(?:\.(?:\*|[0-9]+))?" # Precision
|
|
|
|
|
r"(?:[hljztL]|hh|ll)?" # Length
|
|
|
|
|
r"[tldiuoxXfFeEgGaAcspn]" # Specifiers (note we have Blender-specific %t and %l ones too)
|
|
|
|
|
)
|
|
|
|
|
|
2012-07-02 19:51:06 +00:00
|
|
|
|
# Should po parser warn when finding a first letter not capitalized?
|
|
|
|
|
WARN_MSGID_NOT_CAPITALIZED = True
|
|
|
|
|
|
|
|
|
|
# Strings that should not raise above warning!
|
|
|
|
|
WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"", # Simplifies things... :p
|
|
|
|
|
"ac3",
|
|
|
|
|
"along X",
|
|
|
|
|
"along Y",
|
|
|
|
|
"along Z",
|
|
|
|
|
"along %s X",
|
|
|
|
|
"along %s Y",
|
|
|
|
|
"along %s Z",
|
|
|
|
|
"along local Z",
|
2020-02-17 13:00:01 +01:00
|
|
|
|
"arccos(A)",
|
|
|
|
|
"arcsin(A)",
|
|
|
|
|
"arctan(A)",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"ascii",
|
|
|
|
|
"author", # Addons' field. :/
|
2012-07-02 19:51:06 +00:00
|
|
|
|
"bItasc",
|
2022-07-11 12:46:01 +02:00
|
|
|
|
"blender.org",
|
2024-01-08 12:03:35 +01:00
|
|
|
|
"bytes",
|
2022-04-22 16:18:43 +02:00
|
|
|
|
"color_index is invalid",
|
2020-02-17 13:00:01 +01:00
|
|
|
|
"cos(A)",
|
|
|
|
|
"cosh(A)",
|
2023-11-20 12:19:33 +01:00
|
|
|
|
"dB", # dB audio power unit.
|
2015-07-14 21:41:24 +02:00
|
|
|
|
"dbl-", # Compacted for 'double', for keymap items.
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"description", # Addons' field. :/
|
|
|
|
|
"dx",
|
|
|
|
|
"fBM",
|
|
|
|
|
"flac",
|
|
|
|
|
"fps: %.2f",
|
|
|
|
|
"fps: %i",
|
|
|
|
|
"gimbal",
|
|
|
|
|
"global",
|
2018-12-24 15:02:20 +01:00
|
|
|
|
"glTF 2.0 (.glb/.gltf)",
|
|
|
|
|
"glTF Binary (.glb)",
|
|
|
|
|
"glTF Embedded (.gltf)",
|
2022-09-12 14:18:17 +02:00
|
|
|
|
"glTF Material Output",
|
2022-07-11 12:46:01 +02:00
|
|
|
|
"glTF Original PBR data",
|
2018-12-24 15:02:20 +01:00
|
|
|
|
"glTF Separate (.gltf + .bin + textures)",
|
2024-01-08 12:03:35 +01:00
|
|
|
|
"gltfpack",
|
|
|
|
|
"glTFpack file path",
|
2018-12-24 15:02:20 +01:00
|
|
|
|
"invoke() needs to be called before execute()",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"iScale",
|
2012-07-02 19:51:06 +00:00
|
|
|
|
"iso-8859-15",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"iTaSC",
|
|
|
|
|
"iTaSC parameters",
|
|
|
|
|
"kb",
|
|
|
|
|
"local",
|
|
|
|
|
"location", # Addons' field. :/
|
|
|
|
|
"locking %s X",
|
|
|
|
|
"locking %s Y",
|
|
|
|
|
"locking %s Z",
|
2012-07-02 19:51:06 +00:00
|
|
|
|
"mkv",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"mm",
|
2012-07-02 19:51:06 +00:00
|
|
|
|
"mp2",
|
|
|
|
|
"mp3",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"normal",
|
2012-07-02 19:51:06 +00:00
|
|
|
|
"ogg",
|
2022-07-11 12:46:01 +02:00
|
|
|
|
"oneAPI",
|
2012-07-02 19:51:06 +00:00
|
|
|
|
"p0",
|
2024-01-08 12:03:35 +01:00
|
|
|
|
"parent_index should not be less than -1: %d",
|
|
|
|
|
"parent_index (%d) should be less than the number of bone collections (%d)",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"px",
|
|
|
|
|
"re",
|
2012-07-02 19:51:06 +00:00
|
|
|
|
"res",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"rv",
|
2024-01-08 12:03:35 +01:00
|
|
|
|
"seconds",
|
2020-02-17 13:00:01 +01:00
|
|
|
|
"sin(A)",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"sin(x) / x",
|
2020-02-17 13:00:01 +01:00
|
|
|
|
"sinh(A)",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"sqrt(x*x+y*y+z*z)",
|
|
|
|
|
"sRGB",
|
2022-07-11 12:46:01 +02:00
|
|
|
|
"sRGB display space",
|
|
|
|
|
"sRGB display space with Filmic view transform",
|
2023-08-28 18:02:03 +02:00
|
|
|
|
"sRGB IEC 61966-2-1 compound (piece-wise) encoding",
|
2020-02-17 13:00:01 +01:00
|
|
|
|
"tan(A)",
|
|
|
|
|
"tanh(A)",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"utf-8",
|
2020-02-17 13:00:01 +01:00
|
|
|
|
"uv_on_emitter() requires a modifier from an evaluated object",
|
2013-03-25 08:30:38 +00:00
|
|
|
|
"var",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"vBVH",
|
|
|
|
|
"view",
|
|
|
|
|
"wav",
|
2018-12-24 15:02:20 +01:00
|
|
|
|
"wmOwnerID '%s' not in workspace '%s'",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"y",
|
2021-02-22 15:48:54 +01:00
|
|
|
|
"y = (Ax + B)",
|
2023-11-20 12:19:33 +01:00
|
|
|
|
# ID plural names, defined in IDTypeInfo.
|
|
|
|
|
"armatures",
|
|
|
|
|
"brushes",
|
|
|
|
|
"cache_files",
|
|
|
|
|
"cameras",
|
|
|
|
|
"collections",
|
|
|
|
|
"curves",
|
|
|
|
|
"fonts",
|
|
|
|
|
"grease_pencils",
|
|
|
|
|
"grease_pencils_v3",
|
|
|
|
|
"hair_curves",
|
|
|
|
|
"ipos",
|
|
|
|
|
"lattices",
|
|
|
|
|
"libraries",
|
|
|
|
|
"lightprobes",
|
|
|
|
|
"lights",
|
|
|
|
|
"linestyles",
|
|
|
|
|
"link_placeholders",
|
|
|
|
|
"masks",
|
|
|
|
|
"metaballs",
|
|
|
|
|
"materials",
|
|
|
|
|
"meshes",
|
|
|
|
|
"movieclips",
|
|
|
|
|
"node_groups",
|
|
|
|
|
"objects",
|
|
|
|
|
"paint_curves",
|
|
|
|
|
"palettes",
|
|
|
|
|
"particles",
|
|
|
|
|
"pointclouds",
|
|
|
|
|
"screens",
|
|
|
|
|
"shape_keys",
|
|
|
|
|
"sounds",
|
|
|
|
|
"speakers",
|
|
|
|
|
"texts",
|
|
|
|
|
"textures",
|
|
|
|
|
"volumes",
|
|
|
|
|
"window_managers",
|
|
|
|
|
"workspaces",
|
|
|
|
|
"worlds",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
# Sub-strings.
|
2022-03-28 10:40:14 +02:00
|
|
|
|
"all",
|
|
|
|
|
"all and invert unselected",
|
2023-02-27 16:18:38 +01:00
|
|
|
|
"and AMD driver version %s or newer",
|
|
|
|
|
"and AMD Radeon Pro %s driver or newer",
|
|
|
|
|
"and NVIDIA driver version %s or newer",
|
|
|
|
|
"and Windows driver version %s or newer",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"available with",
|
2015-04-13 21:00:06 +02:00
|
|
|
|
"brown fox",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"can't save image while rendering",
|
2022-09-12 14:18:17 +02:00
|
|
|
|
"category",
|
2016-07-19 15:41:28 +02:00
|
|
|
|
"constructive modifier",
|
2018-12-24 12:31:39 +01:00
|
|
|
|
"cursor",
|
2018-12-24 15:02:20 +01:00
|
|
|
|
"custom",
|
2018-12-24 12:31:39 +01:00
|
|
|
|
"custom matrix",
|
|
|
|
|
"custom orientation",
|
2023-02-27 16:18:38 +01:00
|
|
|
|
"drag-",
|
2016-07-19 15:41:28 +02:00
|
|
|
|
"edge data",
|
2020-02-17 13:00:01 +01:00
|
|
|
|
"exp(A)",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"expected a timeline/animation area to be active",
|
|
|
|
|
"expected a view3d region",
|
|
|
|
|
"expected a view3d region & editcurve",
|
|
|
|
|
"expected a view3d region & editmesh",
|
2016-07-19 15:41:28 +02:00
|
|
|
|
"face data",
|
2018-12-24 12:31:39 +01:00
|
|
|
|
"gimbal",
|
|
|
|
|
"global",
|
2022-03-28 10:40:14 +02:00
|
|
|
|
"glTF Settings",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"image file not found",
|
2015-08-25 21:12:36 +02:00
|
|
|
|
"image format is read-only",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"image path can't be written to",
|
2023-04-17 11:40:14 +02:00
|
|
|
|
"in %i days",
|
|
|
|
|
"in %i hours",
|
|
|
|
|
"in %i minutes",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"in memory to enable editing!",
|
2023-08-28 18:02:03 +02:00
|
|
|
|
"in the asset shelf.",
|
2020-02-17 13:00:01 +01:00
|
|
|
|
"insufficient content",
|
2022-02-07 10:59:24 +01:00
|
|
|
|
"into",
|
2015-04-13 21:00:06 +02:00
|
|
|
|
"jumps over",
|
2016-02-02 20:40:23 +01:00
|
|
|
|
"left",
|
2018-12-24 12:31:39 +01:00
|
|
|
|
"local",
|
2022-08-01 14:36:06 +02:00
|
|
|
|
"matrices", "no matrices",
|
2016-07-19 15:41:28 +02:00
|
|
|
|
"multi-res modifier",
|
2022-09-12 14:18:17 +02:00
|
|
|
|
"name",
|
2016-07-19 15:41:28 +02:00
|
|
|
|
"non-triangle face",
|
2018-12-24 12:31:39 +01:00
|
|
|
|
"normal",
|
2023-04-17 11:40:14 +02:00
|
|
|
|
"on {:%Y-%m-%d}",
|
2023-02-27 16:18:38 +01:00
|
|
|
|
"or AMD with macOS %s or newer",
|
2023-07-10 14:17:06 +02:00
|
|
|
|
"parent",
|
2020-09-21 15:17:41 +02:00
|
|
|
|
"performance impact!",
|
2022-08-01 14:36:06 +02:00
|
|
|
|
"positions", "no positions",
|
2022-04-22 16:18:43 +02:00
|
|
|
|
"read",
|
|
|
|
|
"remove",
|
2016-02-02 20:40:23 +01:00
|
|
|
|
"right",
|
2022-03-28 10:40:14 +02:00
|
|
|
|
"selected",
|
|
|
|
|
"selected and lock unselected",
|
|
|
|
|
"selected and unlock unselected",
|
2023-01-09 09:20:17 +01:00
|
|
|
|
"screen",
|
2015-04-13 21:00:06 +02:00
|
|
|
|
"the lazy dog",
|
2022-04-22 16:18:43 +02:00
|
|
|
|
"this legacy pose library to pose assets",
|
2022-02-07 10:59:24 +01:00
|
|
|
|
"to the top level of the tree",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"unable to load movie clip",
|
|
|
|
|
"unable to load text",
|
|
|
|
|
"unable to open the file",
|
|
|
|
|
"unknown error reading file",
|
2023-07-10 14:17:06 +02:00
|
|
|
|
"unknown error statting file",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"unknown error writing file",
|
2022-03-28 10:40:14 +02:00
|
|
|
|
"unselected",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"unsupported font format",
|
|
|
|
|
"unsupported format",
|
|
|
|
|
"unsupported image format",
|
|
|
|
|
"unsupported movie clip format",
|
2022-09-12 14:18:17 +02:00
|
|
|
|
"untitled",
|
2016-07-19 15:41:28 +02:00
|
|
|
|
"vertex data",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"verts only",
|
2018-12-24 12:31:39 +01:00
|
|
|
|
"view",
|
2013-02-28 15:31:20 +00:00
|
|
|
|
"virtual parents",
|
2022-04-22 16:18:43 +02:00
|
|
|
|
"which was replaced by the Asset Browser",
|
2023-04-17 11:40:14 +02:00
|
|
|
|
"within seconds",
|
2022-04-22 16:18:43 +02:00
|
|
|
|
"write",
|
2012-07-02 19:51:06 +00:00
|
|
|
|
}
|
2012-10-22 14:17:30 +00:00
|
|
|
|
WARN_MSGID_NOT_CAPITALIZED_ALLOWED |= set(lng[2] for lng in LANGUAGES)
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
WARN_MSGID_END_POINT_ALLOWED = {
|
2024-03-04 11:17:55 +01:00
|
|
|
|
"Cannot figure out which object this bone belongs to.",
|
2013-02-24 08:50:55 +00:00
|
|
|
|
"Circle|Alt .",
|
|
|
|
|
"Float Neg. Exp.",
|
2013-04-19 16:23:02 +00:00
|
|
|
|
"Max Ext.",
|
2020-02-17 13:00:01 +01:00
|
|
|
|
"Newer graphics drivers may be available to improve Blender support.",
|
2023-11-20 12:19:33 +01:00
|
|
|
|
"Not assigned to any bone collection.",
|
2015-07-14 21:41:24 +02:00
|
|
|
|
"Numpad .",
|
|
|
|
|
"Pad.",
|
2024-03-04 11:17:55 +01:00
|
|
|
|
"Please file a bug report.",
|
2015-07-14 21:41:24 +02:00
|
|
|
|
" RNA Path: bpy.types.",
|
|
|
|
|
"Temp. Diff.",
|
2018-12-24 15:02:20 +01:00
|
|
|
|
"Temperature Diff.",
|
2020-02-17 13:00:01 +01:00
|
|
|
|
"The program will now close.",
|
|
|
|
|
"Your graphics card or driver has limited support. It may work, but with issues.",
|
|
|
|
|
"Your graphics card or driver is not supported.",
|
2022-07-11 12:46:01 +02:00
|
|
|
|
"Invalid surface UVs on %d curves.",
|
2023-08-28 18:02:03 +02:00
|
|
|
|
"The pose library moved.",
|
|
|
|
|
"in the asset shelf.",
|
2024-02-12 12:01:02 +01:00
|
|
|
|
"Remove, local files not found.",
|
|
|
|
|
"Remove all files in \"{}\".",
|
|
|
|
|
"Remove, keeping local files.",
|
2013-02-24 08:50:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-12 16:49:06 +00:00
|
|
|
|
PARSER_CACHE_HASH = 'sha1'
|
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
PARSER_TEMPLATE_ID = "__POT__"
|
|
|
|
|
PARSER_PY_ID = "__PY__"
|
|
|
|
|
|
|
|
|
|
PARSER_PY_MARKER_BEGIN = "\n# ##### BEGIN AUTOGENERATED I18N SECTION #####\n"
|
|
|
|
|
PARSER_PY_MARKER_END = "\n# ##### END AUTOGENERATED I18N SECTION #####\n"
|
|
|
|
|
|
2013-03-28 19:33:14 +00:00
|
|
|
|
PARSER_MAX_FILE_SIZE = 2 ** 24 # in bytes, i.e. 16 Mb.
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
# PATHS
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
# The Python3 executable.You’ll likely have to edit it in your user_settings.py
|
|
|
|
|
# if you’re under Windows.
|
|
|
|
|
PYTHON3_EXEC = "python3"
|
|
|
|
|
|
|
|
|
|
# The Blender executable!
|
2013-02-24 08:50:55 +00:00
|
|
|
|
# This is just an example, you’ll have to edit it in your user_settings.py!
|
|
|
|
|
BLENDER_EXEC = os.path.abspath(os.path.join("foo", "bar", "blender"))
|
2013-02-10 07:11:32 +00:00
|
|
|
|
# check for blender.bin
|
|
|
|
|
if not os.path.exists(BLENDER_EXEC):
|
|
|
|
|
if os.path.exists(BLENDER_EXEC + ".bin"):
|
|
|
|
|
BLENDER_EXEC = BLENDER_EXEC + ".bin"
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2012-10-27 11:12:09 +00:00
|
|
|
|
# The gettext msgfmt "compiler". You’ll likely have to edit it in your user_settings.py if you’re under Windows.
|
2012-07-02 19:51:06 +00:00
|
|
|
|
GETTEXT_MSGFMT_EXECUTABLE = "msgfmt"
|
|
|
|
|
|
2023-09-03 21:35:03 +10:00
|
|
|
|
# The FriBidi C compiled library (.so under Linux, `.dll` under windows...).
|
|
|
|
|
# You’ll likely have to edit it in your `user_settings.py` if you’re under Windows., e.g. using the included one:
|
|
|
|
|
# `FRIBIDI_LIB = os.path.join(TOOLS_DIR, "libfribidi.dll")`
|
2012-07-02 19:51:06 +00:00
|
|
|
|
FRIBIDI_LIB = "libfribidi.so.0"
|
|
|
|
|
|
2023-09-03 21:35:03 +10:00
|
|
|
|
# The name of the (currently empty) file that must be present in a po's directory to enable RTL-preprocess.
|
2012-07-02 19:51:06 +00:00
|
|
|
|
RTL_PREPROCESS_FILE = "is_rtl"
|
|
|
|
|
|
|
|
|
|
# The Blender source root path.
|
2013-02-24 08:50:55 +00:00
|
|
|
|
# This is just an example, you’ll have to override it in your user_settings.py!
|
|
|
|
|
SOURCE_DIR = os.path.abspath(os.path.join("blender"))
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
# The bf-translation repository (you'll have to override this in your user_settings.py).
|
|
|
|
|
I18N_DIR = os.path.abspath(os.path.join("i18n"))
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2023-09-15 16:50:25 +02:00
|
|
|
|
# The 'work' path to PO files (relative to I18N_DIR).
|
|
|
|
|
REL_WORK_DIR = os.path.join("")
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
|
|
|
|
|
2023-09-15 16:50:25 +02:00
|
|
|
|
# The path to the Blender translation directory (relative to SOURCE_DIR).
|
|
|
|
|
REL_BLENDER_I18N_DIR = os.path.join("locale")
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2023-09-15 16:50:25 +02:00
|
|
|
|
# The /po path of the Blender translation directory (relative to REL_BLENDER_I18N_DIR).
|
|
|
|
|
REL_BLENDER_I18N_PO_DIR = os.path.join("po")
|
2015-06-13 11:42:54 +02:00
|
|
|
|
|
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
# The Blender source path to check for i18n macros (relative to SOURCE_DIR).
|
|
|
|
|
REL_POTFILES_SOURCE_DIR = os.path.join("source")
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2022-08-01 14:09:41 +02:00
|
|
|
|
# Where to search for preset names (relative to SOURCE_DIR).
|
2023-02-22 09:59:38 +01:00
|
|
|
|
REL_PRESETS_DIR = os.path.join("scripts", "presets")
|
2022-08-01 14:09:41 +02:00
|
|
|
|
|
2022-08-23 11:43:39 +02:00
|
|
|
|
# Where to search for templates (relative to SOURCE_DIR).
|
2023-02-22 09:59:38 +01:00
|
|
|
|
REL_TEMPLATES_DIR = os.path.join("scripts", "startup", "bl_app_templates_system")
|
2022-08-23 11:43:39 +02:00
|
|
|
|
|
2023-03-13 22:41:11 +01:00
|
|
|
|
# Name of the built-in asset catalog file.
|
|
|
|
|
ASSET_CATALOG_FILE = "blender_assets.cats.txt"
|
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
# The template messages file (relative to I18N_DIR).
|
2023-09-15 16:50:25 +02:00
|
|
|
|
REL_FILE_NAME_POT = os.path.join(REL_WORK_DIR, DOMAIN + ".pot")
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
|
|
|
|
|
2024-05-28 13:42:16 +10:00
|
|
|
|
# Mo path generator for a given language (relative to any "locale" directory).
|
2013-02-24 08:50:55 +00:00
|
|
|
|
MO_PATH_ROOT_RELATIVE = os.path.join("locale")
|
|
|
|
|
MO_PATH_TEMPLATE_RELATIVE = os.path.join(MO_PATH_ROOT_RELATIVE, "{}", "LC_MESSAGES")
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
# Mo file name.
|
|
|
|
|
MO_FILE_NAME = DOMAIN + ".mo"
|
|
|
|
|
|
2013-02-27 16:24:20 +00:00
|
|
|
|
# Where to search for py files that may contain ui strings (relative to one of the 'resource_path' of Blender).
|
|
|
|
|
CUSTOM_PY_UI_FILES = [
|
|
|
|
|
os.path.join("scripts", "startup", "bl_ui"),
|
2020-12-21 11:35:02 +01:00
|
|
|
|
os.path.join("scripts", "startup", "bl_operators"),
|
2013-02-27 16:24:20 +00:00
|
|
|
|
os.path.join("scripts", "modules", "rna_prop_ui.py"),
|
2022-11-15 11:02:22 +01:00
|
|
|
|
os.path.join("scripts", "modules", "rna_keymap_ui.py"),
|
2022-11-16 12:27:20 +01:00
|
|
|
|
os.path.join("scripts", "modules", "bpy_types.py"),
|
2022-09-05 15:36:56 +02:00
|
|
|
|
os.path.join("scripts", "presets", "keyconfig"),
|
2013-02-15 18:19:20 +00:00
|
|
|
|
]
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
# An optional text file listing files to force include/exclude from py_xgettext process.
|
|
|
|
|
SRC_POTFILES = ""
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
|
|
|
|
# A cache storing validated msgids, to avoid re-spellchecking them.
|
|
|
|
|
SPELL_CACHE = os.path.join("/tmp", ".spell_cache")
|
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
# Threshold defining whether a new msgid is similar enough with an old one to reuse its translation...
|
|
|
|
|
SIMILAR_MSGID_THRESHOLD = 0.75
|
|
|
|
|
|
2024-05-28 13:42:16 +10:00
|
|
|
|
# Additional import paths to add to `sys.path` (';' separated)...
|
2013-02-24 08:50:55 +00:00
|
|
|
|
INTERN_PY_SYS_PATHS = ""
|
2012-07-02 19:51:06 +00:00
|
|
|
|
|
2024-05-28 13:42:16 +10:00
|
|
|
|
# Custom override settings must be one directory above i18n tools itself!
|
2012-07-02 19:51:06 +00:00
|
|
|
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
|
|
|
|
try:
|
2013-03-19 08:33:24 +00:00
|
|
|
|
from bl_i18n_settings_override import *
|
2012-07-02 19:51:06 +00:00
|
|
|
|
except ImportError: # If no i18n_override_settings available, it’s no error!
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# Override with custom user settings, if available.
|
|
|
|
|
try:
|
2013-03-19 08:33:24 +00:00
|
|
|
|
from settings_user import *
|
2012-07-02 19:51:06 +00:00
|
|
|
|
except ImportError: # If no user_settings available, it’s no error!
|
|
|
|
|
pass
|
2013-02-24 08:50:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for p in set(INTERN_PY_SYS_PATHS.split(";")):
|
|
|
|
|
if p:
|
|
|
|
|
sys.path.append(p)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# The settings class itself!
|
|
|
|
|
def _do_get(ref, path):
|
|
|
|
|
return os.path.normpath(os.path.join(ref, path))
|
|
|
|
|
|
2015-01-29 15:35:06 +11:00
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
def _do_set(ref, path):
|
|
|
|
|
path = os.path.normpath(path)
|
|
|
|
|
# If given path is absolute, make it relative to current ref one (else we consider it is already the case!)
|
|
|
|
|
if os.path.isabs(path):
|
2013-08-18 15:17:33 +00:00
|
|
|
|
# can't always find the relative path (between drive letters on windows)
|
|
|
|
|
try:
|
|
|
|
|
return os.path.relpath(path, ref)
|
|
|
|
|
except ValueError:
|
|
|
|
|
pass
|
|
|
|
|
return path
|
2013-02-24 08:50:55 +00:00
|
|
|
|
|
2015-01-29 15:35:06 +11:00
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
def _gen_get_set_path(ref, name):
|
|
|
|
|
def _get(self):
|
|
|
|
|
return _do_get(getattr(self, ref), getattr(self, name))
|
2018-09-21 08:15:46 +10:00
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
def _set(self, value):
|
|
|
|
|
setattr(self, name, _do_set(getattr(self, ref), value))
|
|
|
|
|
return _get, _set
|
|
|
|
|
|
2015-01-29 15:35:06 +11:00
|
|
|
|
|
2020-05-05 18:04:22 +02:00
|
|
|
|
def _check_valid_data(uid, val):
|
|
|
|
|
return not uid.startswith("_") and type(val) not in tuple(types.__dict__.values()) + (type,)
|
|
|
|
|
|
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
class I18nSettings:
|
|
|
|
|
"""
|
|
|
|
|
Class allowing persistence of our settings!
|
|
|
|
|
Saved in JSon format, so settings should be JSon'able objects!
|
|
|
|
|
"""
|
|
|
|
|
_settings = None
|
|
|
|
|
|
|
|
|
|
def __new__(cls, *args, **kwargs):
|
|
|
|
|
# Addon preferences are singleton by definition, so is this class!
|
|
|
|
|
if not I18nSettings._settings:
|
|
|
|
|
cls._settings = super(I18nSettings, cls).__new__(cls)
|
2020-05-05 18:04:22 +02:00
|
|
|
|
cls._settings.__dict__ = {uid: val for uid, val in globals().items() if _check_valid_data(uid, val)}
|
2013-02-24 08:50:55 +00:00
|
|
|
|
return I18nSettings._settings
|
|
|
|
|
|
2020-05-05 18:04:22 +02:00
|
|
|
|
def __getstate__(self):
|
|
|
|
|
return self.to_dict()
|
|
|
|
|
|
|
|
|
|
def __setstate__(self, mapping):
|
|
|
|
|
return self.from_dict(mapping)
|
|
|
|
|
|
|
|
|
|
def from_dict(self, mapping):
|
2013-02-24 08:50:55 +00:00
|
|
|
|
# Special case... :/
|
2020-05-05 18:04:22 +02:00
|
|
|
|
if "INTERN_PY_SYS_PATHS" in mapping:
|
|
|
|
|
self.PY_SYS_PATHS = mapping["INTERN_PY_SYS_PATHS"]
|
|
|
|
|
self.__dict__.update(mapping)
|
|
|
|
|
|
|
|
|
|
def to_dict(self):
|
|
|
|
|
glob = globals()
|
|
|
|
|
return {uid: val for uid, val in self.__dict__.items() if _check_valid_data(uid, val) and uid in glob}
|
|
|
|
|
|
|
|
|
|
def from_json(self, string):
|
|
|
|
|
self.from_dict(dict(json.loads(string)))
|
2013-02-24 08:50:55 +00:00
|
|
|
|
|
|
|
|
|
def to_json(self):
|
|
|
|
|
# Only save the diff from default i18n_settings!
|
|
|
|
|
glob = globals()
|
2022-04-20 15:55:17 +10:00
|
|
|
|
export_dict = {
|
|
|
|
|
uid: val for uid, val in self.__dict__.items()
|
|
|
|
|
if _check_valid_data(uid, val) and glob.get(uid) != val
|
|
|
|
|
}
|
2013-02-24 08:50:55 +00:00
|
|
|
|
return json.dumps(export_dict)
|
|
|
|
|
|
|
|
|
|
def load(self, fname, reset=False):
|
2020-07-13 12:46:29 +02:00
|
|
|
|
reset = reset or fname is None
|
2013-02-24 08:50:55 +00:00
|
|
|
|
if reset:
|
|
|
|
|
self.__dict__ = {uid: data for uid, data in globals().items() if not uid.startswith("_")}
|
2020-07-13 12:46:29 +02:00
|
|
|
|
if fname is None:
|
|
|
|
|
return
|
2013-02-24 08:50:55 +00:00
|
|
|
|
if isinstance(fname, str):
|
|
|
|
|
if not os.path.isfile(fname):
|
2018-12-23 22:03:12 +01:00
|
|
|
|
# Assume it is already real JSon string...
|
|
|
|
|
self.from_json(fname)
|
2013-02-24 08:50:55 +00:00
|
|
|
|
return
|
2020-03-20 20:49:48 +01:00
|
|
|
|
with open(fname, encoding="utf8") as f:
|
2013-02-24 08:50:55 +00:00
|
|
|
|
self.from_json(f.read())
|
|
|
|
|
# Else assume fname is already a file(like) object!
|
|
|
|
|
else:
|
|
|
|
|
self.from_json(fname.read())
|
|
|
|
|
|
|
|
|
|
def save(self, fname):
|
|
|
|
|
if isinstance(fname, str):
|
2020-03-20 20:49:48 +01:00
|
|
|
|
with open(fname, 'w', encoding="utf8") as f:
|
2013-02-24 08:50:55 +00:00
|
|
|
|
f.write(self.to_json())
|
|
|
|
|
# Else assume fname is already a file(like) object!
|
|
|
|
|
else:
|
|
|
|
|
fname.write(self.to_json())
|
|
|
|
|
|
2023-09-15 16:50:25 +02:00
|
|
|
|
WORK_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_WORK_DIR")))
|
|
|
|
|
BLENDER_I18N_ROOT = property(*(_gen_get_set_path("SOURCE_DIR", "REL_BLENDER_I18N_DIR")))
|
|
|
|
|
BLENDER_I18N_PO_DIR = property(*(_gen_get_set_path("BLENDER_I18N_ROOT", "REL_BLENDER_I18N_PO_DIR")))
|
2013-02-24 08:50:55 +00:00
|
|
|
|
POTFILES_SOURCE_DIR = property(*(_gen_get_set_path("SOURCE_DIR", "REL_POTFILES_SOURCE_DIR")))
|
2022-08-01 14:09:41 +02:00
|
|
|
|
PRESETS_DIR = property(*(_gen_get_set_path("SOURCE_DIR", "REL_PRESETS_DIR")))
|
2022-08-23 11:43:39 +02:00
|
|
|
|
TEMPLATES_DIR = property(*(_gen_get_set_path("SOURCE_DIR", "REL_TEMPLATES_DIR")))
|
2013-02-24 08:50:55 +00:00
|
|
|
|
FILE_NAME_POT = property(*(_gen_get_set_path("I18N_DIR", "REL_FILE_NAME_POT")))
|
|
|
|
|
|
|
|
|
|
def _get_py_sys_paths(self):
|
|
|
|
|
return self.INTERN_PY_SYS_PATHS
|
2018-09-21 08:15:46 +10:00
|
|
|
|
|
2013-02-24 08:50:55 +00:00
|
|
|
|
def _set_py_sys_paths(self, val):
|
|
|
|
|
old_paths = set(self.INTERN_PY_SYS_PATHS.split(";")) - {""}
|
|
|
|
|
new_paths = set(val.split(";")) - {""}
|
|
|
|
|
for p in old_paths - new_paths:
|
|
|
|
|
if p in sys.path:
|
|
|
|
|
sys.path.remove(p)
|
|
|
|
|
for p in new_paths - old_paths:
|
|
|
|
|
sys.path.append(p)
|
|
|
|
|
self.INTERN_PY_SYS_PATHS = val
|
|
|
|
|
PY_SYS_PATHS = property(_get_py_sys_paths, _set_py_sys_paths)
|