plone.app.multilingual

Multilingual Plone Content package


Keywords
language, multilingual, content
License
GPL-2.0+
Install
pip install plone.app.multilingual==5.3.4

Documentation

In the old days before Plone 4.3, talking about multi-language support in Plone was talk about Products.LinguaPlone. It has been the defacto standard for managing translations of Archetypes-based content types in Plone through the years. Somehow its functionality never made its way into the Plone core and today it is in legacy status. Nowadays, Plone faces the rising of Dexterity content types and its adoption into the core since Plone 4.3. With Plone 5 released, the transition is completed and Dexterity is shipped as its default content type story.

plone.app.multilingual was designed originally to add a whole multilingual story to Plone. Using ZCA technologies, it enables translations to Dexterity and Archetypes content types managed via a unified UI.

This module provides the user interface for managing content translations. It's the app package of the next generation Plone multilingual engine. It's designed to work with Dexterity content types and the old fashioned Archetypes based content types as well. It only works with Plone 4.1 and above due to the use of UUIDs for referencing the translations.

After more than 7 years, a GSOC, redesigns, reimplementations due to deprecated libraries and two major Plone versions we are finally able to say that plone.app.multilingual has arrived.

  • 1.x - Plone 4.x with Archetypes and Dexterity
  • 2.x - Plone >= 4.x, < 5.0 with plone.app.contenttypes (Dexterity) and real shared content
  • 3.x - Plone >= 5.x. 3.0.17 will likely be the latest release on this branch. You are encouraged to use 4.x.
  • 4.x - Plone >= 5.x (5.0.3 minimum, due to GenericSetup dependency)

PAM is composed of two packages. One is mandatory:

  • plone.app.multilingual (core, UI, enables Dexterity support via a behavior)

and one optional:

  • archetypes.multilingual (enables Archetypes support)

To use this package with both Dexterity and Archetypes based content types you should add the following line to your eggs buildout section:

eggs =
    plone.app.multilingual[archetypes]

To use this package with plone.app.contenttypes you should add the following line to your eggs buildout section:

eggs =
    plone.app.multilingual

After re-running your buildout and installing the newly available add-ons, you should go to the Languages section of your site's control panel and select at least two or more languages for your site. You will now be able to create translations of Plone's default content types, or to link existing content as translations.

These are the most important features PAM provides.

After the setup, PAM will create root folders for each of your site's languages and put translated content into the appropriate folders. A language folder implements INavigationRoot, so from the user's point of view, each language is "jailed" inside its corresponding language folder. There are event subscribers in place to capture user interaction with content and update the language in contents accordingly, for example when a user moves or copies content between language folders.

An evolution of the LP translate view, unified for either Archetypes and Dexterity content types. It features an already translated content viewer for the current content being edited via an ajaxified dynamic selector that shows them on the fly on user request.

PAM has support for language independent fields, but with a twist regarding the LP implementation. As PAM's design does not give more relevance to one translated object than to its siblings (has no canonical object), fields marked as language independent are always copied over to all members of the translation group. The PAM UI will remind you about this behavior by warning you that the values in the corresponding field of all members of the translation group will be overwritten.

When translating content, the policy influences how the translated content will be placed in the site's structure. There are two policies to choose from:

  • LP way, the translation gets placed in the nearest translated folder in the parent's hierarchy
  • Ask user where to place the translated element in the destination language root folder

While browsing the site, the language selector viewlet allows users to switch the site's content language. There are two policies in place in case the translation of a specific language does not exist (yet):

  • LP way, the selector shows the nearest translated container.
  • Shows the user an informative view that shows the currently available translations for the current content.

The root language folders are used to house the content tree for the corresponding language. However, there are some use cases where we need content that does not belong to any language. For example, for assets or side resources like images, videos and documents. For this reason PAM supplies a special Language Independent Folder to house these kind of objects. After PAM setup, there is a special folder called "Assets" (folder title may depend on the language), which can be accessed through the "Go to Assets folder" item of the "Translate" menu. All items placed in this folder will have neutral as their default language and will be visible from the other root language folders as if they were placed there as well.

Note:
  • Language Independent Folder's have also been historically known as "Neutral root folder", "language neutral folder" and "language shared (folder)".
  • Also don't confuse Language Independent Folders with Language Independent Fields
  • The Language Independent Folder formerly known as Media folder, was renamed to the more generic name Assets (the name may depend on the language).

