Actually, UI scripts should not use directly pgettext, but rather the iface or tooltip variants. Added those to bpy.app.translations, and used pgettext_iface.

(Did not add those when I created that module, because I did not thought we would actually need them in usual UI code, but turned out I was wrong).

Also made some optimizations in those py gettext funcs, when i18n is disabled at build time, no need to do pyobject -> cstring -> pyobject conversions!.
This commit is contained in:
Bastien Montagne 2013-02-10 10:29:38 +00:00
parent 3b8a0f3d67
commit d0f4a2396b
11 changed files with 106 additions and 57 deletions

@ -19,8 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Panel
from bpy.app.translations import pgettext as _
from bpy.app.translations import pgettext_iface as iface_
class ModifierButtonsPanel():
@ -267,7 +266,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
layout.prop(md, "angle_limit")
layout.prop(md, "use_dissolve_boundaries")
layout.label(text=_("Face Count: %d") % md.face_count, translate=False)
layout.label(text=iface_("Face Count: %d") % md.face_count, translate=False)
def DISPLACE(self, layout, ob, md):
has_texture = (md.texture is not None)

@ -20,8 +20,7 @@
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
from bpy.app.translations import pgettext as _
from bpy.app.translations import pgettext_iface as iface_
def active_node_mat(mat):
@ -82,7 +81,7 @@ class MATERIAL_UL_matslots(UIList):
if ma and not context.scene.render.use_shading_nodes:
manode = ma.active_node_material
if manode:
layout.label(text=_("Node %s") % manode.name, translate=False, icon_value=layout.icon(manode))
layout.label(text=iface_("Node %s") % manode.name, translate=False, icon_value=layout.icon(manode))
elif ma.use_nodes:
layout.label(text="Node <none>")
else:

@ -20,8 +20,7 @@
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
from bpy.app.translations import pgettext as _
from bpy.app.translations import pgettext_iface as iface_
from bl_ui.properties_physics_common import (point_cache_ui,
effector_weights_ui,
@ -150,7 +149,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
#row.label(text="Render")
if part.is_fluid:
layout.label(text=_("%d fluid particles for this frame") % part.count, translate=False)
layout.label(text=iface_("%d fluid particles for this frame") % part.count, translate=False)
return
row = col.row()

@ -19,8 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Panel, Menu
from bpy.app.translations import pgettext as _
from bpy.app.translations import pgettext_iface as iface_
class FLUID_MT_presets(Menu):
@ -66,7 +65,7 @@ class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel):
if fluid.type == 'DOMAIN':
# odd formatting here so translation script can extract string
layout.operator("fluid.bake", text=_("Bake (Req. Memory: %s)") % fluid.memory_estimate,
layout.operator("fluid.bake", text=iface_("Bake (Req. Memory: %s)") % fluid.memory_estimate,
translate=False, icon='MOD_FLUIDSIM')
split = layout.split()

@ -20,8 +20,7 @@
import bpy
from bpy.types import Panel, Header, Menu, UIList
from bpy.app.translations import pgettext as _
from bpy.app.translations import pgettext_iface as iface_
class CLIP_UL_tracking_objects(UIList):
@ -913,9 +912,11 @@ class CLIP_MT_view(Menu):
ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
text = _("Zoom %d:%d")
text = iface_("Zoom %d:%d")
for a, b in ratios:
layout.operator("clip.view_zoom_ratio", text=text % (a, b), translate=False).ratio = a / b
layout.operator("clip.view_zoom_ratio",
text=text % (a, b),
translate=False).ratio = a / b
else:
if sc.view == 'GRAPH':
layout.operator_context = 'INVOKE_REGION_PREVIEW'

@ -20,8 +20,7 @@
import bpy
from bpy.types import Header, Menu, Panel
from bl_ui.properties_paint_common import UnifiedPaintPanel, brush_texture_settings
from bpy.app.translations import pgettext as _
from bpy.app.translations import pgettext_iface as iface_
class ImagePaintPanel(UnifiedPaintPanel):
@ -73,7 +72,7 @@ class IMAGE_MT_view(Menu):
ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
for a, b in ratios:
layout.operator("image.view_zoom_ratio", text=_("Zoom %d:%d") % (a, b), translate=False).ratio = a / b
layout.operator("image.view_zoom_ratio", text=iface_("Zoom %d:%d") % (a, b), translate=False).ratio = a / b
layout.separator()

@ -19,8 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext as _
from bpy.app.translations import pgettext_iface as iface_
def act_strip(context):
@ -424,13 +423,15 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel):
col = layout.column(align=True)
row = col.row()
row.label(text=_("Final Length: %s") % bpy.utils.smpte_from_frame(strip.frame_final_duration), translate=False)
row.label(text=iface_("Final Length: %s") % bpy.utils.smpte_from_frame(strip.frame_final_duration),
translate=False)
row = col.row()
row.active = (frame_current >= strip.frame_start and frame_current <= strip.frame_start + strip.frame_duration)
row.label(text=_("Playhead: %d") % (frame_current - strip.frame_start), translate=False)
row.label(text=iface_("Playhead: %d") % (frame_current - strip.frame_start), translate=False)
col.label(text=_("Frame Offset %d:%d") % (strip.frame_offset_start, strip.frame_offset_end), translate=False)
col.label(text=_("Frame Still %d:%d") % (strip.frame_still_start, strip.frame_still_end), translate=False)
col.label(text=iface_("Frame Offset %d:%d") % (strip.frame_offset_start, strip.frame_offset_end),
translate=False)
col.label(text=iface_("Frame Still %d:%d") % (strip.frame_still_start, strip.frame_still_end), translate=False)
elem = False
@ -440,7 +441,7 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel):
elem = strip.elements[0]
if elem and elem.orig_width > 0 and elem.orig_height > 0:
col.label(text=_("Original Dimension: %dx%d") % (elem.orig_width, elem.orig_height), translate=False)
col.label(text=iface_("Original Dimension: %dx%d") % (elem.orig_width, elem.orig_height), translate=False)
else:
col.label(text="Original Dimension: None")
@ -717,7 +718,7 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
if scene:
sta = scene.frame_start
end = scene.frame_end
layout.label(text=_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
@ -746,7 +747,7 @@ class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel):
if mask:
sta = mask.frame_start
end = mask.frame_end
layout.label(text=_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):

