How to set language on copied event with Plone - plone

I'm using LinguaPlone for my personal website and I have set it up using languages folder.
When I try to copy and paste an image from the en language folder into the 'fr' folder, the language is not changed. So I want to fix this behavior.
I'm trying to fix this at the moment in my own code but I just don't know why it doesn't work.
So the question is: how do I achieve this ? am I on the good way to do this ? what is missing here ?
from zope import component
from zope.globalrequest import getRequest
def updatelang(ob, event):
current = event.object
tools = component.getMultiAdapter((ob, getRequest()), name=u'plone_portal_state')
current_lang = current.getLanguage()
lang = tools.language()
if current_lang != lang:
current_object.setLanguage(lang)
ob.reindexObject(idxs=['Language'])
The setLanguage call throws an attribute error on reference_catalog.
Note, I'm working on Plone4.1

Self answer:
LinguaPlone override setLanguage to move the content in the first translated container in the parent chain.
Modify a bit the code to use getField pattern:
from zope import component
from zope.globalrequest import getRequest
def updatelang(ob, event):
current = event.object
tools = component.getMultiAdapter((ob, getRequest()), name=u'plone_portal_state')
current_lang = current.getLanguage()
lang = tools.language()
if current_lang != lang:
current.getField('language').set(current, lang)
current.reindexObject(idxs=['Language'])
Warning this code doesn do any check on already existing translation (if the current object has a translation in that language it will break things). but doing copy paste from one language to the other is a bad action, may be we should try to make them fail at all with a raise exception.

Related

what does this line indicate:- module = _("Polls") in Django CMS PollPluginPublisher

I am trying to learn Django Cms but here is where I have stuck. IN the following code of Django CMS official documentation
Link:-http://docs.django-cms.org/en/release-3.4.x/introduction/plugins.html
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from polls_cms_integration.models import PollPluginModel
from django.utils.translation import ugettext as _
class PollPluginPublisher(CMSPluginBase):
model = PollPluginModel # model where plugin data are saved
module = _("Polls")
name = _("Poll Plugin") # name of the plugin in the interface
render_template = "polls_cms_integration/poll_plugin.html"
def render(self, context, instance, placeholder):
context.update({'instance': instance})
return context
plugin_pool.register_plugin(PollPluginPublisher) # register the plugin
I am unable to get the use of line module = _("Polls")
from django.utils.translation import ugettext as _
Django I18N documentation
In order to make a Django project translatable, you have to add a minimal number of hooks to your Python code and templates. These hooks are called translation strings. They tell Django: “This text should be translated into the end user’s language, if a translation for this text is available in that language.” It’s your responsibility to mark translatable strings; the system can only translate strings it knows about.
...
Specify a translation string by using the function ugettext(). It’s convention to import this as a shorter alias, _, to save typing.

Plone 4.3 - How to build a Form package using Zc3.form without Grok?

I am trying to build a form package for a Plone website. I am currently working with Plone 4.3. Before I was using Dexterity with five.grok and grok libraries. But after reading the Plone 4.3 migration and five.grok dependency section of this article: http://developer.plone.org/components/grok.html it appears that Plone developers are moving away from using grok all together.
So should I move away from using Grok and how would I go about doing so when all the current documentation is currently using Grok? Additionally I am developing from a Windows based machine.
First creating form without grok is not that hard and do not depends on your Operating System.
Creating a form is always the same. Here is how I proceed:
Some imports
from Products.Five.browser import BrowserView
from plone.autoform.form import AutoExtensibleForm
from plone.app.z3cform import layout
from zope import interface
from zope import schema
from zope import component
from z3c.form import form
from collective.my.i18n import _
Create a schema
class AddFormSchema(interface.Interface):
what = schema.Choice(
title=_(u"What"),
vocabulary="plone.app.vocabularies.UserFriendlyTypes"
)
where = schema.Choice(
title=u"Where",
vocabulary="collective.my.vocabulary.groups"
)
create a generic adapter to fill the form from anywhere
class AddFormAdapter(object):
interface.implements(AddFormSchema)
component.adapts(interface.Interface)
def __init__(self, context):
self.what = None
self.where = None
Then write the form
class AddForm(AutoExtensibleForm, form.Form):
schema = AddFormSchema
form_name = 'add_content'
Add a view
class AddButton(layout.FormWrapper):
"""Add button"""
form = AddForm
Now ZCML time this is the step you don't need when using grok:
<adapter factory=".my.AddFormAdapter"/>
<browser:page
for="*"
name="my.addbutton"
class=".my.AddButton"
template="addbutton.pt"
permission="zope2.View"
/>
Should you move from grok:
This is depending of what are you doing. For an addon I say Yes but for a project, it's up to you.
Grok is not parts of the already big Zope. So adding dependency is something that always should be done only if needed. Grok is an option so I have never used it.

How to move/rename object with overwritting in Zope?

I'm trying to move object (i.e. image file) from one folder to another one and then rename it - overwrite with existing object (i.e. updating file).
I'm doing it in Zope (I use Plone 4.2) in the following way:
from zope.component.hooks import getSite
from zope.traversing.api import traverse
site = getSite()
src = traverse(site, "preview/")
dst = traverse(site, "images/")
source = src.manage_cutObjects(ids=[previewName])
dst.manage_pasteObjects(source)
dst.manage_delObjects(ids=[existingName])
That piece of code does what it should do, it moves the object from one folder to another, then, as manage_renameObject procedure doesn't allow overwritting I delete the existing object which will be replaced. But if I add this line of code to achieve the final goal:
dst.manage_renameObject(previewName, existingName)
the exception is thrown, that ID provided by existingName is invalid (because the object with such ID already exists and no matter that I have deleted it before).
It looks like I need some commit or update to finalize object moving (or wait etc) but I can't find anything about that.
UPDATE
I forget to add: all changes (object moving, object deletion) before exception in manage_renameObject was thrown weren't applied. Now, with transaction.commit() (as proposed by lewicki) the changes are applied but exception still occurs. Procedure transaction.savepoint() didn't help much, the exception was still thrown and changes weren't applied.
RESOLVED
I was confused initially by the error message:
<CENTER>
('Empty or invalid id specified', u'27')
</CENTER>
When I tried to reproduce the issue in the ZMI I got:
<CENTER>
The id "27" is invalid - it is already in use.
</CENTER>
and I realized that I needed to look into the code.
I dig into the installed Plone code and then located what I looked for in eggs/Zope2-2.13.18-py2.7.egg/OFS/ObjectManager.py module, in checkValidId() procedure.. There was the root of all my problems:
if not id or not isinstance(id, str):
if isinstance(id, unicode):
id = escape(id)
raise BadRequest, ('Empty or invalid id specified', id)
so, I strict object names (IDs) to str type and it all became working...
Neither commit() nor savepoint() even was needed (but initially when I was figuring out the issue and observing in ZMI that my files was neither moved nor deleted that was confused me a lot).
Thank you for your assistance!
It's dst.manage_renameObject(oldid, newid). This should work
Documentation
Yes, you're right - commit may be requred. I had a similar problem and it was solved that way:
from zope.component.hooks import getSite
from zope.traversing.api import traverse
import transaction
site = getSite()
src = traverse(site, "preview/")
dst = traverse(site, "images/")
source = src.manage_cutObjects(ids=[newName])
dst.manage_pasteObjects(source)
dst.manage_delObjects(ids=[existingName])
transaction.commit()
Now I think that
transaction.savepoint()
should be enough but you have to check on your own.

Why does my content object not show up in the portal_catalog?

