Merge branch 'blender-v4.5-release'

This commit is contained in:
Bastien Montagne
2025-06-11 13:12:48 +02:00
5 changed files with 93 additions and 105 deletions

View File

@@ -1128,9 +1128,6 @@ def dump_messages(do_messages, do_checks, settings):
for lng in settings.LANGUAGES:
process_msg(msgs, settings.DEFAULT_CONTEXT, lng[1], "Languages labels from bl_i18n_utils/settings.py",
reports, None, settings)
for cat in settings.LANGUAGES_CATEGORIES:
process_msg(msgs, settings.DEFAULT_CONTEXT, cat[1],
"Language categories labels from bl_i18n_utils/settings.py", reports, None, settings)
# Get strings from asset catalogs and blend files.
# This loads each asset blend file in turn.

View File

@@ -25,76 +25,70 @@ except ModuleNotFoundError:
###############################################################################
# The languages defined in Blender.
LANGUAGES_CATEGORIES = (
# Min completeness level, UI English label.
(0.95, "Complete"),
(0.33, "In Progress"),
(-1.0, "Starting"),
)
LANGUAGES = (
# ID, UI English label, ISO code.
(0, "Automatic (Automatic)", "DEFAULT"),
(1, "American English (American English)", "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 (Português)", "pt_PT"),
(13, "Simplified Chinese (简体中文)", "zh_HANS"),
(14, "Traditional Chinese (繁體中文)", "zh_HANT"),
(15, "Russian (Русский)", "ru_RU"),
(16, "Croatian (Hrvatski)", "hr_HR"),
(17, "Serbian (Српски)", "sr_RS"),
(18, "Ukrainian (Українська)", "uk_UA"),
(19, "Polish (Polski)", "pl_PL"),
(20, "Romanian (Român)", "ro_RO"),
(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"),
# Using the utf8 flipped form of Arabic (العربية).
(21, "Arabic (ﺔﻴﺑﺮﻌﻟﺍ)", "ar_EG"),
(22, "Bulgarian (Български)", "bg_BG"),
(23, "Greek (Ελληνικά)", "el_GR"),
(24, "Korean (한국어)", "ko_KR"),
(25, "Nepali (नेपाली)", "ne_NP"),
(21, "Arabic - ﺔﻴﺑﺮﻌﻟﺍ", "ar_EG"),
(22, "Bulgarian - Български", "bg_BG"),
(23, "Greek - Ελληνικά", "el_GR"),
(24, "Korean - 한국어", "ko_KR"),
(25, "Nepali - नेपाली", "ne_NP"),
# Using the utf8 flipped form of Persian (فارسی).
(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, "Brazilian Portuguese (Português do Brasil)", "pt_BR"),
(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"),
# Using the utf8 flipped form of Hebrew (עִבְרִית)).
(33, "Hebrew (תירִבְעִ)", "he_IL"),
(34, "Estonian (Eesti keel)", "et_EE"),
(35, "Esperanto (Esperanto)", "eo"),
(33, "Hebrew - תירִבְעִ", "he_IL"),
(34, "Estonian - Eesti keel", "et_EE"),
(35, "Esperanto - Esperanto", "eo"),
# 36 is free, used to be 'Spanish from Spain' (`es_ES`).
(37, "Amharic (አማርኛ)", "am_ET"),
(38, "Uzbek (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"),
(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"),
# Using the utf8 flipped form of Urdu (اُردُو).
(55, "Urdu (وُدرُا)", "ur"),
(56, "Lithuanian (Lietuviškai)", "lt"),
(57, "British English (British English)", "en_GB"),
(55, "Urdu - وُدرُا", "ur"),
(56, "Lithuanian - Lietuviškai", "lt"),
(57, "English (UK)", "en_GB"),
)
# Default context, in py (keep in sync with `BLT_translation.hh`)!

View File

@@ -31,23 +31,22 @@ def gen_menu_file(stats, settings):
else:
tmp.append((0.0, uid_num, label, uid, MISSING))
stats = tmp
limits = sorted(settings.LANGUAGES_CATEGORIES, key=lambda it: it[0], reverse=True)
idx = 0
stats = sorted(stats, key=lambda it: it[0], reverse=True)
langs_cats = [[] for i in range(len(limits))]
langs = []
highest_uid = 0
for lvl, uid_num, label, uid, flag in stats:
if lvl < limits[idx][0]:
# Sub-sort languages by ISO-codes.
langs_cats[idx].sort(key=lambda it: it[2])
idx += 1
if lvl < settings.IMPORT_MIN_LEVEL and flag == OK:
flag = TOOLOW
langs_cats[idx].append((uid_num, label, uid, flag))
if uid_num == 0:
# Insert default language (Automatic) at index 0, after sorting.
default_lang = (uid_num, label, uid, flag, lvl)
continue
langs.append((uid_num, label, uid, flag, lvl))
if abs(uid_num) > highest_uid:
highest_uid = abs(uid_num)
# Sub-sort last group of languages by ISO-codes!
langs_cats[idx].sort(key=lambda it: it[2])
# Sort languages by name.
langs.sort(key=lambda it: it[1])
langs.insert(0, default_lang)
data_lines = [
"# File used by Blender to know which languages (translations) are available, ",
"# and to generate translation menu.",
@@ -57,22 +56,13 @@ def gen_menu_file(stats, settings):
"# ID must be unique, except for 0 value (marks categories for menu).",
"# Line starting with a # are comments!",
"#",
"# Automatically generated by bl_i18n_utils/update_languages_menu.py script.",
"# Automatically generated by bl_i18n_utils/utils_languages_menu.py script.",
"# Highest ID currently in use: {}".format(highest_uid),
]
for cat, langs_cat in zip(limits, langs_cats):
data_lines.append("#")
# Write "category menu label"...
if langs_cat:
data_lines.append("0:{}:".format(cat[1]))
for uid_num, label, uid, flag, lvl in langs:
if flag == OK:
data_lines.append("{}:{}:{}:{}%".format(uid_num, label, uid, round(lvl * 100)))
else:
# Do not write the category if it has no language!
data_lines.append("# Void category! #0:{}:".format(cat[1]))
# ...and all matching language entries!
for uid_num, label, uid, flag in langs_cat:
if flag == OK:
data_lines.append("{}:{}:{}".format(uid_num, label, uid))
else:
# Non-existing, commented entry!
data_lines.append("# {} #{}:{}:{}".format(FLAG_MESSAGES[flag], uid_num, label, uid))
# Non-existing, commented entry!
data_lines.append("# {} #{}:{}:{}:{}%".format(FLAG_MESSAGES[flag], uid_num, label, uid, round(lvl * 100)))
return data_lines

View File

@@ -50,18 +50,18 @@ static int num_locales_menu = 0;
static void free_locales()
{
if (locales) {
if (locales_menu) {
int idx = num_locales_menu - 1; /* Last item does not need to be freed! */
while (idx--) {
MEM_freeN(locales_menu[idx].identifier);
MEM_freeN(locales_menu[idx].identifier); /* Also frees locales's relevant value! */
MEM_freeN(locales_menu[idx].name);
MEM_freeN(locales_menu[idx].description); /* Also frees locales's relevant value! */
MEM_freeN(locales_menu[idx].description);
}
MEM_freeN(locales);
locales = nullptr;
}
MEM_SAFE_FREE(locales_menu);
/* Allocated strings in #locales are shared with #locales_menu[idx].identifier, which are already
* freed above, or are static strings. */
MEM_SAFE_FREE(locales);
num_locales = num_locales_menu = 0;
}
@@ -110,7 +110,7 @@ static void fill_locales()
if (num_locales > 0) {
locales = MEM_calloc_arrayN<const char *>(num_locales, __func__);
while (line) {
const char *loc, *sep1, *sep2, *sep3;
const char *loc, *desc, *sep1, *sep2, *sep3;
char *str = (char *)line->link;
if (ELEM(str[0], '#', '\0')) {
@@ -133,14 +133,19 @@ static void fill_locales()
if (sep3) {
locales_menu[idx].identifier = loc = BLI_strdupn(sep2, sep3 - sep2);
sep3++;
desc = BLI_sprintfN("Locale code: %s. Translation progress: %s", loc, sep3);
}
else {
locales_menu[idx].identifier = loc = BLI_strdup(sep2);
desc = BLI_strdup(sep2);
}
if (id == 0) {
/* The DEFAULT/Automatic item... */
if (BLI_strnlen(loc, 2)) {
MEM_freeN(desc); /* Not used here. */
locales[id] = "";
/* Keep this tip in sync with the one in rna_userdef
* (rna_enum_language_default_items). */
@@ -148,13 +153,15 @@ static void fill_locales()
"Automatically choose system's defined language "
"if available, or fall-back to English");
}
/* Menu "label", not to be stored in locales! */
/* Menu "label", not to be stored in locales!
* NOTE: Not used since Blender 4.5. */
else {
locales_menu[idx].description = BLI_strdup("");
locales_menu[idx].description = desc;
}
}
else {
locales[id] = locales_menu[idx].description = BLI_strdup(loc);
locales[id] = loc;
locales_menu[idx].description = desc;
}
idx++;
}

View File

@@ -253,9 +253,9 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
Vector<TreeElement *> *parent_ob_tree_elements = object_tree_elements_map_.lookup_ptr(
ob->parent);
Vector<TreeElement *> &child_ob_tree_elements = *object_tree_elements_map_.lookup_ptr(ob);
Vector<TreeElement *> *child_ob_tree_elements = object_tree_elements_map_.lookup_ptr(ob);
if (parent_ob_tree_elements == nullptr) {
if (!parent_ob_tree_elements || !child_ob_tree_elements) {
continue;
}
@@ -273,7 +273,7 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
parent_ob_collection_tree_element = parent_ob_collection_tree_element->parent;
}
for (TreeElement *child_ob_tree_element : child_ob_tree_elements) {
for (TreeElement *child_ob_tree_element : *child_ob_tree_elements) {
if (child_ob_tree_element->parent == parent_ob_collection_tree_element) {
/* Move from the collection subtree into the parent object subtree. */
BLI_remlink(&parent_ob_collection_tree_element->subtree, child_ob_tree_element);
@@ -297,7 +297,7 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
0,
false);
child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION;
child_ob_tree_elements.append(child_ob_tree_element);
child_ob_tree_elements->append(child_ob_tree_element);
}
}
}