diff --git a/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/scripts/modules/bl_i18n_utils/bl_extract_messages.py index e9fd9bcf733..f5aa612de8b 100644 --- a/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -928,6 +928,55 @@ def dump_template_messages(msgs, reports, settings): reports, None, settings) +def dump_asset_messages(msgs, reports, settings): + # Where to search for assets, relative to the local user resources. + assets_dir = os.path.join(bpy.utils.resource_path('LOCAL'), "datafiles", "assets") + + # Parse the catalog sidecar file + catalog_file = os.path.join(assets_dir, settings.ASSET_CATALOG_FILE) + with open(catalog_file, encoding="utf8") as f: + data = f.readlines() + + catalogs = set() + + for line in data: + if (line == "\n" or line.startswith("VERSION") or line.startswith("#")): + continue + _UUID, catalog_path, _simple_catalog_name = line.split(":") + catalogs.update(catalog_path.split("/")) + + msgsrc = "Asset catalog from " + settings.ASSET_CATALOG_FILE + for catalog in sorted(catalogs): + process_msg(msgs, settings.DEFAULT_CONTEXT, catalog, msgsrc, + reports, None, settings) + + # Parse the asset blend files + asset_files = {} + + bfiles = glob.glob(assets_dir + "/**/*.blend", recursive=True) + for bfile in bfiles: + basename = os.path.basename(bfile) + bpy.ops.wm.open_mainfile(filepath=bfile) + # For now, only parse node groups. + # Perhaps some other assets will need to be extracted later? + for asset_type in ("node_groups",): + for asset in getattr(bpy.data, asset_type): + if asset.asset_data is None: # Not an asset + continue + assets = asset_files.setdefault(basename, []) + assets.append((asset.name, asset.asset_data.description)) + + for asset_file in sorted(asset_files): + for asset in sorted(asset_files[asset_file]): + name, description = asset + msgsrc = "Asset name from file " + asset_file + process_msg(msgs, settings.DEFAULT_CONTEXT, name, msgsrc, + reports, None, settings) + msgsrc = "Asset description from file " + asset_file + process_msg(msgs, settings.DEFAULT_CONTEXT, description, msgsrc, + reports, None, settings) + + def dump_addon_bl_info(msgs, reports, module, settings): for prop in ('name', 'location', 'description', 'warning'): process_msg( @@ -980,6 +1029,7 @@ def dump_messages(do_messages, do_checks, settings): dump_preset_messages(msgs, reports, settings) # Get strings from startup templates. + # This loads each startup blend file in turn. dump_template_messages(msgs, reports, settings) # Get strings from addons' bl_info. @@ -1019,6 +1069,10 @@ def dump_messages(do_messages, do_checks, settings): 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. + dump_asset_messages(msgs, reports, settings) + # pot.check() pot.unescape() # Strings gathered in py/C source code may contain escaped chars... print_info(reports, pot) diff --git a/scripts/modules/bl_i18n_utils/settings.py b/scripts/modules/bl_i18n_utils/settings.py index 77fd245ee1c..b14c82cbbc0 100644 --- a/scripts/modules/bl_i18n_utils/settings.py +++ b/scripts/modules/bl_i18n_utils/settings.py @@ -527,6 +527,9 @@ REL_PRESETS_DIR = os.path.join("scripts", "presets") # Where to search for templates (relative to SOURCE_DIR). REL_TEMPLATES_DIR = os.path.join("scripts", "startup", "bl_app_templates_system") +# Name of the built-in asset catalog file. +ASSET_CATALOG_FILE = "blender_assets.cats.txt" + # The template messages file (relative to I18N_DIR). REL_FILE_NAME_POT = os.path.join(REL_BRANCHES_DIR, DOMAIN + ".pot") diff --git a/source/blender/editors/space_node/add_menu_assets.cc b/source/blender/editors/space_node/add_menu_assets.cc index 710eac2be0f..1eda82d4af8 100644 --- a/source/blender/editors/space_node/add_menu_assets.cc +++ b/source/blender/editors/space_node/add_menu_assets.cc @@ -190,7 +190,7 @@ static void node_add_catalog_assets_draw(const bContext *C, Menu *menu) uiLayoutSetContextPointer(col, "asset_library_ref", &library_ptr); uiItemO( - col, AS_asset_representation_name_get(&item.asset), ICON_NONE, "NODE_OT_add_group_asset"); + col, IFACE_(AS_asset_representation_name_get(&item.asset)), ICON_NONE, "NODE_OT_add_group_asset"); } catalog_item->foreach_child([&](asset_system::AssetCatalogTreeItem &child_item) { @@ -200,7 +200,7 @@ static void node_add_catalog_assets_draw(const bContext *C, Menu *menu) &screen.id, &RNA_AssetCatalogPath, const_cast(&path)}; uiLayout *col = uiLayoutColumn(layout, false); uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); - uiItemM(col, "NODE_MT_node_add_catalog_assets", path.name().c_str(), ICON_NONE); + uiItemM(col, "NODE_MT_node_add_catalog_assets", IFACE_(path.name().c_str()), ICON_NONE); }); } @@ -270,7 +270,7 @@ static void add_root_catalogs_draw(const bContext *C, Menu *menu) &screen.id, &RNA_AssetCatalogPath, const_cast(&path)}; uiLayout *col = uiLayoutColumn(layout, false); uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); - uiItemM(col, "NODE_MT_node_add_catalog_assets", path.name().c_str(), ICON_NONE); + uiItemM(col, "NODE_MT_node_add_catalog_assets", IFACE_(path.name().c_str()), ICON_NONE); }); } diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index 60a7ed590e6..ff5f84038be 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -468,7 +468,7 @@ static char *node_add_group_asset_get_description(struct bContext *C, if (!asset_data.description) { return nullptr; } - return BLI_strdup(asset_data.description); + return BLI_strdup(DATA_(asset_data.description)); } void NODE_OT_add_group_asset(wmOperatorType *ot)