diff --git a/scripts/addons_core/ui_translate/__init__.py b/scripts/addons_core/ui_translate/__init__.py index e414ce53208..91f75193b30 100644 --- a/scripts/addons_core/ui_translate/__init__.py +++ b/scripts/addons_core/ui_translate/__init__.py @@ -5,9 +5,9 @@ bl_info = { "name": "Manage UI translations", "author": "Bastien Montagne", - "version": (2, 0, 0), - "blender": (4, 0, 0), - "location": "Main \"File\" menu, text editor, any UI control", + "version": (2, 1, 0), + "blender": (4, 2, 0), + "location": "Render properties, I18n Update Translation panel", "description": "Allows managing UI translations directly from Blender " "(update main .po files, update scripts' translations, etc.)", "doc_url": "https://developer.blender.org/docs/handbook/translating/translator_guide/", @@ -18,7 +18,6 @@ bl_info = { from . import ( settings, - edit_translation, update_repo, update_addon, update_ui, @@ -26,7 +25,6 @@ from . import ( if "bpy" in locals(): import importlib importlib.reload(settings) - importlib.reload(edit_translation) importlib.reload(update_repo) importlib.reload(update_addon) importlib.reload(update_ui) @@ -34,7 +32,7 @@ if "bpy" in locals(): import bpy -classes = settings.classes + edit_translation.classes + update_repo.classes + update_addon.classes + update_ui.classes +classes = settings.classes + update_repo.classes + update_addon.classes + update_ui.classes def register(): diff --git a/scripts/addons_core/ui_translate/edit_translation.py b/scripts/addons_core/ui_translate/edit_translation.py deleted file mode 100644 index f35b46c707f..00000000000 --- a/scripts/addons_core/ui_translate/edit_translation.py +++ /dev/null @@ -1,408 +0,0 @@ -# SPDX-FileCopyrightText: 2012-2022 Blender Foundation -# -# SPDX-License-Identifier: GPL-2.0-or-later - -import os -import shutil -if "bpy" in locals(): - import importlib - importlib.reload(settings) - importlib.reload(utils_i18n) -else: - import bpy - from bpy.types import Operator - from bpy.props import ( - BoolProperty, - EnumProperty, - StringProperty, - ) - from . import settings - from bl_i18n_utils import utils as utils_i18n - - -# A global cache for I18nMessages objects, as parsing po files takes a few seconds. -PO_CACHE = {} - - -def _get_messages(lang, fname): - if fname not in PO_CACHE: - PO_CACHE[fname] = utils_i18n.I18nMessages(uid=lang, kind='PO', key=fname, src=fname, settings=settings.settings) - return PO_CACHE[fname] - - -class UI_OT_i18n_edittranslation_update_mo(Operator): - """Try to "compile" given po file into relevant blender.mo file""" - """(WARNING: it will replace the official mo file in your user dir!)""" - bl_idname = "ui.i18n_edittranslation_update_mo" - bl_label = "Edit Translation Update Mo" - - # Operator Arguments - lang: StringProperty( - description="Current (translated) language", - options={'SKIP_SAVE'}, - ) - - po_file: StringProperty( - description="Path to the matching po file", - subtype='FILE_PATH', - options={'SKIP_SAVE'}, - ) - - clean_mo: BoolProperty( - description="Remove all local translation files, to be able to use the system ones again", - default=False, - options={'SKIP_SAVE'} - ) - # /End Operator Arguments - - def execute(self, context): - if self.clean_mo: - root = bpy.utils.user_resource('DATAFILES', path=settings.settings.MO_PATH_ROOT_RELATIVE) - if root: - shutil.rmtree(root) - elif not (self.lang and self.po_file): - return {'CANCELLED'} - else: - mo_dir = bpy.utils.user_resource( - 'DATAFILES', - path=settings.settings.MO_PATH_TEMPLATE_RELATIVE.format(self.lang), - create=True, - ) - mo_file = os.path.join(mo_dir, settings.settings.MO_FILE_NAME) - _get_messages(self.lang, self.po_file).write(kind='MO', dest=mo_file) - - bpy.ops.ui.reloadtranslation() - return {'FINISHED'} - - -class UI_OT_i18n_edittranslation(Operator): - """Translate the label and tooltip of the given property""" - bl_idname = "ui.edittranslation" - bl_label = "Edit Translation" - - # Operator Arguments - but_label: StringProperty( - description="Label of the control", - options={'SKIP_SAVE'}, - ) - - rna_label: StringProperty( - description="RNA-defined label of the control, if any", - options={'SKIP_SAVE'}, - ) - - enum_label: StringProperty( - description="Label of the enum item of the control, if any", - options={'SKIP_SAVE'}, - ) - - but_tip: StringProperty( - description="Tip of the control", - options={'SKIP_SAVE'}, - ) - - rna_tip: StringProperty( - description="RNA-defined tip of the control, if any", - options={'SKIP_SAVE'}, - ) - - enum_tip: StringProperty( - description="Tip of the enum item of the control, if any", - options={'SKIP_SAVE'}, - ) - - rna_struct: StringProperty( - description="Identifier of the RNA struct, if any", - options={'SKIP_SAVE'}, - ) - - rna_prop: StringProperty( - description="Identifier of the RNA property, if any", - options={'SKIP_SAVE'}, - ) - - rna_enum: StringProperty( - description="Identifier of the RNA enum item, if any", - options={'SKIP_SAVE'}, - ) - - rna_ctxt: StringProperty( - description="RNA context for label", - options={'SKIP_SAVE'}, - ) - - lang: StringProperty( - description="Current (translated) language", - options={'SKIP_SAVE'}, - ) - - po_file: StringProperty( - description="Path to the matching po file", - subtype='FILE_PATH', - options={'SKIP_SAVE'}, - ) - - # Found in po file. - org_but_label: StringProperty( - description="Original label of the control", - options={'SKIP_SAVE'}, - ) - - org_rna_label: StringProperty( - description="Original RNA-defined label of the control, if any", - options={'SKIP_SAVE'}, - ) - - org_enum_label: StringProperty( - description="Original label of the enum item of the control, if any", - options={'SKIP_SAVE'}, - ) - - org_but_tip: StringProperty( - description="Original tip of the control", - options={'SKIP_SAVE'}, - ) - - org_rna_tip: StringProperty( - description="Original RNA-defined tip of the control, if any", options={'SKIP_SAVE'} - ) - - org_enum_tip: StringProperty( - description="Original tip of the enum item of the control, if any", - options={'SKIP_SAVE'}, - ) - - flag_items = ( - ('FUZZY', "Fuzzy", "Message is marked as fuzzy in po file"), - ('ERROR', "Error", "Some error occurred with this message"), - ) - - but_label_flags: EnumProperty( - description="Flags about the label of the button", - items=flag_items, - options={'SKIP_SAVE', 'ENUM_FLAG'}, - ) - - rna_label_flags: EnumProperty( - description="Flags about the RNA-defined label of the button", - items=flag_items, - options={'SKIP_SAVE', 'ENUM_FLAG'}, - ) - - enum_label_flags: EnumProperty( - description="Flags about the RNA enum item label of the button", - items=flag_items, - options={'SKIP_SAVE', 'ENUM_FLAG'}, - ) - - but_tip_flags: EnumProperty( - description="Flags about the tip of the button", - items=flag_items, - options={'SKIP_SAVE', 'ENUM_FLAG'}, - ) - - rna_tip_flags: EnumProperty( - description="Flags about the RNA-defined tip of the button", - items=flag_items, - options={'SKIP_SAVE', 'ENUM_FLAG'}, - ) - - enum_tip_flags: EnumProperty( - description="Flags about the RNA enum item tip of the button", - items=flag_items, - options={'SKIP_SAVE', 'ENUM_FLAG'}, - ) - - stats_str: StringProperty( - description="Stats from opened po", options={'SKIP_SAVE'}) - - update_po: BoolProperty( - description="Update po file, try to rebuild mo file, and refresh Blender's UI", - default=False, - options={'SKIP_SAVE'}, - ) - - update_mo: BoolProperty( - description="Try to rebuild mo file, and refresh Blender's UI", - default=False, - options={'SKIP_SAVE'}, - ) - - clean_mo: BoolProperty( - description="Remove all local translation files, to be able to use the system ones again", - default=False, - options={'SKIP_SAVE'}, - ) - # /End Operator Arguments - - def execute(self, context): - if not hasattr(self, "msgmap"): - self.report('ERROR', "invoke() needs to be called before execute()") - return {'CANCELLED'} - - msgs = _get_messages(self.lang, self.po_file) - done_keys = set() - for mmap in self.msgmap.values(): - if 'ERROR' in getattr(self, mmap["msg_flags"]): - continue - k = mmap["key"] - if k not in done_keys and len(k) == 1: - k = tuple(k)[0] - msgs.msgs[k].msgstr = getattr(self, mmap["msgstr"]) - msgs.msgs[k].is_fuzzy = 'FUZZY' in getattr(self, mmap["msg_flags"]) - done_keys.add(k) - - if self.update_po: - # Try to overwrite .po file, may fail if there are no permissions. - try: - msgs.write(kind='PO', dest=self.po_file) - except Exception as e: - self.report('ERROR', "Could not write to po file ({})".format(str(e))) - # Always invalidate reverse messages cache afterward! - msgs.invalidate_reverse_cache() - if self.update_mo: - lang = os.path.splitext(os.path.basename(self.po_file))[0] - bpy.ops.ui.i18n_edittranslation_update_mo(po_file=self.po_file, lang=lang) - elif self.clean_mo: - bpy.ops.ui.i18n_edittranslation_update_mo(clean_mo=True) - return {'FINISHED'} - - def invoke(self, context, event): - self.msgmap = { - "but_label": { - "msgstr": "but_label", "msgid": "org_but_label", "msg_flags": "but_label_flags", "key": set()}, - "rna_label": { - "msgstr": "rna_label", "msgid": "org_rna_label", "msg_flags": "rna_label_flags", "key": set()}, - "enum_label": { - "msgstr": "enum_label", "msgid": "org_enum_label", "msg_flags": "enum_label_flags", "key": set()}, - "but_tip": { - "msgstr": "but_tip", "msgid": "org_but_tip", "msg_flags": "but_tip_flags", "key": set()}, - "rna_tip": { - "msgstr": "rna_tip", "msgid": "org_rna_tip", "msg_flags": "rna_tip_flags", "key": set()}, - "enum_tip": { - "msgstr": "enum_tip", "msgid": "org_enum_tip", "msg_flags": "enum_tip_flags", "key": set()}, - } - - msgs = _get_messages(self.lang, self.po_file) - msgs.find_best_messages_matches(self, self.msgmap, self.rna_ctxt, self.rna_struct, self.rna_prop, self.rna_enum) - msgs.update_info() - self.stats_str = "{}: {} messages, {} translated.".format(os.path.basename(self.po_file), msgs.nbr_msgs, - msgs.nbr_trans_msgs) - - for mmap in self.msgmap.values(): - k = tuple(mmap["key"]) - if k: - if len(k) == 1: - k = k[0] - ctxt, msgid = k - setattr(self, mmap["msgstr"], msgs.msgs[k].msgstr) - setattr(self, mmap["msgid"], msgid) - if msgs.msgs[k].is_fuzzy: - setattr(self, mmap["msg_flags"], {'FUZZY'}) - else: - setattr(self, mmap["msgid"], - "ERROR: Button label “{}” matches several messages in po file ({})!" - "".format(self.but_label, k)) - setattr(self, mmap["msg_flags"], {'ERROR'}) - else: - setattr(self, mmap["msgstr"], "") - setattr(self, mmap["msgid"], "") - - wm = context.window_manager - return wm.invoke_props_dialog(self, width=600) - - def draw(self, context): - layout = self.layout - layout.label(text=self.stats_str) - src, _a, _b = bpy.utils.make_rna_paths(self.rna_struct, self.rna_prop, self.rna_enum) - if src: - layout.label(text=" RNA Path: bpy.types." + src) - if self.rna_ctxt: - layout.label(text=" RNA Context: " + self.rna_ctxt) - - if self.org_but_label or self.org_rna_label or self.org_enum_label: - # XXX Can't use box, labels are not enough readable in them :/ - box = layout.box() - box.label(text="Labels:") - split = box.split(factor=0.15) - col1 = split.column() - col2 = split.column() - if self.org_but_label: - col1.label(text="Button Label:") - row = col2.row() - row.enabled = False - if 'ERROR' in self.but_label_flags: - row.alert = True - else: - col1.prop_enum(self, "but_label_flags", 'FUZZY', text="Fuzzy") - col2.prop(self, "but_label", text="") - row.prop(self, "org_but_label", text="") - if self.org_rna_label: - col1.label(text="RNA Label:") - row = col2.row() - row.enabled = False - if 'ERROR' in self.rna_label_flags: - row.alert = True - else: - col1.prop_enum(self, "rna_label_flags", 'FUZZY', text="Fuzzy") - col2.prop(self, "rna_label", text="") - row.prop(self, "org_rna_label", text="") - if self.org_enum_label: - col1.label(text="Enum Item Label:") - row = col2.row() - row.enabled = False - if 'ERROR' in self.enum_label_flags: - row.alert = True - else: - col1.prop_enum(self, "enum_label_flags", 'FUZZY', text="Fuzzy") - col2.prop(self, "enum_label", text="") - row.prop(self, "org_enum_label", text="") - - if self.org_but_tip or self.org_rna_tip or self.org_enum_tip: - # XXX Can't use box, labels are not enough readable in them :/ - box = layout.box() - box.label(text="Tool Tips:") - split = box.split(factor=0.15) - col1 = split.column() - col2 = split.column() - if self.org_but_tip: - col1.label(text="Button Tip:") - row = col2.row() - row.enabled = False - if 'ERROR' in self.but_tip_flags: - row.alert = True - else: - col1.prop_enum(self, "but_tip_flags", 'FUZZY', text="Fuzzy") - col2.prop(self, "but_tip", text="") - row.prop(self, "org_but_tip", text="") - if self.org_rna_tip: - col1.label(text="RNA Tip:") - row = col2.row() - row.enabled = False - if 'ERROR' in self.rna_tip_flags: - row.alert = True - else: - col1.prop_enum(self, "rna_tip_flags", 'FUZZY', text="Fuzzy") - col2.prop(self, "rna_tip", text="") - row.prop(self, "org_rna_tip", text="") - if self.org_enum_tip: - col1.label(text="Enum Item Tip:") - row = col2.row() - row.enabled = False - if 'ERROR' in self.enum_tip_flags: - row.alert = True - else: - col1.prop_enum(self, "enum_tip_flags", 'FUZZY', text="Fuzzy") - col2.prop(self, "enum_tip", text="") - row.prop(self, "org_enum_tip", text="") - - row = layout.row() - row.prop(self, "update_po", text="Save to PO File", toggle=True) - row.prop(self, "update_mo", text="Rebuild MO File", toggle=True) - row.prop(self, "clean_mo", text="Erase Local MO files", toggle=True) - - -classes = ( - UI_OT_i18n_edittranslation_update_mo, - UI_OT_i18n_edittranslation, -) diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index b338a138a2b..cc73e9d0186 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -1408,10 +1408,6 @@ std::string UI_but_extra_icon_string_get_tooltip(bContext &C, const uiButExtraOp std::string UI_but_extra_icon_string_get_operator_keymap(const bContext &C, const uiButExtraOpIcon &extra_icon); -/* Edit i18n stuff. */ -/* Name of the main py op from i18n addon. */ -#define EDTSRC_I18N_OP_NAME "UI_OT_edittranslation" - /** * Special Buttons * diff --git a/source/blender/editors/interface/interface_context_menu.cc b/source/blender/editors/interface/interface_context_menu.cc index 3c7f47c1629..a8881a73854 100644 --- a/source/blender/editors/interface/interface_context_menu.cc +++ b/source/blender/editors/interface/interface_context_menu.cc @@ -1346,17 +1346,6 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev } } - if (BKE_addon_find(&U.addons, "ui_translate")) { - uiItemFullO(layout, - "UI_OT_edittranslation_init", - nullptr, - ICON_NONE, - nullptr, - WM_OP_INVOKE_DEFAULT, - UI_ITEM_NONE, - nullptr); - } - /* Show header tools for header buttons. */ if (ui_block_is_popup_any(but->block) == false) { const ARegion *region = CTX_wm_region(C); diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc index 00a830e4d53..8dea3c87cff 100644 --- a/source/blender/editors/interface/interface_ops.cc +++ b/source/blender/editors/interface/interface_ops.cc @@ -2186,142 +2186,8 @@ static void UI_OT_editsource(wmOperatorType *ot) /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Edit Translation Operator - * \{ */ - -/** - * EditTranslation utility functions and operator. - * - * \note this includes utility functions and button matching checks. - * this only works in conjunction with a Python operator! - */ -static void edittranslation_find_po_file(const char *root, - const char *uilng, - char *path, - const size_t path_maxncpy) -{ - char tstr[32]; /* Should be more than enough! */ - - /* First, full lang code. */ - SNPRINTF(tstr, "%s.po", uilng); - BLI_path_join(path, path_maxncpy, root, uilng, tstr); - if (BLI_is_file(path)) { - return; - } - - /* Now try without the second ISO code part (`_BR` in `pt_BR`). */ - { - const char *tc = nullptr; - size_t szt = 0; - tstr[0] = '\0'; - - tc = strchr(uilng, '_'); - if (tc) { - szt = tc - uilng; - if (szt < sizeof(tstr)) { /* Paranoid, should always be true! */ - BLI_strncpy(tstr, uilng, szt + 1); /* +1 for '\0' char! */ - } - } - if (tstr[0]) { - /* Because of some codes like sr_SR@latin... */ - tc = strchr(uilng, '@'); - if (tc) { - BLI_strncpy(tstr + szt, tc, sizeof(tstr) - szt); - } - - BLI_path_join(path, path_maxncpy, root, tstr); - BLI_strncat(tstr, ".po", sizeof(tstr)); - BLI_path_append(path, path_maxncpy, tstr); - if (BLI_is_file(path)) { - return; - } - } - } - - /* Else no po file! */ - path[0] = '\0'; -} - -static int edittranslation_exec(bContext *C, wmOperator *op) -{ - uiBut *but = UI_context_active_but_get(C); - if (but == nullptr) { - BKE_report(op->reports, RPT_ERROR, "Active button not found"); - return OPERATOR_CANCELLED; - } - - wmOperatorType *ot; - PointerRNA ptr; - char popath[FILE_MAX]; - const char *root = U.i18ndir; - const char *uilng = BLT_lang_get(); - - if (!BLI_is_dir(root)) { - BKE_report(op->reports, - RPT_ERROR, - "Please set your Preferences' 'Translation Branches " - "Directory' path to a valid directory"); - return OPERATOR_CANCELLED; - } - ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, false); - if (ot == nullptr) { - BKE_reportf(op->reports, - RPT_ERROR, - "Could not find operator '%s'! Please enable ui_translate add-on " - "in the User Preferences", - EDTSRC_I18N_OP_NAME); - return OPERATOR_CANCELLED; - } - /* Try to find a valid po file for current language... */ - edittranslation_find_po_file(root, uilng, popath, FILE_MAX); - // printf("po path: %s\n", popath); - if (popath[0] == '\0') { - BKE_reportf( - op->reports, RPT_ERROR, "No valid po found for language '%s' under %s", uilng, root); - return OPERATOR_CANCELLED; - } - - WM_operator_properties_create_ptr(&ptr, ot); - RNA_string_set(&ptr, "lang", uilng); - RNA_string_set(&ptr, "po_file", popath); - - const EnumPropertyItem enum_item = UI_but_rna_enum_item_get(*C, *but).value_or( - EnumPropertyItem{}); - RNA_string_set(&ptr, "enum_label", enum_item.name); - RNA_string_set(&ptr, "enum_tip", enum_item.description); - RNA_string_set(&ptr, "rna_enum", enum_item.identifier); - - RNA_string_set(&ptr, "but_label", UI_but_string_get_label(*but).c_str()); - RNA_string_set(&ptr, "rna_label", UI_but_string_get_rna_label(*but).c_str()); - - RNA_string_set(&ptr, "but_tip", UI_but_string_get_tooltip(*C, *but).c_str()); - RNA_string_set(&ptr, "rna_tip", UI_but_string_get_rna_tooltip(*C, *but).c_str()); - - RNA_string_set(&ptr, "rna_struct", UI_but_string_get_rna_struct_identifier(*but).c_str()); - RNA_string_set(&ptr, "rna_prop", UI_but_string_get_rna_property_identifier(*but).c_str()); - RNA_string_set(&ptr, "rna_ctxt", UI_but_string_get_rna_label_context(*but).c_str()); - - const int ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr); - - return ret; -} - -static void UI_OT_edittranslation_init(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Edit Translation"; - ot->idname = "UI_OT_edittranslation_init"; - ot->description = "Edit i18n in current language for the active button"; - - /* callbacks */ - ot->exec = edittranslation_exec; -} - #endif /* WITH_PYTHON */ -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Reload Translation Operator * \{ */ @@ -2884,7 +2750,6 @@ void ED_operatortypes_ui() WM_operatortype_append(UI_OT_drop_material); #ifdef WITH_PYTHON WM_operatortype_append(UI_OT_editsource); - WM_operatortype_append(UI_OT_edittranslation_init); #endif WM_operatortype_append(UI_OT_reloadtranslation); WM_operatortype_append(UI_OT_button_execute);