Personal tools
You are here: Home Source News Software Plone and Internationalization
Document Actions

Plone and Internationalization

One of the features that immediately attracted me to Plone was its multilingual capability. Plone's content (labels, menu items, dialog boxes, etc.) have already been translated into 30+ languages, so if a user sets their browser settings properly (technically, it's the "accept_language" header), they'll see a Plone web site in their chosen language.

With a few product add-ons, namely Plone Language Tool, I18NFolder and I18NLayer, content managers can create their own multilingual content. These add-ons work very smoothly -- a creator can easily create a new document (or Event, or News Item) in multiple languages; but when published, the browser sees the document only in their chosen language. C'est belle!

This is all well, but, Plone's built-in slots -- the News, Calendar, and Recent Events portlets -- don't behave so well with multilingual content. I was very dissatisfied; but, in the open source community, you don't just complain, you fix! So, while I'm a novice to Python, and tal and such, last night I set out to fix the recent events portlet ...

The Problem

Plone's built-in portlets don't behave well with multilingual (I18NLayer) content. Instead of showing just the browser's "accepted language" version of an Event or News item (or the default language, if the accepted language does not exist), the portlets will show all versions of the document. This is sometimes acceptable - "recent items", for example, I'm fine with it showing all recently published documents, in any language. It's a good way to keep up with what's new. But others, such as upcoming events (portlet_events), is just confusing to see the same event in more than one language.

My preference is to have this slot show just one version of each Event document -- the accepted language version, if it exists, otherwise the default language version.

So, I customized portal_skins/plone_portlets/portlet_events. Nicely, it didn't require that many changes to the code. But, you'll notice that I did sacrifice a couple of features -- I dropped showing the event's Location details Actually, it wouldn't be too hard to re-add the Location, but for my purposes I didn't want to display it, so it's not in the version below.

The Solution

So, here's the customized code. The major change to the code is in the following block:

results python:[ 
     [test(brain.getObject().getParentNode().portal_type == 'I18NLayer', brain.getObject().getParentNode(), brain.getObject() )
      , brain.getObject().start() ]
     for brain in brains if brain.getObject()];
resultsasSet python:[];
temp python:[resultsasSet.append(i) for i in results if i not in resultsasSet];
resultsasSet python: resultsasSet[:5]

The goal of this block is to get the parent node of the Event object, if the parent node is an I18NLayer. However, since multilingual events share the same parent, we also have to remove duplicates from the results set. Hence the for i in results ... loop.

I'd like to take this time to thank Karl Ulbrich, who helped simplify my original code (as well as get me interested in Python in the first place -- I'm just an itinerant Smalltalk developer!).

/portal_skins/custom/portlet_events

<!-- Customized for internationalization -->
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
      xmlns:metal="http://xml.zope.org/namespaces/metal"
      i18n:domain="plone">
<body>
<!-- The events box -->
<div metal:define-macro="portlet"
     tal:define="brains python:here.portal_catalog.searchResults( portal_type='Event'
                                                                 , end={'query':here.ZopeTime(),
                                                                        'range': 'min'}
                                                                 , sort_on='start'
                                                                 , review_state='published');
                results python:[ 
                    [test(brain.getObject().getParentNode().portal_type == 'I18NLayer', brain.getObject().getParentNode(), brain.getObject() )
                    , brain.getObject().start() ]
for brain in brains if brain.getObject()];
                resultsasSet python:[];
                temp python:[resultsasSet.append(i) for i in results if i not in resultsasSet];
                resultsasSet python: resultsasSet[:5]
                "
     tal:condition="python:test(results, 1, 0)">
    <div class="portlet" id="portlet-events">
        <h5 i18n:translate="box_events">Upcoming Events</h5>
        <div class="portletBody">
            <tal:block tal:repeat="obj resultsasSet">
                <div tal:define="oddrow repeat/obj/odd"
                     tal:attributes="class python:test(oddrow, 'portletContent even', 'portletContent odd')">
                    <a href=""
                       tal:attributes="href python:obj[0].absolute_url();
                                       title python:obj[0].Description()">
                        <tal:block replace="structure here/event_icon.gif"/>
                        <span tal:replace="python:test(obj[0].Title(), obj[0].Title(), obj[0].getId())"> Event </span>
                    </a>
                    <div class="portletDetails">
                        <tal:date content="python:here.toLocalizedTime(obj[1])">July 7, 08:11</tal:date>
                    </div>
                </div>
            </tal:block>
        </div>
    </div>
</div>
</body>
</html>
Houston Tech Calendar

Events in the Houston area that have caught our attention ... or attendance ;)

« January 2009 »
Su Mo Tu We Th Fr Sa
123
45678910
11121314151617
18192021222324
25262728293031
 

Powered by Plone CMS, the Open Source Content Management System Hosted by WebFaction

This site conforms to the following standards: