Pyramid custom JSON renderer, translate TranslationString

259 Views Asked by At

I have a problem with returning a JSON response with translated strings in my application's endpoints.

The default pyramid renderer is my custom JSON renderer. Some of the objects in response are TranslationStrings. I would like to have them automatically translated. Now I am using this: Pyramid TranslationString not working on json renderer, but it's not an ideal solution for me. I do not want to translate all of the responses manually.

For translations I am using the TransationStringFactory:

_ = i18n.TranslationStringFactory('coma')

I already have some renderer's adapters. So I added a new one - for TransationString class:

def includeme(config):
    json_renderer = JSON()

    def date_adapter(obj, request):
        return obj.isoformat()

    def set_adapter(obj, request):
        return list(obj)

    def uuid_adapter(obj, request):
        return str(obj)

    def enum_adapter(obj, request):
        return obj.value

    def trans_string_adapter(obj, request):
        return request.localizer.translate(obj)

    json_renderer.add_adapter(TranslationString, trans_string_adapter)
    json_renderer.add_adapter(datetime.date, date_adapter)
    json_renderer.add_adapter(set, set_adapter)
    json_renderer.add_adapter(uuid.UUID, uuid_adapter)
    json_renderer.add_adapter(enum.Enum, enum_adapter)

    config.add_renderer('json', json_renderer)

Here is the example of the JSON object I want to return:

return {
    'label': _('Estimated net income'),
    'value': round(income_net, self.decimal_places),
    ...
}

Why my custom JSON renderer cannot call adapter for TranslationString object?

1

There are 1 best solutions below

0
On

The reason it's not being called is because json.dumps only invokes the default adapters if a type is not json-serializable. A TranslationString subclasses str so it is json-serializable and your adapters are not used.

I think, in general, this is an issue with TranslationString and how it works. It expects you to always pass the string through the localizer, and so you should do that as soon as possible instead of waiting for egress. Unfortunately that basically means passing the localizer all over the place, or making it available as a threadlocal.