Personal tools
Skip to content. | Skip to navigation
The Plone Mockup is a project to modernize Plone's javascripts. Check out a demo at http://plone.github.io/mockup/ The project tries to achieve several goals: * Standardize configuration of patterns implemented in js to use HTML data attributes, so they can be developed and without running a backend server. * Use modern AMD approach to declaring dependencies on other js libs. * Full unit testing of js
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.