diff --git a/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/scripts/modules/bl_i18n_utils/bl_extract_messages.py index 634572d0bdc..b49401c6d53 100644 --- a/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -573,6 +573,7 @@ def dump_py_messages_from_files(msgs, reports, files, settings): ("pgettext", ("_",)), ("pgettext_iface", ("iface_",)), ("pgettext_tip", ("tip_",)), + ("pgettext_rpt", ("rpt_",)), ("pgettext_data", ("data_",)), ) pgettext_variants_args = {"msgid": (0, {"msgctxt": 1})} diff --git a/scripts/modules/bl_i18n_utils/settings.py b/scripts/modules/bl_i18n_utils/settings.py index bec1240a7ee..1f0515c3e3e 100644 --- a/scripts/modules/bl_i18n_utils/settings.py +++ b/scripts/modules/bl_i18n_utils/settings.py @@ -243,10 +243,10 @@ _ctxt_re = _ctxt_re_gen("") _msg_re = r"(?P" + _str_whole_re.format(_="_msg") + r")" PYGETTEXT_KEYWORDS = (() + tuple((r"{}\(\s*" + _msg_re + r"\s*\)").format(it) - for it in ("IFACE_", "TIP_", "DATA_", "N_")) + + for it in ("IFACE_", "TIP_", "RPT_", "DATA_", "N_")) + tuple((r"{}\(\s*" + _ctxt_re + r"\s*,\s*" + _msg_re + r"\s*\)").format(it) - for it in ("CTX_IFACE_", "CTX_TIP_", "CTX_DATA_", "CTX_N_")) + + for it in ("CTX_IFACE_", "CTX_TIP_", "CTX_RPT_", "CTX_DATA_", "CTX_N_")) + tuple(("{}\\((?:[^\"',]+,){{1,2}}\\s*" + _msg_re + r"\s*(?:\)|,)").format(it) for it in ("BKE_report", "BKE_reportf", "BKE_reports_prepend", "BKE_reports_prependf", diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index 4dc7e4eb79a..f845cde10f2 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -260,6 +260,7 @@ class USERPREF_PT_interface_translation(InterfacePanel, CenterAlignMixIn, Panel) col.active = (bpy.app.translations.locale != "en_US") col.prop(view, "use_translate_tooltips", text="Tooltips") col.prop(view, "use_translate_interface", text="Interface") + col.prop(view, "use_translate_reports", text="Reports") col.prop(view, "use_translate_new_dataname", text="New Data") diff --git a/source/blender/blenloader/intern/versioning_userdef.cc b/source/blender/blenloader/intern/versioning_userdef.cc index e092fd5a9c7..884b0dce164 100644 --- a/source/blender/blenloader/intern/versioning_userdef.cc +++ b/source/blender/blenloader/intern/versioning_userdef.cc @@ -494,8 +494,8 @@ void blo_do_versions_userdef(UserDef *userdef) USER_FLAG_UNUSED_6 | USER_FLAG_UNUSED_7 | USER_FLAG_UNUSED_9 | USER_DEVELOPER_UI); userdef->uiflag &= ~(USER_HEADER_BOTTOM); - userdef->transopts &= ~(USER_TR_UNUSED_2 | USER_TR_UNUSED_3 | USER_TR_UNUSED_4 | - USER_TR_UNUSED_6 | USER_TR_UNUSED_7); + userdef->transopts &= ~(USER_TR_UNUSED_3 | USER_TR_UNUSED_4 | USER_TR_UNUSED_6 | + USER_TR_UNUSED_7); userdef->uiflag |= USER_LOCK_CURSOR_ADJUST; } diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h index 6104d0abde9..ccdd69ed278 100644 --- a/source/blender/blentranslation/BLT_translation.h +++ b/source/blender/blentranslation/BLT_translation.h @@ -19,14 +19,21 @@ extern "C" { bool BLT_is_default_context(const char *msgctxt); const char *BLT_pgettext(const char *msgctxt, const char *msgid); -/* translation */ +/* Translation */ +/* - iface includes buttons in the user interface: short labels displayed in windows, panels, + * menus. + * - tooltips only include the popup tooltips when hovering a button. + * - report is for longer, additional information displayed in the UI, such as error messages. + * - new_dataname is the actual user-created data such as objects, meshes, etc. */ bool BLT_translate(void); bool BLT_translate_iface(void); bool BLT_translate_tooltips(void); +bool BLT_translate_reports(void); bool BLT_translate_new_dataname(void); const char *BLT_translate_do(const char *msgctxt, const char *msgid); const char *BLT_translate_do_iface(const char *msgctxt, const char *msgid); const char *BLT_translate_do_tooltip(const char *msgctxt, const char *msgid); +const char *BLT_translate_do_report(const char *msgctxt, const char *msgid); const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid); /* The "translation-marker" macro. */ @@ -37,9 +44,11 @@ const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid /*# define _(msgid) BLT_gettext(msgid) */ #define IFACE_(msgid) BLT_translate_do_iface(NULL, msgid) #define TIP_(msgid) BLT_translate_do_tooltip(NULL, msgid) +#define RPT_(msgid) BLT_translate_do_report(NULL, msgid) #define DATA_(msgid) BLT_translate_do_new_dataname(NULL, msgid) #define CTX_IFACE_(context, msgid) BLT_translate_do_iface(context, msgid) #define CTX_TIP_(context, msgid) BLT_translate_do_tooltip(context, msgid) +#define CTX_RPT_(context, msgid) BLT_translate_do_report(context, msgid) #define CTX_DATA_(context, msgid) BLT_translate_do_new_dataname(context, msgid) /* Helper macro, when we want to define a same msgid for multiple msgctxt... diff --git a/source/blender/blentranslation/intern/blt_translation.cc b/source/blender/blentranslation/intern/blt_translation.cc index e6779b305e5..b7e9cf38094 100644 --- a/source/blender/blentranslation/intern/blt_translation.cc +++ b/source/blender/blentranslation/intern/blt_translation.cc @@ -90,6 +90,15 @@ bool BLT_translate_tooltips() #endif } +bool BLT_translate_reports() +{ +#ifdef WITH_INTERNATIONAL + return BLT_translate() && (U.transopts & USER_TR_REPORTS); +#else + return false; +#endif +} + bool BLT_translate_new_dataname() { #ifdef WITH_INTERNATIONAL @@ -144,6 +153,21 @@ const char *BLT_translate_do_tooltip(const char *msgctxt, const char *msgid) #endif } +const char *BLT_translate_do_report(const char *msgctxt, const char *msgid) +{ +#ifdef WITH_INTERNATIONAL + if (BLT_translate_reports()) { + return BLT_pgettext(msgctxt, msgid); + } + + return msgid; + +#else + (void)msgctxt; + return msgid; +#endif +} + const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid) { #ifdef WITH_INTERNATIONAL diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 1e13bb3f95c..15eeac0be6e 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1323,7 +1323,7 @@ typedef enum eUserpref_Anim_Flags { typedef enum eUserpref_Translation_Flags { USER_TR_TOOLTIPS = (1 << 0), USER_TR_IFACE = (1 << 1), - USER_TR_UNUSED_2 = (1 << 2), /* cleared */ + USER_TR_REPORTS = (1 << 2), USER_TR_UNUSED_3 = (1 << 3), /* cleared */ USER_TR_UNUSED_4 = (1 << 4), /* cleared */ USER_DOTRANSLATE_DEPRECATED = (1 << 5), /* Deprecated in 2.83. */ diff --git a/source/blender/makesrna/intern/rna_userdef.cc b/source/blender/makesrna/intern/rna_userdef.cc index b1ae943a097..992a79a6039 100644 --- a/source/blender/makesrna/intern/rna_userdef.cc +++ b/source/blender/makesrna/intern/rna_userdef.cc @@ -330,10 +330,10 @@ static void rna_userdef_language_update(Main * /*bmain*/, Scene * /*scene*/, Poi const char *uilng = BLT_lang_get(); if (STREQ(uilng, "en_US")) { - U.transopts &= ~(USER_TR_IFACE | USER_TR_TOOLTIPS | USER_TR_NEWDATANAME); + U.transopts &= ~(USER_TR_IFACE | USER_TR_TOOLTIPS | USER_TR_REPORTS | USER_TR_NEWDATANAME); } else { - U.transopts |= (USER_TR_IFACE | USER_TR_TOOLTIPS | USER_TR_NEWDATANAME); + U.transopts |= (USER_TR_IFACE | USER_TR_TOOLTIPS | USER_TR_REPORTS | USER_TR_NEWDATANAME); } USERDEF_TAG_DIRTY; @@ -5196,6 +5196,12 @@ static void rna_def_userdef_view(BlenderRNA *brna) "(note that this might make it hard to follow tutorials or the manual)"); RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "use_translate_reports", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "transopts", USER_TR_REPORTS); + RNA_def_property_ui_text( + prop, "Translate Reports", "Translate additional information, such as error messages"); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "use_translate_new_dataname", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, nullptr, "transopts", USER_TR_NEWDATANAME); RNA_def_property_ui_text(prop, diff --git a/source/blender/python/intern/bpy_app_translations.cc b/source/blender/python/intern/bpy_app_translations.cc index eb74714d611..5ba843ff8df 100644 --- a/source/blender/python/intern/bpy_app_translations.cc +++ b/source/blender/python/intern/bpy_app_translations.cc @@ -646,6 +646,29 @@ static PyObject *app_translations_pgettext_tip(BlenderAppTranslations * /*self*/ return _py_pgettext(args, kw, BLT_translate_do_tooltip); } +PyDoc_STRVAR( + app_translations_pgettext_rpt_doc, + ".. method:: pgettext_rpt(msgid, msgctxt=None)\n" + "\n" + " Try to translate the given msgid (with optional msgctxt), if reports' translation " + "is enabled.\n" + "\n" + " .. note::\n" + " See :func:`pgettext` notes.\n" + "\n" + " :arg msgid: The string to translate.\n" + " :type msgid: string\n" + " :arg msgctxt: The translation context (defaults to BLT_I18NCONTEXT_DEFAULT).\n" + " :type msgctxt: string or None\n" + " :return: The translated string (or msgid if no translation was found).\n" + "\n"); +static PyObject *app_translations_pgettext_rpt(BlenderAppTranslations * /*self*/, + PyObject *args, + PyObject *kw) +{ + return _py_pgettext(args, kw, BLT_translate_do_report); +} + PyDoc_STRVAR(app_translations_pgettext_data_doc, ".. method:: pgettext_data(msgid, msgctxt=None)\n" "\n" @@ -740,6 +763,10 @@ static PyMethodDef app_translations_methods[] = { (PyCFunction)app_translations_pgettext_tip, METH_VARARGS | METH_KEYWORDS | METH_STATIC, app_translations_pgettext_tip_doc}, + {"pgettext_rpt", + (PyCFunction)app_translations_pgettext_rpt, + METH_VARARGS | METH_KEYWORDS | METH_STATIC, + app_translations_pgettext_rpt_doc}, {"pgettext_data", (PyCFunction)app_translations_pgettext_data, METH_VARARGS | METH_KEYWORDS | METH_STATIC, diff --git a/tools/utils_api/bpy_introspect_ui.py b/tools/utils_api/bpy_introspect_ui.py index db3a5f650bc..df7c89491c3 100644 --- a/tools/utils_api/bpy_introspect_ui.py +++ b/tools/utils_api/bpy_introspect_ui.py @@ -322,6 +322,7 @@ def fake_main(): bpy.app.translations = module_add("bpy.app.translations") bpy.app.translations.pgettext_iface = lambda s, context="": s bpy.app.translations.pgettext_data = lambda s: s + bpy.app.translations.pgettext_report = lambda s: s bpy.app.translations.pgettext_tip = lambda s: s # id's are chosen at random here... bpy.app.translations.contexts = module_add("bpy.app.translations.contexts")