zope.app.i18n-3.6.4/0000775000177100020040000000000012062644246015172 5ustar menesismenesis00000000000000zope.app.i18n-3.6.4/README.txt0000664000177100020040000000017212062644232016663 0ustar menesismenesis00000000000000This package provides placeful persistent translation domains and message catalogs along with ZMI views for managing them.zope.app.i18n-3.6.4/src/0000775000177100020040000000000012062644246015761 5ustar menesismenesis00000000000000zope.app.i18n-3.6.4/src/zope.app.i18n.egg-info/0000775000177100020040000000000012062644246021765 5ustar menesismenesis00000000000000zope.app.i18n-3.6.4/src/zope.app.i18n.egg-info/namespace_packages.txt0000664000177100020040000000001612062644242026311 0ustar menesismenesis00000000000000zope zope.app zope.app.i18n-3.6.4/src/zope.app.i18n.egg-info/not-zip-safe0000664000177100020040000000000112062644232024206 0ustar menesismenesis00000000000000 zope.app.i18n-3.6.4/src/zope.app.i18n.egg-info/requires.txt0000664000177100020040000000025512062644242024363 0ustar menesismenesis00000000000000setuptools zope.publisher>=3.9 zope.component>=3.6 zope.container zope.configuration zope.i18n zope.i18nmessageid zope.interface zope.security ZODB3 [test] zope.app.testingzope.app.i18n-3.6.4/src/zope.app.i18n.egg-info/dependency_links.txt0000664000177100020040000000000112062644242026027 0ustar menesismenesis00000000000000 zope.app.i18n-3.6.4/src/zope.app.i18n.egg-info/SOURCES.txt0000664000177100020040000000272612062644242023654 0ustar menesismenesis00000000000000CHANGES.txt COPYRIGHT.txt LICENSE.txt README.txt bootstrap.py buildout.cfg setup.py src/zope/__init__.py src/zope.app.i18n.egg-info/PKG-INFO src/zope.app.i18n.egg-info/SOURCES.txt src/zope.app.i18n.egg-info/dependency_links.txt src/zope.app.i18n.egg-info/namespace_packages.txt src/zope.app.i18n.egg-info/not-zip-safe src/zope.app.i18n.egg-info/requires.txt src/zope.app.i18n.egg-info/top_level.txt src/zope/app/__init__.py src/zope/app/i18n/__init__.py src/zope/app/i18n/configure.zcml src/zope/app/i18n/filters.py src/zope/app/i18n/interfaces.py src/zope/app/i18n/messagecatalog.py src/zope/app/i18n/translationdomain.py src/zope/app/i18n/browser/__init__.py src/zope/app/i18n/browser/configure.zcml src/zope/app/i18n/browser/exportimport.pt src/zope/app/i18n/browser/exportimport.py src/zope/app/i18n/browser/i18n_domain.gif src/zope/app/i18n/browser/synchronize.pt src/zope/app/i18n/browser/synchronize.py src/zope/app/i18n/browser/translate.pt src/zope/app/i18n/browser/translate.py src/zope/app/i18n/browser/translatemessage.pt src/zope/app/i18n/browser/tests/__init__.py src/zope/app/i18n/browser/tests/test_translate.py src/zope/app/i18n/tests/__init__.py src/zope/app/i18n/tests/configure.zcml src/zope/app/i18n/tests/placelesssetup.py src/zope/app/i18n/tests/test_filters.py src/zope/app/i18n/tests/test_messagecatalog.py src/zope/app/i18n/tests/test_translationdomain.py src/zope/app/i18n/xmlrpc/__init__.py src/zope/app/i18n/xmlrpc/configure.zcml src/zope/app/i18n/xmlrpc/methods.pyzope.app.i18n-3.6.4/src/zope.app.i18n.egg-info/PKG-INFO0000664000177100020040000000734112062644242023063 0ustar menesismenesis00000000000000Metadata-Version: 1.1 Name: zope.app.i18n Version: 3.6.4 Summary: Persistent translation domains and message catalogs Home-page: http://pypi.python.org/pypi/zope.app.i18n Author: Zope Corporation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: This package provides placeful persistent translation domains and message catalogs along with ZMI views for managing them. ======= CHANGES ======= 3.6.4 (2012-12-14) ------------------ - Fix translate() when used with ZODB 4. - Remove test dependency on zope.app.component 3.6.3 (2010-09-01) ------------------ - Remove undeclared dependency on zope.deferredimport. - Use zope.publisher >= 3.9 instead of zope.app.publisher. 3.6.2 (2009-10-07) ------------------ - Fix test_translate and follow recent change of HTTPResponse.redirect. 3.6.1 (2009-08-15) ------------------ - Added a missing testing dependency on zope.app.component. 3.6.0 (2009-03-18) ------------------ - Some of ZCML configuration was moved into another packages: * The global INegotiator utility registration was moved into ``zope.i18n``. * The include of ``zope.i18n.locales`` was also moved into ``zope.i18n``. * The registration of IModifiableUserPreferredLanguages adapter was moved into ``zope.app.publisher``. * The IAttributeAnnotation implementation statement for HTTPRequest was moved into ``zope.publisher`` and will only apply if ``zope.annotation`` is available. * The IUserPreferredCharsets adapter registration was also moved into ``zope.publisher``. - Depend on zope.component >= 3.6 instead of zope.app.component as the `queryNextUtility` function was moved there. - Remove the old ``zope.app.i18n.metadirectives`` module as the directive was moved to ``zope.i18n`` ages ago. 3.5.0 (2009-02-01) ------------------ - Use zope.container instead of zope.app.container. 3.4.6 (2009-01-27) ------------------ - Fix a simple inconsistent MRO problem in tests - Substitute zope.app.zapi by direct calls to its wrapped apis. See bug 219302. 3.4.5 (unreleased) ------------------ - This was skipped over by accident. 3.4.4 (2007-10-23) ------------------ - Fix deprecation warning. 3.4.3 (2007-10-23) ------------------ - Fix imports in tests. - Clean up long lines. 3.4.2 (2007-9-26) ----------------- - Release to fix packaging issues with 3.4.1. 3.4.1 (2007-9-25) ----------------- - Added missing Changes.txt and README.txt files to egg 3.4.0 (2007-9-25) ----------------- - Initial documented release - Move ZopeMessageFactory to zope.i18nmessageid Keywords: zope3 i18n message factory Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zope.app.i18n-3.6.4/src/zope.app.i18n.egg-info/top_level.txt0000664000177100020040000000000512062644242024506 0ustar menesismenesis00000000000000zope zope.app.i18n-3.6.4/src/zope/0000775000177100020040000000000012062644246016736 5ustar menesismenesis00000000000000zope.app.i18n-3.6.4/src/zope/__init__.py0000664000177100020040000000031012062644231021033 0ustar menesismenesis00000000000000# this is a namespace package try: import pkg_resources pkg_resources.declare_namespace(__name__) except ImportError: import pkgutil __path__ = pkgutil.extend_path(__path__, __name__) zope.app.i18n-3.6.4/src/zope/app/0000775000177100020040000000000012062644246017516 5ustar menesismenesis00000000000000zope.app.i18n-3.6.4/src/zope/app/i18n/0000775000177100020040000000000012062644246020275 5ustar menesismenesis00000000000000zope.app.i18n-3.6.4/src/zope/app/i18n/filters.py0000664000177100020040000001524012062644231022313 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Translation Domain Message Export and Import Filters $Id: filters.py 126935 2012-06-18 15:48:16Z tseaver $ """ __docformat__ = 'restructuredtext' import time, re from types import StringTypes from zope.interface import implements from zope.i18n.interfaces import IMessageExportFilter, IMessageImportFilter from zope.app.i18n.interfaces import ILocalTranslationDomain class ParseError(Exception): def __init__(self, state, lineno): Exception.__init__(self, state, lineno) self.state = state self.lineno = lineno def __str__(self): return "state %s, line %s" % (self.state, self.lineno) class GettextExportFilter(object): implements(IMessageExportFilter) __used_for__ = ILocalTranslationDomain def __init__(self, domain): self.domain = domain def exportMessages(self, languages): 'See IMessageExportFilter' domain = self.domain.domain if isinstance(languages, StringTypes): language = languages elif len(languages) == 1: language = languages[0] else: raise TypeError( 'Only one language at a time is supported for gettext export.') dt = time.time() dt = time.localtime(dt) dt = time.strftime('%Y/%m/%d %H:%M', dt) output = _file_header %(dt, language.encode('UTF-8'), domain.encode('UTF-8')) for msgid in self.domain.getMessageIds(): msgstr = self.domain.translate(msgid, target_language=language) msgstr = msgstr.encode('UTF-8') msgid = msgid.encode('UTF-8') output += _msg_template %(msgid, msgstr) return output class GettextImportFilter(object): implements(IMessageImportFilter) __used_for__ = ILocalTranslationDomain def __init__(self, domain): self.domain = domain def importMessages(self, languages, file): 'See IMessageImportFilter' if isinstance(languages, StringTypes): language = languages elif len(languages) == 1: language = languages[0] else: raise TypeError( 'Only one language at a time is supported for gettext export.') result = parseGetText(file.readlines())[3] headers = parserHeaders(''.join(result[('',)][1])) del result[('',)] charset = extractCharset(headers['content-type']) for msg in result.items(): msgid = unicode(''.join(msg[0]), charset) msgid = msgid.replace('\\n', '\n') msgstr = unicode(''.join(msg[1][1]), charset) msgstr = msgstr.replace('\\n', '\n') self.domain.addMessage(msgid, msgstr, language) def extractCharset(header): charset = header.split('charset=')[-1] return charset.lower() def parserHeaders(headers_text): headers = {} for line in headers_text.split('\\n'): name = line.split(':')[0] value = ''.join(line.split(':')[1:]) headers[name.lower()] = value return headers def parseGetText(content): # The regular expressions com = re.compile('^#.*') msgid = re.compile(r'^ *msgid *"(.*?[^\\]*)"') msgstr = re.compile(r'^ *msgstr *"(.*?[^\\]*)"') re_str = re.compile(r'^ *"(.*?[^\\])"') blank = re.compile(r'^\s*$') trans = {} pointer = 0 state = 0 COM, MSGID, MSGSTR = [], [], [] while pointer < len(content): line = content[pointer] #print 'STATE:', state #print 'LINE:', line, content[pointer].strip() if state == 0: COM, MSGID, MSGSTR = [], [], [] if com.match(line): COM.append(line.strip()) state = 1 pointer = pointer + 1 elif msgid.match(line): MSGID.append(msgid.match(line).group(1)) state = 2 pointer = pointer + 1 elif blank.match(line): pointer = pointer + 1 else: raise ParseError(0, pointer + 1) elif state == 1: if com.match(line): COM.append(line.strip()) state = 1 pointer = pointer + 1 elif msgid.match(line): MSGID.append(msgid.match(line).group(1)) state = 2 pointer = pointer + 1 elif blank.match(line): pointer = pointer + 1 else: raise ParseError(1, pointer + 1) elif state == 2: if com.match(line): COM.append(line.strip()) state = 2 pointer = pointer + 1 elif re_str.match(line): MSGID.append(re_str.match(line).group(1)) state = 2 pointer = pointer + 1 elif msgstr.match(line): MSGSTR.append(msgstr.match(line).group(1)) state = 3 pointer = pointer + 1 elif blank.match(line): pointer = pointer + 1 else: raise ParseError(2, pointer + 1) elif state == 3: if com.match(line) or msgid.match(line): # print "\nEn", language, "detected", MSGID trans[tuple(MSGID)] = (COM, MSGSTR) state = 0 elif re_str.match(line): MSGSTR.append(re_str.match(line).group(1)) state = 3 pointer = pointer + 1 elif blank.match(line): pointer = pointer + 1 else: raise ParseError(3, pointer + 1) # the last also goes in if tuple(MSGID): trans[tuple(MSGID)] = (COM, MSGSTR) return COM, MSGID, MSGSTR, trans _file_header = ''' msgid "" msgstr "" "Project-Id-Version: Zope 3\\n" "PO-Revision-Date: %s\\n" "Last-Translator: Zope 3 Gettext Export Filter\\n" "Zope-Language: %s\\n" "Zope-Domain: %s\\n" "MIME-Version: 1.0\\n" "Content-Type: text/plain; charset=UTF-8\\n" "Content-Transfer-Encoding: 8bit\\n" ''' _msg_template = ''' msgid "%s" msgstr "%s" ''' zope.app.i18n-3.6.4/src/zope/app/i18n/browser/0000775000177100020040000000000012062644246021760 5ustar menesismenesis00000000000000zope.app.i18n-3.6.4/src/zope/app/i18n/browser/translate.pt0000664000177100020040000001227012062644231024316 0ustar menesismenesis00000000000000 Translation Domain - Translate
Select Languages:
New Language:
Filter (% - wildcard):
  Message Id de
default
Add new messages
 
 
zope.app.i18n-3.6.4/src/zope/app/i18n/browser/exportimport.py0000664000177100020040000000257012062644231025104 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Message Export/Import View $Id: exportimport.py 126935 2012-06-18 15:48:16Z tseaver $ """ __docformat__ = 'restructuredtext' from zope.app.i18n.browser import BaseView from zope.i18n.interfaces import IMessageExportFilter, IMessageImportFilter class ExportImport(BaseView): def exportMessages(self, languages): self.request.response.setHeader('content-type', 'application/x-gettext') filter = IMessageExportFilter(self.context) return filter.exportMessages(languages) def importMessages(self, languages, file): filter = IMessageImportFilter(self.context) filter.importMessages(languages, file) return self.request.response.redirect(self.request.URL[-1]) zope.app.i18n-3.6.4/src/zope/app/i18n/browser/synchronize.pt0000664000177100020040000001102712062644231024673 0ustar menesismenesis00000000000000 Translation Domain - Synchronize
Server URL
Username
Password
Select Languages:


  Message Id Language Status
Hello World! en status

No connection could be made to remote data source.

zope.app.i18n-3.6.4/src/zope/app/i18n/browser/exportimport.pt0000664000177100020040000000306612062644231025100 0ustar menesismenesis00000000000000 Translation Domain - Translate

Import and Export Messages

Here you can export and import messages from your Translation Domain.

Select Languages:
Import File Name:
zope.app.i18n-3.6.4/src/zope/app/i18n/browser/__init__.py0000664000177100020040000000200712062644231024062 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Translation Domain Views $Id: __init__.py 126935 2012-06-18 15:48:16Z tseaver $ """ __docformat__ = 'restructuredtext' from zope.i18n.interfaces import ITranslationDomain class BaseView(object): __used_for__ = ITranslationDomain def getAllLanguages(self): """Get all available languages from the Translation Domain.""" return self.context.getAllLanguages() zope.app.i18n-3.6.4/src/zope/app/i18n/browser/translatemessage.pt0000664000177100020040000000217312062644231025664 0ustar menesismenesis00000000000000 Translation Domain - Translate
Message Id Message Id of the message.
Language
zope.app.i18n-3.6.4/src/zope/app/i18n/browser/configure.zcml0000664000177100020040000000424412062644231024626 0ustar menesismenesis00000000000000 zope.app.i18n-3.6.4/src/zope/app/i18n/browser/tests/0000775000177100020040000000000012062644246023122 5ustar menesismenesis00000000000000zope.app.i18n-3.6.4/src/zope/app/i18n/browser/tests/test_translate.py0000664000177100020040000001006112062644231026520 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Test Translation Domain 'Translate' screen. $Id: test_translate.py 128565 2012-12-10 21:53:48Z menesis $ """ import unittest from StringIO import StringIO from zope.component.testing import PlacelessSetup from zope.component.interfaces import IFactory from zope.component.factory import Factory from zope.component import provideAdapter, provideUtility from zope.app.i18n.browser.translate import Translate from zope.app.i18n.translationdomain import TranslationDomain from zope.app.i18n.messagecatalog import MessageCatalog from zope.i18n.interfaces import IUserPreferredCharsets from zope.publisher.http import IHTTPRequest from zope.publisher.http import HTTPCharsets from zope.publisher.browser import BrowserRequest class Translate(Translate): """Make Translate a valid Browser view. Usually done by ZCML.""" def __init__(self, context, request): self.context = context self.request = request class TranslateTest(PlacelessSetup, unittest.TestCase): def setUp(self): super(TranslateTest, self).setUp() # Setup the registries provideAdapter(HTTPCharsets, (IHTTPRequest,), IUserPreferredCharsets) provideUtility(Factory(MessageCatalog), IFactory, 'zope.app.MessageCatalog') domain = TranslationDomain() domain.domain = 'default' en_catalog = MessageCatalog('en', 'default') de_catalog = MessageCatalog('de', 'default') en_catalog.setMessage('short_greeting', 'Hello!') de_catalog.setMessage('short_greeting', 'Hallo!') en_catalog.setMessage('greeting', 'Hello $name, how are you?') de_catalog.setMessage('greeting', 'Hallo $name, wie geht es Dir?') domain['en-1'] = en_catalog domain['de-1'] = de_catalog self._view = Translate(domain, self._getRequest()) def _getRequest(self, **kw): kw['HTTP_HOST'] = 'foo' request = BrowserRequest(StringIO(''), kw) request._cookies = {'edit_languages': 'en,de'} request._traversed_names = ['foo', 'bar'] return request def testGetMessages(self): ids = [m[0] for m in self._view.getMessages()] ids.sort() self.assertEqual(ids, ['greeting', 'short_greeting']) def testGetTranslation(self): self.assertEqual(self._view.getTranslation('short_greeting', 'en'), 'Hello!') def testGetAllLanguages(self): languages = self._view.getAllLanguages() languages.sort() self.assertEqual(languages, ['de', 'en']) def testGetEditLanguages(self): languages = self._view.getEditLanguages() languages.sort() self.assertEqual(languages, ['de', 'en']) def testAddDeleteLanguage(self): self._view.addLanguage('es') self.assert_('es' in self._view.getAllLanguages()) self._view.deleteLanguages(['es']) self.assert_('es' not in self._view.getAllLanguages()) class SynchronizeTest(unittest.TestCase): def test_synchronize_imports(self): # Trivial test that imports the module. This would have triggered a # deprecation warning in previous versions. import zope.app.i18n.browser.synchronize def test_suite(): loader = unittest.TestLoader() return unittest.TestSuite([ loader.loadTestsFromTestCase(TranslateTest), loader.loadTestsFromTestCase(SynchronizeTest), ]) return if __name__=='__main__': unittest.main() zope.app.i18n-3.6.4/src/zope/app/i18n/browser/tests/__init__.py0000664000177100020040000000007512062644231025227 0ustar menesismenesis00000000000000# # This file is necessary to make this directory a package. zope.app.i18n-3.6.4/src/zope/app/i18n/browser/i18n_domain.gif0000664000177100020040000000040012062644231024541 0ustar menesismenesis00000000000000GIF89aݮԝˍ|m\RIrAez8Wi/IY' ,p8O^LP\)@X< X =@`[@^ax`#AR^/V^$) 4 XXfp@;  ) k5+c,. 5B$&tN+!;zope.app.i18n-3.6.4/src/zope/app/i18n/browser/synchronize.py0000664000177100020040000001672712062644231024714 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Synchronize with Foreign Translation Domains $Id: synchronize.py 126935 2012-06-18 15:48:16Z tseaver $ """ __docformat__ = 'restructuredtext' import httplib import urllib import xmlrpclib from base64 import encodestring import zope.i18nmessageid from zope.security.proxy import removeSecurityProxy from zope.app.i18n.browser import BaseView _ = zope.i18nmessageid.MessageFactory("zope") DEFAULT = 'http://localhost:8080/++etc++site/default/zope' class Synchronize(BaseView): messageStatus = [_('Up to Date'), _('New Remote'), _('Out of Date'), _('Newer Local'), _('Does not exist')] def __init__(self, context, request): super(Synchronize, self).__init__(context, request) self.sync_url = self.request.cookies.get( 'sync_url', DEFAULT) self.sync_url = urllib.unquote(self.sync_url) self.sync_username = self.request.cookies.get('sync_username', 'admin') self.sync_password = self.request.cookies.get('sync_password', 'admin') self.sync_languages = filter(None, self.request.cookies.get( 'sync_languages', '').split(',')) def _connect(self): '''Connect to the remote server via XML-RPC HTTP; return status''' # make sure the URL contains the http:// prefix if not self.sync_url.startswith('http://'): url = 'http://' + self.sync_url else: url = self.sync_url # Now try to connect self._connection = xmlrpclib.Server( url, transport = BasicAuthTransport(self.sync_username, self.sync_password)) # check whether the connection was made and the Master Babel Tower # exists try: self._connection.getAllLanguages() return 1 except: self._connection = None return 0 def _disconnect(self): '''Disconnect from the sever; return ``None``''' if hasattr(self, '_connection') and self._connection is not None: self._connection = None def _isConnected(self): '''Check whether we are currently connected to the server; return boolean''' if not hasattr(self, '_connection'): self._connection = None if not self._connection is None and self._connection.getAllLanguages(): return 1 else: return 0 def canConnect(self): '''Checks whether we can connect using this server and user data; return boolean''' if self._isConnected(): return 1 else: try: return self._connect() except: return 0 def getAllLanguages(self): connected = self._isConnected() if not connected: connected = self._connect() if connected: return self._connection.getAllLanguages() else: return [] def queryMessages(self): connected = self._isConnected() if not connected: connected = self._connect() if connected: fmsgs = self._connection.getMessagesFor(self.sync_languages) else: fmsgs = [] return self.context.getMessagesMapping(self.sync_languages, fmsgs) def queryMessageItems(self): items = self.queryMessages().items() items = removeSecurityProxy(items) items.sort(lambda x, y: cmp(x[0][0] + x[0][1], y[0][0]+y[0][1])) return items def getStatus(self, fmsg, lmsg, verbose=1): state = 0 if fmsg is None: state = 4 elif lmsg is None: state = 1 elif fmsg['mod_time'] > lmsg['mod_time']: state = 2 elif fmsg['mod_time'] < lmsg['mod_time']: state = 3 elif fmsg['mod_time'] == lmsg['mod_time']: state = 0 if verbose: return self.messageStatus[state] return state def saveSettings(self): self.sync_languages = self.request.form.get('sync_languages', []) self.request.response.setCookie('sync_languages', ','.join(self.sync_languages)) self.request.response.setCookie('sync_url', urllib.quote(self.request['sync_url']).strip()) self.request.response.setCookie('sync_username', self.request['sync_username']) self.request.response.setCookie('sync_password', self.request['sync_password']) return self.request.response.redirect(self.request.URL[-1]+ '/@@synchronizeForm.html') def synchronize(self): mapping = self.queryMessages() self.context.synchronize(mapping) return self.request.response.redirect(self.request.URL[-1]+ '/@@synchronizeForm.html') def synchronizeMessages(self): idents = [] for id in self.request.form['message_ids']: msgid = self.request.form['update-msgid-'+id] language = self.request.form['update-language-'+id] idents.append((msgid, language)) mapping = self.queryMessages() new_mapping = {} for item in mapping.items(): if item[0] in idents: new_mapping[item[0]] = item[1] self.context.synchronize(new_mapping) return self.request.response.redirect(self.request.URL[-1]+ '/@@synchronizeForm.html') class BasicAuthTransport(xmlrpclib.Transport): def __init__(self, username=None, password=None, verbose=0): self.username=username self.password=password self.verbose=verbose def request(self, host, handler, request_body, verbose=0): # issue XML-RPC request self.verbose = verbose h = httplib.HTTP(host) h.putrequest("POST", handler) # required by HTTP/1.1 h.putheader("Host", host) # required by XML-RPC h.putheader("User-Agent", self.user_agent) h.putheader("Content-Type", "text/xml") h.putheader("Content-Length", str(len(request_body))) # basic auth if self.username is not None and self.password is not None: h.putheader("AUTHORIZATION", "Basic %s" % encodestring("%s:%s" % (self.username, self.password) ).replace("\012", "")) h.endheaders() if request_body: h.send(request_body) errcode, errmsg, headers = h.getreply() if errcode != 200: raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers) return self.parse_response(h.getfile()) zope.app.i18n-3.6.4/src/zope/app/i18n/browser/translate.py0000664000177100020040000001017412062644231024324 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Translation GUI $Id: translate.py 126935 2012-06-18 15:48:16Z tseaver $ """ __docformat__ = 'restructuredtext' from zope.app.i18n.browser import BaseView class Translate(BaseView): def getMessages(self): """Get messages""" filter = self.request.get('filter', '%') messages = [] for msg_id in self.context.getMessageIds(filter): messages.append((msg_id, len(messages))) return messages def getTranslation(self, msgid, target_lang): return self.context.translate(msgid, target_language=target_lang) def getEditLanguages(self): '''get the languages that are selected for editing''' languages = self.request.cookies.get('edit_languages', '') return filter(None, languages.split(',')) def editMessage(self): msg_id = self.request['msg_id'] for language in self.getEditLanguages(): msg = self.request['msg_lang_%s' %language] if msg != self.context.translate(msg_id, target_language=language): self.context.updateMessage(msg_id, msg, language) return self.request.response.redirect(self.request.URL[-1]) def editMessages(self): # Handle new Messages for count in range(5): msg_id = self.request.get('new-msg_id-%i' %count, '') if msg_id: for language in self.getEditLanguages(): msg = self.request.get('new-%s-%i' %(language, count), msg_id) self.context.addMessage(msg_id, msg, language) # Handle edited Messages keys = filter(lambda k: k.startswith('edit-msg_id-'), self.request.keys()) keys = map(lambda k: k[12:], keys) for key in keys: msg_id = self.request['edit-msg_id-'+key] for language in self.getEditLanguages(): msg = self.request['edit-%s-%s' %(language, key)] if msg != self.context.translate(msg_id, target_language=language): self.context.updateMessage(msg_id, msg, language) return self.request.response.redirect(self.request.URL[-1]) def deleteMessages(self, message_ids): for id in message_ids: msgid = self.request.form['edit-msg_id-%s' %id] for language in self.context.getAvailableLanguages(): # Some we edit a language, but no translation exists... try: self.context.deleteMessage(msgid, language) except KeyError: pass return self.request.response.redirect(self.request.URL[-1]) def addLanguage(self, language): self.context.addLanguage(language) return self.request.response.redirect(self.request.URL[-1]) def changeEditLanguages(self, languages=[]): self.request.response.setCookie('edit_languages', ','.join(languages)) return self.request.response.redirect(self.request.URL[-1]) def changeFilter(self): filter = self.request.get('filter', '%') self.request.response.setCookie('filter', filter) return self.request.response.redirect(self.request.URL[-1]) def deleteLanguages(self, languages): for language in languages: self.context.deleteLanguage(language) return self.request.response.redirect(self.request.URL[-1]) zope.app.i18n-3.6.4/src/zope/app/i18n/xmlrpc/0000775000177100020040000000000012062644246021602 5ustar menesismenesis00000000000000zope.app.i18n-3.6.4/src/zope/app/i18n/xmlrpc/methods.py0000664000177100020040000000217112062644231023612 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Translation Domain XML-RPC Methods $Id: methods.py 126935 2012-06-18 15:48:16Z tseaver $ """ __docformat__ = 'restructuredtext' from zope.publisher.xmlrpc import XMLRPCView class Methods(XMLRPCView): def getAllLanguages(self): return self.context.getAllLanguages() def getMessagesFor(self, languages): messages = [] for msg in self.context.getMessages(): if msg['language'] in languages: messages.append(msg) return messages zope.app.i18n-3.6.4/src/zope/app/i18n/xmlrpc/__init__.py0000664000177100020040000000007512062644231023707 0ustar menesismenesis00000000000000# # This file is necessary to make this directory a package. zope.app.i18n-3.6.4/src/zope/app/i18n/xmlrpc/configure.zcml0000664000177100020040000000057112062644231024447 0ustar menesismenesis00000000000000 zope.app.i18n-3.6.4/src/zope/app/i18n/translationdomain.py0000664000177100020040000002314012062644231024367 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """This is the standard, placeful Translation Domain for TTW development. $Id: translationdomain.py 128545 2012-12-09 10:50:01Z menesis $ """ __docformat__ = 'restructuredtext' import re from BTrees.OOBTree import OOBTree import zope.component from zope.interface import implements from zope.i18n import interpolate from zope.i18n.interfaces import INegotiator, ITranslationDomain from zope.i18n.simpletranslationdomain import SimpleTranslationDomain from zope.container.btree import BTreeContainer from zope.container.contained import Contained from zope.app.i18n.interfaces import ILocalTranslationDomain class TranslationDomain(BTreeContainer, SimpleTranslationDomain, Contained): implements(ILocalTranslationDomain) def __init__(self): super(TranslationDomain, self).__init__() self._catalogs = OOBTree() self.domain = '' def _registerMessageCatalog(self, language, catalog_name): if language not in self._catalogs.keys(): self._catalogs[language] = [] mc = self._catalogs[language] mc.append(catalog_name) def _unregisterMessageCatalog(self, language, catalog_name): self._catalogs[language].remove(catalog_name) def __setitem__(self, name, object): 'See IWriteContainer' super(TranslationDomain, self).__setitem__(name, object) self._registerMessageCatalog(object.language, name) def __delitem__(self, name): 'See IWriteContainer' object = self[name] super(TranslationDomain, self).__delitem__(name) self._unregisterMessageCatalog(object.language, name) def translate(self, msgid, mapping=None, context=None, target_language=None, default=None): """See interface `ITranslationDomain`""" if target_language is None and context is not None: avail_langs = self.getAvailableLanguages() # Let's negotiate the language to translate to. :) negotiator = zope.component.getUtility(INegotiator, context=self) target_language = negotiator.getLanguage(avail_langs, context) # Get the translation. Default is the source text itself. if target_language is not None: catalog_names = self._catalogs.get(target_language, []) else: catalog_names = [] for name in catalog_names: catalog = super(TranslationDomain, self).__getitem__(name) text = catalog.queryMessage(msgid) if text is not None: break else: # If nothing found, delegate to a translation server higher up the # tree. domain = zope.component.queryNextUtility(self, ITranslationDomain, self.domain) if domain is not None: return domain.translate(msgid, mapping, context, target_language, default=default) if default is None: default = unicode(msgid) text = default # Now we need to do the interpolation return interpolate(text, mapping) def getMessageIds(self, filter='%'): 'See `IWriteTranslationDomain`' filter = filter.replace('%', '.*') filter_re = re.compile(filter) msgids = {} for language in self.getAvailableLanguages(): for name in self._catalogs[language]: for msgid in self[name].getMessageIds(): if filter_re.match(msgid) >= 0: msgids[msgid] = None return msgids.keys() def getMessages(self): 'See `IWriteTranslationDomain`' messages = [] languages = self.getAvailableLanguages() for language in languages: for name in self._catalogs[language]: messages += self[name].getMessages() return messages def getMessage(self, msgid, language): 'See `IWriteTranslationDomain`' for name in self._catalogs.get(language, []): try: return self[name].getFullMessage(msgid) except: pass return None def getAllLanguages(self): 'See `IWriteTranslationDomain`' languages = {} for key in self._catalogs.keys(): languages[key] = None return languages.keys() def getAvailableLanguages(self): 'See `IWriteTranslationDomain`' return list(self._catalogs.keys()) def addMessage(self, msgid, msg, language, mod_time=None): 'See `IWriteTranslationDomain`' if not self._catalogs.has_key(language): if language not in self.getAllLanguages(): self.addLanguage(language) catalog_name = self._catalogs[language][0] catalog = self[catalog_name] catalog.setMessage(msgid, msg, mod_time) def updateMessage(self, msgid, msg, language, mod_time=None): 'See `IWriteTranslationDomain`' catalog_name = self._catalogs[language][0] catalog = self[catalog_name] catalog.setMessage(msgid, msg, mod_time) def deleteMessage(self, msgid, language): 'See `IWriteTranslationDomain`' catalog_name = self._catalogs[language][0] catalog = self[catalog_name] catalog.deleteMessage(msgid) def addLanguage(self, language): 'See `IWriteTranslationDomain`' catalog = zope.component.createObject(u'zope.app.MessageCatalog', language) catalog.domain = self.domain self[language] = catalog def deleteLanguage(self, language): 'See `IWriteTranslationDomain`' # Delete all catalogs from the data storage for name in self._catalogs[language]: if self.has_key(name): del self[name] # Now delete the specifc catalog registry for this language del self._catalogs[language] def getMessagesMapping(self, languages, foreign_messages): 'See `ISyncTranslationDomain`' mapping = {} # Get all relevant local messages local_messages = [] for language in languages: for name in self._catalogs.get(language, []): local_messages += self[name].getMessages() for fmsg in foreign_messages: ident = (fmsg['msgid'], fmsg['language']) mapping[ident] = (fmsg, self.getMessage(*ident)) for lmsg in local_messages: ident = (lmsg['msgid'], lmsg['language']) if ident not in mapping.keys(): mapping[ident] = (None, lmsg) return mapping def synchronize(self, messages_mapping): 'See `ISyncTranslationDomain`' for value in messages_mapping.values(): fmsg = value[0] lmsg = value[1] if fmsg is None: self.deleteMessage(lmsg['msgid'], lmsg['language']) elif lmsg is None: self.addMessage(fmsg['msgid'], fmsg['msgstr'], fmsg['language'], fmsg['mod_time']) elif fmsg['mod_time'] > lmsg['mod_time']: self.updateMessage(fmsg['msgid'], fmsg['msgstr'], fmsg['language'], fmsg['mod_time']) def setDomainOnActivation(domain, event): """Set the permission id upon registration activation. Let's see how this notifier can be used. First we need to create an event using the permission instance and a registration stub: >>> class Registration: ... def __init__(self, obj, name): ... self.component = obj ... self.name = name >>> domain1 = TranslationDomain() >>> domain1.domain '' >>> import zope.component.interfaces >>> event = zope.component.interfaces.Registered( ... Registration(domain1, 'domain1')) Now we pass the event into this function, and the id of the domain should be set to 'domain1'. >>> setDomainOnActivation(domain1, event) >>> domain1.domain 'domain1' """ domain.domain = event.object.name def unsetDomainOnDeactivation(domain, event): """Unset the permission id up registration deactivation. Let's see how this notifier can be used. First we need to create an event using the permission instance and a registration stub: >>> class Registration: ... def __init__(self, obj, name): ... self.component = obj ... self.name = name >>> domain1 = TranslationDomain() >>> domain1.domain = 'domain1' >>> import zope.component.interfaces >>> event = zope.component.interfaces.Unregistered( ... Registration(domain1, 'domain1')) Now we pass the event into this function, and the id of the role should be set to ''. >>> unsetDomainOnDeactivation(domain1, event) >>> domain1.domain '' """ domain.domain = '' zope.app.i18n-3.6.4/src/zope/app/i18n/__init__.py0000664000177100020040000000136712062644231022407 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2003 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Customization of zope.i18n for the Zope application server """ # BBB from zope.i18nmessageid import ZopeMessageFactory zope.app.i18n-3.6.4/src/zope/app/i18n/configure.zcml0000664000177100020040000000413512062644231023142 0ustar menesismenesis00000000000000 zope.app.i18n-3.6.4/src/zope/app/i18n/interfaces.py0000664000177100020040000001235212062644231022767 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2003 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Placeful internationalization of content objects. $Id: interfaces.py 126935 2012-06-18 15:48:16Z tseaver $ """ __docformat__ = 'restructuredtext' from zope.interface import Interface from zope.i18n.interfaces import ITranslationDomain, IMessageCatalog from zope.container.interfaces import IContainer class IWriteTranslationDomain(Interface): """This interface describes the methods that are necessary for an editable Translation Domain to work. For a translation domain to be editable its 'messages' have to support the following information: id, string, domain, language, date Most of the information will be natural, since they are required by the translation domain, but especially the date is not a necessary info (in fact, it is meta data) """ def getMessage(msgid, langauge): """Get the full message of a particular language.""" def getMessageIds(filter='%'): """Get all the message ids of this domain.""" def getMessages(): """Get all the messages of this domain.""" def getAllLanguages(): """Find all the languages that are available""" def getAvailableLanguages(): """Find all the languages that are available.""" def addMessage(msgid, msg, language, mod_time=None): """Add a message to the translation domain. If `mod_time` is ``None``, then the current time should be inserted. """ def updateMessage(msgid, msg, language, mod_time=None): """Update a message in the translation domain. If `mod_time` is ``None``, then the current time should be inserted. """ def deleteMessage(domain, msgid, language): """Delete a messahe in the translation domain.""" def addLanguage(language): """Add Language to Translation Domain""" def deleteLanguage(language): """Delete a Domain from the Translation Domain.""" class ISyncTranslationDomain(Interface): """This interface allows translation domains to be synchronized. The following four synchronization states can exist: 0 - uptodate: The two messages are in sync. Default Action: Do nothing. 1 - new: The message exists on the foreign TS, but is locally unknown. Default Action: Add the message to the local catalog. 2 - older: The local version of the message is older than the one on the server. Default Action: Update the local message. 3 - newer: The local version is newer than the foreign version. Default Action: Do nothing. 4 - deleted: The message does not exist in the foreign TS. Default Action: Delete local version of message. """ def getMessagesMapping(languages, foreign_messages): """Creates a mapping of the passed foreign messages and the local ones. Returns a status report in a dictionary with keys of the form (msgid, domain, language) and values being a tuple of: foreign_mod_date, local_mod_date """ def synchronize(messages_mapping): """Update the local message catalogs based on the foreign data. """ class ILocalTranslationDomain(ITranslationDomain, IWriteTranslationDomain, ISyncTranslationDomain, IContainer): """This is the common and full-features translation domain. Almost all translation domain implementations will use this interface. An exception to this is the `GlobalMessageCatalog` as it will be read-only. """ class ILocalMessageCatalog(IMessageCatalog): """If this interfaces is implemented by a message catalog, then we will be able to update our messages. Note that not all methods here require write access, but they should not be required for an `IReadMessageCatalog` and are used for editing only. Therefore this is the more suitable interface to put them. """ def getFullMessage(msgid): """Get the message data and meta data as a nice dictionary. More advanced implementation might choose to return an object with the data, but the object should then implement `IEnumerableMapping`. An exception is raised if the message id is not found. """ def setMessage(msgid, message, mod_time=None): """Set a message to the catalog. If `mod_time` is ``None`` use the current time instead as modification time.""" def deleteMessage(msgid): """Delete a message from the catalog.""" def getMessageIds(): """Get a list of all the message ids.""" def getMessages(): """Get a list of all the messages.""" zope.app.i18n-3.6.4/src/zope/app/i18n/tests/0000775000177100020040000000000012062644246021437 5ustar menesismenesis00000000000000zope.app.i18n-3.6.4/src/zope/app/i18n/tests/test_filters.py0000664000177100020040000000567712062644231024531 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """This module tests the Gettext Export and Import funciotnality of the Translation Domain. $Id: test_filters.py 128565 2012-12-10 21:53:48Z menesis $ """ import unittest import time from cStringIO import StringIO from zope.interface import implements from zope.component.testing import PlacelessSetup from zope.component.interfaces import IFactory from zope.component.factory import Factory from zope.component import provideUtility from zope.app.i18n.messagecatalog import MessageCatalog from zope.i18n.negotiator import negotiator from zope.i18n.interfaces import INegotiator, IUserPreferredLanguages from zope.app.i18n.translationdomain import TranslationDomain from zope.app.i18n.filters import GettextImportFilter, GettextExportFilter class Environment(object): implements(IUserPreferredLanguages) def __init__(self, langs=()): self.langs = langs def getPreferredLanguages(self): return self.langs class TestGettextExportImport(PlacelessSetup, unittest.TestCase): _data = '''msgid "" msgstr "" "Project-Id-Version: Zope 3\\n" "PO-Revision-Date: %s\\n" "Last-Translator: Zope 3 Gettext Export Filter\\n" "Zope-Language: de\\n" "Zope-Domain: default\\n" "MIME-Version: 1.0\\n" "Content-Type: text/plain; charset=UTF-8\\n" "Content-Transfer-Encoding: 8bit\\n" msgid "Choose" msgstr "Ausw\xc3\xa4hlen!" msgid "greeting" msgstr "hallo" ''' def setUp(self): super(TestGettextExportImport, self).setUp() # Setup the negotiator utility provideUtility(negotiator, INegotiator) self._domain = TranslationDomain() self._domain.domain = 'default' provideUtility(Factory(MessageCatalog), IFactory, 'zope.app.MessageCatalog') def testImportExport(self): imp = GettextImportFilter(self._domain) imp.importMessages(['de'], StringIO(self._data %'2002/02/02 02:02')) exp = GettextExportFilter(self._domain) result = exp.exportMessages(['de']) dt = time.time() dt = time.localtime(dt) dt = time.strftime('%Y/%m/%d %H:%M', dt) self.assertEqual(result.strip(), (self._data %dt).strip()) def test_suite(): loader = unittest.TestLoader() return loader.loadTestsFromTestCase(TestGettextExportImport) if __name__ == '__main__': unittest.TextTestRunner().run(test_suite()) zope.app.i18n-3.6.4/src/zope/app/i18n/tests/test_messagecatalog.py0000664000177100020040000000700212062644231026020 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Test the generic persistent Message Catalog. $Id: test_messagecatalog.py 126935 2012-06-18 15:48:16Z tseaver $ """ import unittest from zope.interface.verify import verifyObject from zope.app.i18n.messagecatalog import MessageCatalog from zope.app.i18n.interfaces import ILocalMessageCatalog from zope.i18n.tests.test_imessagecatalog import TestIMessageCatalog # This is a mixin class -- don't add it to the suite class TestILocalMessageCatalog(object): # This should be overwritten by every class that inherits this test def _getMessageCatalog(self): pass def _getUniqueIndentifier(self): pass def setUp(self): self._catalog = self._getMessageCatalog() def testInterface(self): verifyObject(ILocalMessageCatalog, self._catalog) def testGetFullMessage(self): catalog = self._catalog self.assertEqual(catalog.getFullMessage('short_greeting'), {'domain': 'default', 'language': 'en', 'msgid': 'short_greeting', 'msgstr': 'Hello!', 'mod_time': 0}) def testSetMessage(self): catalog = self._catalog catalog.setMessage('test', 'Test', 1) self.assertEqual(catalog.getFullMessage('test'), {'domain': 'default', 'language': 'en', 'msgid': 'test', 'msgstr': 'Test', 'mod_time': 1}) catalog.deleteMessage('test') def testDeleteMessage(self): catalog = self._catalog self.assertEqual(catalog.queryMessage('test'), None) catalog.setMessage('test', 'Test', 1) self.assertEqual(catalog.queryMessage('test'), 'Test') catalog.deleteMessage('test') self.assertEqual(catalog.queryMessage('test'), None) def testGetMessageIds(self): catalog = self._catalog ids = catalog.getMessageIds() ids.sort() self.assertEqual(ids, ['greeting', 'short_greeting']) def testGetMessages(self): catalog = self._catalog ids = catalog.getMessageIds() ids.sort() self.assertEqual(ids, ['greeting', 'short_greeting']) class LocalMessageCatalogTest(TestIMessageCatalog, TestILocalMessageCatalog): def setUp(self): TestIMessageCatalog.setUp(self) TestILocalMessageCatalog.setUp(self) def _getMessageCatalog(self): catalog = MessageCatalog('en', 'default') catalog.setMessage('short_greeting', 'Hello!', 0) catalog.setMessage('greeting', 'Hello $name, how are you?', 0) return catalog def _getUniqueIndentifier(self): return ('en', 'default') def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(LocalMessageCatalogTest)) return suite zope.app.i18n-3.6.4/src/zope/app/i18n/tests/__init__.py0000664000177100020040000000007312062644231023542 0ustar menesismenesis00000000000000# This file is necessary to make this directory a package. zope.app.i18n-3.6.4/src/zope/app/i18n/tests/placelesssetup.py0000664000177100020040000000025312062644231025037 0ustar menesismenesis00000000000000# This module has moved to zope.i18n.testing # and will go away in Zope 3.5 import zope.deprecation zope.deprecation.moved( 'zope.i18n.testing', "Zope 3.5", ) zope.app.i18n-3.6.4/src/zope/app/i18n/tests/configure.zcml0000664000177100020040000000032112062644231024275 0ustar menesismenesis00000000000000 zope.app.i18n-3.6.4/src/zope/app/i18n/tests/test_translationdomain.py0000664000177100020040000002572512062644231026603 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """This module tests the regular persistent Translation Domain. $Id: test_translationdomain.py 128565 2012-12-10 21:53:48Z menesis $ """ import unittest import doctest from zope.component import getGlobalSiteManager from zope.component import provideUtility from zope.component.interfaces import IFactory from zope.component.factory import Factory from zope.i18n.interfaces import ITranslationDomain from zope.i18n.interfaces import IUserPreferredLanguages from zope.i18n.tests.test_itranslationdomain import TestITranslationDomain from zope.i18n.translationdomain \ import TranslationDomain as GlobalTranslationDomain from zope.interface import implements from zope.interface.verify import verifyObject from zope.traversing.api import traverse from zope.app.i18n import interfaces from zope.app.i18n.messagecatalog import MessageCatalog from zope.app.i18n.translationdomain import TranslationDomain from zope.app.testing import setup class Environment(object): implements(IUserPreferredLanguages) def __init__(self, langs=()): self.langs = langs def getPreferredLanguages(self): return self.langs class TestILocalTranslationDomain(object): def _getTranslationDomain(self): """This should be overwritten by every clas that inherits this test. We expect the TranslationDomain to contain exactly 2 languages: de and en """ def setUp(self): self._domain = self._getTranslationDomain() def testInterface(self): verifyObject(ITranslationDomain, self._domain) def _getLanguages(self, domain): languages = domain.getAllLanguages() languages.sort() return languages def testGetAddDeleteLanguage(self): domain = self._domain langs = self._getLanguages(domain) domain.addLanguage('es') self.assertEqual(self._getLanguages(domain), langs+['es']) domain.addLanguage('fr') self.assertEqual(self._getLanguages(domain), langs+['es', 'fr']) self.assertEqual(domain.getAvailableLanguages(), langs+['es', 'fr']) domain.deleteLanguage('es') self.assertEqual(self._getLanguages(domain), langs+['fr']) domain.deleteLanguage('fr') self.assertEqual(self._getLanguages(domain), langs) def testAddUpdateDeleteMessage(self): domain = self._domain self.assertEqual(domain.translate('greeting2', target_language='de'), 'greeting2') self.assertEqual(domain.translate( 'greeting2', target_language='de', default=42), 42) domain.addMessage('greeting2', 'Hallo!', 'de') self.assertEqual(domain.translate('greeting2', target_language='de'), 'Hallo!') domain.updateMessage('greeting2', 'Hallo Ihr da!', 'de') self.assertEqual(domain.translate('greeting2', target_language='de'), 'Hallo Ihr da!') domain.deleteMessage('greeting2', 'de') self.assertEqual(domain.translate('greeting2', target_language='de'), 'greeting2') # A test mixing -- don't add this to the suite class TestISyncTranslationDomain(object): foreign_messages = [ # Message that is not locally available {'domain': 'default', 'language': 'en', 'msgid': 'test', 'msgstr': 'Test', 'mod_time': 0}, # This message is newer than the local one. {'domain': 'default', 'language': 'de', 'msgid': 'short_greeting', 'msgstr': 'Hallo.', 'mod_time': 20}, # This message is older than the local one. {'domain': 'default', 'language': 'en', 'msgid': 'short_greeting', 'msgstr': 'Hello', 'mod_time': 0}, # This message is up-to-date. {'domain': 'default', 'language': 'en', 'msgid': 'greeting', 'msgstr': 'Hello $name, how are you?', 'mod_time': 0}] local_messages = [ # This message is older than the foreign one. {'domain': 'default', 'language': 'de', 'msgid': 'short_greeting', 'msgstr': 'Hallo!', 'mod_time': 10}, # This message is newer than the foreign one. {'domain': 'default', 'language': 'en', 'msgid': 'short_greeting', 'msgstr': 'Hello!', 'mod_time': 10}, # This message is up-to-date. {'domain': 'default', 'language': 'en', 'msgid': 'greeting', 'msgstr': 'Hello $name, how are you?', 'mod_time': 0}, # This message is only available locally. {'domain': 'default', 'language': 'de', 'msgid': 'greeting', 'msgstr': 'Hallo $name, wie geht es Dir?', 'mod_time': 0}, ] # This should be overwritten by every clas that inherits this test def _getTranslationDomain(self): pass def setUp(self): self._domain = self._getTranslationDomain() def testInterface(self): verifyObject(interfaces.ISyncTranslationDomain, self._domain) def testGetMessagesMapping(self): mapping = self._domain.getMessagesMapping(['de', 'en'], self.foreign_messages) self.assertEqual(mapping[('test', 'en')], (self.foreign_messages[0], None)) self.assertEqual(mapping[('short_greeting', 'de')], (self.foreign_messages[1], self.local_messages[0])) self.assertEqual(mapping[('short_greeting', 'en')], (self.foreign_messages[2], self.local_messages[1])) self.assertEqual(mapping[('greeting', 'en')], (self.foreign_messages[3], self.local_messages[2])) self.assertEqual(mapping[('greeting', 'de')], (None, self.local_messages[3])) def testSynchronize(self): domain = self._domain mapping = domain.getMessagesMapping(['de', 'en'], self.foreign_messages) domain.synchronize(mapping) self.assertEqual(domain.getMessage('test', 'en'), self.foreign_messages[0]) self.assertEqual(domain.getMessage('short_greeting', 'de'), self.foreign_messages[1]) self.assertEqual(domain.getMessage('short_greeting', 'en'), self.local_messages[1]) self.assertEqual(domain.getMessage('greeting', 'en'), self.local_messages[2]) self.assertEqual(domain.getMessage('greeting', 'en'), self.foreign_messages[3]) self.assertEqual(domain.getMessage('greeting', 'de'), None) class TestTranslationDomain(TestITranslationDomain, TestISyncTranslationDomain, TestILocalTranslationDomain, unittest.TestCase): def setUp(self): TestITranslationDomain.setUp(self) # placefulSetup setup.setUpTraversal() setup.setUpSiteManagerLookup() self.rootFolder = setup.buildSampleFolderTree() self.sm = setup.createSiteManager(self.rootFolder, setsite=True) setup.addUtility(self.sm, 'default', ITranslationDomain, self._domain) provideUtility(Factory(MessageCatalog), IFactory, 'zope.app.MessageCatalog') def _getTranslationDomain(self): domain = TranslationDomain() domain.domain = 'default' en_catalog = MessageCatalog('en', 'default') de_catalog = MessageCatalog('de', 'default') # Populate the catalogs with translations of a message id en_catalog.setMessage('short_greeting', 'Hello!', 10) de_catalog.setMessage('short_greeting', 'Hallo!', 10) # And another message id with interpolation placeholders en_catalog.setMessage('greeting', 'Hello $name, how are you?', 0) de_catalog.setMessage('greeting', 'Hallo $name, wie geht es Dir?', 0) domain['en-1'] = en_catalog domain['de-1'] = de_catalog return domain def testParameterNames(self): # Test that the second argument is called `msgid' self.assertEqual( self._domain.translate('short_greeting', target_language='en'), 'Hello!') def testCatalogDomain(self): domain = self._domain domain.domain = 'myfault' domain.addMessage('greeting2', 'Hola!', 'ca') self.assertEqual(domain['ca'].domain, domain.domain) domain.domain = 'default' class TestTranslationDomainInAction(unittest.TestCase): def setUp(self): setup.placefulSetUp() self.rootFolder = setup.buildSampleFolderTree() gsm = getGlobalSiteManager() de_catalog = MessageCatalog('de', 'default') de_catalog.setMessage('short_greeting', 'Hallo!', 10) de_catalog.setMessage('long_greeting', 'Guten Tag!', 10) # register global translation domain and add the catalog. domain = GlobalTranslationDomain('default') domain.addCatalog(de_catalog) gsm.registerUtility(domain, ITranslationDomain, 'default') # create a local site manager and add a local translation domain td = TranslationDomain() td.domain = 'default' de_catalog = MessageCatalog('de', 'default') de_catalog.setMessage('short_greeting', 'Hallo Welt!', 10) td['de-default-1'] = de_catalog mgr = setup.createSiteManager(traverse(self.rootFolder, 'folder1')) setup.addUtility( mgr, 'default', interfaces.ILocalTranslationDomain, td) self.trans1 = td self.trans = domain def tearDown(self): setup.placefulTearDown() def test_translate(self): self.assertEqual( self.trans.translate('short_greeting', context='default', target_language='de'), 'Hallo!') self.assertEqual( self.trans1.translate('short_greeting', context='default', target_language='de'), 'Hallo Welt!') self.assertEqual( self.trans1.translate('long_greeting', context='default', target_language='de'), 'Guten Tag!') def test_suite(): return unittest.TestSuite(( unittest.makeSuite(TestTranslationDomain), doctest.DocTestSuite('zope.app.i18n.translationdomain'), unittest.makeSuite(TestTranslationDomainInAction), )) if __name__=='__main__': unittest.main(defaultTest='test_suite') zope.app.i18n-3.6.4/src/zope/app/i18n/messagecatalog.py0000664000177100020040000000621612062644231023625 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """A simple implementation of a Message Catalog. $Id: messagecatalog.py 126935 2012-06-18 15:48:16Z tseaver $ """ __docformat__ = 'restructuredtext' from zope.interface import classProvides, providedBy, implements import time from BTrees.OOBTree import OOBTree from persistent import Persistent from zope.component.interfaces import IFactory from zope.app.i18n.interfaces import ILocalMessageCatalog class MessageCatalog(Persistent): implements(ILocalMessageCatalog) classProvides(IFactory) def __init__(self, language, domain="default"): """Initialize the message catalog""" self.id = '' self.title = '' self.description = '' self.language = language self.domain = domain self._messages = OOBTree() def getMessage(self, id): 'See `IReadMessageCatalog`' return self._messages[id][0] def queryMessage(self, id, default=None): 'See `IReadMessageCatalog`' result = self._messages.get(id) if result is not None: result = result[0] else: result = default return result def getIdentifier(self): 'See `IReadMessageCatalog`' return (self.language, self.domain) def getFullMessage(self, msgid): 'See `IWriteMessageCatalog`' message = self._messages[msgid] return {'domain' : self.domain, 'language' : self.language, 'msgid' : msgid, 'msgstr' : message[0], 'mod_time' : message[1]} def setMessage(self, msgid, message, mod_time=None): 'See `IWriteMessageCatalog`' if mod_time is None: mod_time = int(time.time()) self._messages[msgid] = (message, mod_time) def deleteMessage(self, msgid): 'See `IWriteMessageCatalog`' del self._messages[msgid] def getMessageIds(self): 'See IWriteMessageCatalog' return list(self._messages.keys()) def getMessages(self): 'See `IWriteMessageCatalog`' messages = [] for message in self._messages.items(): messages.append({'domain' : self.domain, 'language' : self.language, 'msgid' : message[0], 'msgstr' : message[1][0], 'mod_time' : message[1][1]}) return messages def getInterfaces(self): 'See `IFactory`' return tuple(providedBy(self)) getInterfaces = classmethod(getInterfaces) zope.app.i18n-3.6.4/src/zope/app/__init__.py0000664000177100020040000000031012062644231021613 0ustar menesismenesis00000000000000# this is a namespace package try: import pkg_resources pkg_resources.declare_namespace(__name__) except ImportError: import pkgutil __path__ = pkgutil.extend_path(__path__, __name__) zope.app.i18n-3.6.4/buildout.cfg0000664000177100020040000000014712062644231017476 0ustar menesismenesis00000000000000[buildout] develop = . parts = test [test] recipe = zc.recipe.testrunner eggs = zope.app.i18n [test] zope.app.i18n-3.6.4/COPYRIGHT.txt0000664000177100020040000000004012062644231017267 0ustar menesismenesis00000000000000Zope Foundation and Contributorszope.app.i18n-3.6.4/setup.py0000664000177100020040000000513212062644231016677 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2006 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## # This package is developed by the Zope Toolkit project, documented here: # http://docs.zope.org/zopetoolkit # When developing and releasing this package, please follow the documented # Zope Toolkit policies as described by this documentation. ############################################################################## """Setup for zope.app.i18n package """ import os from setuptools import setup, find_packages def read(*rnames): return open(os.path.join(os.path.dirname(__file__), *rnames)).read() setup(name='zope.app.i18n', version='3.6.4', author='Zope Corporation and Contributors', author_email='zope-dev@zope.org', description='Persistent translation domains and message catalogs', long_description=( read('README.txt') + '\n\n' + read('CHANGES.txt') ), keywords = "zope3 i18n message factory", classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Programming Language :: Python', 'Natural Language :: English', 'Operating System :: OS Independent', 'Topic :: Internet :: WWW/HTTP', 'Framework :: Zope3'], url='http://pypi.python.org/pypi/zope.app.i18n', license='ZPL 2.1', packages=find_packages('src'), package_dir = {'': 'src'}, namespace_packages=['zope', 'zope.app'], extras_require = dict(test=['zope.app.testing']), install_requires=['setuptools', 'zope.publisher>=3.9', 'zope.component>=3.6', 'zope.container', 'zope.configuration', 'zope.i18n', 'zope.i18nmessageid', 'zope.interface', 'zope.security', 'ZODB3', ], include_package_data = True, zip_safe = False, ) zope.app.i18n-3.6.4/PKG-INFO0000664000177100020040000000734112062644246016274 0ustar menesismenesis00000000000000Metadata-Version: 1.1 Name: zope.app.i18n Version: 3.6.4 Summary: Persistent translation domains and message catalogs Home-page: http://pypi.python.org/pypi/zope.app.i18n Author: Zope Corporation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: This package provides placeful persistent translation domains and message catalogs along with ZMI views for managing them. ======= CHANGES ======= 3.6.4 (2012-12-14) ------------------ - Fix translate() when used with ZODB 4. - Remove test dependency on zope.app.component 3.6.3 (2010-09-01) ------------------ - Remove undeclared dependency on zope.deferredimport. - Use zope.publisher >= 3.9 instead of zope.app.publisher. 3.6.2 (2009-10-07) ------------------ - Fix test_translate and follow recent change of HTTPResponse.redirect. 3.6.1 (2009-08-15) ------------------ - Added a missing testing dependency on zope.app.component. 3.6.0 (2009-03-18) ------------------ - Some of ZCML configuration was moved into another packages: * The global INegotiator utility registration was moved into ``zope.i18n``. * The include of ``zope.i18n.locales`` was also moved into ``zope.i18n``. * The registration of IModifiableUserPreferredLanguages adapter was moved into ``zope.app.publisher``. * The IAttributeAnnotation implementation statement for HTTPRequest was moved into ``zope.publisher`` and will only apply if ``zope.annotation`` is available. * The IUserPreferredCharsets adapter registration was also moved into ``zope.publisher``. - Depend on zope.component >= 3.6 instead of zope.app.component as the `queryNextUtility` function was moved there. - Remove the old ``zope.app.i18n.metadirectives`` module as the directive was moved to ``zope.i18n`` ages ago. 3.5.0 (2009-02-01) ------------------ - Use zope.container instead of zope.app.container. 3.4.6 (2009-01-27) ------------------ - Fix a simple inconsistent MRO problem in tests - Substitute zope.app.zapi by direct calls to its wrapped apis. See bug 219302. 3.4.5 (unreleased) ------------------ - This was skipped over by accident. 3.4.4 (2007-10-23) ------------------ - Fix deprecation warning. 3.4.3 (2007-10-23) ------------------ - Fix imports in tests. - Clean up long lines. 3.4.2 (2007-9-26) ----------------- - Release to fix packaging issues with 3.4.1. 3.4.1 (2007-9-25) ----------------- - Added missing Changes.txt and README.txt files to egg 3.4.0 (2007-9-25) ----------------- - Initial documented release - Move ZopeMessageFactory to zope.i18nmessageid Keywords: zope3 i18n message factory Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zope.app.i18n-3.6.4/bootstrap.py0000664000177100020040000000337312062644231017561 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2006 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Bootstrap a buildout-based project Simply run this script in a directory containing a buildout.cfg. The script accepts buildout command-line options, so you can use the -c option to specify an alternate configuration file. $Id: bootstrap.py 126935 2012-06-18 15:48:16Z tseaver $ """ import os, shutil, sys, tempfile, urllib2 tmpeggs = tempfile.mkdtemp() ez = {} exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' ).read() in ez ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) import pkg_resources cmd = 'from setuptools.command.easy_install import main; main()' if sys.platform == 'win32': cmd = '"%s"' % cmd # work around spawn lamosity on windows ws = pkg_resources.working_set assert os.spawnle( os.P_WAIT, sys.executable, sys.executable, '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout', dict(os.environ, PYTHONPATH= ws.find(pkg_resources.Requirement.parse('setuptools')).location ), ) == 0 ws.add_entry(tmpeggs) ws.require('zc.buildout') import zc.buildout.buildout zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap']) shutil.rmtree(tmpeggs) zope.app.i18n-3.6.4/setup.cfg0000664000177100020040000000007312062644246017013 0ustar menesismenesis00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 zope.app.i18n-3.6.4/CHANGES.txt0000664000177100020040000000420512062644231016776 0ustar menesismenesis00000000000000======= CHANGES ======= 3.6.4 (2012-12-14) ------------------ - Fix translate() when used with ZODB 4. - Remove test dependency on zope.app.component 3.6.3 (2010-09-01) ------------------ - Remove undeclared dependency on zope.deferredimport. - Use zope.publisher >= 3.9 instead of zope.app.publisher. 3.6.2 (2009-10-07) ------------------ - Fix test_translate and follow recent change of HTTPResponse.redirect. 3.6.1 (2009-08-15) ------------------ - Added a missing testing dependency on zope.app.component. 3.6.0 (2009-03-18) ------------------ - Some of ZCML configuration was moved into another packages: * The global INegotiator utility registration was moved into ``zope.i18n``. * The include of ``zope.i18n.locales`` was also moved into ``zope.i18n``. * The registration of IModifiableUserPreferredLanguages adapter was moved into ``zope.app.publisher``. * The IAttributeAnnotation implementation statement for HTTPRequest was moved into ``zope.publisher`` and will only apply if ``zope.annotation`` is available. * The IUserPreferredCharsets adapter registration was also moved into ``zope.publisher``. - Depend on zope.component >= 3.6 instead of zope.app.component as the `queryNextUtility` function was moved there. - Remove the old ``zope.app.i18n.metadirectives`` module as the directive was moved to ``zope.i18n`` ages ago. 3.5.0 (2009-02-01) ------------------ - Use zope.container instead of zope.app.container. 3.4.6 (2009-01-27) ------------------ - Fix a simple inconsistent MRO problem in tests - Substitute zope.app.zapi by direct calls to its wrapped apis. See bug 219302. 3.4.5 (unreleased) ------------------ - This was skipped over by accident. 3.4.4 (2007-10-23) ------------------ - Fix deprecation warning. 3.4.3 (2007-10-23) ------------------ - Fix imports in tests. - Clean up long lines. 3.4.2 (2007-9-26) ----------------- - Release to fix packaging issues with 3.4.1. 3.4.1 (2007-9-25) ----------------- - Added missing Changes.txt and README.txt files to egg 3.4.0 (2007-9-25) ----------------- - Initial documented release - Move ZopeMessageFactory to zope.i18nmessageid zope.app.i18n-3.6.4/LICENSE.txt0000664000177100020040000000402612062644231017011 0ustar menesismenesis00000000000000Zope Public License (ZPL) Version 2.1 A copyright notice accompanies this license document that identifies the copyright holders. This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF). Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without prior written permission from the copyright holders. 4. The right to distribute this software or to use it for any purpose does not give you the right to use Servicemarks (sm) or Trademarks (tm) of the copyright holders. Use of them is covered by separate agreement with the copyright holders. 5. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. Disclaimer THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.