From: Matthew W. <svn...@pl...> - 2010-03-14 23:48:36
|
Author: matthewwilkes Date: Sun Mar 14 23:48:28 2010 New Revision: 34730 Added: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/setup.py - copied unchanged from r34729, Products.LinguaPlone/trunk/Products/LinguaPlone/browser/setup.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/switcher.py - copied unchanged from r34729, Products.LinguaPlone/trunk/Products/LinguaPlone/browser/switcher.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/catalog.py - copied unchanged from r34729, Products.LinguaPlone/trunk/Products/LinguaPlone/catalog.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/language_setup.txt - copied unchanged from r34729, Products.LinguaPlone/trunk/Products/LinguaPlone/tests/language_setup.txt Products.LinguaPlone/branches/matthewwilkes-fallback/bootstrap.py - copied unchanged from r34729, Products.LinguaPlone/trunk/bootstrap.py Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/ (props changed) Products.LinguaPlone/branches/matthewwilkes-fallback/CHANGES.txt Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/I18NBaseObject.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/I18NOrderedBaseFolder.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/LanguageIndex.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/__init__.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/configure.zcml Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/language.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/selector.pt Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/config.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/events.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/examples/LinguaItem.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/LanguageIndex.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/__init__.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/configure.zcml Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/interfaces.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/migrations.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/patches.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/permissions.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/public.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/skins/LinguaPlone/manage_translations_form.pt Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testAPI.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testCatalog.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testFunctional.py Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/utils.py Products.LinguaPlone/branches/matthewwilkes-fallback/README.txt Products.LinguaPlone/branches/matthewwilkes-fallback/docs/FAQ.txt Products.LinguaPlone/branches/matthewwilkes-fallback/setup.py Products.LinguaPlone/branches/matthewwilkes-fallback/test-plone-3.3.x.cfg Log: Merge from trunk Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/CHANGES.txt ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/CHANGES.txt (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/CHANGES.txt Sun Mar 14 23:48:28 2010 @@ -1,10 +1,78 @@ Changelog ========= -3.0.1 - unreleased +3.1a2 - unreleased ------------------ +- Some PEP8 cleanup. + [hannosch] + +- Minor documentation updates. + [hannosch] + +3.1a1 - 2010-02-19 +------------------ + +- Factor out filtering of "Language" parameter so it can be reused elsewhere. + [hannosch, witsch] + +- Made the manage_translations_form compatible with Plone 4 by replacing a + call to referencebrowser_startupDirectory with hardcoding the current context + as the startup directory. + [huub_bouma] + +- Added workflow transitions to the setup view to publish the language folders. + [hannosch] + +- Changed the setup view to give the folders native language titles. + [hannosch] + +- Added automatic setup of the language switcher to the setup view. + [hannosch] + +- Added new ``language-switcher`` view usable as a default view method for the + Plone site object to dispatch to the appropriate language root folder. + [hannosch] + +- Added new ``language-setup-folders`` helper view to set up a regular structure + of language root folders for each supported language each marked as a + navigation root. + [hannosch] + +- Added more CSS classes to the language selector making it possible to target + each language. Inspired by http://www.thirtysomething.it/. + [hannosch] + +- Only register the catalog export import handlers if they aren't already part + of Archetypes. This avoids conflicts in Plone 4.0. + [hannosch] + +3.0.1 - 2010-02-02 +------------------ + +- Adjusted the FAQ related to changing the language of an item. This closes + http://plone.org/products/linguaplone/issues/234. + [hannosch] + +- Clarify ITranslatable interface description for the getTranslation method. + This closes http://plone.org/products/linguaplone/issues/226. + [hannosch] + +- Made language index more forgiving when dealing with broken canonical + references. This closes http://plone.org/products/linguaplone/issues/231. + [hannosch] + +- Fixed a regression introduced in 3.0b4. The title of translations wasn't + generated from the title anymore. While we retain the ability to specify an + explicit id, by default the new id is now generated from the title again. + This closes http://plone.org/products/linguaplone/issues/233. + [hannosch] + +- The language portlet was broken due to a prior change of the selector. + [jensens] + - Small documentation updates. + [hannosch] 3.0 - 2009-12-21 ---------------- Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/I18NBaseObject.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/I18NBaseObject.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/I18NBaseObject.py Sun Mar 14 23:48:28 2010 @@ -48,7 +48,6 @@ def __nonzero__(self): return bool(self.__typeinfo) - security.declarePublic('getActionInfo') def getActionInfo(self, action_chain, object=None, check_visibility=0, check_condition=0): @@ -56,13 +55,11 @@ check_visibility, check_condition) if action_chain=='object/edit': urlparts=res['url'].split('/') - if urlparts[-1] in [ ('atct_edit', 'base_edit') ]: + if urlparts[-1] in [('atct_edit', 'base_edit')]: urlparts[-1]='translate_item' res['url']='/'.join(urlparts) - return res - security.declarePublic('queryMethodID') def queryMethodID(self, alias, default=None, context=None): if alias == 'edit': @@ -93,7 +90,7 @@ """Adds a translation.""" if self.hasTranslation(language): translation = self.getTranslation(language) - raise AlreadyTranslated, translation.absolute_url() + raise AlreadyTranslated(translation.absolute_url()) locator = ILocateTranslation(self) parent = locator.findLocationForTranslation(language) @@ -104,7 +101,8 @@ kwargs[config.KWARGS_TRANSLATION_KEY] = canonical factory = ITranslationFactory(self) - translation = factory.createTranslation(parent, language, *args, **kwargs) + translation = factory.createTranslation( + parent, language, *args, **kwargs) translation.reindexObject() notify(events.ObjectTranslatedEvent(self, translation, language)) @@ -117,7 +115,7 @@ """Adds the reference used to keep track of translations.""" if self.hasTranslation(translation.Language()): double = self.getTranslation(translation.Language()) - raise AlreadyTranslated, double.absolute_url() + raise AlreadyTranslated(double.absolute_url()) self.addReference(translation, config.RELATIONSHIP) security.declareProtected(permissions.ModifyPortalContent, @@ -199,9 +197,9 @@ if workflow_tool is None: # No context, most likely FTP or WebDAV if review_state: - return {lang : [self, None]} + return {lang: [self, None]} else: - return {lang : self} + return {lang: self} if review_state: state = workflow_tool.getInfoFor(self, 'review_state', None) if include_canonical: @@ -297,7 +295,7 @@ if translation == self: return else: - raise AlreadyTranslated, translation.absolute_url() + raise AlreadyTranslated(translation.absolute_url()) self.getField('language').set(self, value, **kwargs) if not value: @@ -318,7 +316,8 @@ def defaultLanguage(self): """Returns the initial default language.""" parent = aq_parent(aq_inner(self)) - if getattr(parent, 'portal_type', None) == 'TempFolder':# We have factory tool + if getattr(parent, 'portal_type', None) == 'TempFolder': + # We have factory tool parent = aq_parent(aq_parent(parent)) if ITranslatable.providedBy(parent): language = parent.Language() @@ -361,9 +360,9 @@ if not canonical: # On non-canonical items the translate screen shows language # independent fields in view mode. This means the form will not - # contain their data. The contract for processForm is that missing - # fields can be interpreted as "delete all". We need to avoid this - # for LP or we might accidentally delete data. + # contain their data. The contract for processForm is that + # missing fields can be interpreted as "delete all". We need to + # avoid this for LP or we might accidentally delete data. if getattr(field, 'languageIndependent', False): continue @@ -411,6 +410,7 @@ security.declareProtected(permissions.ModifyPortalContent, 'processForm') def processForm(self, data=1, metadata=0, REQUEST=None, values=None): """Process the schema looking for data in the form.""" + is_new_object = self.checkCreationFlag() BaseObject.processForm(self, data=data, metadata=metadata, REQUEST=REQUEST, values=values) # LP specific bits @@ -418,6 +418,24 @@ if self.isCanonical(): self.invalidateTranslations() + # Check if an explicit id has been passed + explicit_id = False + if REQUEST is None: + REQUEST = getattr(self, 'REQUEST', None) + + if REQUEST is not None: + if 'id' in REQUEST.form and REQUEST.form.get('id'): + explicit_id = True + + if values is not None: + if 'id' in values and values.get('id'): + explicit_id = True + + if (is_new_object and not explicit_id and + self._at_rename_after_creation): + # Renames an object like its normalized title + new_id = self._renameAfterCreation() + if shasattr(self, '_lp_default_page'): delattr(self, '_lp_default_page') language = self.Language() @@ -437,7 +455,8 @@ if shasattr(self, '_lp_outdated'): delattr(self, '_lp_outdated') - security.declareProtected(permissions.ModifyPortalContent, 'invalidateTranslations') + security.declareProtected( + permissions.ModifyPortalContent, 'invalidateTranslations') def invalidateTranslations(self): """Outdates all translations except the canonical one.""" translations = self.getNonCanonicalTranslations() @@ -463,10 +482,11 @@ # veto deletion of the canonical translation object. if config.CANONICAL_DELETE_PROTECTION: if self.isCanonical() and self.getNonCanonicalTranslations(): - raise BeforeDeleteException, 'Please delete translations first.' + raise BeforeDeleteException('Delete translations first.') # Wrapper around typeinfo to hook into the edit alias - security.declareProtected(permissions.AccessContentsInformation, 'getTypeInfo') + security.declareProtected( + permissions.AccessContentsInformation, 'getTypeInfo') def getTypeInfo(self): """Get the TypeInformation object specified by the portal type, possibly wrapped to intercept the edit alias. @@ -484,10 +504,8 @@ brains = tool._queryFor(sid=sID, relationship=config.RELATIONSHIP) if brains: if objects: - return [ - self._getReferenceObject(brain.targetUID) - for brain in brains - ] + return [self._getReferenceObject(brain.targetUID) + for brain in brains] else: return brains return [] @@ -500,10 +518,8 @@ brains = tool._queryFor(tid=tID, relationship=config.RELATIONSHIP) if brains: if objects: - return [ - self._getReferenceObject(brain.sourceUID) - for brain in brains - ] + return [self._getReferenceObject(brain.sourceUID) + for brain in brains] else: return brains return [] Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/I18NOrderedBaseFolder.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/I18NOrderedBaseFolder.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/I18NOrderedBaseFolder.py Sun Mar 14 23:48:28 2010 @@ -8,6 +8,7 @@ from Products.LinguaPlone.I18NBaseObject import I18NBaseObject + class I18NOrderedBaseFolder(I18NBaseObject, OrderedBaseFolder): """Base class for translatable objects.""" Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/LanguageIndex.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/LanguageIndex.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/LanguageIndex.py Sun Mar 14 23:48:28 2010 @@ -38,8 +38,8 @@ id. When used as mapping keys, these indexes are deemed the same object when their canonical id is identical, avoiding returning multiple translations of the same content. - """ + def __init__(self, docid, main, sub, cid): self.docid = docid self.main = main @@ -57,9 +57,11 @@ # Mapping key functions, cid is the actual key def __hash__(self): return hash(self.cid) + def __cmp__(self, other): return cmp(self.cid, other.cid) + class LanguageIndex(SimpleItem, PropertyManager): implements(ILanguageIndex, IUniqueValueIndex, ISortIndex) @@ -70,7 +72,7 @@ meta_type = 'LanguageIndex' manage_options = PropertyManager.manage_options + ( - dict(label='Histogram', action='manage_histogram'),) + dict(label='Histogram', action='manage_histogram'), ) security = ClassSecurityInfo() @@ -127,7 +129,11 @@ return 0 if ITranslatable.providedBy(obj): - cid = obj.getCanonical().UID() + canonical = obj.getCanonical() + # Gracefully deal with broken references + if canonical is None: + return 0 + cid = canonical.UID() else: # Also index non-translatable content, otherwise # LinguaPlone only shows translatable content. @@ -179,9 +185,10 @@ for language in record.keys: rows = self._search(language, fallback) result = ii_union(result, rows) - return (result or IISet()), ('Language',) + return (result or IISet()), ('Language', ) - security.declareProtected(Permissions.manage_zcatalog_indexes, 'numObjects') + security.declareProtected( + Permissions.manage_zcatalog_indexes, 'numObjects') def numObjects(self): """Return the number of indexed objects""" return len(self) @@ -269,7 +276,8 @@ if entry in self._index[entry.main][entry.sub]: self._index[entry.main][entry.sub].remove(entry) else: - LOG.warning("entry %s existed in _unindex but not in _index." % str(entry)) + LOG.warning("entry %s existed in _unindex " + "but not in _index." % str(entry)) if not self._index[entry.main][entry.sub]: del self._index[entry.main][entry.sub] @@ -397,6 +405,7 @@ manage_addLanguageIndexForm = PageTemplateFile('www/addLanguageIndex.pt', GLOBALS) + def manage_addLanguageIndex(self, id, extra=None, REQUEST=None, RESPONSE=None, URL3=None): """Add a LanguageIndex to the catalog (with the strange indirection)""" Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/__init__.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/__init__.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/__init__.py Sun Mar 14 23:48:28 2010 @@ -25,10 +25,10 @@ extra_constructors = constructors, fti = ftis, ).initialize(context) - + from Products.LinguaPlone import LanguageIndex context.registerClass( - LanguageIndex.LanguageIndex, + LanguageIndex.LanguageIndex, permission=permissions.AddLanguageIndex, constructors=(LanguageIndex.manage_addLanguageIndexForm, LanguageIndex.manage_addLanguageIndex), @@ -46,4 +46,4 @@ crit_reg.criterion2index[crit_id] = indices + (index, ) value = crit_reg.index2criterion.get(index, ()) - crit_reg.index2criterion[index] = value + (crit_id,) + crit_reg.index2criterion[index] = value + (crit_id, ) Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/configure.zcml ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/configure.zcml (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/configure.zcml Sun Mar 14 23:48:28 2010 @@ -3,9 +3,10 @@ xmlns:browser="http://namespaces.zope.org/browser" xmlns:plone="http://namespaces.plone.org/plone"> - <adapter - factory=".controlpanel.MultiLanguageControlPanelAdapter" - /> + <include package="plone.app.contentmenu" /> + <include package="plone.app.portlets" /> + + <adapter factory=".controlpanel.MultiLanguageControlPanelAdapter" /> <plone:portletRenderer portlet="plone.app.portlets.portlets.language.ILanguagePortlet" @@ -21,6 +22,21 @@ layer="..interfaces.ILinguaPloneProductLayer" /> + <browser:page + for="Products.CMFPlone.interfaces.IPloneSiteRoot" + name="language-setup-folders" + class=".setup.SetupView" + permission="cmf.ManagePortal" /> + + <browser:view + for="Products.CMFPlone.interfaces.IPloneSiteRoot" + class=".switcher.LanguageSwitcher" + name="language-switcher" + permission="zope.Public" + menu="plone_displayviews" + title="Root language switcher" + /> + <browser:page for="..interfaces.ITranslatable" name="translate" @@ -59,22 +75,22 @@ /> <browser:menu - id="plone_contentmenu_translate" - title="Translate menu - contains translation-related actions" - class=".menu.TranslateMenu" - /> - - <adapter for="..interfaces.ITranslatable *" - name="plone.contentmenu.translate" - factory=".menu.TranslateSubMenuItem" - provides="plone.app.contentmenu.interfaces.IContentMenuItem" /> - - <browser:viewlet - name="plone.app.i18n.locales.languageselector" - manager="plone.app.layout.viewlets.interfaces.IPortalTop" - class=".selector.TranslatableLanguageSelector" - permission="zope2.View" - layer="..interfaces.ILinguaPloneProductLayer" - /> + id="plone_contentmenu_translate" + title="Translate menu - contains translation-related actions" + class=".menu.TranslateMenu" + /> + + <adapter for="..interfaces.ITranslatable *" + name="plone.contentmenu.translate" + factory=".menu.TranslateSubMenuItem" + provides="plone.app.contentmenu.interfaces.IContentMenuItem" /> + + <browser:viewlet + name="plone.app.i18n.locales.languageselector" + manager="plone.app.layout.viewlets.interfaces.IPortalTop" + class=".selector.TranslatableLanguageSelector" + permission="zope2.View" + layer="..interfaces.ILinguaPloneProductLayer" + /> </configure> Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/language.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/language.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/language.py Sun Mar 14 23:48:28 2010 @@ -8,16 +8,19 @@ class Renderer(base.Renderer): + def __init__(self, context, request, view, manager, data): base.Renderer.__init__(self, context, request, view, manager, data) - self.selector=TranslatableLanguageSelector(context, request, None, None) - self.languages=self.selector.languages() + self.selector = TranslatableLanguageSelector(context, request, None, None) + self.selector.update() + self.languages = self.selector.languages() self.languages.sort(key=operator.itemgetter("native")) - portal_state = getMultiAdapter((context, request), name=u'plone_portal_state') + portal_state = getMultiAdapter((context, request), + name=u'plone_portal_state') self.portal_url = portal_state.portal_url() def show(self): - return self.selector.available() and len(self.languages)>1 + return self.selector.available() and len(self.languages) > 1 def showFlags(self): return self.selector.showFlags() @@ -49,4 +52,3 @@ updater(lang) return self.languages - Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/selector.pt ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/selector.pt (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/browser/selector.pt Sun Mar 14 23:48:28 2010 @@ -4,25 +4,26 @@ languages view/languages;"> <tal:language repeat="lang languages"> <li tal:define="code lang/code; - selected lang/selected" - tal:attributes="class python: selected and 'currentLanguage' or '';"> + selected lang/selected; + codeclass string:language-${code}; + current python: selected and 'currentLanguage ' or '';" + tal:attributes="class string:${current}${codeclass}"> <a href="" tal:define="flag lang/flag|nothing; - name lang/native|lang/name" + name lang/native|lang/name; + showflag python:showFlags and flag;" tal:attributes="href lang/url; title name"> - <tal:flag condition="python:showFlags and flag"> - <img - width="14" + <tal:flag condition="showflag"> + <img width="14" height="11" alt="" tal:attributes="src string:${view/portal_url}${flag}; - alt python: name; - title python: name; - class python: selected and 'currentItem' or '';" /> + alt name; + title name;" /> </tal:flag - ><tal:nonflag condition="python:not showFlags or not flag" - replace="name">language name</tal:nonflag + ><tal:nonflag condition="python:not showflag" + replace="name">language name</tal:nonflag ></a> </li> </tal:language> Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/config.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/config.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/config.py Sun Mar 14 23:48:28 2010 @@ -7,7 +7,7 @@ PKG_NAME = "LinguaPlone" SKIN_NAME = "LinguaPlone" -SKIN_LAYERS = (SKIN_NAME,) +SKIN_LAYERS = (SKIN_NAME, ) RELATIONSHIP = 'translationOf' @@ -46,5 +46,6 @@ logger = logging.getLogger("LinguaPlone") + def log(msg, level=logging.INFO): logger.log(level, msg) Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/events.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/events.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/events.py Sun Mar 14 23:48:28 2010 @@ -2,18 +2,21 @@ from zope.interface import Attribute from zope.component.interfaces import IObjectEvent + class IObjectWillBeTranslatedEvent(IObjectEvent): """Sent before an object is translated.""" object = Attribute("The object to be translated.") - language = Attribute("Target language.") + language = Attribute("Target language.") + class IObjectTranslatedEvent(IObjectEvent): """Sent after an object was translated.""" object = Attribute("The object to be translated.") target = Attribute("The translation target object.") - language = Attribute("Target language.") + language = Attribute("Target language.") + class ObjectWillBeTranslatedEvent(object): """Sent before an object is translated.""" @@ -23,6 +26,7 @@ self.object = context self.language = language + class ObjectTranslatedEvent(object): """Sent after an object was translated.""" implements(IObjectTranslatedEvent) Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/examples/LinguaItem.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/examples/LinguaItem.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/examples/LinguaItem.py Sun Mar 14 23:48:28 2010 @@ -10,8 +10,9 @@ schema = BaseSchema + Schema(( StringField('contact', languageIndependent = 1, - widget = StringWidget(description="Enter a contact email address" - " (this field is language independent).") + widget = StringWidget( + description="Enter a contact email address (this field is " + "language independent)."), ), TextField('body', required = 1, @@ -49,19 +50,22 @@ archetypes_name = portal_type = meta_type = 'Lingua Item' schema = schema - actions = [{ 'id': 'edit', - 'name': 'Edit', - 'action': 'string:${object_url}/base_edit', - 'condition': 'python: object.isTranslatable() and object.isCanonical()', - 'permissions': (ModifyPortalContent,), - }, - { 'id': 'translate', - 'name': 'Edit', - 'action': 'string:${object_url}/translate_item', - 'condition': 'python: object.isTranslatable() and not object.isCanonical()', - 'permissions': (ModifyPortalContent,), - }, - ] + actions = [ + {'id': 'edit', + 'name': 'Edit', + 'action': 'string:${object_url}/base_edit', + 'condition': + 'python: object.isTranslatable() and object.isCanonical()', + 'permissions': (ModifyPortalContent, ), + }, + {'id': 'translate', + 'name': 'Edit', + 'action': 'string:${object_url}/translate_item', + 'condition': + 'python:object.isTranslatable() and not object.isCanonical()', + 'permissions': (ModifyPortalContent, ), + }, + ] security = ClassSecurityInfo() Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/LanguageIndex.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/LanguageIndex.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/LanguageIndex.py Sun Mar 14 23:48:28 2010 @@ -15,14 +15,14 @@ def _exportNode(self): """Export the object as a DOM node.""" - + node = self._getObjectNode('index') node.appendChild(self._extractProperties()) return node def _importNode(self, node): """Import the object from the DOM node.""" - + if self.environ.shouldPurge(): self._purgeProperties() Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/__init__.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/__init__.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/__init__.py Sun Mar 14 23:48:28 2010 @@ -1 +1 @@ -# make this a package +# Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/configure.zcml ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/configure.zcml (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/exportimport/configure.zcml Sun Mar 14 23:48:28 2010 @@ -1,40 +1,46 @@ <configure xmlns="http://namespaces.zope.org/zope" xmlns:genericsetup="http://namespaces.zope.org/genericsetup" + xmlns:zcml="http://namespaces.zope.org/zcml" i18n_domain="linguaplone"> <adapter factory=".LanguageIndex.LanguageIndexNodeAdapter" /> - <adapter factory=".reference.ReferenceCatalogXMLAdapter"/> - <adapter factory=".uid.UIDCatalogXMLAdapter"/> - <genericsetup:importStep - name="reference_catalog" - title="Reference Catalog" - description="Import reference catalog." - handler=".reference.importCatalogTool"> - <depends name="toolset" /> - </genericsetup:importStep> - - <genericsetup:exportStep - name="reference_catalog" - title="Reference Catalog" - description="Export reference catalog." - handler=".reference.exportCatalogTool" - /> - - <genericsetup:importStep - name="uid_catalog" - title="UID Catalog" - description="Import uid catalog." - handler=".uid.importCatalogTool"> - <depends name="toolset" /> - </genericsetup:importStep> - - <genericsetup:exportStep - name="uid_catalog" - title="UID Catalog" - description="Export uid catalog." - handler=".uid.exportCatalogTool" - /> + <configure zcml:condition="not-installed Products.Archetypes.exportimport.catalog"> + + <adapter factory=".reference.ReferenceCatalogXMLAdapter"/> + <adapter factory=".uid.UIDCatalogXMLAdapter"/> + + <genericsetup:importStep + name="reference_catalog" + title="Reference Catalog" + description="Import reference catalog." + handler=".reference.importCatalogTool"> + <depends name="toolset" /> + </genericsetup:importStep> + + <genericsetup:exportStep + name="reference_catalog" + title="Reference Catalog" + description="Export reference catalog." + handler=".reference.exportCatalogTool" + /> + + <genericsetup:importStep + name="uid_catalog" + title="UID Catalog" + description="Import uid catalog." + handler=".uid.importCatalogTool"> + <depends name="toolset" /> + </genericsetup:importStep> + + <genericsetup:exportStep + name="uid_catalog" + title="UID Catalog" + description="Export uid catalog." + handler=".uid.exportCatalogTool" + /> + + </configure> </configure> Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/interfaces.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/interfaces.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/interfaces.py Sun Mar 14 23:48:28 2010 @@ -5,6 +5,7 @@ from plone.theme.interfaces import IDefaultPloneLayer + class ILinguaPloneProductLayer(IDefaultPloneLayer): """A layer specific for LinguaPlone. @@ -15,47 +16,48 @@ class ILanguageIndex(IPluggableIndex): """Index for ITranslatable Language tags - + The index treats language tags according to RFC 1766, with the assumption - that languages with more than one subtag but with the same initial subtag + that languages with more than one subtag but with the same initial subtag as related; en-us is related to en-gb, and will fall back to related content (same canonical UID) when queried. - + Language tags are treated as containing a initial subtag, and one optional second subtag, splitting a tag on the first dash. Thus, this index does - not support additional subtags, but modern browsers never send anything + not support additional subtags, but modern browsers never send anything more complicated than a main language with a region or dialect, nor do current Plone i18n tools support anything else. - - Fallback rules are as follows: if searching for a given language tag, a + + Fallback rules are as follows: if searching for a given language tag, a union is returned of: - + 1. Exact tag match 2. Initial subtag match, no second subtag (if not the original search) 3. Any other second subtags indexed for the initial subtag in alfabetical order. - + Results are filtered for unique canonical UIDs, thus ensuring only one translation per content item is returned. - + So, when searching for en-gb, all matches for en-gb are returned, plus any matches for en, en-au, en-ca, en-nz, en-us if such tags were indexed and not already translated into en-gb. - + The fallback behaviour can be disabled by setting index.fallback to False, or passing a 'fallback' query parameter (also a boolean) to the index when querying. """ - + fallback = Attribute( 'fallback', """Wether or not to enable language fallback querying. - + Boolean, defaults to True. """, ) + class ITranslatable(Interface): """ Interface for translatable content. @@ -65,8 +67,8 @@ """ def isTranslation(): - """ - return language if this object is used as multilingual content, 0 otherwise + """Return language if this object is used as multilingual content, + 0 otherwise. """ def addTranslation(language, **kwargs): @@ -83,11 +85,14 @@ def getTranslation(language='language'): """ - Return the object corresponding to a translated version or None. + Return the object corresponding to a translated version or None if no + translation exists. + If called without arguments it returns the translation in the currently - selected language, or self. + selected language. If the object is already in the selected language + it returns self. """ - + def getTranslationLanguages(): """ Return a list of language codes @@ -176,4 +181,3 @@ def copyFields(translation): """Copy language independent fields to translation.""" - Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/migrations.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/migrations.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/migrations.py Sun Mar 14 23:48:28 2010 @@ -85,7 +85,8 @@ def add_properties_sheet(context): log = logging.getLogger("LinguaPlone") - context.runImportStepFromProfile('profile-Products.LinguaPlone:LinguaPlone', - 'propertiestool', - run_dependencies=False, - purge_old=False) + context.runImportStepFromProfile( + 'profile-Products.LinguaPlone:LinguaPlone', + 'propertiestool', + run_dependencies=False, + purge_old=False) Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/patches.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/patches.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/patches.py Sun Mar 14 23:48:28 2010 @@ -1,8 +1,9 @@ from Products.LinguaPlone.config import I18NAWARE_CATALOG -from Products.LinguaPlone.config import NOFILTERKEYS +from Products.LinguaPlone.catalog import languageFilter _enabled = [] + def AlreadyApplied(patch): if patch in _enabled: return True @@ -10,8 +11,8 @@ return False -# Patches the catalog tool to filter languages def I18nAwareCatalog(): + # Patches the catalog tool to filter languages if AlreadyApplied('I18nAwareCatalog'): return @@ -21,7 +22,6 @@ from Globals import DTMLFile from Products.CMFPlone.CatalogTool import CatalogTool - from Products.CMFCore.utils import getToolByName def searchResults(self, REQUEST=None, **kw): """ Calls ZCatalog.searchResults with extra arguments that @@ -31,35 +31,16 @@ language, unless you explicitly ask for all results by providing the Language="all" keyword. """ - kw = kw.copy() - languageTool = getToolByName(self, 'portal_languages', None) - - # When searching on certain indexes we don't want language filtering. - def filterSearch(query, nofilter=NOFILTERKEYS): - if not query: - return 1 - for key in nofilter: - if key in query: - return 0 - return 1 - - if languageTool is not None and filterSearch(REQUEST) and filterSearch(kw): - try: - kw['Language'] = [languageTool.getPreferredLanguage(), ''] - except AttributeError: - pass - # 'all' deletes the query key - elif REQUEST and REQUEST.get('Language', '') == 'all': - del REQUEST['Language'] - elif kw.get('Language', '') == 'all': - del kw['Language'] - + if REQUEST is not None: + languageFilter(REQUEST) + else: + languageFilter(kw) return self.__lp_old_searchResults(REQUEST, **kw) CatalogTool.__lp_old_searchResults = CatalogTool.searchResults CatalogTool.searchResults = searchResults CatalogTool.__call__ = searchResults - CatalogTool.manage_catalogView = DTMLFile('www/catalogView',globals()) + CatalogTool.manage_catalogView = DTMLFile('www/catalogView', globals()) if I18NAWARE_CATALOG: @@ -70,6 +51,7 @@ # vocabularies from Products.PloneLanguageTool import LanguageTool + def new_addSupportedLanguage(self, langCode): """Registers a language code as supported.""" value = str(langCode) Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/permissions.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/permissions.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/permissions.py Sun Mar 14 23:48:28 2010 @@ -6,6 +6,6 @@ AccessContentsInformation = permissions.AccessContentsInformation AddLanguageIndex = 'LinguaPlone: Add LanguageIndex' -permissions.setDefaultRoles(AddLanguageIndex, ('Manager',)) +permissions.setDefaultRoles(AddLanguageIndex, ('Manager', )) del permissions Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/public.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/public.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/public.py Sun Mar 14 23:48:28 2010 @@ -4,13 +4,15 @@ from Products.LinguaPlone.I18NBaseObject import I18NBaseObject as BaseObject from Products.LinguaPlone.I18NBaseContent import I18NBaseContent as BaseContent from Products.LinguaPlone.I18NBaseFolder import I18NBaseFolder as BaseFolder -from Products.LinguaPlone.I18NBaseBTreeFolder import I18NBaseBTreeFolder as BaseBTreeFolder -from Products.LinguaPlone.I18NOrderedBaseFolder import I18NOrderedBaseFolder as OrderedBaseFolder +from Products.LinguaPlone.I18NBaseBTreeFolder import \ + I18NBaseBTreeFolder as BaseBTreeFolder +from Products.LinguaPlone.I18NOrderedBaseFolder import \ + I18NOrderedBaseFolder as OrderedBaseFolder # Calculate which modules should be exported import sys -skipExports = ('skipExports', 'sys',) -__all__ = tuple([ export - for export in dir(sys.modules[__name__]) - if export not in skipExports and not export.startswith('_') - ]) +skipExports = ('skipExports', 'sys', ) + +__all__ = tuple([export + for export in dir(sys.modules[__name__]) + if export not in skipExports and not export.startswith('_')]) Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/skins/LinguaPlone/manage_translations_form.pt ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/skins/LinguaPlone/manage_translations_form.pt (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/skins/LinguaPlone/manage_translations_form.pt Sun Mar 14 23:48:28 2010 @@ -145,8 +145,7 @@ </div> <div class="field" - tal:define="startup_method nocall:here/referencebrowser_startupDirectory|nothing; - startup_directory python:startup_method and startup_method('') or ''; + tal:define="startup_directory python:'/'.join(here.getPhysicalPath()); value request/link_content | nothing; fieldName string:link_content; fieldRealName fieldName; Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testAPI.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testAPI.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testAPI.py Sun Mar 14 23:48:28 2010 @@ -322,10 +322,10 @@ self.english.processForm(values={'title':'Not Second'}) self.assertEqual(self.english.getId(), 'only-first') - def testProcessFormDoesNotRenameTranslation(self): + def testProcessFormRenamesTranslation(self): transaction.savepoint(optimistic=True) self.german.processForm(values={'title' : 'Renamed Too'}) - self.assertEqual(self.german.getId(), 'doc-de') + self.assertEqual(self.german.getId(), 'renamed-too') def testProcessFormRenameTranslationWithId(self): transaction.savepoint(optimistic=True) Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testCatalog.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testCatalog.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testCatalog.py Sun Mar 14 23:48:28 2010 @@ -2,11 +2,63 @@ # Catalog Tests # +from Products.LinguaPlone.config import NOFILTERKEYS +from Products.LinguaPlone.catalog import languageFilter from Products.LinguaPlone.tests import LinguaPloneTestCase from Products.LinguaPlone.tests.utils import makeContent from Products.LinguaPlone.tests.utils import makeTranslation +class TestLanguageFilter(LinguaPloneTestCase.LinguaPloneTestCase): + + def afterSetUp(self): + LinguaPloneTestCase.LinguaPloneTestCase.afterSetUp(self) + self.addLanguage('de') + self.setLanguage('en') + + def testEnglish(self): + query = {'review_state' : 'published'} + languageFilter(query) + self.failUnless('Language' in query) + self.assertEquals(query['Language'], ['en', '']) + + def testGerman(self): + query = {'review_state' : 'published', 'Language' : 'de'} + languageFilter(query) + self.failUnless('Language' in query) + self.assertEquals(query['Language'], 'de') + + def testMultiple(self): + query = {'review_state' : 'published', 'Language' : ['en', 'de']} + languageFilter(query) + self.failUnless('Language' in query) + self.assertEquals(query['Language'], ['en', 'de']) + + def testNeutral(self): + query = {'review_state' : 'published', 'Language' : ''} + languageFilter(query) + self.failUnless('Language' in query) + self.assertEquals(query['Language'], '') + + def testAll(self): + query = {'review_state' : 'published', 'Language' : 'all'} + languageFilter(query) + self.failIf('Language' in query) + + def testNoFilter(self): + self.failUnless('UID' in NOFILTERKEYS) + query = {'UID' : '123'} + languageFilter(query) + self.failIf('Language' in query) + + def testNoFilterExplicitLanguage(self): + self.failUnless('UID' in NOFILTERKEYS) + query = {'UID' : '123', 'Language' : 'de'} + languageFilter(query) + self.failUnless('Language' in query) + self.assertEquals(query['Language'], 'de') + + class TestMultilingualCatalog(LinguaPloneTestCase.LinguaPloneTestCase): def afterSetUp(self): @@ -74,6 +126,6 @@ def test_suite(): from unittest import TestSuite, makeSuite suite = TestSuite() + suite.addTest(makeSuite(TestLanguageFilter)) suite.addTest(makeSuite(TestMultilingualCatalog)) return suite - Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testFunctional.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testFunctional.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/tests/testFunctional.py Sun Mar 14 23:48:28 2010 @@ -11,6 +11,7 @@ 'dynamic_view.txt', 'translate_edit.txt', 'migration.txt', + 'language_setup.txt', ] PLONE40 = False Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/utils.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/utils.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/Products/LinguaPlone/utils.py Sun Mar 14 23:48:28 2010 @@ -28,10 +28,10 @@ AT_GENERATE_METHOD = [] _modes.update({ - 't' : { 'prefix' : 'setTranslation', - 'attr' : 'translation_mutator', - 'security' : 'write_permission', - }, + 't': {'prefix': 'setTranslation', + 'attr': 'translation_mutator', + 'security': 'write_permission', + }, }) @@ -70,6 +70,7 @@ def generatedAccessorWrapper(name): + def generatedAccessor(self, **kw): """Default Accessor.""" if 'schema' in kw: @@ -82,6 +83,7 @@ def generatedEditAccessorWrapper(name): + def generatedEditAccessor(self, **kw): """Default Edit Accessor.""" if 'schema' in kw: @@ -94,6 +96,7 @@ def generatedMutatorWrapper(name): + def generatedMutator(self, value, **kw): """LinguaPlone Default Mutator.""" if 'schema' in kw: @@ -149,6 +152,7 @@ def generatedTranslationMutatorWrapper(name): + def generatedTranslationMutator(self, value, **kw): """Delegated Mutator.""" if 'schema' in kw: @@ -187,8 +191,8 @@ # Zope security requires all security protected methods to have a # function name. It uses this name to determine which roles are allowed # to access the method. - # This code is renaming the internal name from e.g. generatedAccessor to - # methodName. + # This code is renaming the internal name from e.g. generatedAccessor + # to methodName. method = function(method.func_code, method.func_globals, methodName, @@ -318,8 +322,8 @@ if canonical is not None: o.addReference(canonical, '%(RELATIONSHIP)s') return o.getId() -""" % {'name':name, 'KWARGS_TRANSLATION_KEY':KWARGS_TRANSLATION_KEY, - 'RELATIONSHIP':RELATIONSHIP} +""" % {'name': name, 'KWARGS_TRANSLATION_KEY': KWARGS_TRANSLATION_KEY, + 'RELATIONSHIP': RELATIONSHIP} exec ctor in module.__dict__ return getattr(module, 'add%s' % name) @@ -330,9 +334,11 @@ from copy import deepcopy from Products.Archetypes.ArchetypeTool import base_factory_type_information from Products.Archetypes.ArchetypeTool import modify_fti + + def process_types(types, pkg_name): content_types = () - constructors = () + constructors = () ftis = () for rti in types: @@ -363,13 +369,13 @@ if ctor is None: ctor = generateCtor(typeName, module) - content_types += (klass,) - constructors += (ctor,) + content_types += (klass, ) + constructors += (ctor, ) ftis += fti return content_types, constructors, ftis -# Language tag splitting + def splitLanguage(tag): """Split a language tag (RFC 1766) into components @@ -442,7 +448,6 @@ def __init__(self, context): self.context=context - def findLocationForTranslation(self, language): parent = aq_parent(aq_inner(self.context)) trans_parent = ITranslatable(parent, None) @@ -462,7 +467,6 @@ def __init__(self, context): self.context=context - def generateId(self, container, canonical_id, language): new_id = canonical_id suffix = "-" + str(language) # unicode breaks `checkValidId()` @@ -471,11 +475,9 @@ return new_id - def getTranslationPortalType(self, container, language): return self.context.portal_type - def createTranslation(self, container, language, *args, **kwargs): context = aq_inner(self.context) canonical = context.getCanonical() Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/README.txt ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/README.txt (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/README.txt Sun Mar 14 23:48:28 2010 @@ -50,8 +50,8 @@ Installation ============ -If you are upgrading LinguaPlone there may be an upgrade step that you -need to do. Please check the 'Add-on Products' control panel for this. +If you are upgrading LinguaPlone there may be an upgrade step that you need to +do. Please check the 'Add-ons' control panel for this. Frequently asked questions @@ -78,7 +78,7 @@ - (Re)start Zope -- 'Site Setup' → 'Add/Remove Products', install LinguaPlone +- 'Site Setup' → 'Addons', install LinguaPlone For the demonstration to make sense, we need to define a list of languages: @@ -93,8 +93,7 @@ - Press 'Save' Now we have a few languages to play with, and can go back to the Plone -interface. Notice how you now have flags indicating your selected languages -under the print/sendto area. +interface. Notice how you now have a few language names in the top right corner. We now want to add a simple type: Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/docs/FAQ.txt ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/docs/FAQ.txt (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/docs/FAQ.txt Sun Mar 14 23:48:28 2010 @@ -45,7 +45,7 @@ with the same language currently in the original folder will be moved to the new folder, automatically. -What happens whe I translate the default view of a folder? +What happens when I translate the default view of a folder? The default view is the content selected to be displayed when directly accessing a folder. In this case, when translating it, LinguaPlone first creates a translation for the folder, then the content. @@ -73,17 +73,18 @@ the same language. How can I change the content language? - Both the 'Properties' tab and the 'Manage Translations' menu item allows - you to change the language to 'neutral' again. The difference - is that the latter also performs some restrictions to only display sane - values, while the former display all languages. We recommend using the - 'Manage Translations' entry in the Translate pulldown. + Both the 'Categorization' tab and the 'Manage Translations' menu item allows + you to change the language of an item. The difference is that the latter also + performs some restrictions to only display sane values, while the former + display all languages. We recommend using the 'Manage Translations' entry in + the Translate pulldown. Can I make an already translated content be language independent again? - Yes. You just need to change the language to 'neutral'. + Yes. You just need to change the language to 'neutral'. This only works on + 'Categorization' tab of an item. What is the 'neutral' language? - It's exacty what it means: neutral. In other words, it's a way to represent + It's exactly what it means: neutral. In other words, it's a way to represent the content in all languages. The content becomes language independent and can be displayed for any language when both navigating and searching. Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/setup.py ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/setup.py (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/setup.py Sun Mar 14 23:48:28 2010 @@ -1,7 +1,7 @@ from setuptools import setup, find_packages import os.path -version = '3.0.1' +version = '3.1a2' setup(name='Products.LinguaPlone', version=version, Modified: Products.LinguaPlone/branches/matthewwilkes-fallback/test-plone-3.3.x.cfg ============================================================================== --- Products.LinguaPlone/branches/matthewwilkes-fallback/test-plone-3.3.x.cfg (original) +++ Products.LinguaPlone/branches/matthewwilkes-fallback/test-plone-3.3.x.cfg Sun Mar 14 23:48:28 2010 @@ -4,3 +4,27 @@ package-name = Products.LinguaPlone +parts = + instance + test + coverage-test + coverage-report + + +[coverage-test] +<= test +entry-points = coverage-test=plone.recipe.zope2instance.ctl:main +arguments = + ["-C", "${instance:location}/etc/zope.conf", "test", "-s", + "${buildout:package-name}", "--test-path=.", "--coverage", + "./coverage"] + sys.argv[1:] + + +[coverage-report] +recipe = zc.recipe.egg +eggs = z3c.coverage +arguments = ('coverage', 'coverage/report') + + +[versions] +z3c.coverage = 1.2.0 |