[Zope3-checkins] CVS: Zope3/src/zope/products/i18nfile -
__init__.py:1.1.2.1 browser.py:1.1.2.1 configure.zcml:1.1.2.1
edit.pt:1.1.2.1 i18nfile.py:1.1.2.1 interfaces.py:1.1.2.1
tests.py:1.1.2.1
Philipp von Weitershausen
philikon at philikon.de
Wed Feb 11 11:29:23 EST 2004
Update of /cvs-repository/Zope3/src/zope/products/i18nfile
In directory cvs.zope.org:/tmp/cvs-serv21715/i18nfile
Added Files:
Tag: philikon-movecontent-branch
__init__.py browser.py configure.zcml edit.pt i18nfile.py
interfaces.py tests.py
Log Message:
Get rid of zope.products.content and zope.products.codecontent and move
content components in their own packages at zope.products.
See the package geddon proposal: http://dev.zope.org/Zope3/PackageGeddon
=== Added File Zope3/src/zope/products/i18nfile/__init__.py ===
#
# This file is necessary to make this directory a package.
=== Added File Zope3/src/zope/products/i18nfile/browser.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""I18n versions of several content objects.
$Id: browser.py,v 1.1.2.1 2004/02/11 16:29:21 philikon Exp $
"""
from zope.i18n.negotiator import negotiator
__metaclass__ = type
class I18nFileView:
def __call__(self):
"""Call the File
"""
request = self.request
language = None
if request is not None:
langs = self.context.getAvailableLanguages()
language = negotiator.getLanguage(langs, request)
request.response.setHeader('Content-Type',
self.context.getContentType())
request.response.setHeader('Content-Length',
self.context.getSize(language))
return self.context.getData(language)
class I18nFileEdit:
name = 'editForm'
title = 'Edit Form'
description = ('This edit form allows you to make changes to the ' +
'properties of this file.')
def action(self, contentType, data, language, defaultLanguage,
selectLanguage=None, removeLanguage=None,
addLanguage=None, newLanguage=None):
if selectLanguage:
pass
elif removeLanguage:
self.context.removeLanguage(language)
language = self.context.getDefaultLanguage()
else:
if addLanguage:
language = newLanguage
self.context.setDefaultLanguage(defaultLanguage)
self.context.edit(data, contentType, language)
return self.request.response.redirect(self.request.URL[-1] +
"/editForm.html?language=%s" %language) # XXX url_quote
=== Added File Zope3/src/zope/products/i18nfile/configure.zcml ===
<configure
xmlns='http://namespaces.zope.org/zope'
xmlns:browser='http://namespaces.zope.org/browser'
i18n_domain='zope'
>
<interface
interface=".i18nfile.II18nFile"
type="zope.app.interfaces.content.IContentType"
/>
<content class=".i18nfile.I18nFile">
<factory
id=".I18nFile"
permission="zope.ManageContent"
title="I18n File"
description="An Internationalized File"
/>
<require
permission="zope.View"
interface="zope.products.file.interfaces.IReadFile"
/>
<require
permission="zope.ManageContent"
interface="zope.products.file.interfaces.IWriteFile"
/>
<require
permission="zope.View"
attributes="getDefaultLanguage getAvailableLanguages"
/>
<require
permission="zope.ManageContent"
attributes="setDefaultLanguage removeLanguage"
/>
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
/>
</content>
<!-- browser directives -->
<browser:page
name="index.html"
for=".interfaces.II18nFile"
permission="zope.View"
class=".browser.I18nFileView"
/>
<browser:pages
for=".interfaces.II18nFile"
permission="zope.View"
class=".browser.I18nFileEdit">
<browser:page name="editForm.html" template="edit.pt" />
<browser:page name="edit.html" attribute="action" />
</browser:pages>
<browser:menuItems
menu="zmi_views"
for=".interfaces.II18nFile">
<!-- Keep original edit view, for now -->
<browser:menuItem title="Edit" action="editForm.html" />
<!-- Supress the upload view from file -->
<browser:menuItem title="Upload" action="editForm.html"
filter="python: False" />
</browser:menuItems>
<browser:menuItem
menu="add_content"
for="zope.app.interfaces.container.IAdding"
title="I18n File"
action="zope.products.i18nfile.I18nFile"
description="A file that supports multiple locales."
permission="zope.ManageContent"
/>
</configure>
=== Added File Zope3/src/zope/products/i18nfile/edit.pt ===
<html metal:use-macro="views/standard_macros/page">
<head>
<style metal:fill-slot="headers" type="text/css">
<!--
.ContentIcon {
width: 20px;
}
.ContentTitle {
text-align: left;
}
-->
</style>
</head>
<body>
<div metal:fill-slot="body">
<p tal:content="context/msg"
tal:condition="python: hasattr(context, 'msg')">
Message will go here.
</p>
<p tal:content="view/description">
Description of the Form.
</p>
<form action="edit.html" method="post">
<div class="row">
<div class="label" i18n:translate="">Content Type</div>
<div class="field">
<input name="contentType" type="text" size="20"
tal:attributes="value context/getContentType" />
</div>
</div>
<div class="row">
<div class="label" i18n:translate="">Default Language</div>
<div class="field">
<select name="defaultLanguage">
<span tal:repeat="lang context/getAvailableLanguages"
tal:omit-tag="">
<option tal:attributes="
value lang;
selected python:context.getDefaultLanguage() == lang"
tal:content="lang" />
</span>
</select>
</div>
</div>
<hr />
<div class="row">
<div class="label" i18n:translate="">Language</div>
<div class="field">
<select name="language">
<span tal:repeat="lang context/getAvailableLanguages"
tal:omit-tag="">
<option tal:attributes="
value lang;
selected python:request.get('language',
context.getDefaultLanguage()) == lang"
tal:content="lang" />
</span>
</select>
<input type="submit" name="selectLanguage" value="Show"
i18n:attributes="value show-button"/>
<input type="submit" name="removeLanguage"
i18n:attributes="value remove-button"/>
<input type="submit" name="addLanguage"
value="Add new language"
i18n:attributes="value" />
<input type="text" name="newLanguage" size="10" />
</div>
</div>
<div class="row">
<div class="label" i18n:translate="">Data</div>
<div class="field">
<textarea name="data" cols="70" rows="10"
tal:content="python:context.getData(request.get('language'))" />
</div>
</div>
<div class="row">
<div class="controls">
<input type="submit" name="edit" value="Save Changes"
i18n:attributes="value save-changes-button"/>
</div>
</div>
</form>
</div>
</body>
</html>
=== Added File Zope3/src/zope/products/i18nfile/i18nfile.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: i18nfile.py,v 1.1.2.1 2004/02/11 16:29:21 philikon Exp $
"""
import persistence
from zope.interface import implements
from zope.publisher.browser import FileUpload
from zope.products.file.file import File
from interfaces import II18nFile
class I18nFile(persistence.Persistent):
"""I18n aware file object. It contains a number of File objects --
one for each language.
"""
implements(II18nFile)
def __init__(self, data='', contentType=None, defaultLanguage='en'):
self._data = {}
self.defaultLanguage = defaultLanguage
self.setData(data, language=defaultLanguage)
if contentType is None:
self.setContentType('')
else:
self.setContentType(contentType)
def __len__(self):
return self.getSize()
def _create(self, data):
"""Create a new subobject of the appropriate type. Should be
overriden in subclasses.
"""
return File(data)
def _get(self, language):
"""Helper function -- return a subobject for a given language,
and if it does not exist, return a subobject for the default
language.
"""
file = self._data.get(language)
if not file:
file = self._data[self.defaultLanguage]
return file
def _get_or_add(self, language, data=''):
"""Helper function -- return a subobject for a given language,
and if it does not exist, create and return a new subobject.
"""
if language is None:
language = self.defaultLanguage
file = self._data.get(language)
if not file:
self._data[language] = file = self._create(data)
self._p_changed = 1
return file
def setContentType(self, contentType):
'''See interface IFile'''
self._contentType = contentType
def getContentType(self):
'''See interface IFile'''
return self._contentType
contentType = property(getContentType, setContentType)
def edit(self, data, contentType=None, language=None):
'''See interface IFile'''
# XXX This seems broken to me, as setData can override the
# content type explicitly passed in.
if contentType is not None:
self.setContentType(contentType)
if isinstance(data, FileUpload) and not data.filename:
data = None # Ignore empty files
if data is not None:
self.setData(data, language)
def getData(self, language=None):
'''See interface IFile'''
return self._get(language).getData()
def setData(self, data, language=None):
'''See interface IFile'''
self._get_or_add(language).setData(data)
data = property(getData, setData)
def getSize(self, language=None):
'''See interface IFile'''
return self._get(language).getSize()
def getDefaultLanguage(self):
'See II18nAware'
return self.defaultLanguage
def setDefaultLanguage(self, language):
'See II18nAware'
if not self._data.has_key(language):
raise ValueError, \
'cannot set nonexistent language (%s) as default' % language
self.defaultLanguage = language
def getAvailableLanguages(self):
'See II18nAware'
return self._data.keys()
def removeLanguage(self, language):
'''See interface II18nFile'''
if language == self.defaultLanguage:
raise ValueError, 'cannot remove default language (%s)' % language
if self._data.has_key(language):
del self._data[language]
self._p_changed = True
=== Added File Zope3/src/zope/products/i18nfile/interfaces.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: interfaces.py,v 1.1.2.1 2004/02/11 16:29:21 philikon Exp $
"""
from zope.i18n.interfaces import II18nAware
from zope.products.file.interfaces import IFile
class II18nFile(IFile, II18nAware):
"""I18n aware file interface."""
def removeLanguage(language):
"""Remove translated content for a given language.
"""
=== Added File Zope3/src/zope/products/i18nfile/tests.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id: tests.py,v 1.1.2.1 2004/02/11 16:29:21 philikon Exp $
"""
import unittest
from zope.interface.verify import verifyClass
from zope.i18n.tests.testii18naware import TestII18nAware
from zope.products.file.file import FileChunk
from i18nfile import I18nFile
def sorted(list):
list.sort()
return list
class Test(TestII18nAware):
def _makeFile(self, *args, **kw):
return I18nFile(*args, **kw)
def _createObject(self):
obj = self._makeFile(defaultLanguage='fr')
obj.setData('', 'lt')
obj.setData('', 'en')
return obj
def testEmpty(self):
file = self._makeFile()
self.assertEqual(file.getContentType(), '')
self.assertEqual(file.getData(), '')
self.assertEqual(file.getDefaultLanguage(), 'en')
def testConstructor(self):
file = self._makeFile('Foobar')
self.assertEqual(file.getContentType(), '')
self.assertEqual(file.getData(), 'Foobar')
self.assertEqual(file.getData('en'), 'Foobar')
self.assertEqual(file.getData('nonexistent'), 'Foobar')
self.assertEqual(file.getDefaultLanguage(), 'en')
self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
file = self._makeFile('Foobar', 'text/plain')
self.assertEqual(file.getContentType(), 'text/plain')
self.assertEqual(file.getData(), 'Foobar')
self.assertEqual(file.getData('en'), 'Foobar')
self.assertEqual(file.getData('nonexistent'), 'Foobar')
self.assertEqual(file.getDefaultLanguage(), 'en')
self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
file = self._makeFile(data='Foobar', contentType='text/plain')
self.assertEqual(file.getContentType(), 'text/plain')
self.assertEqual(file.getData(), 'Foobar')
self.assertEqual(file.getData('en'), 'Foobar')
self.assertEqual(file.getData('nonexistent'), 'Foobar')
self.assertEqual(file.getDefaultLanguage(), 'en')
self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
file = self._makeFile(data='Foobar', contentType='text/plain',
defaultLanguage='fr')
self.assertEqual(file.getContentType(), 'text/plain')
self.assertEqual(file.getData(), 'Foobar')
self.assertEqual(file.getData('en'), 'Foobar')
self.assertEqual(file.getData('nonexistent'), 'Foobar')
self.assertEqual(file.getDefaultLanguage(), 'fr')
self.assertEqual(sorted(file.getAvailableLanguages()), ['fr'])
def testMutators(self):
file = self._makeFile()
file.setContentType('text/plain')
self.assertEqual(file.getContentType(), 'text/plain')
self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
file.setData('Foobar')
self.assertEqual(file.getData(), 'Foobar')
self.assertEqual(sorted(file.getAvailableLanguages()), ['en'])
file.setData('Barbaz', language='fr')
self.assertEqual(file.getData(), 'Foobar')
self.assertEqual(file.getData('fr'), 'Barbaz')
self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr'])
file.edit('Blah', 'text/html')
self.assertEqual(file.getContentType(), 'text/html')
self.assertEqual(file.getData(), 'Blah')
self.assertEqual(file.getData('fr'), 'Barbaz')
self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr'])
file.edit('Quux', 'text/html', 'lt')
self.assertEqual(file.getContentType(), 'text/html')
self.assertEqual(file.getData(), 'Blah')
self.assertEqual(file.getData('fr'), 'Barbaz')
self.assertEqual(file.getData('lt'), 'Quux')
self.assertEqual(file.getSize(), len('Blah'))
self.assertEqual(file.getSize('fr'), len('Barbaz'))
self.assertEqual(file.getSize('lt'), len('Quux'))
self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr', 'lt'])
file.removeLanguage('lt')
self.assertEqual(file.getContentType(), 'text/html')
self.assertEqual(file.getData(), 'Blah')
self.assertEqual(file.getData('fr'), 'Barbaz')
self.assertEqual(file.getSize(), len('Blah'))
self.assertEqual(file.getSize('fr'), len('Barbaz'))
self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr'])
self.assertEqual(file.getData('lt'), 'Blah')
self.assertEqual(file.getSize('lt'), len('Blah'))
file.removeLanguage('nonexistent')
self.assertEqual(file.getContentType(), 'text/html')
self.assertEqual(file.getData(), 'Blah')
self.assertEqual(file.getData('fr'), 'Barbaz')
self.assertEqual(file.getSize(), len('Blah'))
self.assertEqual(file.getSize('fr'), len('Barbaz'))
self.assertEqual(sorted(file.getAvailableLanguages()), ['en', 'fr'])
self.assertEqual(file.getData('lt'), 'Blah')
self.assertEqual(file.getSize('lt'), len('Blah'))
self.assertRaises(ValueError, file.removeLanguage, file.getDefaultLanguage())
self.assertRaises(ValueError, file.setDefaultLanguage, 'nonexistent')
def testLargeDataInput(self):
file = self._makeFile()
# Insert as string
file.setData('Foobar'*60000, 'en')
self.assertEqual(file.getSize('en'), 6*60000)
self.assertEqual(file.getData('en'), 'Foobar'*60000)
# Insert data as FileChunk
fc = FileChunk('Foobar'*4000)
file.setData(fc, 'lt')
self.assertEqual(file.getSize('lt'), 6*4000)
self.assertEqual(file.getData('lt'), 'Foobar'*4000)
# Insert data from file object
import cStringIO
sio = cStringIO.StringIO()
sio.write('Foobar'*100000)
sio.seek(0)
file.setData(sio, 'fr')
self.assertEqual(file.getSize('fr'), 6*100000)
self.assertEqual(file.getData('fr'), 'Foobar'*100000)
def testInterface(self):
from zope.products.file.interfaces import IFile
from interfaces import II18nFile
from zope.i18n.interfaces import II18nAware
self.failUnless(IFile.isImplementedByInstancesOf(I18nFile))
self.failUnless(verifyClass(IFile, I18nFile))
self.failUnless(II18nAware.isImplementedByInstancesOf(I18nFile))
self.failUnless(verifyClass(II18nAware, I18nFile))
self.failUnless(II18nFile.isImplementedByInstancesOf(I18nFile))
self.failUnless(verifyClass(II18nFile, I18nFile))
def testSetDefaultLanguage(self):
# getDefaultLanguage and getAvailableLanguages are tested in the
# above tests
file = self._makeFile()
file.setData('', language='lt')
file.setDefaultLanguage('lt')
self.assertEqual(file.getDefaultLanguage(), 'lt')
def test_suite():
loader = unittest.TestLoader()
return loader.loadTestsFromTestCase(Test)
if __name__=='__main__':
unittest.TextTestRunner().run(test_suite())
More information about the Zope3-Checkins
mailing list