Add the possibility to define the translation context for py rna classes (operators...
authorBastien Montagne <montagne29@wanadoo.fr>
Fri, 15 Mar 2013 14:32:29 +0000 (14:32 +0000)
committerBastien Montagne <montagne29@wanadoo.fr>
Fri, 15 Mar 2013 14:32:29 +0000 (14:32 +0000)
Thanks to Campell and Brecht for the reviews!

source/blender/blenfont/BLF_translation.h
source/blender/blenfont/intern/blf_translation.c
source/blender/blenkernel/BKE_screen.h
source/blender/editors/interface/interface_layout.c
source/blender/editors/interface/interface_panel.c
source/blender/makesrna/intern/rna_ui.c
source/blender/makesrna/intern/rna_wm.c
source/blender/python/intern/bpy_operator_wrap.c
source/blender/python/intern/bpy_rna.c
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm_operators.c

index 2f40cc3f57157d7e29d02f032ddb1dc5b76dcc63..db449995b8fcf89c3ee5bf1decd7fa85c3a0bbe1 100644 (file)
@@ -110,12 +110,14 @@ const char *BLF_translate_do_tooltip(const char *msgctxt, const char *msgid);
  * All i18n contexts must be defined here.
  * This is a nice way to be sure not to use a context twice for different
  * things, and limit the number of existing contexts!
+ * WARNING! Contexts should not be longer than BKE_ST_MAXNAME - 1!
  */
 
 /* Default, void context.
  * WARNING! The "" context is not the same as no (NULL) context at mo/boost::locale level!
  * NOTE: We translate BLF_I18NCONTEXT_DEFAULT as BLF_I18NCONTEXT_DEFAULT_BPY in Python, as we can't use "natural"
  *       None value in rna string properties... :/
+ *       The void string "" is also interpreted as BLF_I18NCONTEXT_DEFAULT.
  *       For perf reason, we only use the first char to detect this context, so other contexts should never start
  *       with the same char!
  */
index 2483c59d3ecd0952970cb19683e087d45a4525a9..4e9408c512a3a9bfd8389fa0e1111071cc3ef363 100644 (file)
@@ -132,7 +132,7 @@ const char *BLF_pgettext(const char *msgctxt, const char *msgid)
 
        if (msgid && msgid[0]) {
                /*if (msgctxt && !strcmp(msgctxt, BLF_I18NCONTEXT_DEFAULT_BPY_INTERN)) { */
-               if (msgctxt && msgctxt[0] == BLF_I18NCONTEXT_DEFAULT_BPY[0]) {
+               if (msgctxt && (!msgctxt[0] || msgctxt[0] == BLF_I18NCONTEXT_DEFAULT_BPY[0])) {
                        /* BLF_I18NCONTEXT_DEFAULT_BPY context is reserved and considered the same as default NULL one. */
                        msgctxt = BLF_I18NCONTEXT_DEFAULT;
                }
index 629acab9e347dce0bf39cd1e1c48ca20e396f683..f1a169c4fac91a7e40f792a94184a0d2908a0513 100644 (file)
@@ -163,9 +163,10 @@ typedef struct ARegionType {
 typedef struct PanelType {
        struct PanelType *next, *prev;
        
-       char idname[BKE_ST_MAXNAME];            /* unique name */
-       char label[BKE_ST_MAXNAME];             /* for panel header */
-       char context[BKE_ST_MAXNAME];           /* for buttons window */
+       char idname[BKE_ST_MAXNAME];              /* unique name */
+       char label[BKE_ST_MAXNAME];               /* for panel header */
+       char translation_context[BKE_ST_MAXNAME];
+       char context[BKE_ST_MAXNAME];             /* for buttons window */
        int space_type;
        int region_type;
 
@@ -227,7 +228,8 @@ typedef struct MenuType {
 
        char idname[BKE_ST_MAXNAME];        /* unique name */
        char label[BKE_ST_MAXNAME];         /* for button text */
-       char       *description;
+       char translation_context[BKE_ST_MAXNAME];
+       char *description;
 
        /* verify if the menu should draw or not */
        int (*poll)(const struct bContext *, struct MenuType *);
index 1e95b4df7624e1680ac33a640ce8f1608f61d0dc..ea6ecadd924b7b3da190916ec514a763e0877eba 100644 (file)
@@ -1567,7 +1567,7 @@ void uiItemM(uiLayout *layout, bContext *UNUSED(C), const char *menuname, const
        }
 
        if (!name) {
-               name = IFACE_(mt->label);
+               name = CTX_IFACE_(mt->translation_context, mt->label);
        }
 
        if (layout->root->type == UI_LAYOUT_MENU && !icon)
index e466c4811514da1af8941b8774a9434e48a9ee94..a741ea432a50c3488991d069afb7f05c41b21ea2 100644 (file)
@@ -191,7 +191,7 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar)
 Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, int *open)
 {
        Panel *pa, *patab, *palast, *panext;
-       char *drawname = pt->label;
+       const char *drawname = CTX_IFACE_(pt->translation_context, pt->label);
        char *idname = pt->idname;
        char *tabname = pt->idname;
        char *hookname = NULL;
@@ -469,7 +469,7 @@ static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, rcti *r
        Panel *panel = block->panel;
        rcti hrect;
        int pnl_icons;
-       const char *activename = IFACE_(panel->drawname[0] ? panel->drawname : panel->panelname);
+       const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname;
 
        /* + 0.001f to avoid flirting with float inaccuracy */
        if (panel->control & UI_PNL_CLOSE) pnl_icons = (panel->labelofs + 2 * PNL_ICON + 5) / block->aspect + 0.001f;
index e5585b4f72d6f3c04f7aebc5a25b4eb0b1388d44..05056574a719857a344cf9bb5817cba14182d5a5 100644 (file)
@@ -29,6 +29,8 @@
 
 #include "DNA_screen_types.h"
 
+#include "BLF_translation.h"
+
 #include "RNA_define.h"
 
 #include "rna_internal.h"
@@ -226,6 +228,7 @@ static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *dat
        memcpy(pt, &dummypt, sizeof(dummypt));
 
        pt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, pt->idname, &RNA_Panel);
+       RNA_def_struct_translation_context(pt->ext.srna, pt->translation_context);
        pt->ext.data = data;
        pt->ext.call = call;
        pt->ext.free = free;
@@ -573,6 +576,7 @@ static StructRNA *rna_Menu_register(Main *bmain, ReportList *reports, void *data
        }
 
        mt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, mt->idname, &RNA_Menu);
+       RNA_def_struct_translation_context(mt->ext.srna, mt->translation_context);
        mt->ext.data = data;
        mt->ext.call = call;
        mt->ext.free = free;
@@ -773,6 +777,7 @@ static void rna_def_panel(BlenderRNA *brna)
        RNA_def_struct_sdna(srna, "Panel");
        RNA_def_struct_refine_func(srna, "rna_Panel_refine");
        RNA_def_struct_register_funcs(srna, "rna_Panel_register", "rna_Panel_unregister", NULL);
+       RNA_def_struct_translation_context(srna, BLF_I18NCONTEXT_DEFAULT);
 
        /* poll */
        func = RNA_def_function(srna, "poll", NULL);
@@ -819,7 +824,13 @@ static void rna_def_panel(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Label",
                                 "The panel label, shows up in the panel header at the right of the "
                                 "triangle used to collapse the panel");
-       
+
+       prop = RNA_def_property(srna, "bl_translation_context", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_sdna(prop, NULL, "type->translation_context");
+       RNA_def_property_string_default(prop, BLF_I18NCONTEXT_DEFAULT);
+       RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+       RNA_define_verify_sdna(TRUE);
+
        prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_sdna(prop, NULL, "type->space_type");
        RNA_def_property_enum_items(prop, space_type_items);
@@ -956,6 +967,7 @@ static void rna_def_menu(BlenderRNA *brna)
        RNA_def_struct_sdna(srna, "Menu");
        RNA_def_struct_refine_func(srna, "rna_Menu_refine");
        RNA_def_struct_register_funcs(srna, "rna_Menu_register", "rna_Menu_unregister", NULL);
+       RNA_def_struct_translation_context(srna, BLF_I18NCONTEXT_DEFAULT);
 
        /* poll */
        func = RNA_def_function(srna, "poll", NULL);
@@ -972,7 +984,7 @@ static void rna_def_menu(BlenderRNA *brna)
        parm = RNA_def_pointer(func, "context", "Context", "", "");
        RNA_def_property_flag(parm, PROP_REQUIRED);
 
-       RNA_define_verify_sdna(0); /* not in sdna */
+       RNA_define_verify_sdna(FALSE); /* not in sdna */
 
        prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE);
        RNA_def_property_pointer_sdna(prop, NULL, "layout");
@@ -994,6 +1006,11 @@ static void rna_def_menu(BlenderRNA *brna)
        RNA_def_property_flag(prop, PROP_REGISTER);
        RNA_def_property_ui_text(prop, "Label", "The menu label");
 
+       prop = RNA_def_property(srna, "bl_translation_context", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_sdna(prop, NULL, "type->translation_context");
+       RNA_def_property_string_default(prop, BLF_I18NCONTEXT_DEFAULT);
+       RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
        prop = RNA_def_property(srna, "bl_description", PROP_STRING, PROP_NONE);
        RNA_def_property_string_sdna(prop, NULL, "type->description");
        RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */
index 9a160d8bb1e670927af5bb2fe8eff1cbbb2842d3..0dd95d17260e240769de3536903163858fe90f2f 100644 (file)
@@ -33,6 +33,8 @@
 
 #include "BLI_utildefines.h"
 
+#include "BLF_translation.h"
+
 #include "RNA_access.h"
 #include "RNA_define.h"
 #include "RNA_enum_types.h"
@@ -1050,6 +1052,7 @@ void macro_wrapper(wmOperatorType *ot, void *userdata);
 static char _operator_idname[OP_MAX_TYPENAME];
 static char _operator_name[OP_MAX_TYPENAME];
 static char _operator_descr[RNA_DYN_DESCR_MAX];
+static char _operator_ctxt[RNA_DYN_DESCR_MAX];
 static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
                                         StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
 {
@@ -1063,10 +1066,11 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
        dummyot.idname = _operator_idname; /* only assigne the pointer, string is NULL'd */
        dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
        dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
+       dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
        RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr);
 
        /* clear in case they are left unset */
-       _operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0';
+       _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_ctxt[0] = '\0';
 
        /* validate the python class */
        if (validate(&dummyotr, data, have_function) != 0)
@@ -1117,9 +1121,10 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
                        int idlen = strlen(_operator_idname) + 4;
                        int namelen = strlen(_operator_name) + 1;
                        int desclen = strlen(_operator_descr) + 1;
+                       int ctxtlen = strlen(_operator_ctxt) + 1;
                        char *ch;
                        /* 2 terminators and 3 to convert a.b -> A_OT_b */
-                       ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen), "_operator_idname");
+                       ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname");
                        WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
                        dummyot.idname = ch;
                        ch += idlen;
@@ -1128,6 +1133,9 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
                        ch += namelen;
                        strcpy(ch, _operator_descr);
                        dummyot.description = ch;
+                       ch += desclen;
+                       strcpy(ch, _operator_ctxt);
+                       dummyot.translation_context = ch;
                }
        }
 
