[Zope3-checkins] CVS: Zope3/src/zope/app/services/translation - __init__.py:1.2 configure.zcml:1.2 gettextexportfilter.py:1.2 gettextimportfilter.py:1.2 i18n_service.gif:1.2 messagecatalog.py:1.2 translationservice.py:1.2
Jim Fulton
jim@zope.com
Wed, 25 Dec 2002 09:13:52 -0500
Update of /cvs-repository/Zope3/src/zope/app/services/translation
In directory cvs.zope.org:/tmp/cvs-serv15352/src/zope/app/services/translation
Added Files:
__init__.py configure.zcml gettextexportfilter.py
gettextimportfilter.py i18n_service.gif messagecatalog.py
translationservice.py
Log Message:
Grand renaming:
- Renamed most files (especially python modules) to lower case.
- Moved views and interfaces into separate hierarchies within each
project, where each top-level directory under the zope package
is a separate project.
- Moved everything to src from lib/python.
lib/python will eventually go away. I need access to the cvs
repository to make this happen, however.
There are probably some bits that are broken. All tests pass
and zope runs, but I haven't tried everything. There are a number
of cleanups I'll work on tomorrow.
=== Zope3/src/zope/app/services/translation/__init__.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:52 2002
+++ Zope3/src/zope/app/services/translation/__init__.py Wed Dec 25 09:13:21 2002
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
=== Zope3/src/zope/app/services/translation/configure.zcml 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:52 2002
+++ Zope3/src/zope/app/services/translation/configure.zcml Wed Dec 25 09:13:21 2002
@@ -0,0 +1,50 @@
+<zopeConfigure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:service="http://namespaces.zope.org/service"
+ xmlns:gts="http://namespaces.zope.org/gts">
+
+<!-- Register the Translation Service as a content object -->
+<content class="zope.app.services.translation.translationservice.TranslationService">
+ <factory id="TranslationService" permission="zope.ManageServices" />
+ <require permission="zope.Public"
+ interface="zope.interfaces.i18n.ITranslationService" />
+ <require permission="zope.ManageServices"
+ interface="zope.app.interfaces.container.IContainer" />
+ <implements interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
+</content>
+
+<browser:icon name="zmi_icon" for="zope.interfaces.i18n.ITranslationService"
+ file="./i18n_service.gif" />
+
+<!-- Setup Message Catalogs -->
+<content class="zope.app.services.translation.messagecatalog.MessageCatalog">
+
+ <require permission="zope.View"
+ interface="zope.interfaces.i18n.IReadMessageCatalog" />
+
+ <require permission="zope.ManageServices"
+ attributes="setMessage getMessageIds" />
+ <implements interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
+ interface="zope.interfaces.i18n.IWriteMessageCatalog" />
+
+
+</content>
+
+<factory component="zope.app.services.translation.messagecatalog.MessageCatalog" id="Message Catalog"/>
+
+<!-- Setup Export and Import Filters -->
+<adapter factory="zope.app.services.translation.gettextexportfilter.GettextExportFilter"
+ for="zope.interfaces.i18n.IWriteTranslationService"
+ provides="zope.interfaces.i18n.IMessageExportFilter" />
+
+<adapter factory="zope.app.services.translation.gettextimportfilter.GettextImportFilter"
+ for="zope.interfaces.i18n.IWriteTranslationService"
+ provides="zope.interfaces.i18n.IMessageImportFilter" />
+
+<gts:registerTranslations directory="./locale" />
+<gts:defaultLanguages languages="en" />
+
+<include package=".Views" />
+
+</zopeConfigure>
=== Zope3/src/zope/app/services/translation/gettextexportfilter.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:52 2002
+++ Zope3/src/zope/app/services/translation/gettextexportfilter.py Wed Dec 25 09:13:21 2002
@@ -0,0 +1,90 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Translation Service Message Export Filter
+
+$Id$
+"""
+import time
+from types import StringTypes
+
+from zope.interfaces.i18n import IMessageExportFilter
+from zope.interfaces.i18n import IWriteTranslationService
+
+
+class GettextExportFilter:
+
+ __implements__ = IMessageExportFilter
+ __used_for__ = IWriteTranslationService
+
+
+ def __init__(self, service):
+ self.service = service
+
+ def exportMessages(self, domains, languages):
+ 'See IMessageExportFilter'
+
+ if isinstance(domains, StringTypes):
+ domain = domains
+ elif len(domains) == 1:
+ domain = domains[0]
+ else:
+ raise TypeError, \
+ 'Only one domain at a time is supported for gettext export.'
+
+ 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'))
+ service = self.service
+
+ for msgid in service.getMessageIdsOfDomain(domain):
+ msgstr = service.translate(domain, msgid,
+ target_language=language)
+ msgstr = msgstr.encode('UTF-8')
+ msgid = msgid.encode('UTF-8')
+ output += _msg_template %(msgid, msgstr)
+
+ return output
+
+ #
+ ############################################################
+
+
+
+_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"
+'''
=== Zope3/src/zope/app/services/translation/gettextimportfilter.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:52 2002
+++ Zope3/src/zope/app/services/translation/gettextimportfilter.py Wed Dec 25 09:13:21 2002
@@ -0,0 +1,164 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Translation Service Message Import Filter
+
+$Id$
+"""
+import time, re
+from types import StringTypes
+
+from zope.interfaces.i18n import IMessageImportFilter
+from zope.interfaces.i18n import IWriteTranslationService
+
+
+class GettextImportFilter:
+
+ __implements__ = IMessageImportFilter
+ __used_for__ = IWriteTranslationService
+
+
+ def __init__(self, service):
+ self.service = service
+
+ def importMessages(self, domains, languages, file):
+ 'See IMessageImportFilter'
+
+ if isinstance(domains, StringTypes):
+ domain = domains
+ elif len(domains) == 1:
+ domain = domains[0]
+ else:
+ raise TypeError, \
+ 'Only one domain at a time is supported for gettext export.'
+
+ 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'])
+ service = self.service
+ 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')
+ service.addMessage(domain, 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', 'state 0, line %d\n' % (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', 'state 1, line %d\n' % (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', 'state 2, line %d\n' % (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', 'state 3, line %d\n' % (pointer + 1)
+
+ # the last also goes in
+ if tuple(MSGID):
+ trans[tuple(MSGID)] = (COM, MSGSTR)
+
+ return COM, MSGID, MSGSTR, trans
=== Zope3/src/zope/app/services/translation/i18n_service.gif 1.1 => 1.2 ===
<Binary-ish file>
=== Zope3/src/zope/app/services/translation/messagecatalog.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:52 2002
+++ Zope3/src/zope/app/services/translation/messagecatalog.py Wed Dec 25 09:13:21 2002
@@ -0,0 +1,101 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""A simple implementation of a Message Catalog.
+
+$Id$
+"""
+import time
+
+from zodb.btrees.OOBTree import OOBTree
+from persistence import Persistent
+from zope.proxy.introspection import removeAllProxies
+from zope.component.interfaces import IFactory
+from zope.app.security.registries.registeredobject import RegisteredObject
+from zope.interfaces.i18n import IMessageCatalog
+
+
+class MessageCatalog(RegisteredObject, Persistent):
+
+ __implements__ = IMessageCatalog
+ __class_implements__ = IFactory
+
+ def __init__(self, language, domain="default"):
+ """Initialize the message catalog"""
+ super(MessageCatalog, self).__init__('', '', '')
+ self._language = language
+ self._domain = domain
+ self._messages = OOBTree()
+
+ def getMessage(self, id):
+ 'See IReadMessageCatalog'
+ return removeAllProxies(self._messages[id][0])
+
+ def queryMessage(self, id, default=None):
+ 'See IReadMessageCatalog'
+ result = removeAllProxies(self._messages.get(id))
+ if result is not None:
+ result = result[0]
+ else:
+ result = default
+ return result
+
+ def getLanguage(self):
+ 'See IReadMessageCatalog'
+ return self._language
+
+ def getDomain(self):
+ 'See IReadMessageCatalog'
+ return self._domain
+
+ def getIdentifier(self):
+ 'See IReadMessageCatalog'
+ return (self._language, self._domain)
+
+ def getFullMessage(self, msgid):
+ 'See IWriteMessageCatalog'
+ message = removeAllProxies(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 self.__implements__
=== Zope3/src/zope/app/services/translation/translationservice.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:52 2002
+++ Zope3/src/zope/app/services/translation/translationservice.py Wed Dec 25 09:13:21 2002
@@ -0,0 +1,292 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""This is the standard, placeful Translation Service for TTW development.
+
+$Id$
+"""
+import re
+from types import StringTypes, TupleType
+
+import persistence
+from zodb.btrees.OOBTree import OOBTree
+
+from zope.component import createObject, getService
+from zope.app.component.nextservice import queryNextService
+
+from zope.app.container.btree import BTreeContainer
+from zope.app.interfaces.container import IContainer
+
+from zope.i18n.negotiator import negotiator
+from zope.i18n.domain import Domain
+from zope.interfaces.i18n import IMessageCatalog
+from zope.interfaces.i18n import ITranslationService
+from zope.i18n.simpletranslationservice import SimpleTranslationService
+
+
+class ILocalTranslationService(ITranslationService, IContainer):
+ """TTW manageable translation service"""
+
+
+class TranslationService(BTreeContainer, SimpleTranslationService):
+
+ __implements__ = ILocalTranslationService
+
+ def __init__(self, default_domain='global'):
+ super(TranslationService, self).__init__()
+ self._catalogs = OOBTree()
+ self.default_domain = default_domain
+
+
+ def _registerMessageCatalog(self, language, domain, catalog_name):
+ if (language, domain) not in self._catalogs.keys():
+ self._catalogs[(language, domain)] = []
+
+ mc = self._catalogs[(language, domain)]
+ mc.append(catalog_name)
+
+
+ def _unregisterMessageCatalog(self, language, domain, catalog_name):
+ self._catalogs[(language, domain)].remove(catalog_name)
+
+
+ def setObject(self, name, object):
+ 'See IWriteContainer'
+ super(TranslationService, self).setObject(name, object)
+ self._registerMessageCatalog(object.getLanguage(), object.getDomain(),
+ name)
+ return name
+
+ def __delitem__(self, name):
+ 'See IWriteContainer'
+ object = self[name]
+ super(TranslationService, self).__delitem__(name)
+ self._unregisterMessageCatalog(object.getLanguage(),
+ object.getDomain(), name)
+
+ def translate(self, domain, msgid, mapping=None, context=None,
+ target_language=None):
+ """See interface ITranslationService"""
+ if domain is None:
+ domain = self.default_domain
+
+ if target_language is None:
+ if context is None:
+ raise TypeError, 'No destination language'
+ else:
+ avail_langs = self.getAvailableLanguages(domain)
+ # Let's negotiate the language to translate to. :)
+ negotiator = getService(self, 'LanguageNegotiation')
+ target_language = negotiator.getLanguage(avail_langs, context)
+
+ # Get the translation. Default is the source text itself.
+ catalog_names = self._catalogs.get((target_language, domain), [])
+
+ text = msgid
+ for name in catalog_names:
+ catalog = super(TranslationService, self).__getitem__(name)
+ text = catalog.queryMessage(msgid)
+
+ # If the message id equals the returned text, then we should look up
+ # a translation server higher up the tree.
+ if text == msgid:
+ ts = queryNextService(self, 'Translation')
+ if ts is not None:
+ return ts.translate(domain, msgid, mapping, context,
+ target_language)
+ else:
+ return text
+
+ # Now we need to do the interpolation
+ return self.interpolate(text, mapping)
+
+ def getMessageIdsOfDomain(self, domain, filter='%'):
+ 'See IWriteTranslationService'
+ filter = filter.replace('%', '.*')
+ filter_re = re.compile(filter)
+
+ msgids = {}
+ languages = self.getAvailableLanguages(domain)
+ for language in languages:
+ for name in self._catalogs[(language, domain)]:
+ for msgid in self[name].getMessageIds():
+ if filter_re.match(msgid) >= 0:
+ msgids[msgid] = None
+ return msgids.keys()
+
+
+ def getMessagesOfDomain(self, domain):
+ 'See IWriteTranslationService'
+ messages = []
+ languages = self.getAvailableLanguages(domain)
+ for language in languages:
+ for name in self._catalogs[(language, domain)]:
+ messages += self[name].getMessages()
+ return messages
+
+
+ def getMessage(self, msgid, domain, language):
+ 'See IWriteTranslationService'
+ for name in self._catalogs.get((language, domain), []):
+ try:
+ return self[name].getFullMessage(msgid)
+ except:
+ pass
+ return None
+
+ def getAllLanguages(self):
+ 'See IWriteTranslationService'
+ languages = {}
+ for key in self._catalogs.keys():
+ languages[key[0]] = None
+ return languages.keys()
+
+
+ def getAllDomains(self):
+ 'See IWriteTranslationService'
+ domains = {}
+ for key in self._catalogs.keys():
+ domains[key[1]] = None
+ return domains.keys()
+
+
+ def getAvailableLanguages(self, domain):
+ 'See IWriteTranslationService'
+ identifiers = self._catalogs.keys()
+ identifiers = filter(lambda x, d=domain: x[1] == d, identifiers)
+ languages = map(lambda x: x[0], identifiers)
+ return languages
+
+
+ def getAvailableDomains(self, language):
+ 'See IWriteTranslationService'
+ identifiers = self._catalogs.keys()
+ identifiers = filter(lambda x, l=language: x[0] == l, identifiers)
+ domains = map(lambda x: x[1], identifiers)
+ return domains
+
+
+ def addMessage(self, domain, msgid, msg, language, mod_time=None):
+ 'See IWriteTranslationService'
+ if not self._catalogs.has_key((language, domain)):
+ if language not in self.getAllLanguages():
+ self.addLanguage(language)
+ if domain not in self.getAllDomains():
+ self.addDomain(domain)
+
+ catalog_name = self._catalogs[(language, domain)][0]
+ catalog = self[catalog_name]
+ catalog.setMessage(msgid, msg, mod_time)
+
+
+ def updateMessage(self, domain, msgid, msg, language, mod_time=None):
+ 'See IWriteTranslationService'
+ catalog_name = self._catalogs[(language, domain)][0]
+ catalog = self[catalog_name]
+ catalog.setMessage(msgid, msg, mod_time)
+
+
+ def deleteMessage(self, domain, msgid, language):
+ 'See IWriteTranslationService'
+ catalog_name = self._catalogs[(language, domain)][0]
+ catalog = self[catalog_name]
+ catalog.deleteMessage(msgid)
+
+
+ def addLanguage(self, language):
+ 'See IWriteTranslationService'
+ domains = self.getAllDomains()
+ if not domains:
+ domains = [self.default_domain]
+
+ for domain in domains:
+ catalog = createObject(self, 'Message Catalog', language, domain)
+ self.setObject('%s-%s' %(domain, language), catalog)
+
+
+ def addDomain(self, domain):
+ 'See IWriteTranslationService'
+ languages = self.getAllLanguages()
+ if not languages:
+ languages = ['en']
+
+ for language in languages:
+ catalog = createObject(self, 'Message Catalog', language, domain)
+ self.setObject('%s-%s' %(domain, language), catalog)
+
+
+ def deleteLanguage(self, language):
+ 'See IWriteTranslationService'
+ domains = self.getAvailableDomains(language)
+ for domain in domains:
+ # Delete all catalogs from the data storage
+ for name in self._catalogs[(language, domain)]:
+ if self.has_key(name):
+ del self[name]
+ # Now delete the specifc catalog registry for this lang/domain
+ del self._catalogs[(language, domain)]
+
+ def deleteDomain(self, domain):
+ 'See IWriteTranslationService'
+ languages = self.getAvailableLanguages(domain)
+ for language in languages:
+ # Delete all catalogs from the data storage
+ for name in self._catalogs[(language, domain)]:
+ if self.has_key(name):
+ del self[name]
+ # Now delete the specifc catalog registry for this lang/domain
+ del self._catalogs[(language, domain)]
+
+ def getMessagesMapping(self, domains, languages, foreign_messages):
+ 'See ISyncTranslationService'
+ mapping = {}
+ # Get all relevant local messages
+ local_messages = []
+ for domain in domains:
+ for language in languages:
+ for name in self._catalogs.get((language, domain), []):
+ local_messages += self[name].getMessages()
+
+
+ for fmsg in foreign_messages:
+ ident = (fmsg['msgid'], fmsg['domain'], fmsg['language'])
+ mapping[ident] = (fmsg, self.getMessage(*ident))
+
+ for lmsg in local_messages:
+ ident = (lmsg['msgid'], lmsg['domain'], lmsg['language'])
+ if ident not in mapping.keys():
+ mapping[ident] = (None, lmsg)
+
+ return mapping
+
+
+ def synchronize(self, messages_mapping):
+ 'See ISyncTranslationService'
+
+ for value in messages_mapping.values():
+ fmsg = value[0]
+ lmsg = value[1]
+ if fmsg is None:
+ self.deleteMessage(lmsg['domain'], lmsg['msgid'],
+ lmsg['language'])
+ elif lmsg is None:
+ self.addMessage(fmsg['domain'], fmsg['msgid'],
+ fmsg['msgstr'], fmsg['language'],
+ fmsg['mod_time'])
+ elif fmsg['mod_time'] > lmsg['mod_time']:
+ self.updateMessage(fmsg['domain'], fmsg['msgid'],
+ fmsg['msgstr'], fmsg['language'],
+ fmsg['mod_time'])
+
+ #
+ ############################################################