I am trying to implement a basic Zope2 content type directly without using dexterity or Archetypes because I need this to be extremely lean.
from OFS.SimpleItem import SimpleItem
from Products.ZCatalog.CatalogPathAwareness import CatalogAware
from persistent.list import PersistentList
class Doculite(SimpleItem, CatalogAware):
""" implement our class """
meta_type = 'Doculite'
def __init__(self, id, title="No title", desc=''):
self.id = id
self.title = title
self.desc = desc
self.tags = PersistentList()
self.default_catalog = 'portal_catalog'
def add_tags(self, tags):
self.tags.extend(tags)
def Subject(self):
return self.tags
def indexObject(self):
self.reindex_object()
From an external method I am doing this:
def doit(self):
pc = self.portal_catalog
res1 = pc.searchResults()
o1 = self['doc1']
o1.add_tags(['test1', 'test2'])
o1.reindex_object()
res2 = pc.searchResults()
return 'Done'
I clear the catalog and run my external method. My object does not get into the catalog. But from the indexes tab, when I browse the Subject index, I can see my content item listed with the values. Both res1 and res2 and empty.
Why is my content item not showing up inside the searchResuts() of the catalog?
Plone is a full-fat content management system, if you're after something lean it's probably not the right choice (perhaps try Pyramid.)
For your content type to be a full part of a Plone site it has to fulfil a number of requirements across the Zope2, CMF and Plone layers. plone.app.content.item.Item is about the simplest base class you can get for a content item for a Plone site, though a simpler base class in itself will not really make instances of your content type any more 'lean' - an instance of a class in Python is basically just a dict and a pointer to it's class.
Most of the work on a page view will be rendering the various user interface features of a site. Rendering the schema based add/edit forms of frameworks like Archetypes and Dexterity is also relatively expensive.
I'd spend a little time profiling your application using one of the supported content type systems before putting time into building your own.
In order to see your objects in the "Catalog" tab of the portal_catalog your objects need to have a "getPhysicalPath()" method that returns a tuple representing their path (ex. ('','Plone','myobject')).
Also try to use this:
from Products.CMFCore.CMFCatalogAware import CMFCatalogAware
as base class.
You need to register your type with the catalog multiplexer. Look at the configuration in the zmi -> archetypes_tool.
I'm not sure, but you may also need a portal_type registration also...
Like Lawrence said though, you're better off just using one of the current content type frameworks if you want to be able to catalog your data with plone's portal catalog. If you can deal with a separate catalog, take a look at repoze.catalog.
Plone needs every content object to provide an "allowedRolesAndUsers" index to return the object in searchResults.
There is probably a zcml snippet that will enable this for my content type. But I was able to get things working by adding another method as follows:
def allowedRolesAndUsers(self):
return ['Manager', 'Authenticated', 'Anonymous']
CatalogAware will be removed in Zope 4 and then can't be used any more.
cf https://github.com/zopefoundation/Products.ZCatalog/issues/26

Setting the default page using quintagroup.transmogrifier generic setup import doesn't work with dexterity

We're using a quintagroup.transmogrifier content import profile to load content for our automated tests (very useful). Setting the default page doesn't seem to work.
The docs suggest quintagroup.transmogrifier supports setting default pages but not whether it does for generic set-up import steps. I eventually figured out you need to add a properties.xml file into the folder of the folderish item with the following:
<?xml version="1.0" encoding="utf-8"?>
<properties>
<property name="default_page" type="string">
index
</property>
</properties>
where index is replaced by the id of the default page and also in your import.cfg you need
[transmogrifier]
pipeline =
reader
…
propertiesimporter
[reader]
…
.properties.xml = propertymanager
[propertiesimporter]
blueprint = quintagroup.transmogrifier.propertiesimporter
However this doesn't work. We're running Plone 4.1rc3 + Dexterity 1.0 and presumably it's not compatible with Dexterity. I've tracked down the bit of code in quintagroup.transmogrifier.propertymanager.PropertiesImporterSection where it is falling down:
path = item[pathkey]
obj = self.context.unrestrictedTraverse(path, None)
Here path is a unicode string and unrestrictedTraverse returns None. If you use a byte string then it returns the correct object. Is this an incompatibility with Dexterity or am I doing something wrong?
This is a bug you'll need to report with the authors of the quintagroup.transmogrifier package. Paths must always be ASCII bytestrings, not Unicode objects. All sections in collective.transmogrifier (the underlying engine that quintagroup.transmogrifier uses) encode paths to ASCII.
Here is a code snippet from collective.transmogrifier.sections.constructor for example:
type_, path = item[typekey], item[pathkey]
fti = self.ttool.getTypeInfo(type_)
if fti is None: # not an existing type
yield item; continue
path = path.encode('ASCII')
elems = path.strip('/').rsplit('/', 1)
container, id = (len(elems) == 1 and ('', elems[0]) or elems)
context = self.context.unrestrictedTraverse(container, None)
Report it to the dedicated issue tracker on Plone.org so the authors can fix it for you.

Resources