From 4abbe8ff6538c7a220dd186cce34621ecc824cb7 Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Mon, 13 Mar 2023 20:57:28 +0100 Subject: [PATCH 1/2] I18n: Translate Node Add menus generated from asset files The Node Add menu can have special submenus containing node assets. These submenus are generated by parsing the asset blend files from release/datafiles/assets, and the interface drawing is specific to these menus. This commit enables the translation of these dynamic menus, including their names and the description of the operators. --- source/blender/editors/space_node/add_menu_assets.cc | 6 +++--- source/blender/editors/space_node/node_add.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) 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) -- 2.30.2 From a849bb3dc405605d18526ccbf46193e5851dd42e Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Mon, 13 Mar 2023 22:41:11 +0100 Subject: [PATCH 2/2] I18n: Extract asset catalog and asset names and descriptions The asset catalogs are used in Geometry nodes Add Node menu to generate the hierarchy of submenus. The assets themselves are used to generate the operator names in the same menu, and their descriptions. This commits enables extraction of this data by parsing the catalog sidecar file, as well as opening each asset blend file to search for assets. --- .../bl_i18n_utils/bl_extract_messages.py | 54 +++++++++++++++++++ scripts/modules/bl_i18n_utils/settings.py | 3 ++ 2 files changed, 57 insertions(+) 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") -- 2.30.2