Translate the default XBlock data

Thanks @braden for chiming in. I’ve checked the wiki page and what it says (thank you for working on t that) still holds true. The HTML/JS code can indeed be i18n’ed, even Python strings can be i18n’ed like below:

class MyXBlock(...):
    ...
    def get_something_for_html(self):
        ugettext = self.runtime.service(self, "i18n").ugettext
        return ugettext("I'm translatable!")

However, there’s no way (yet) to translate this:
ugettext_noop = lambda s: s
class MyXBlock(…):
display_name = String(
display_name=ugettext_noop(“Display name.”),
help=ugettext_noop(“The display name for this component.”),
scope=Scope.settings
)

First, we have to use an actual ugettext function instead of noop, ugettext_lazy can work. But when it’s used the following error shows up:

edx.devstack.studio | Traceback (most recent call last):
edx.devstack.studio |   File "/edx/app/edxapp/edx-platform/cms/djangoapps/contentstore/views/preview.py", line 326, in get_preview_fragment
edx.devstack.studio |     fragment = module.render(preview_view, context)
edx.devstack.studio |   File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/xblock/core.py", line 202, in render
edx.devstack.studio |     return self.runtime.render(self, view, context)
edx.devstack.studio |   File "/edx/app/edxapp/edx-platform/common/lib/xmodule/xmodule/x_module.py", line 1903, in render
edx.devstack.studio |     return self.__getattr__('render')(block, view_name, context)
edx.devstack.studio |   File "/edx/app/edxapp/edx-platform/common/lib/xmodule/xmodule/x_module.py", line 1310, in render
edx.devstack.studio |     return super(MetricsMixin, self).render(block, view_name, context=context)
edx.devstack.studio |   File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/xblock/runtime.py", line 810, in render
edx.devstack.studio |     frag = view_fn(context)
edx.devstack.studio |   File "/edx/app/edxapp/edx-platform/common/lib/xmodule/xmodule/vertical_block.py", line 119, in author_view
edx.devstack.studio |     self.render_children(context, fragment, can_reorder=True, can_add=True)
edx.devstack.studio |   File "/edx/app/edxapp/edx-platform/common/lib/xmodule/xmodule/studio_editable.py", line 26, in render_children
edx.devstack.studio |     rendered_child = child.render(StudioEditableModule.get_preview_view_name(child), context)
edx.devstack.studio |   File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/xblock/core.py", line 202, in render
edx.devstack.studio |     return self.runtime.render(self, view, context)
edx.devstack.studio |   File "/edx/app/edxapp/edx-platform/common/lib/xmodule/xmodule/x_module.py", line 1903, in render
edx.devstack.studio |     return self.__getattr__('render')(block, view_name, context)
edx.devstack.studio |   File "/edx/app/edxapp/edx-platform/common/lib/xmodule/xmodule/x_module.py", line 1310, in render
edx.devstack.studio |     return super(MetricsMixin, self).render(block, view_name, context=context)
edx.devstack.studio |   File "/edx/app/edxapp/venvs/edxapp/local/lib/python2.7/site-packages/xblock/runtime.py", line 814, in render
edx.devstack.studio |     updated_frag = self.wrap_xblock(block, view_name, frag, context)
edx.devstack.studio |   File "/edx/app/edxapp/edx-platform/common/lib/xmodule/xmodule/x_module.py", line 1262, in wrap_xblock
edx.devstack.studio |     frag = wrapper(block, view, frag, context)
edx.devstack.studio |   File "/edx/app/edxapp/edx-platform/openedx/core/lib/xblock_utils/__init__.py", line 146, in wrap_xblock
edx.devstack.studio |     template_context['js_init_parameters'] = json.dumps(frag.json_init_args).replace("/", r"\/")
edx.devstack.studio |   File "/usr/lib/python2.7/json/__init__.py", line 244, in dumps
edx.devstack.studio |     return _default_encoder.encode(obj)
edx.devstack.studio |   File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
edx.devstack.studio |     chunks = self.iterencode(o, _one_shot=True)
edx.devstack.studio |   File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
edx.devstack.studio |     return _iterencode(o, 0)
edx.devstack.studio |   File "/usr/lib/python2.7/json/encoder.py", line 184, in default
edx.devstack.studio |     raise TypeError(repr(o) + " is not JSON serializable")
edx.devstack.studio | TypeError: u'Drag and Drop' is not JSON serializable

I think the solution is to use something like this in the XBlock Utils, but I don’t know if that will work for all XBlocks, therefore I’m opening this for discussion:

For now the issue is that because the XBlock Utils is unable to deal with Promise objects resulting from ugettext_lazy. One solution is to use a custom JSON encoder like:

from rest_framework.utils.encoders import JSONEncoder
value = json.dumps(..., cls=JSONEncoder)

What do you think?