Using LANGUAGE_TOOL.LANGUAGE to specify language of translated strings in TAL template -what makes this work?

I needed to export some HTML content from a multilingual site, where the HTML is a column in a csv table.

After reaching a "works for me" solution, I have two questions:

  • what magic makes this even work?
  • and, is there a less magical approach which I could use instead?

The HTML is generated using a TAL template with translatable strings.

<h3 i18n:translate="">
    Document Summary
<p tal:content="value">
    Value goes here

Calling the view directly on the respective documents, e.g.


would result in the "Content Summary" term being translated correctly, but not when calling the view from a script to create my csv. e.g.


# related items can be in various languages
for related_item in related_items:
    related_object = related_item.from_object
    item_html = getView(related_object, request, 'my_view').index()

This would result in the "Content Summary" term always being in the language determined by the context of @@my_summary_view

Eventually, I stumbled on the example given here:

# Fake new language for all authenticated users
event.request['LANGUAGE'] = language
event.request.LANGUAGE_TOOL.LANGUAGE = language

I updated my script and attempted to use the language of the related object

custom_request = request
for related_item in related_items:
    related_object = related_item.from_object

    custom_request['LANGUAGE'] = related_object.language
    custom_request.LANGUAGE_TOOL.LANGUAGE = related_object.language

    item_html = getView(related_object, custom_request, 'my_view').index()

This would result in a single language being used throughout, depending on the language of the first related object

I finally settled in passing the language as a parameter, filtering the related items, and generating separate csv's for each language.

My knowledge of events and event subscribers is lacking, would this have been the correct approach?

Appreciate any clues...


It is quite common that the request object contains in some way the language to be used as localization target. In simple cases (sites not having multilingual content) the information about the target language comes from the browser (in the Accept-Language request header). Especially, this controls typically (everything is in principle customizable by appropriate adapter registrations) the page template translation machinery.

Your case seems to be a multilingual site with content for different languages in respective folders.

I have not yet worked with such a multilingual site. Potentially, your multilingual framework (you did not yet tell us which this is) is using a traversal hook to change the translation related information in the request during the traversal of the language folders. Traversal hooks are only activated (automatically) during web traversal; if you access an objects in a different way, they are not activated (automatically).

Your workaround does not yet seem perfect: as you set the request information for each object, you should get for each object its respective language, not for all objects the first object's language. Your observation indicates that you do not yet set the language information in the request object in the correct way.

I would look at the source of your multilingual framework for traversal hook registrations and try to understand what the corresponding handlers are doing to control the translation target language. Likely, you could then call those handlers manually in your script.

1 Like

Thanks for the in-depth answer @dieter

We're using Plone 5.0.7 with 5.0.3

The folder structure is explained here

The "active" language negotiation itself is not handled by but by the plone.i18n.negotiator module. I should have paid more attention to the introduction section of - namely: "Language is negotiated at the beginning of the page view."

Also noticing there is likely an error on that page: a reference to Products.PloneLanguageTool. It seems the tool was made part of plone.i18n in version 3.0.0 (2015-03-26).

I think I may understand why in my workaround all translated strings were in the language of the first document. Looking here:

binding = request.get('LANGUAGE_TOOL', None)
if not isinstance(binding, LanguageBinding):
    # Not bound -> bind
binding = request.get('LANGUAGE_TOOL')

This creates a new language binding when called the first time around...

Finally solved my issue using plone.subrequest

from plone.subrequest import subrequest
for related_item in related_items:
    related_path = related_item.from_path
    subrequest_path = '%s/@@my_view' % related_path
    item_html = subrequest(subrequest_path).getBody()