From 8bb6f8062f1bdb082ba203f47d88b8d7c7db9a81 Mon Sep 17 00:00:00 2001 From: David Murmann Date: Wed, 11 Jun 2025 09:19:57 +0200 Subject: [PATCH 1/3] Fix #110701: ffmpeg: Output settings lost when switching the output format When switching render output between different formats (e.g. ffmpeg video and png images), the previously used ffmpeg settings were lost if audio codec was set to "No Audio" (which is the default). Pull Request: https://projects.blender.org/blender/blender/pulls/139878 --- source/blender/imbuf/movie/intern/movie_util.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/imbuf/movie/intern/movie_util.cc b/source/blender/imbuf/movie/intern/movie_util.cc index da8610eda31..21fbce617ba 100644 --- a/source/blender/imbuf/movie/intern/movie_util.cc +++ b/source/blender/imbuf/movie/intern/movie_util.cc @@ -461,7 +461,7 @@ void MOV_validate_output_settings(RenderData *rd, const ImageFormatData *imf) if (imf->imtype == R_IMF_IMTYPE_FFMPEG) { if (rd->ffcodecdata.type <= 0 || rd->ffcodecdata.codec <= 0 || - rd->ffcodecdata.audio_codec <= 0 || rd->ffcodecdata.video_bitrate <= 1) + rd->ffcodecdata.audio_codec < 0 || rd->ffcodecdata.video_bitrate <= 1) { ffmpeg_preset_set(rd, FFMPEG_PRESET_H264); rd->ffcodecdata.constant_rate_factor = FFM_CRF_MEDIUM; From 39a138aa928c28e78231a95fda554c9f12261b86 Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Wed, 11 Jun 2025 11:38:53 +0200 Subject: [PATCH 2/3] Fix #139887: Outliner crash after excluding collection Caused by 6fe4496f4c This is due to missing null check Pull Request: https://projects.blender.org/blender/blender/pulls/140024 --- .../space_outliner/tree/tree_display_view_layer.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc index d376cde0782..685332c651e 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc @@ -253,9 +253,9 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections() Vector *parent_ob_tree_elements = object_tree_elements_map_.lookup_ptr( ob->parent); - Vector &child_ob_tree_elements = *object_tree_elements_map_.lookup_ptr(ob); + Vector *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); } } } From 798f85a7108fc5206620716180f9622608436299 Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Wed, 11 Jun 2025 13:11:40 +0200 Subject: [PATCH 3/3] Fix #139838: UI: Improve languages list and labels Edit the language list to make it simpler to scan. - Display languages in a form "Language (Variant)", such as "English (US)" instead of "American English" and "Portuguese (Brazil)" instead of "Brazilian Portuguese". This allows alphabetical sorting by language first. This does not apply to endonyms (languages in their own language). - Use a dash instead of parentheses to separate the endonyms. - Deduplicate languages (Automatic, American English, British English), which all are in English and don't appear in another language. - Remove language categories as headers. They are replaced with percentages in the language tooltips. The percentages are generated in utils_languages_menu.py and stored in locale/languages. Co-authored-by: Bastien Montagne Pull Request: https://projects.blender.org/blender/blender/pulls/140087 --- .../bl_i18n_utils/bl_extract_messages.py | 3 - scripts/modules/bl_i18n_utils/settings.py | 120 +++++++++--------- .../bl_i18n_utils/utils_languages_menu.py | 40 +++--- .../blentranslation/intern/blt_lang.cc | 27 ++-- 4 files changed, 89 insertions(+), 101 deletions(-) diff --git a/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/scripts/modules/bl_i18n_utils/bl_extract_messages.py index d171022a6b5..65bf9047f2a 100644 --- a/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -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. diff --git a/scripts/modules/bl_i18n_utils/settings.py b/scripts/modules/bl_i18n_utils/settings.py index 623a2f4c357..e91fc03350a 100644 --- a/scripts/modules/bl_i18n_utils/settings.py +++ b/scripts/modules/bl_i18n_utils/settings.py @@ -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`)! diff --git a/scripts/modules/bl_i18n_utils/utils_languages_menu.py b/scripts/modules/bl_i18n_utils/utils_languages_menu.py index f15c59ad3ca..c8c20cdc330 100755 --- a/scripts/modules/bl_i18n_utils/utils_languages_menu.py +++ b/scripts/modules/bl_i18n_utils/utils_languages_menu.py @@ -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 diff --git a/source/blender/blentranslation/intern/blt_lang.cc b/source/blender/blentranslation/intern/blt_lang.cc index d908260dd8a..ebfa06fff71 100644 --- a/source/blender/blentranslation/intern/blt_lang.cc +++ b/source/blender/blentranslation/intern/blt_lang.cc @@ -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(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++; }