In order to ease the translation tasks, we devised a tool that displays in a useful way all the current translated objects and its current translation information. The map also shows a list of missing translations in case you want to build a mirrored (completely) translated site.

If you are subscriber of the Google Translation service (a paid service), you can setup your API key on Languages site setup. Then, you will notice a new icon in the babel view that takes the original field on the left side and using Google Translations service, translates its contents and fill the right side field.

You can migrate your existing LP powered sites to PAM using the Migration tab in the Languages control panel. The migration has been divided into 4 steps for separation of concerns and for improving the success of each of the required procedures.

The migration of LinguaPlone content depends on an up-to-date Language index. Use this step to refresh this index. Warning: Depending on the number of items in your site, this can take a considerable amount of time. This step is not destructive and can be executed as many times as needed.

This step will move the site's content to its correspondent root language folder and previously will make a search for misplaced content through the site's content tree and will move them to its nearest translated parent. Warning: This step is destructive as it will alter your content tree structure. Make sure you have previously configured your site's languages properly in the 'Site Languages' tab of the 'Languages' control panel. It's advisable that you do not perform this step on production servers having not tried it in development/preproduction servers previously. Depending on the distribution of your site's content and the accuracy of the language information on each content object you may need to relocate manually some misplaced content after this step. Despite the fact that this step is 'destructive' it can be executed as times as needed if some problem is detected and afterwards you fix the problem. Please, refer to the procedure log when it finishes.

This step will transfer the relations between translations stored by LinguaPlone to the PAM catalog. This step is not destructive and can be executed as many times as needed.

This step will search and fix some lost dependencies to the ITranslatable interface hidden in the relation catalog and it gets rid of them. It must be run only when LinguaPlone is already uninstalled, so this step is hidden until then.

By default, if PAM is installed, Archetypes-based content types are marked as translatables

Users should mark a dexterity content type as translatable by assigning a the multilingual behavior to the definition of the content type either via file system, supermodel or through the web.

The language independent fields on Archetype-based content are marked the same way as in LinguaPlone:

atapi.StringField(
    'myField',
    widget=atapi.StringWidget(
    ....
    ),
    languageIndependent=True
),

Note

If you want to completely remove LinguaPlone of your installation, you should make sure that your code are dependent in any way of LP.

There are four ways of achieve it.

In your content type class declaration:

from plone.app.multilingual.dx import directives
directives.languageindependent('field')

In your content type XML file declaration:

<field name="myField" type="zope.schema.TextLine" lingua:independent="true">
    <description />
    <title>myField</title>
</field>

In your code:

from plone.app.multilingual.dx.interfaces import ILanguageIndependentField
alsoProvides(ISchema['myField'], ILanguageIndependentField)

Via the content type definition in the Dexterity Content Types control panel.

All the internal features are implemented on the package plone.app.multilingual.

The key points are:

  1. Each translation is a content object
  2. There is no canonical object
  3. The translation reference storage is external to the content object
  4. Adapt all the steps on translation
  5. Language get/set via an unified adapter
  6. Translatable marker interface(s)

Having a canonical object on the content space produces a dependency which is not orthogonal with the normal behavior of Plone. Content objects should be autonomous and you should be able to remove it. This is the reason because we removed the canonical content object. There is a canonical object on the translation infrastructure but is not on the content space.

In order to maintain the relations between the different language objects we designed a common object called a translation group. This translation group has an UUID on its own and each object member of the group stores it in the object catalog register. You can use the ITranslationManager utility to access and manipulate the members of a translation group given one object of the group.

The different aspects involved on a translation are adapted, so it's possible to create different policies for different types, sites, etc.

ITranslationFactory
General factory used to create a new content
ITranslationLocator

Where we are going to locate the new translated content

Default : If the parent folder is translated create the content on the translated parent folder, otherwise create on the parent folder.

ITranslationCloner

Method to clone the original object to the new one

Default : Nothing

ITranslationIdChooser

Which id is the translation

Default : The original id + lang code-block

ILanguageIndependentFieldsManager

Manager for language independent fields

Default: Nothing

In order to access and modify the language of a content type there is a interface/adapter:

plone.base.interfaces.ILanguage

You can use:

from plone.base.interfaces import ILanguage
language = ILanguage(context).get_language()

or in case you want to set the language of a content:

language = ILanguage(context).set_language('ca')

In order to know if a content can be translated there is a marker interface:

plone.app.multilingual.interfaces.ITranslatable

Contributors please read the document Process for Plone core's development

Sources are at the Plone code repository hosted at Github.

GNU General Public License, version 2