From e69c4482f16d51e5fda4da70abb94a23f8c5b3d9 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 15 Jul 2022 11:41:13 +0200 Subject: I18n: Add suport for labels from modifiers' subpanels. Was a bit oif a struggle since those functions take a first string which is not our label, but should work fine now. Reported/detected as part of D15418. --- .../modules/bl_i18n_utils/bl_extract_messages.py | 23 +++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'release/scripts/modules/bl_i18n_utils/bl_extract_messages.py') diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index 319fd3396a0..3edb5b445fe 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -803,20 +803,21 @@ def dump_src_messages(msgs, reports, settings): line += data[pos:m.start()].count('\n') msgsrc = rel_path + ":" + str(line) _msgid = d.get("msg_raw") - # First, try the "multi-contexts" stuff! - _msgctxts = tuple(d.get("ctxt_raw{}".format(i)) for i in range(settings.PYGETTEXT_MAX_MULTI_CTXT)) - if _msgctxts[0]: - for _msgctxt in _msgctxts: - if not _msgctxt: - break + if _msgid not in {'""', "''"}: + # First, try the "multi-contexts" stuff! + _msgctxts = tuple(d.get("ctxt_raw{}".format(i)) for i in range(settings.PYGETTEXT_MAX_MULTI_CTXT)) + if _msgctxts[0]: + for _msgctxt in _msgctxts: + if not _msgctxt: + break + msgctxt, msgid = process_entry(_msgctxt, _msgid) + process_msg(msgs, msgctxt, msgid, msgsrc, reports, check_ctxt_src, settings) + reports["src_messages"].append((msgctxt, msgid, msgsrc)) + else: + _msgctxt = d.get("ctxt_raw") msgctxt, msgid = process_entry(_msgctxt, _msgid) process_msg(msgs, msgctxt, msgid, msgsrc, reports, check_ctxt_src, settings) reports["src_messages"].append((msgctxt, msgid, msgsrc)) - else: - _msgctxt = d.get("ctxt_raw") - msgctxt, msgid = process_entry(_msgctxt, _msgid) - process_msg(msgs, msgctxt, msgid, msgsrc, reports, check_ctxt_src, settings) - reports["src_messages"].append((msgctxt, msgid, msgsrc)) pos = m.end() line += data[m.start():pos].count('\n') -- cgit v1.2.3 From c48dc61749fbf2f118651bb757e186df72b85acf Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Wed, 20 Jul 2022 11:04:38 +0200 Subject: I18n: fixes to add-on message extraction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes several issues in add-ons UI messages extraction code: - In multi-file modules, the script would crash because it tried to write to the dir instead of a `translations.py` file; - The add-on message extraction works by enabling the add-on, getting all messages; disabling the add-on, getting all messages; then comparing the two message sets. But often a bug happens where a class gets a description from somewhere else in memory. I couldn’t debug that, so a workaround is to check that the message isn’t a corrupted one before removing it; - `printf()` doesn't exist in Python and would crash the script; - `self.src[self.settings.PARSER_PY_ID]` can be replaced by `self.py_file` in class `I18n`, since a property exists to do that; - At one point a generator was printed instead of its values, so let's unpack the generator to get the values. Maybe the print could be deleted entirely; - Use SPDX license identifier instead of GPL license block, to be more in line with other scripts from the codebase. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D15474 --- release/scripts/modules/bl_i18n_utils/bl_extract_messages.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'release/scripts/modules/bl_i18n_utils/bl_extract_messages.py') diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index 3edb5b445fe..bfc111dd3c1 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -962,7 +962,12 @@ def dump_addon_messages(module_name, do_checks, settings): # and make the diff! for key in minus_msgs: if key != settings.PO_HEADER_KEY: - del msgs[key] + if key in msgs: + del msgs[key] + else: + # This should not happen, but some messages seem to have + # leaked on add-on unregister and register? + print(f"Key not found in msgs: {key}") if check_ctxt: _diff_check_ctxt(check_ctxt, minus_check_ctxt) -- cgit v1.2.3 From 3239cea726c7409f9fc6be53c078c3087a76c233 Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Mon, 1 Aug 2022 14:09:41 +0200 Subject: I18n: make presets translatable Presets are used all over the Blender UI, but were so far untranslatable. This adds the translation code as well as a new `dump_preset_messages()` function in the message extraction. This goes over all bundled preset file names and extracts them. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D15570 --- .../modules/bl_i18n_utils/bl_extract_messages.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'release/scripts/modules/bl_i18n_utils/bl_extract_messages.py') diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index bfc111dd3c1..d7755532614 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -853,6 +853,25 @@ def dump_src_messages(msgs, reports, settings): dump_src_file(path, rel_path, msgs, reports, settings) +def dump_preset_messages(msgs, reports, settings): + files = [] + for dpath, _, fnames in os.walk(settings.PRESETS_DIR): + for fname in fnames: + if fname.startswith("_") or not fname.endswith(".py"): + continue + path = os.path.join(dpath, fname) + try: # can't always find the relative path (between drive letters on windows) + rel_path = os.path.relpath(path, settings.PRESETS_DIR) + except ValueError: + rel_path = path + files.append(rel_path) + for rel_path in files: + msgsrc, msgid = os.path.split(rel_path) + msgsrc = "Preset from " + msgsrc + msgid = bpy.path.display_name(msgid, title_case=False) + process_msg(msgs, settings.DEFAULT_CONTEXT, msgid, msgsrc, reports, None, settings) + + ##### Main functions! ##### def dump_messages(do_messages, do_checks, settings): bl_ver = "Blender " + bpy.app.version_string @@ -885,6 +904,9 @@ def dump_messages(do_messages, do_checks, settings): # Get strings from C source code. dump_src_messages(msgs, reports, settings) + # Get strings from presets. + dump_preset_messages(msgs, reports, settings) + # Get strings from addons' categories. for uid, label, tip in bpy.types.WindowManager.addon_filter.keywords['items']( bpy.context.window_manager, -- cgit v1.2.3 From a2bdd6a71aafe565c0a7f5df5aa396d02f37aa62 Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Tue, 9 Aug 2022 11:41:05 +0200 Subject: I18n: remove Window class from message extraction blacklist Messages from the bpy.types.Window class were blacklisted in the message extraction script. This change allows a few new messages to be translated, including at least two which show up in the UI. There are only 12 new messages in the .po files, so even if some never need to be translated, that's not too many. Ref. T43295 Reviewed By: mont29 Differential Revision: https://developer.blender.org/D15628 --- release/scripts/modules/bl_i18n_utils/bl_extract_messages.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'release/scripts/modules/bl_i18n_utils/bl_extract_messages.py') diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index d7755532614..e4845215ff3 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -206,8 +206,6 @@ def dump_rna_messages(msgs, reports, settings, verbose=False): "Context", "Event", "Function", "UILayout", "UnknownType", "Property", "Struct", # registerable classes "Panel", "Menu", "Header", "RenderEngine", "Operator", "OperatorMacro", "Macro", "KeyingSetInfo", - # window classes - "Window", ) } -- cgit v1.2.3 From 2de1b06287023000850cfd969584fe0927327c5b Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 9 Aug 2022 12:22:30 +0200 Subject: I18n: add extraction of modal event names. Alternative fix to the one proposed in D15607. Reviewed By: campbellbarton Differential Revision: https://developer.blender.org/D15643 --- .../scripts/modules/bl_i18n_utils/bl_extract_messages.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'release/scripts/modules/bl_i18n_utils/bl_extract_messages.py') diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index e4845215ff3..a44b3ac132b 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -359,12 +359,25 @@ def dump_rna_messages(msgs, reports, settings, verbose=False): walk_properties(cls) + def walk_keymap_modal_events(keyconfigs, keymap_name, msgsrc_prev, km_i18n_context): + for keyconfig in keyconfigs: + keymap = keyconfig.keymaps.get(keymap_name, None) + if keymap and keymap.is_modal: + for modal_event in keymap.modal_event_values: + msgsrc = msgsrc_prev + ":'{}'".format(modal_event.identifier) + if modal_event.name: + process_msg(msgs, km_i18n_context, modal_event.name, msgsrc, reports, None, settings) + if modal_event.description: + process_msg(msgs, default_context, modal_event.description, msgsrc, reports, None, settings) + def walk_keymap_hierarchy(hier, msgsrc_prev): km_i18n_context = bpy.app.translations.contexts.id_windowmanager for lvl in hier: msgsrc = msgsrc_prev + "." + lvl[1] if isinstance(lvl[0], str): # Can be a function too, now, with tool system... - process_msg(msgs, km_i18n_context, lvl[0], msgsrc, reports, None, settings) + keymap_name = lvl[0] + process_msg(msgs, km_i18n_context, keymap_name, msgsrc, reports, None, settings) + walk_keymap_modal_events(bpy.data.window_managers[0].keyconfigs, keymap_name, msgsrc, km_i18n_context) if lvl[3]: walk_keymap_hierarchy(lvl[3], msgsrc) -- cgit v1.2.3 From af59e32c1320b02fe29806ebfecbbdf1a9bf71b7 Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Tue, 9 Aug 2022 12:42:16 +0200 Subject: I18n: make more parts of the UI translatable - "Name collisions" label in mesh properties - "Threshold" labels in Vertex Weight Edit modifier - "Particle System" label in Particle Instance modifier - Slot number in the Shader Editor - Status bar keymap items during modal operations: add TIP_() macro to status bar interface template - On dumping messages, sort preset files so their messages are stable between runs Ref. T43295 Reviewed By: mont29 Differential Revision: https://developer.blender.org/D15607 --- release/scripts/modules/bl_i18n_utils/bl_extract_messages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release/scripts/modules/bl_i18n_utils/bl_extract_messages.py') diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index a44b3ac132b..9f22b2417ed 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -876,7 +876,7 @@ def dump_preset_messages(msgs, reports, settings): except ValueError: rel_path = path files.append(rel_path) - for rel_path in files: + for rel_path in sorted(files): msgsrc, msgid = os.path.split(rel_path) msgsrc = "Preset from " + msgsrc msgid = bpy.path.display_name(msgid, title_case=False) -- cgit v1.2.3 From 4ac96a483bf1567d37ec0357c5430c731c4f884e Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Tue, 23 Aug 2022 11:43:39 +0200 Subject: I18n: make workspaces translatable This makes workspaces more translatable: - New Workspace menu - header - preset menus - preset entries - workspace names upon factory file template load - new workspace name upon workspace addition To properly translate those names, an extraction function for workspace names from app templates was added as well. (Do not do anything when loading a user-saved file!) Reviewed By: mont29 Differential Revision: https://developer.blender.org/D15727 --- .../modules/bl_i18n_utils/bl_extract_messages.py | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'release/scripts/modules/bl_i18n_utils/bl_extract_messages.py') diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index 9f22b2417ed..f6dc2ae7ca0 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -8,6 +8,7 @@ import datetime import os import re import sys +import glob # XXX Relative import does not work here when used from Blender... from bl_i18n_utils import settings as settings_i18n, utils @@ -883,6 +884,29 @@ def dump_preset_messages(msgs, reports, settings): process_msg(msgs, settings.DEFAULT_CONTEXT, msgid, msgsrc, reports, None, settings) +def dump_template_messages(msgs, reports, settings): + bfiles = [""] # General template, no name needed + bfiles += glob.glob(settings.TEMPLATES_DIR + "/**/*.blend", recursive=True) + + workspace_names = {} + + for bfile in bfiles: + template = os.path.dirname(bfile) + template = os.path.basename(template) + bpy.ops.wm.read_homefile(use_factory_startup=True, app_template=template) + for ws in bpy.data.workspaces: + names = workspace_names.setdefault(ws.name, []) + names.append(template or "General") + + from bpy.app.translations import contexts as i18n_contexts + msgctxt = i18n_contexts.id_workspace + for workspace_name in sorted(workspace_names): + for msgsrc in sorted(workspace_names[workspace_name]): + msgsrc = "Workspace from template " + msgsrc + process_msg(msgs, msgctxt, workspace_name, msgsrc, + reports, None, settings) + + ##### Main functions! ##### def dump_messages(do_messages, do_checks, settings): bl_ver = "Blender " + bpy.app.version_string @@ -918,6 +942,9 @@ def dump_messages(do_messages, do_checks, settings): # Get strings from presets. dump_preset_messages(msgs, reports, settings) + # Get strings from startup templates. + dump_template_messages(msgs, reports, settings) + # Get strings from addons' categories. for uid, label, tip in bpy.types.WindowManager.addon_filter.keywords['items']( bpy.context.window_manager, -- cgit v1.2.3 From 649807a8cd3ba7815a5609b92ffb3f3ac77e1fea Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 23 Aug 2022 23:13:47 +1000 Subject: Cleanup: format --- release/scripts/modules/bl_i18n_utils/bl_extract_messages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'release/scripts/modules/bl_i18n_utils/bl_extract_messages.py') diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index f6dc2ae7ca0..fc7cbe566c3 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -885,7 +885,7 @@ def dump_preset_messages(msgs, reports, settings): def dump_template_messages(msgs, reports, settings): - bfiles = [""] # General template, no name needed + bfiles = [""] # General template, no name needed. bfiles += glob.glob(settings.TEMPLATES_DIR + "/**/*.blend", recursive=True) workspace_names = {} -- cgit v1.2.3 From 73bfd8058f7506fa50f806227256f11ec8eeab85 Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Mon, 29 Aug 2022 14:02:24 +0200 Subject: I18n: make add-ons' info translatable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The info provided by add-ons is very valuable to users, yet it wasn’t translatable yet. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D15747 --- .../scripts/modules/bl_i18n_utils/bl_extract_messages.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'release/scripts/modules/bl_i18n_utils/bl_extract_messages.py') diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index fc7cbe566c3..683ca2bc5fe 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -907,6 +907,11 @@ def dump_template_messages(msgs, reports, settings): reports, None, settings) +def dump_addon_bl_info(msgs, reports, module, settings): + for prop in ('name', 'location', 'description'): + process_msg(msgs, settings.DEFAULT_CONTEXT, module.bl_info[prop], "Add-on " + module.bl_info['name'] + " info: " + prop, reports, None, settings) + + ##### Main functions! ##### def dump_messages(do_messages, do_checks, settings): bl_ver = "Blender " + bpy.app.version_string @@ -945,6 +950,13 @@ def dump_messages(do_messages, do_checks, settings): # Get strings from startup templates. dump_template_messages(msgs, reports, settings) + # Get strings from addons' bl_info. + import addon_utils + for module in addon_utils.modules(): + if module.bl_info['support'] != 'OFFICIAL': + continue + dump_addon_bl_info(msgs, reports, module, settings) + # Get strings from addons' categories. for uid, label, tip in bpy.types.WindowManager.addon_filter.keywords['items']( bpy.context.window_manager, @@ -1041,6 +1053,9 @@ def dump_addon_messages(module_name, do_checks, settings): reports["check_ctxt"] = check_ctxt dump_py_messages(msgs, reports, {addon}, settings, addons_only=True) + # Get strings from the addon's bl_info + dump_addon_bl_info(msgs, reports, addon, settings) + pot.unescape() # Strings gathered in py/C source code may contain escaped chars... print_info(reports, pot) -- cgit v1.2.3 From 24b8ccaa94a66a3552dc7100996d83d492a55ada Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 30 Aug 2022 16:15:45 +1000 Subject: Cleanup: format --- .../scripts/modules/bl_i18n_utils/bl_extract_messages.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'release/scripts/modules/bl_i18n_utils/bl_extract_messages.py') diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index 683ca2bc5fe..dea538af39b 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -97,7 +97,7 @@ def check(check_ctxt, msgs, key, msgsrc, settings): if key in py_in_rna[1]: py_in_rna[0].add(key) if not_capitalized is not None: - if(key[1] not in settings.WARN_MSGID_NOT_CAPITALIZED_ALLOWED and + if (key[1] not in settings.WARN_MSGID_NOT_CAPITALIZED_ALLOWED and key[1][0].isalpha() and not key[1][0].isupper()): not_capitalized.add(key) if end_point is not None: @@ -909,7 +909,18 @@ def dump_template_messages(msgs, reports, settings): def dump_addon_bl_info(msgs, reports, module, settings): for prop in ('name', 'location', 'description'): - process_msg(msgs, settings.DEFAULT_CONTEXT, module.bl_info[prop], "Add-on " + module.bl_info['name'] + " info: " + prop, reports, None, settings) + process_msg( + msgs, + settings.DEFAULT_CONTEXT, + module.bl_info[prop], + "Add-on " + + module.bl_info['name'] + + " info: " + + prop, + reports, + None, + settings, + ) ##### Main functions! ##### -- cgit v1.2.3 From 19b9ea72b00b85200da0900b327a9d37378c83f4 Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Mon, 5 Sep 2022 15:36:56 +0200 Subject: I18n: extract keymap preferences The per-keymap user preferences messages were not extracted. This goes through the keymap preferences RNA, as well as Python files for UI. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D15871 --- .../modules/bl_i18n_utils/bl_extract_messages.py | 24 +++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'release/scripts/modules/bl_i18n_utils/bl_extract_messages.py') diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index dea538af39b..21ca38bff20 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -258,11 +258,12 @@ def dump_rna_messages(msgs, reports, settings, verbose=False): bl_rna_base_props = set() if bl_rna_base: bl_rna_base_props |= set(bl_rna_base.properties.values()) - for cls_base in cls.__bases__: - bl_rna_base = getattr(cls_base, "bl_rna", None) - if not bl_rna_base: - continue - bl_rna_base_props |= set(bl_rna_base.properties.values()) + if hasattr(cls, "__bases__"): + for cls_base in cls.__bases__: + bl_rna_base = getattr(cls_base, "bl_rna", None) + if not bl_rna_base: + continue + bl_rna_base_props |= set(bl_rna_base.properties.values()) props = sorted(bl_rna.properties, key=lambda p: p.identifier) for prop in props: @@ -450,6 +451,19 @@ def dump_rna_messages(msgs, reports, settings, verbose=False): process_msg(msgs, bpy.app.translations.contexts.operator_default, cat_str, "Generated operator category", reports, check_ctxt_rna, settings) + # Parse keymap preset preferences + for preset_filename in sorted( + os.listdir(os.path.join(settings.PRESETS_DIR, "keyconfig"))): + preset_path = os.path.join(settings.PRESETS_DIR, "keyconfig", preset_filename) + if not (os.path.isfile(preset_path) and preset_filename.endswith(".py")): + continue + preset_name, _ = os.path.splitext(preset_filename) + + bpy.utils.keyconfig_set(preset_path) + preset = bpy.data.window_managers[0].keyconfigs[preset_name] + if preset.preferences is not None: + walk_properties(preset.preferences) + # And parse keymaps! from bl_keymap_utils import keymap_hierarchy walk_keymap_hierarchy(keymap_hierarchy.generate(), "KM_HIERARCHY") -- cgit v1.2.3