@@ -1144,6 +1152,7 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *
        /* create a new operator type */
        dummyot.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummyot.idname, &RNA_Operator);
        RNA_def_struct_flag(dummyot.ext.srna, STRUCT_NO_IDPROPERTIES); /* operator properties are registered separately */
+       RNA_def_struct_translation_context(dummyot.ext.srna, dummyot.translation_context);
        dummyot.ext.data = data;
        dummyot.ext.call = call;
        dummyot.ext.free = free;
@@ -1182,6 +1191,7 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
        dummyot.idname = _operator_idname; /* only assigne the pointer, string is NULL'd */
        dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */
        dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */
+       dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */
        RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr);
 
        /* validate the python class */
@@ -1193,9 +1203,10 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
                int idlen = strlen(_operator_idname) + 4;
                int namelen = strlen(_operator_name) + 1;
                int desclen = strlen(_operator_descr) + 1;
+               int ctxtlen = strlen(_operator_ctxt) + 1;
                char *ch;
                /* 2 terminators and 3 to convert a.b -> A_OT_b */
-               ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen), "_operator_idname");
+               ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname");
                WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */
                dummyot.idname = ch;
                ch += idlen;
@@ -1204,6 +1215,9 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
                ch += namelen;
                strcpy(ch, _operator_descr);
                dummyot.description = ch;
+               ch += desclen;
+               strcpy(ch, _operator_ctxt);
+               dummyot.translation_context = ch;
        }
 
        if (strlen(identifier) >= sizeof(dummyop.idname)) {
@@ -1224,6 +1238,7 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v
 
        /* create a new operator type */
        dummyot.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummyot.idname, &RNA_Operator);
+       RNA_def_struct_translation_context(dummyot.ext.srna, dummyot.translation_context);
        dummyot.ext.data = data;
        dummyot.ext.call = call;
        dummyot.ext.free = free;
@@ -1273,6 +1288,16 @@ static void rna_Operator_bl_label_set(PointerRNA *ptr, const char *value)
                assert(!"setting the bl_label on a non-builtin operator");
 }
 
+static void rna_Operator_bl_translation_context_set(PointerRNA *ptr, const char *value)
+{
+       wmOperator *data = (wmOperator *)(ptr->data);
+       char *str = (char *)data->type->translation_context;
+       if (!str[0])
+               BLI_strncpy(str, value, RNA_DYN_DESCR_MAX);    /* utf8 already ensured */
+       else
+               assert(!"setting the bl_translation_context on a non-builtin operator");
+}
+
 static void rna_Operator_bl_description_set(PointerRNA *ptr, const char *value)
 {
        wmOperator *data = (wmOperator *)(ptr->data);
@@ -1303,6 +1328,7 @@ static void rna_def_operator(BlenderRNA *brna)
 #ifdef WITH_PYTHON
        RNA_def_struct_register_funcs(srna, "rna_Operator_register", "rna_Operator_unregister", "rna_Operator_instance");
 #endif
+       RNA_def_struct_translation_context(srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
 
        prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1341,6 +1367,14 @@ static void rna_def_operator(BlenderRNA *brna)
        /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
        RNA_def_property_flag(prop, PROP_REGISTER);
 
+       prop = RNA_def_property(srna, "bl_translation_context", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_sdna(prop, NULL, "type->translation_context");
+       RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */
+       RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_translation_context_set");
+       RNA_def_property_string_default(prop, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
+       RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+       RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+
        prop = RNA_def_property(srna, "bl_description", PROP_STRING, PROP_NONE);
        RNA_def_property_string_sdna(prop, NULL, "type->description");
        RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */
@@ -1377,6 +1411,7 @@ static void rna_def_macro_operator(BlenderRNA *brna)
        RNA_def_struct_register_funcs(srna, "rna_MacroOperator_register", "rna_Operator_unregister",
                                      "rna_Operator_instance");
 #endif
+       RNA_def_struct_translation_context(srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
 
        prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1405,6 +1440,14 @@ static void rna_def_macro_operator(BlenderRNA *brna)
        /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
        RNA_def_property_flag(prop, PROP_REGISTER);
 
+       prop = RNA_def_property(srna, "bl_translation_context", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_sdna(prop, NULL, "type->translation_context");
+       RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */
+       RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_translation_context_set");
+       RNA_def_property_string_default(prop, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
+       RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+       RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */
+
        prop = RNA_def_property(srna, "bl_description", PROP_STRING, PROP_NONE);
        RNA_def_property_string_sdna(prop, NULL, "type->description");
        RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */
index 9d92ff512132e8c03e7c43c3333f3e7c4f32f3af..1c7222434248e30755c07d15aa3656123e6a8dbe 100644 (file)
@@ -127,6 +127,11 @@ void operator_wrapper(wmOperatorType *ot, void *userdata)
        *ot = *((wmOperatorType *)userdata);
        ot->srna = srna; /* restore */
 
+       /* Use i18n context from ext.srna if possible (py operators). */
+       if (ot->ext.srna) {
+               RNA_def_struct_translation_context(ot->srna, RNA_struct_translation_context(ot->ext.srna));
+       }
+
        operator_properties_init(ot);
 }
 
@@ -143,6 +148,11 @@ void macro_wrapper(wmOperatorType *ot, void *userdata)
        ot->ui = data->ui;
        ot->ext = data->ext;
 
+       /* Use i18n context from ext.srna if possible (py operators). */
+       if (ot->ext.srna) {
+               RNA_def_struct_translation_context(ot->srna, RNA_struct_translation_context(ot->ext.srna));
+       }
+
        operator_properties_init(ot);
 }
 
index bdb2f8fcc1262481287b61f275bb8a1a9d53b5c1..0adb5e2e90ecf2cb449115fc83b1293ffb860088 100644 (file)
@@ -6950,7 +6950,7 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr, StructRNA *srna, v
                        }                                                                 \
                }                                                                     \
                Py_XDECREF(item);                                                     \
-       }  /* intendionally allow else here */
+       }  /* intentionally allow else here */
 
                        if      BPY_REPLACEMENT_STRING("bl_idname",      bpy_intern_str___name__)
                        else if BPY_REPLACEMENT_STRING("bl_description", bpy_intern_str___doc__)
index f2750aa6d99385e732f915e35df7a308e9b0ff10..5c2aae11a60d2150461d1ff2b4a91a4fbcdc9189 100644 (file)
@@ -512,6 +512,7 @@ typedef struct wmTimer {
 typedef struct wmOperatorType {
        const char *name;               /* text for ui, undo */
        const char *idname;             /* unique identifier */
+       const char *translation_context;
        const char *description;        /* tooltips and python docs */
 
        /* this callback executes the operator without any interactive input,
index cb2caa52d15230971a6dd8945d55729c560b9e91..8ea507f97e8cc4cbf8ff4c7707bacbf782f2b380 100644 (file)
@@ -381,7 +381,9 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
        
        RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
        RNA_def_struct_identifier(ot->srna, ot->idname);
-       RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
+       /* Use i18n context from ext.srna if possible (py operators). */
+       RNA_def_struct_translation_context(ot->srna, ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) :
+                                                                   BLF_I18NCONTEXT_OPERATOR_DEFAULT);
 
        BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);