Personal tools
Skip to content. | Skip to navigation
NOT in development. This package is beeing merged on plone.app.multilingual .. image:: https://travis-ci.org/plone/plone.multilingual.png :target: http://travis-ci.org/plone/plone.multilingual plone.multilingual ================== This package contains the core functionality for the next generation multilingual engine. These are the main artifacts and its purposes: canonical: * the canonical organizes the information about a "translation-group" * it's using a dictionary with language-codes as keys and uuids (provided by plone.uuid) as values storage: * persistent storage, which holds the canonicals in an IOBTree * the OOBTree's key is the UUID of the content, the according value is the canonical manager: * adapter for ITranslatable * provides the translations API adapters: * ITranslationLocator - where to put a translation * ITranslationIdChooser - generates a valid id for a translation * ITranslationCloner - copy the language-independent content to the translation * ITranslationFactory - creates the translation In order to have a test we have a type called Demo that has an adapter called DemoLanguage that will allow to get the language of the object:: >>> from plone.multilingual.interfaces import ITranslationManager >>> from plone.multilingual.interfaces import ILanguage >>> from plone.app.testing import setRoles, login, TEST_USER_ID, TEST_USER_NAME >>> from zope.lifecycleevent import modified >>> portal = layer['portal'] >>> setRoles(portal, TEST_USER_ID, ['Manager']) >>> login(portal, TEST_USER_NAME) >>> portal.invokeFactory('Folder', 'ob1', title=u"An archetypes based folder") 'ob1' >>> ILanguage(portal['ob1']).set_language('ca') >>> portal['ob1'].reindexObject() >>> modified(portal['ob1']) Ensuring that the new object gets its UUID:: >>> from plone.uuid.interfaces import IUUID >>> ob1_uuid = IUUID(portal['ob1']) >>> isinstance(ob1_uuid, str) True We create a new translation in 'en' language:: >>> ITranslationManager(portal['ob1']).add_translation('en') We try to create a new translation in 'ca' that already exists:: >>> ITranslationManager(portal['ob1']).add_translation('ca') Traceback (most recent call last): ... KeyError: 'Translation already exists' We try to create a new translation without language:: >>> ITranslationManager(portal['ob1']).add_translation(None) Traceback (most recent call last): ... KeyError: 'There is no target language' We get the 'en' translation:: >>> ITranslationManager(portal['ob1']).get_translation('en') <ATFolder at /plone/ob1-en> >>> ILanguage(ITranslationManager(portal['ob1']).get_translation('en')).get_language() == 'en' True let's get all the translations:: >>> ITranslationManager(portal['ob1']).get_translations() {'ca': <ATFolder at /plone/ob1>, 'en': <ATFolder at /plone/ob1-en>} let's get only the languages:: >>> ITranslationManager(portal['ob1']).get_translated_languages() ['ca', 'en'] has_translation:: >>> ITranslationManager(portal['ob1']).has_translation('en') True >>> ITranslationManager(portal['ob1']).has_translation('it') False register_translation with invalid language:: >>> ITranslationManager(portal['ob1']).remove_translation('en') >>> ITranslationManager(portal['ob1']).register_translation(None, portal['ob1-en']) Traceback (most recent call last): ... KeyError: 'There is no target language' register a translation with content:: >>> ITranslationManager(portal['ob1']).register_translation('en', portal['ob1-en']) >>> ITranslationManager(portal['ob1']).get_translations() {'ca': <ATFolder at /plone/ob1>, 'en': <ATFolder at /plone/ob1-en>} changing the content-language (there should act a subscriber):: >>> ILanguage(portal['ob1-en']).set_language('it') >>> from zope.event import notify >>> from zope.lifecycleevent import ObjectModifiedEvent >>> notify(ObjectModifiedEvent(portal['ob1-en'])) >>> ITranslationManager(portal['ob1']).get_translations() {'ca': <ATFolder at /plone/ob1>, 'it': <ATFolder at /plone/ob1-en>} test more translations:: >>> obj_it = ITranslationManager(portal['ob1']).get_translation('it') >>> ITranslationManager(obj_it).add_translation('fr') >>> ITranslationManager(obj_it).add_translation('pt') >>> ITranslationManager(portal['ob1']).get_translated_languages() ['ca', 'it', 'fr', 'pt'] >>> ITranslationManager(obj_it).get_translated_languages() ['ca', 'it', 'fr', 'pt'] test if canonicals objects are the same:: >>> obj_ca = ITranslationManager(obj_it).get_translation('ca') >>> canonical_it = ITranslationManager(obj_it).query_canonical() >>> canonical_ca = ITranslationManager(obj_ca).query_canonical() >>> canonical_it == canonical_ca True Messing up with content ----------------------- In case that we do mess up things with content (users always do):: >>> from zope.lifecycleevent import modified >>> portal.invokeFactory('Folder', 'ob2', title=u"An archetypes based doc") 'ob2' >>> ILanguage(portal['ob2']).set_language('it') >>> modified(portal['ob2']) >>> ILanguage(portal['ob2']).get_language() 'it' >>> ITranslationManager(portal['ob2']).add_translation('en') >>> ob2_en = ITranslationManager(portal['ob2']).get_translation('en') >>> portal.invokeFactory('Folder', 'ob3', title=u"An archetypes based doc") 'ob3' >>> ILanguage(portal['ob3']).set_language('it') >>> modified(portal['ob3']) >>> ILanguage(portal['ob3']).get_language() 'it' >>> ITranslationManager(portal['ob3']).add_translation('es') >>> ob3_es = ITranslationManager(portal['ob3']).get_translation('es') >>> from OFS.event import ObjectWillBeRemovedEvent >>> notify(ObjectWillBeRemovedEvent(portal['ob2'])) >>> portal.manage_delObjects('ob2') >>> notify(ObjectWillBeRemovedEvent(ob3_es)) >>> portal.manage_delObjects(ob3_es.id) >>> c_old = ITranslationManager(portal['ob3']).query_canonical() >>> c_new = ITranslationManager(ob2_en).query_canonical() >>> c_old == c_new False >>> isinstance(c_old, str) True >>> isinstance(c_new, str) True >>> ITranslationManager(ob2_en).register_translation('it', portal['ob3']) >>> c1 = ITranslationManager(portal['ob3']).query_canonical() >>> c2 = ITranslationManager(ob2_en).query_canonical() >>> c1 == c2 True Other use case, A('it' + 'en') and B('it' + 'es'), and we want A('en') -> B('es'):: >>> portal.invokeFactory('Folder', 'mess1', title=u"An archetypes based doc") 'mess1' >>> ILanguage(portal['mess1']).set_language('it') >>> modified(portal['mess1']) >>> ILanguage(portal['mess1']).get_language() 'it' >>> ITranslationManager(portal['mess1']).add_translation('en') >>> mess1_en = ITranslationManager(portal['mess1']).get_translation('en') >>> portal.invokeFactory('Folder', 'mess2', title=u"An archetypes based doc") 'mess2' >>> ILanguage(portal['mess2']).set_language('it') >>> ITranslationManager(portal['mess2']).add_translation('es') >>> mess2_es = ITranslationManager(portal['mess2']).get_translation('es') >>> ITranslationManager(mess1_en).register_translation('es', mess2_es) >>> ITranslationManager(portal['mess2']).get_translation('es') >>> ITranslationManager(portal['mess1']).get_translation('es') <ATFolder at /plone/mess2-es> Default-Adapters ---------------- id-chooser:: >>> from plone.multilingual.interfaces import ITranslationIdChooser >>> chooser = ITranslationIdChooser(portal['ob1-en']) >>> chooser(portal, 'es') 'ob1-es' locator:: >>> ITranslationManager(portal['ob1']).add_translation('es') >>> child_id = portal.ob1.invokeFactory('Folder', 'ob1_child', language="ca") >>> from plone.multilingual.interfaces import ITranslationLocator >>> locator = ITranslationLocator(portal['ob1-en']) >>> locator('es') == portal True >>> child_locator = ITranslationLocator(portal.ob1.ob1_child) >>> child_locator('es') == portal['ob1-es'] True >>> ITranslationManager(portal['ob1']).remove_translation('es') Convert intids to uuids upgrade step ------------------------------------ An upgrade step is available in case of having an existing site with the experimental 0.1 plone.multilingual version:: >>> from plone.multilingual.upgrades.to02 import upgrade .. note:: You must reinstall the plone.multilingual package in order to install the required new utility in place before upgrading. If you are using a version of Dexterity below 2.0, you must install the package plone.app.referenceablebehavior and enable the *Referenceable* (plone.app.referenceablebehavior.referenceable.IReferenceable) behavior for all your Dexterity content types before you attempt to upgrade your site. You can run the @@pml-upgrade view at the root of your site or follow the upgrade step in portal_setup > upgrades. If you can't see the upgrade step, press *Show old upgrades* and select the *Convert translation based intids to uuids (0.1 → 02)* Upgrade to catalog ------------------ :: >>> from plone.multilingual.upgrades.to03 import upgrade we shouldn't find the storage-utility anymore:: >>> from plone.multilingual.interfaces import IMultilingualStorage >>> gsm = portal.getSiteManager() >>> gsm.queryUtility(IMultilingualStorage) is None True
plone.multilingualbehavior adds multilingual behavior to content types built with Dexterity. It uses the next generation multilingual engine powered by five/Zope3 technologies, plone.multilingual. The behavior provides the Dexterity-driven content with a marker interface "ITranslatable", and makes available to that translation enabled type all the translation UI components such as menus, views, etc... To make your Dexterity content type translatable, add the following line to the <!-- enabled behaviors --> section in your type's profile: <!-- enabled behaviors --> <property name="behaviors"> <element value="plone.multilingualbehavior.interfaces.IDexterityTranslatable" /> </property> plone.multilingualbehavior implements language independent fields. The content of language independent fields is the same across all language versions. This is convenient, but also a little dangerous, because editing the field on any language version will change the content on all other language versions. For details on how to make fields language independent, see the examples in the test folder. tests/schemata.py shows how to make fields language independent when using the Grok framework; tests/samplecontent_type.xml shows how to achieve the same thing in an xml file. It is also possible to set a field to be language independent through the web, given a sufficiently new version of plone.schemaeditor.
This package contains fields and wrapper objects for storing: * A file with a filename * An image with a filename BLOB based types are supported if the z3c.blobfile package is installed. This will also require the ZODB3 package to be at version 3.8.1 or later, and BLOBs to be configured in zope.conf.
This product implements OpenID_ authentication support for Zope_ via a Pluggable Authentication Service plugin. Using this package everyone with an OpenID authentity will be able to login on your Zope site. OpenID accounts are not given any extra roles beyond the standard Authenticated role. This allows you to make a distinction between people that have explicitly signed up to your site and people who are unknown but have succesfully verified their identity. Authentication flow ------------------- The OpenID authentication flow goes like this: - user submits a OpenID identity (which is a URL) to you site. This is done through a HTTP POST using a form variable called __ac_identity_url - the PAS plugin sees this variable during credential extraction and initiates a OpenID challenge. This results in a transaction commit and a redirect to an OpenID server. - the OpenID server takes care of authenticating the user and redirect the user back to the Zope site. - the OpenID PAS plugin extracts the information passed in via the OpenID server redirect and uses that in its authentication code to complete the OpenID authentication Session management ------------------ The PAS plugin only takes care of authenticating users. In almost all environments it will be needed to also setup a session so users stay logged in when they visit another page. This can be done via a special session management PAS plugin, for example plone.session.
plone.outputfilters provides a framework for registering filters that get applied to text as it is rendered. By default, these filters are wired up to occur when text is transformed from the text/html mimetype to the text/x-html-safe mimetype via the PortalTransforms machinery. With both Archetypes TextFields and the RichText field of plone.app.textfield, this transform is typically applied when the field value is first accessed. The result of the transform is then cached in a volatile attribute for an hour or until the value is replaced. Included Filters A default filter is included which provides the following features: Resolving UID-based links Adding captions to images (These are implemented as one filter to avoid the overhead of parsing the HTML twice.) These features used to be provided by similar transforms in both Products.kupu and Products.TinyMCE. New releases of these editors are being prepared which depend on the transform in plone.outputfilters, so that bugs don't need to be fixed in multiple places.
============ plone.portlet module
A portlet that fetches results from a collection
============ A simple static HTML portlet for Plone 3.
plone.portlets provides a generic infrastructure for managing portlets. Portlets are a bit like viewlets, except they can be manipulated at runtime, using local components. This package is used by plone.app.portlets to provide Plone-specific portlets, but should be generic enough to work on other platforms. It should work in a "pure Zope 3" environment.
This package provides a queriable sources (vocabularies) that return PAS users, groups or principals (both users and groups). They are registered as named vocabularies, so you can do: class IMyInterface(Interface): users = schema.Choice(title=u"Users", vocabulary="plone.principalsource.Users") groups = schema.Choice(title=u"Groups", vocabulary="plone.principalsource.Groups") principals = schema.Choice(title=u"Principals", vocabulary="plone.principalsource.Principals") The underlying source (see source.py) implements the IQuerySource interface from z3c.formwidget.query. This means that it can be used for a query-select widget, including the one in plone.formwidget.autocomplete. A note about unicode The source attempts to make it safe to do a __contains__ check, a getTerm() lookup, and searches using unicode strings. This is somewhat constrained by the underlying plugins. In particular, the standard ZODBGroups plugin is incapable of searching for groups with unicode titles or ids, and returns a list of all groups if passed a unicode string. As such, the source forces all unicode strings used to search for groups to UTF-8 (searching for users is unaffected). Also, remember that tokens should be 7-bit ASCII strings. getTermByToken() is forgiving in that it silently encodes a unicode string to utf-8, but really you should only pass unicode to this method.