I18n: Translate messages in extensions, operator descriptions, Node Wrangler
- Operator descriptions use tip_() since they will be displayed in tooltips. - Extension messages: - Split "(Add-on|Theme) \"{:s}\" already installed!" into two messages. - Use rpt_() to translate error messages. - Restore core add-on name and description translation. - Use DATA_ to translate paint material slot name, so that translation happens only if the user enabled it for user-created data. - Node Wrangler contains functions used to build operators' poll methods. This change allows them to be properly translated by using str.format() instead of f-strings, and explicit extraction with tip_(). Pull Request: https://projects.blender.org/blender/blender/pulls/123795
This commit is contained in:
parent
2aee84a611
commit
6a52c76a65
@ -34,6 +34,7 @@ from bpy.props import (
|
||||
)
|
||||
from bpy.app.translations import (
|
||||
pgettext_iface as iface_,
|
||||
pgettext_tip as tip_,
|
||||
pgettext_rpt as rpt_,
|
||||
|
||||
)
|
||||
@ -1399,7 +1400,7 @@ class EXTENSIONS_OT_repo_sync_all(Operator, _ExtCmdMixIn):
|
||||
@classmethod
|
||||
def description(cls, _context, props):
|
||||
if props.use_active_only:
|
||||
return "Refresh the list of extensions for the active repository"
|
||||
return tip_("Refresh the list of extensions for the active repository")
|
||||
return "" # Default.
|
||||
|
||||
def exec_command_iter(self, is_modal):
|
||||
@ -1596,7 +1597,7 @@ class EXTENSIONS_OT_package_upgrade_all(Operator, _ExtCmdMixIn):
|
||||
@classmethod
|
||||
def description(cls, _context, props):
|
||||
if props.use_active_only:
|
||||
return "Upgrade all the extensions to their latest version for the active repository"
|
||||
return tip_("Upgrade all the extensions to their latest version for the active repository")
|
||||
return "" # Default.
|
||||
|
||||
def exec_command_iter(self, is_modal):
|
||||
@ -2812,15 +2813,16 @@ class EXTENSIONS_OT_package_install(Operator, _ExtCmdMixIn):
|
||||
return False
|
||||
|
||||
if item_local is not None:
|
||||
if item_local.type == "add-on":
|
||||
message = rpt_("Add-on \"{:s}\" already installed!")
|
||||
elif item_local.type == "theme":
|
||||
message = rpt_("Theme \"{:s}\" already installed!")
|
||||
else:
|
||||
assert False, "Unreachable"
|
||||
self._draw_override = (
|
||||
self._draw_override_errors,
|
||||
{
|
||||
"errors": [
|
||||
iface_("{:s} \"{:s}\" already installed!").format(
|
||||
iface_(string.capwords(item_local.type)),
|
||||
item_local.name,
|
||||
)
|
||||
]
|
||||
"errors": [message.format(item_local.name)]
|
||||
}
|
||||
)
|
||||
return False
|
||||
@ -2989,7 +2991,7 @@ class EXTENSIONS_OT_package_uninstall_system(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, _context, _props):
|
||||
return EXTENSIONS_OT_package_uninstall.__doc__
|
||||
return tip_(EXTENSIONS_OT_package_uninstall.__doc__)
|
||||
|
||||
def execute(self, _context):
|
||||
return {'CANCELLED'}
|
||||
@ -3448,18 +3450,18 @@ class EXTENSIONS_OT_userpref_allow_online_popup(Operator):
|
||||
col = layout.column()
|
||||
if bpy.app.online_access_override:
|
||||
lines = (
|
||||
"Online access required to install or update.",
|
||||
rpt_("Online access required to install or update."),
|
||||
"",
|
||||
"Launch Blender without --offline-mode"
|
||||
rpt_("Launch Blender without --offline-mode"),
|
||||
)
|
||||
else:
|
||||
lines = (
|
||||
"Please turn Online Access on the System settings.",
|
||||
rpt_("Please turn Online Access on the System settings."),
|
||||
"",
|
||||
"Internet access is required to install extensions from the internet."
|
||||
rpt_("Internet access is required to install extensions from the internet."),
|
||||
)
|
||||
for line in lines:
|
||||
col.label(text=line)
|
||||
col.label(text=line, translate=False)
|
||||
|
||||
|
||||
class EXTENSIONS_OT_package_enable_not_installed(Operator):
|
||||
|
@ -225,7 +225,7 @@ def addon_draw_item_expanded(
|
||||
item_tracker_url, # `str`
|
||||
):
|
||||
from bpy.app.translations import (
|
||||
pgettext_iface as iface_,
|
||||
contexts as i18n_contexts,
|
||||
)
|
||||
|
||||
split = layout.split(factor=0.8)
|
||||
@ -242,7 +242,7 @@ def addon_draw_item_expanded(
|
||||
rowsub.alignment = 'RIGHT'
|
||||
if addon_type == ADDON_TYPE_LEGACY_CORE:
|
||||
rowsub.active = False
|
||||
rowsub.label(text=iface_("Built-in"))
|
||||
rowsub.label(text="Built-in")
|
||||
rowsub.separator()
|
||||
elif addon_type == ADDON_TYPE_LEGACY_USER:
|
||||
rowsub.operator("preferences.addon_remove", text="Uninstall").module = mod.__name__
|
||||
@ -268,7 +268,7 @@ def addon_draw_item_expanded(
|
||||
# Only add "Report a Bug" button if tracker_url is set
|
||||
# or the add-on is bundled (use official tracker then).
|
||||
if item_tracker_url or (addon_type == ADDON_TYPE_LEGACY_CORE):
|
||||
col_a.label(text="Feedback")
|
||||
col_a.label(text="Feedback", text_ctxt=i18n_contexts.editor_preferences)
|
||||
if item_tracker_url:
|
||||
col_b.split(factor=0.5).operator(
|
||||
"wm.url_open", text="Report a Bug", icon='URL',
|
||||
@ -1065,6 +1065,8 @@ def extensions_panel_draw_online_extensions_request_impl(
|
||||
self,
|
||||
_context,
|
||||
):
|
||||
from bpy.app.translations import pgettext_rpt as rpt_
|
||||
|
||||
layout = self.layout
|
||||
layout_header, layout_panel = layout.panel("advanced", default_closed=False)
|
||||
layout_header.label(text="Online Extensions")
|
||||
@ -1076,10 +1078,10 @@ def extensions_panel_draw_online_extensions_request_impl(
|
||||
|
||||
# Text wrapping isn't supported, manually wrap.
|
||||
for line in (
|
||||
"Internet access is required to install and update online extensions. ",
|
||||
"You can adjust this later from \"System\" preferences.",
|
||||
rpt_("Internet access is required to install and update online extensions. "),
|
||||
rpt_("You can adjust this later from \"System\" preferences."),
|
||||
):
|
||||
box.label(text=line)
|
||||
box.label(text=line, translate=False)
|
||||
|
||||
row = box.row(align=True)
|
||||
row.alignment = 'LEFT'
|
||||
|
@ -5,6 +5,7 @@
|
||||
import bpy
|
||||
from bpy_extras.node_utils import connect_sockets
|
||||
from math import hypot, inf
|
||||
from bpy.app.translations import pgettext_tip as tip_
|
||||
|
||||
|
||||
def force_update(context):
|
||||
@ -214,12 +215,15 @@ def nw_check_selected(cls, context, min=1, max=inf):
|
||||
num_selected = len(context.selected_nodes)
|
||||
if num_selected < min:
|
||||
if min > 1:
|
||||
cls.poll_message_set(f"At least {min} nodes must be selected.")
|
||||
poll_message = tip_("At least {:s} nodes must be selected.").format(min)
|
||||
else:
|
||||
cls.poll_message_set(f"At least {min} node must be selected.")
|
||||
poll_message = tip_("At least one node must be selected.")
|
||||
cls.poll_message_set(poll_message)
|
||||
return False
|
||||
if num_selected > max:
|
||||
cls.poll_message_set(f"{num_selected} nodes are selected, but this operator can only work on {max}.")
|
||||
poll_message = tip_("{:s} nodes are selected, but this operator can only work on {:s}.").format(
|
||||
num_selected, max)
|
||||
cls.poll_message_set(poll_message)
|
||||
return False
|
||||
return True
|
||||
|
||||
@ -227,18 +231,21 @@ def nw_check_selected(cls, context, min=1, max=inf):
|
||||
def nw_check_space_type(cls, context, types):
|
||||
if context.space_data.tree_type not in types:
|
||||
tree_types_str = ", ".join(t.split('NodeTree')[0].lower() for t in sorted(types))
|
||||
cls.poll_message_set("Current node tree type not supported.\n"
|
||||
"Should be one of " + tree_types_str + ".")
|
||||
poll_message = tip_("Current node tree type not supported.\n"
|
||||
"Should be one of {:s}.").format(tree_types_str)
|
||||
cls.poll_message_set(poll_message)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def nw_check_node_type(cls, context, type, invert=False):
|
||||
if invert and context.active_node.type == type:
|
||||
cls.poll_message_set(f"Active node should be not of type {type}.")
|
||||
poll_message = tip_("Active node should not be of type {:s}.").format(type)
|
||||
cls.poll_message_set(poll_message)
|
||||
return False
|
||||
elif not invert and context.active_node.type != type:
|
||||
cls.poll_message_set(f"Active node should be of type {type}.")
|
||||
poll_message = tip_("Active node should be of type {:s}.").format(type)
|
||||
cls.poll_message_set(poll_message)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
@ -377,8 +377,8 @@ class POSELIB_OT_pose_asset_select_bones(PoseAssetUser, Operator):
|
||||
@classmethod
|
||||
def description(cls, _context: Context, properties: 'POSELIB_OT_pose_asset_select_bones') -> str:
|
||||
if properties.select:
|
||||
return cls.bl_description
|
||||
return cls.bl_description.replace("Select", "Deselect")
|
||||
return tip_(cls.bl_description)
|
||||
return tip_("Deselect those bones that are used in this pose")
|
||||
|
||||
|
||||
class POSELIB_OT_convert_old_poselib(Operator):
|
||||
|
@ -207,11 +207,11 @@ def description_from_data_path(base, data_path, *, prefix, value=Ellipsis):
|
||||
|
||||
if (
|
||||
(rna_prop := context_path_to_rna_property(base, data_path)) and
|
||||
(description := iface_(rna_prop.description))
|
||||
(description := tip_(rna_prop.description))
|
||||
):
|
||||
description = iface_("{:s}: {:s}").format(prefix, description)
|
||||
description = tip_("{:s}: {:s}").format(prefix, description)
|
||||
if value != Ellipsis:
|
||||
description = "{:s}\n{:s}: {:s}".format(description, iface_("Value"), str(value))
|
||||
description = "{:s}\n{:s}: {:s}".format(description, tip_("Value"), str(value))
|
||||
return description
|
||||
return None
|
||||
|
||||
@ -288,7 +288,7 @@ class WM_OT_context_set_boolean(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Assign"), value=props.value)
|
||||
|
||||
execute = execute_context_assign
|
||||
|
||||
@ -309,7 +309,7 @@ class WM_OT_context_set_int(Operator): # same as enum
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Assign"), value=props.value)
|
||||
|
||||
execute = execute_context_assign
|
||||
|
||||
@ -329,7 +329,7 @@ class WM_OT_context_scale_float(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Scale"), value=props.value)
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Scale"), value=props.value)
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
@ -367,7 +367,7 @@ class WM_OT_context_scale_int(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Scale"), value=props.value)
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Scale"), value=props.value)
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
@ -411,7 +411,7 @@ class WM_OT_context_set_float(Operator): # same as enum
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Assign"), value=props.value)
|
||||
|
||||
execute = execute_context_assign
|
||||
|
||||
@ -431,7 +431,7 @@ class WM_OT_context_set_string(Operator): # same as enum
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Assign"), value=props.value)
|
||||
|
||||
execute = execute_context_assign
|
||||
|
||||
@ -451,7 +451,7 @@ class WM_OT_context_set_enum(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Assign"), value=props.value)
|
||||
|
||||
execute = execute_context_assign
|
||||
|
||||
@ -471,7 +471,7 @@ class WM_OT_context_set_value(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Assign"), value=props.value)
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
@ -495,7 +495,7 @@ class WM_OT_context_toggle(Operator):
|
||||
# Currently unsupported, it might be possible to extract this.
|
||||
if props.module:
|
||||
return None
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Toggle"))
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Toggle"))
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
@ -536,7 +536,7 @@ class WM_OT_context_toggle_enum(Operator):
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
value = "({!r}, {!r})".format(props.value_1, props.value_2)
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Toggle"), value=value)
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Toggle"), value=value)
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
@ -575,7 +575,7 @@ class WM_OT_context_cycle_int(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Cycle"))
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
@ -615,7 +615,7 @@ class WM_OT_context_cycle_enum(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Cycle"))
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
@ -664,7 +664,7 @@ class WM_OT_context_cycle_array(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Cycle"))
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
@ -693,7 +693,7 @@ class WM_OT_context_menu_enum(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Menu"))
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Menu"))
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.data_path
|
||||
@ -724,7 +724,7 @@ class WM_OT_context_pie_enum(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Pie Menu"))
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Pie Menu"))
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
@ -765,7 +765,7 @@ class WM_OT_operator_pie_enum(Operator):
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, props):
|
||||
return description_from_data_path(context, props.data_path, prefix=iface_("Pie Menu"))
|
||||
return description_from_data_path(context, props.data_path, prefix=tip_("Pie Menu"))
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
|
@ -6814,7 +6814,7 @@ static void get_default_texture_layer_name_for_object(Object *ob,
|
||||
{
|
||||
Material *ma = BKE_object_material_get(ob, ob->actcol);
|
||||
const char *base_name = ma ? &ma->id.name[2] : &ob->id.name[2];
|
||||
BLI_snprintf(dst, dst_maxncpy, "%s %s", base_name, layer_type_items[texture_type].name);
|
||||
BLI_snprintf(dst, dst_maxncpy, "%s %s", base_name, DATA_(layer_type_items[texture_type].name));
|
||||
}
|
||||
|
||||
static int texture_paint_add_texture_paint_slot_invoke(bContext *C,
|
||||
|
Loading…
Reference in New Issue
Block a user