Personal tools
Portale con sezioni in lingue diverse: una possibile soluzione

it, en, fr, de. ogni sezione ha la sua lingua!

Oct 16, 2013

Portale con sezioni in lingue diverse: una possibile soluzione

Un esempio pratico di come avere delle parti di un sito con l'interfaccia Plone in una lingua differente dal resto del portale

Ultimamente mi è capitato un problema interessante: un cliente ha chiesto la possibilità di avere un sito in una lingua (italiano) e solo alcune sezioni in un'altra (inglese).

Queste sezioni, oltre al testo inserito nei contenuti, dovevano anche avere tutta l'interfaccia di Plone in inglese, ovviamente.
Come prima idea mi è venuto in mente di utilizzare LinguaPlone o plone.app.multilingual, ma non avevo bisogno di tutto il meccanismo per le traduzioni e il cambio di lingua che forniscono.

Mi sono allora messo a cercare un'alternativa, sfruttando magari quello che Plone offre già.
Innanzitutto, ho provato a giocare con le impostazioni del tool Portal Languages e ho notato che tra esse si poteva determinare la lingua dell'interfaccia in base alla lingua del contenuto corrente.

translation tool

Era praticamente tutto ciò di cui avevo bisogno! Con questo settaggio, infatti, una volta creato un contenuto in inglese, quando ci si entra in visualizzazione o modifica tutta l'interfaccia è in quella lingua.

Rimaneva però un problema: se si creava una cartella in inglese, poi i contenuti creati al suo interno non ereditavano in automatico la lingua selezionata (a meno che non la si andava a cambiare a mano dal tab "categorizzazione"), quindi questi visualizzavano l'interfaccia del sito con la lingua predefinita.

A questo punto quindi, mi servivano due cose:

  • in fase di creazione di un nuovo contenuto, la lingua dell'interfaccia del sito doveva essere la stessa del padre
  • la lingua del nuovo contenuto doveva avere di default la stessa del padre (per risparmiare al redattore un lavoro inutile).

Cercando su internet idee, ho trovato una domanda che mi ha incuriosito su stackoverflow in cui l'autore voleva forzare l'interfaccia di Plone sempre in inglese per gli admin: gli veniva consigliato di scrivere un multi-adapter per il tool di negoziazione della lingua di Products.PloneLanguageTool, per fargli fare quello che voleva.
Questo risolveva il primo punto, infatti registrando un multiadapter per il mio browserlayer in questo modo:

<adapter
factory=".set_language.NegotiateLanguage"
for="* .interfaces.IMyBrowserLayer"
provides="Products.PloneLanguageTool.interfaces.INegotiateLanguage"/>
potevo utilizzare un negotiator che, in fase di creazione di un nuovo contenuto prendeva la lingua dal padre, altrimenti usava il comportamento base di Plone.
from Products.PloneLanguageTool.interfaces import INegotiateLanguage
from Products.PloneLanguageTool.LanguageTool import NegotiateLanguage as NegotiateLanguageBase
from zope.interface import implements


class NegotiateLanguage(object):
"""
Perform default language negotiation.
If we are in portal_factory, get parent's language,
otherwise use default negotiator
"""
implements(INegotiateLanguage)

def __init__(self, site, request):
"""Setup the current language stuff."""
base_negotiate = NegotiateLanguageBase(site, request)
self.default_language = base_negotiate.default_language
self.language_list = base_negotiate.language_list
if "portal_factory" in request.path:
fixed_path = reversed(request.path[request.path.index('portal_factory') + 1:])
folder_path = "/".join(fixed_path)
parent = site.unrestrictedTraverse(folder_path, None)
if parent and hasattr(parent, 'getRawLanguage'):
self.language = parent.getRawLanguage()
else:
self.language = base_negotiate.language
else:
self.language = base_negotiate.language

Per il secondo problema, la soluzione era ancora più semplice - è bastato utilizzare il solito archetypes.schemaextender e assegnare un default_method personalizzato al campo "language":

<adapter
factory=".extender.MyLanguageExtender"
for="Products.ATContentTypes.interface.interfaces.IATContentType"
provides="archetypes.schemaextender.interfaces.IOrderableSchemaExtender" 
name="my-language-extender"/> 
class MyLanguageExtender(object):
    """
    Re-define language field and use a custom default method
for all Content types
    """
    adapts(IATContentType)
    implements(IOrderableSchemaExtender, IBrowserLayerAwareExtender)
    layer = IMyBrowserLayer
    fields = [CustomStringField('language',
                        accessor="Language",
                        schemata="categorization",
                        default_method='myDefaultLanguage',
                        vocabulary_factory='plone.app.vocabularies.SupportedContentLanguages',
                        widget=LanguageWidget(
                            label=_(u'label_language', default=u'Language'),
                            format="select",),
                    ),]

    def __init__(self, context):
        self.context = context

    def getFields(self):
        return self.fields

    def getOrder(self, original):
        return original

Per poter utilizzare il metodo myDefaultLanguage, ho dovuto aggiungerlo tra i metodi di ExtensibleMetadata con una monkeypatch:

<monkey:patch
description="Add a new default method for language field"
class="Products.Archetypes.ExtensibleMetadata.ExtensibleMetadata"
original="myDefaultLanguage"
replacement=".monkey.myDefaultLanguage"
ignoreOriginal="True"/>
from Products.Archetypes import config
from Products.CMFCore.utils import getToolByName

def myDefaultLanguage(self):
    """Retrieve the default language"""
    parent = self.getFolderWhenPortalFactory()
    if hasattr(parent, 'getRawLanguage') and parent.getRawLanguage():
    return parent.getRawLanguage()
    tool = getToolByName(self, 'portal_languages', None)
    if tool is not None:
    return tool.getDefaultLanguage()
    return config.LANGUAGE_DEFAULT

Tutto qui! Non so se sia l'approccio più corretto per affrontare il problema, ma è abbastanza semplice e soprattutto sembra funzionare senza problemi.

Filed under: , ,
comments powered by Disqus