@ -19,8 +19,7 @@
# <pep8-80 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext as _
from bpy.app.translations import pgettext_iface as iface_
class TEXT_HT_header(Header):
@ -74,10 +73,10 @@ class TEXT_HT_header(Header):
row = layout.row()
if text.filepath:
if text.is_dirty:
row.label(text=_("File: *%r (unsaved)") %
row.label(text=iface_("File: *%r (unsaved)") %
text.filepath, translate=False)
else:
row.label(text=pgettext("File: %r") %
row.label(text=iface_("File: %r") %
text.filepath, translate=False)
else:
row.label(text="Text: External"

@ -19,8 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext as _
from bpy.app.translations import pgettext_iface as iface_
def ui_style_items(col, context):
@ -782,7 +781,7 @@ class USERPREF_PT_theme(Panel):
col = split.column()
for i, ui in enumerate(theme.bone_color_sets):
col.label(text=_("Color Set %d:") % (i + 1), translate=False) # i starts from 0
col.label(text=iface_("Color Set %d:") % (i + 1), translate=False) # i starts from 0
row = col.row()

@ -19,8 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Menu
from bpy.app.translations import pgettext as _
from bpy.app.translations import pgettext_iface as iface_
class USERPREF_MT_keyconfigs(Menu):
@ -99,7 +98,7 @@ class InputKeyMapPanel:
subcol = self.indented_layout(col, level + 1)
subrow = subcol.row()
subrow.prop(km, "show_expanded_items", text="", emboss=False)
subrow.label(text=_("%s (Global)") % km.name, translate=False)
subrow.label(text=iface_("%s (Global)") % km.name, translate=False)
else:
km.show_expanded_items = True

@ -495,6 +495,37 @@ PyGetSetDef app_translations_getseters[] = {
{NULL}
};
/* pgettext helper. */
static PyObject *_py_pgettext(PyObject *args, PyObject *kw, const char *(*_pgettext)(const char *, const char *))
{
static const char *kwlist[] = {"msgid", "msgctxt", NULL};
#ifdef WITH_INTERNATIONAL
char *msgid, *msgctxt = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|z:bpy.app.translations.pgettext", (char **)kwlist,
&msgid, &msgctxt))
{
return NULL;
}
return PyUnicode_FromString((*_pgettext)(msgctxt ? msgctxt : BLF_I18NCONTEXT_DEFAULT, msgid));
#else
PyObject *msgid, *msgctxt;
(void)_pgettext;
if (!PyArg_ParseTupleAndKeywords(args, kw, "O|O:bpy.app.translations.pgettext", (char **)kwlist,
&msgid, &msgctxt))
{
return NULL;
}
Py_INCREF(msgid);
return msgid;
#endif
}
PyDoc_STRVAR(app_translations_pgettext_doc,
".. method:: pgettext(msgid, msgctxt)\n"
"\n"
@ -502,7 +533,8 @@ PyDoc_STRVAR(app_translations_pgettext_doc,
" NOTE: The (msgid, msgctxt) parameter orders has been switched compared to gettext function, to allow\n"
" single-parameter calls (context then defaults to BLF_I18NCONTEXT_DEFAULT).\n"
" NOTE: You should really rarely need to use this function in regular addon code, as all translation should be\n"
" handled by Blender internal code.\n"
" handled by Blender internal code. The only exception are string containing formatting (like \"File: %r\"),\n"
" but you should rather use pgettext_iface/_tip in those cases!\n"
" Note: Does nothing when Blender is built without internationalization support (hence always returns msgid).\n"
"\n"
" :arg msgid: The string to translate.\n"
@ -515,26 +547,45 @@ PyDoc_STRVAR(app_translations_pgettext_doc,
);
static PyObject *app_translations_pgettext(BlenderAppTranslations *UNUSED(self), PyObject *args, PyObject *kw)
{
/* Note we could optimize this a bit when WITH_INTERNATIONAL is not defined, but don't think "code complexity" would
* be worth it, as this func should not often be used!
*/
/* XXX This code fails with scons when WITH_INTERNATIONAL is not defined, at link time, stating that BLF_pgettext
* is undefined... So using #ifdef after all, rather than removing scons from blender trunk!
*/
static const char *kwlist[] = {"msgid", "msgctxt", NULL};
char *msgid, *msgctxt = NULL;
return _py_pgettext(args, kw, BLF_pgettext);
}
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|z:bpy.app.translations.pgettext", (char **)kwlist,
&msgid, &msgctxt))
{
return NULL;
}
PyDoc_STRVAR(app_translations_pgettext_iface_doc,
".. method:: pgettext_iface(msgid, msgctxt)\n"
"\n"
" Try to translate the given msgid (with optional msgctxt), if labels' translation is enabled.\n"
" NOTE: See pgettext notes.\n"
"\n"
" :arg msgid: The string to translate.\n"
" :type msgid: string\n"
" :arg msgctxt: The translation context.\n"
" :type msgctxt: string or None\n"
" :default msgctxt: BLF_I18NCONTEXT_DEFAULT value.\n"
" :return: The translated string (or msgid if no translation was found).\n"
"\n"
);
static PyObject *app_translations_pgettext_iface(BlenderAppTranslations *UNUSED(self), PyObject *args, PyObject *kw)
{
return _py_pgettext(args, kw, BLF_translate_do_iface);
}
#ifdef WITH_INTERNATIONAL
return PyUnicode_FromString(BLF_pgettext(msgctxt ? msgctxt : BLF_I18NCONTEXT_DEFAULT, msgid));
#else
return PyUnicode_FromString(msgid);
#endif
PyDoc_STRVAR(app_translations_pgettext_tip_doc,
".. method:: pgettext(msgid, msgctxt)\n"
"\n"
" Try to translate the given msgid (with optional msgctxt), if tooltips' translation is enabled.\n"
" NOTE: See pgettext notes.\n"
"\n"
" :arg msgid: The string to translate.\n"
" :type msgid: string\n"
" :arg msgctxt: The translation context.\n"
" :type msgctxt: string or None\n"
" :default msgctxt: BLF_I18NCONTEXT_DEFAULT value.\n"
" :return: The translated string (or msgid if no translation was found).\n"
"\n"
);
static PyObject *app_translations_pgettext_tip(BlenderAppTranslations *UNUSED(self), PyObject *args, PyObject *kw)
{
return _py_pgettext(args, kw, BLF_translate_do_tooltip);
}
PyDoc_STRVAR(app_translations_locale_explode_doc,
@ -575,6 +626,10 @@ PyMethodDef app_translations_methods[] = {
app_translations_py_messages_unregister_doc},
{(char *)"pgettext", (PyCFunction)app_translations_pgettext, METH_VARARGS | METH_KEYWORDS | METH_STATIC,
app_translations_pgettext_doc},
{(char *)"pgettext_iface", (PyCFunction)app_translations_pgettext_iface, METH_VARARGS | METH_KEYWORDS | METH_STATIC,
app_translations_pgettext_iface_doc},
{(char *)"pgettext_tip", (PyCFunction)app_translations_pgettext_tip, METH_VARARGS | METH_KEYWORDS | METH_STATIC,
app_translations_pgettext_tip_doc},
{(char *)"locale_explode", (PyCFunction)app_translations_locale_explode, METH_VARARGS | METH_KEYWORDS | METH_STATIC,
app_translations_locale_explode_doc},
{NULL}