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++; } 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); } } }