[Zope3-checkins] CVS: Zope3/src/zope/app/browser/services/translation - __init__.py:1.2 basetranslationserviceview.py:1.2 configure.zcml:1.2 exportimport.pt:1.2 exportimport.py:1.2 synchronize.pt:1.2 synchronize.py:1.2 translate.pt:1.2 translate.py:1.2 translatemessage.pt:1.2
Jim Fulton
jim@zope.com
Wed, 25 Dec 2002 09:14:10 -0500
Update of /cvs-repository/Zope3/src/zope/app/browser/services/translation
In directory cvs.zope.org:/tmp/cvs-serv15352/src/zope/app/browser/services/translation
Added Files:
__init__.py basetranslationserviceview.py configure.zcml
exportimport.pt exportimport.py synchronize.pt synchronize.py
translate.pt translate.py translatemessage.pt
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/browser/services/translation/__init__.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/browser/services/translation/__init__.py Wed Dec 25 09:12:38 2002
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
=== Zope3/src/zope/app/browser/services/translation/basetranslationserviceview.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/browser/services/translation/basetranslationserviceview.py Wed Dec 25 09:12:38 2002
@@ -0,0 +1,34 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Synchronize with Foreign Translation Services
+
+$Id$
+"""
+
+from zope.publisher.browser import BrowserView
+from zope.interfaces.i18n import ITranslationService
+
+
+class BaseTranslationServiceView(BrowserView):
+
+ __used_for__ = ITranslationService
+
+
+ def getAllLanguages(self):
+ """Get all available languages from the Translation Service."""
+ return self.context.getAllLanguages()
+
+
+ def getAllDomains(self):
+ return self.context.getAllDomains()
=== Zope3/src/zope/app/browser/services/translation/configure.zcml 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/browser/services/translation/configure.zcml Wed Dec 25 09:12:38 2002
@@ -0,0 +1,71 @@
+<zopeConfigure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser">
+
+<browser:defaultView for="zope.interfaces.i18n.ITranslationService" name="index.html" />
+
+<browser:view
+ permission="zope.ManageServices"
+ for="zope.interfaces.i18n.ITranslationService"
+ factory="zope.app.browser.services.translation.translate.Translate">
+
+ <browser:page name="index.html" attribute="index" />
+ <browser:page name="translateMessage.html" attribute="translateMessage" />
+
+ <browser:page name="editMessages.html" attribute="editMessages" />
+ <browser:page name="editMessage.html" attribute="editMessage" />
+
+ <browser:page name="deleteMessages.html" attribute="deleteMessages" />
+
+ <browser:page name="addLanguage.html" attribute="addLanguage" />
+ <browser:page name="addDomain.html" attribute="addDomain" />
+
+ <browser:page name="changeEditLanguages.html"
+ attribute="changeEditLanguages" />
+ <browser:page name="changeEditDomains.html"
+ attribute="changeEditDomains" />
+ <browser:page name="changeFilter.html"
+ attribute="changeFilter" />
+
+ <browser:page name="deleteLanguages.html" attribute="deleteLanguages" />
+ <browser:page name="deleteDomains.html" attribute="deleteDomains" />
+
+</browser:view>
+
+<browser:view
+ permission="zope.ManageServices"
+ for="zope.interfaces.i18n.ITranslationService"
+ factory="zope.app.browser.services.translation.exportimport.ExportImport">
+
+ <browser:page name="exportImportForm.html" attribute="exportImportForm" />
+
+ <browser:page name="export.html" attribute="exportMessages" />
+ <browser:page name="import.html" attribute="importMessages" />
+
+</browser:view>
+
+<browser:view
+ permission="zope.ManageServices"
+ for="zope.interfaces.i18n.ITranslationService"
+ factory="zope.app.browser.services.translation.synchronize.Synchronize">
+
+ <browser:page name="synchronizeForm.html" attribute="synchronizeForm" />
+ <browser:page name="synchronize.html" attribute="synchronize" />
+ <browser:page name="synchronizeMessages.html"
+ attribute="synchronizeMessages" />
+ <browser:page name="saveSettings.html" attribute="saveSettings" />
+
+</browser:view>
+
+
+<browser:menuItems menu="zmi_views" for="zope.interfaces.i18n.ITranslationService">
+ <browser:menuItem title="Translate" action="@@index.html"/>
+ <browser:menuItem title="Import/Export" action="@@exportImportForm.html"/>
+ <browser:menuItem title="Synchronize" action="@@synchronizeForm.html"/>
+</browser:menuItems>
+
+<browser:menuItem menu="add_component" for="zope.app.interfaces.container.IAdding"
+ action="TranslationService" title="Translation Service"
+ description="A Persistent Translation Service for TTW development" />
+
+</zopeConfigure>
=== Zope3/src/zope/app/browser/services/translation/exportimport.pt 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/browser/services/translation/exportimport.pt Wed Dec 25 09:12:38 2002
@@ -0,0 +1,56 @@
+<html metal:use-macro="views/standard_macros/page">
+<head>
+ <title>Translation Service - Translate</title>
+</head>
+<body>
+
+<div metal:fill-slot="body">
+
+<h3>Import and Export Messages</h3>
+
+<p>Here you can export and import messages from your Translation Service.</p>
+
+<form action="./" method="post" enctype="multipart/form-data"
+ i18n:domain="Zope-I18n">
+ <table cols="4" width="100%" border="0">
+ <tr>
+ <td width="25%">
+ <div class="form-label" i18n:translate="">Select Languages:</div>
+ <div>
+ <select name="languages:list" size="3" style="width: 80%" multiple>
+ <option value=""
+ tal:attributes="value language"
+ tal:content="language"
+ tal:repeat="language view/getAllLanguages"></option>
+ </select>
+ </div>
+ </td>
+ <td width="25%">
+ <div class="form-label" i18n:translate="">Select Domains:</div>
+ <div>
+ <select name="domains:list" size="3" style="width: 80%" multiple>
+ <option value=""
+ tal:attributes="value domain"
+ tal:content="domain"
+ tal:repeat="domain view/getAllDomains"></option>
+ </select>
+ </div>
+ </td>
+ <td width="25%" valign="top">
+ <div class="form-label" i18n:translate="">Import File Name:</div>
+ <div>
+ <input type="file" name="file" size="20" value="">
+ </div>
+ <div>
+ <input type="submit" name="@@import.html:method" value="Import">
+ <input type="submit" name="@@export.html:method" value="Export">
+ </div>
+ </td>
+ </tr>
+ </table>
+</form>
+
+</div>
+
+</body>
+</html>
=== Zope3/src/zope/app/browser/services/translation/exportimport.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/browser/services/translation/exportimport.py Wed Dec 25 09:12:38 2002
@@ -0,0 +1,39 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Message Export/Import View
+
+$Id$
+"""
+from zope.component import getAdapter
+from zope.interfaces.i18n import IMessageExportFilter, IMessageImportFilter
+
+from zope.app.browser.services.translation.basetranslationserviceview \
+ import BaseTranslationServiceView
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+
+
+class ExportImport(BaseTranslationServiceView):
+
+ exportImportForm = ViewPageTemplateFile('exportimport.pt')
+
+ def exportMessages(self, domains, languages):
+ self.request.response.setHeader('content-type',
+ 'application/x-gettext')
+ filter = getAdapter(self.context, IMessageExportFilter)
+ return filter.exportMessages(domains, languages)
+
+ def importMessages(self, domains, languages, file):
+ filter = getAdapter(self.context, IMessageImportFilter)
+ filter.importMessages(domains, languages, file)
+ return self.request.response.redirect(self.request.URL[-1])
=== Zope3/src/zope/app/browser/services/translation/synchronize.pt 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/browser/services/translation/synchronize.pt Wed Dec 25 09:12:38 2002
@@ -0,0 +1,144 @@
+<html metal:use-macro="views/standard_macros/page">
+ <head>
+ <title>Translation Service - Synchronize</title>
+ </head>
+<body>
+
+<div metal:fill-slot="body">
+
+<style type="text/css">
+ <!--
+ .state0 {color: green;}
+ .state1 {color: yellow;}
+ .state2 {color: yellow;}
+ .state3 {color: red;}
+ .state4 {color: red;}
+ -->
+</style>
+
+ <table cols="4" width="100%" border="0" cellspacing="0">
+ <form action="./" method="post">
+ <tr>
+ <td width="30%">
+ <div class="form-label">Server URL</div>
+ <div>
+ <input type="text" size="40" name="sync_url" value=""
+ tal:attributes="value view/sync_url" />
+ </div>
+ <div>Username</div>
+ <div>
+ <input type="text" size="40" name="sync_username" value=""
+ tal:attributes="value view/sync_username" />
+ </div>
+ <div>Password</div>
+ <div>
+ <input type="password" size="40" name="sync_password" value=""
+ tal:attributes="value view/sync_password" />
+ </div>
+ </td>
+ <td width="25%">
+ <div>Select Domains:</div>
+ <div>
+ <select name="sync_domains:list" size="6" style="width: 80%"
+ multiple>
+ <tal:block repeat="domain view/getAllDomains">
+ <option value=""
+ tal:attributes="value domain"
+ tal:content="domain"
+ tal:condition="python: domain not in
+ view.sync_domains" ></option>
+ <option value="" selected="1"
+ tal:attributes="value domain"
+ tal:content="domain"
+ tal:condition="python: domain in
+ view.sync_domains" ></option>
+ </tal:block>
+ </select>
+ </div>
+ </td>
+ <td width="25%">
+ <div>Select Languages:</div>
+ <div>
+ <select name="sync_languages:list" size="6" style="width: 80%"
+ multiple>
+ <tal:block repeat="language view/getAllLanguages">
+ <option value=""
+ tal:attributes="value language"
+ tal:content="language"
+ tal:condition="python: language not in
+ view.sync_languages" ></option>
+ <option value="" selected="1"
+ tal:attributes="value language"
+ tal:content="language"
+ tal:condition="python: language in
+ view.sync_languages" ></option>
+ </tal:block>
+ </select>
+ </div>
+ </td>
+ <td width="20%">
+ <center>
+ <div><input type="submit" name="saveSettings.html:method"
+ value="Save Settings"></div><br>
+ <div><input type="submit" name="synchronize.html:method"
+ value="Synchronize"></div>
+ </center>
+ </td>
+ </tr>
+ </form>
+ </table>
+ <br>
+
+<form action="./"
+ tal:condition="view/canConnect">
+ <table cols="5" width="95%" border="0" cellpadding="2" cellspacing="0"
+ class="listing">
+ <tr>
+ <th width="16"> </th>
+ <th width="55%">Message Id</th>
+ <th width="15%">Domain</th>
+ <th width="10%">Language</th>
+ <th width="15%">Status</th>
+ </tr>
+ <tal:block repeat="message python: view.queryMessages().items()">
+ <tr tal:define="number repeat/message/number;
+ oddrow repeat/message/odd"
+ tal:attributes="class python: oddrow and 'odd' or 'even'">
+ <td width="16">
+ <input type="hidden"
+ tal:attributes="name python: 'update-msgid-%i' %number;
+ value python: message[0][0]">
+ <input type="hidden"
+ tal:attributes="name python: 'update-domain-%i' %number;
+ value python: message[0][1]">
+ <input type="hidden"
+ tal:attributes="name python: 'update-language-%i' %number;
+ value python: message[0][2]">
+ <input type="checkbox" name="message_ids:list"
+ tal:attributes="value python: number">
+ </td>
+ <td tal:content="python: message[0][0]">Hello World!</td>
+ <td tal:content="python: message[0][1]">default</td>
+ <td tal:content="python: message[0][2]">en</td>
+ <td>
+ <b tal:content="python: view.getStatus(*message[1])"
+ tal:attributes="class python:'state%i' %
+ view.getStatus(message[1][0], message[1][1], 0)"
+ >status</b>
+ </td>
+ </tr>
+ </tal:block>
+ </table>
+ <div><input type="submit" name="@@synchronizeMessages.html:method"
+ value="Update"></div>
+
+</form>
+
+<p tal:condition="python: not view.canConnect()">
+No connection could be made to remote data source.
+</p>
+
+</div>
+
+</body>
+</html>
\ No newline at end of file
=== Zope3/src/zope/app/browser/services/translation/synchronize.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/browser/services/translation/synchronize.py Wed Dec 25 09:12:38 2002
@@ -0,0 +1,241 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Synchronize with Foreign Translation Services
+
+$Id$
+"""
+import httplib
+import urllib
+import xmlrpclib
+
+from base64 import encodestring
+
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+from zope.app.browser.services.translation.basetranslationserviceview \
+ import BaseTranslationServiceView
+
+
+class Synchronize(BaseTranslationServiceView):
+
+ synchronizeForm = ViewPageTemplateFile('synchronize.pt')
+
+ 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',
+ 'http://localhost:8081/++etc++Services/ts/')
+ 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_domains = filter(None, self.request.cookies.get(
+ 'sync_domains', '').split(','))
+ 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.getAllDomains()
+ 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.getAllDomains():
+ 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 getAllDomains(self):
+ connected = self._isConnected()
+ if not connected: connected = self._connect()
+
+ if connected:
+
+ return self._connection.getAllDomains()
+ else:
+ return []
+
+
+ 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_domains,
+ self.sync_languages)
+ else:
+ fmdgs = []
+
+ return self.context.getMessagesMapping(self.sync_domains,
+ self.sync_languages,
+ fmsgs)
+
+
+ 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_domains = self.request.form.get('sync_domains', [])
+ self.sync_languages = self.request.form.get('sync_languages', [])
+ self.request.response.setCookie('sync_domains',
+ ','.join(self.sync_domains))
+ 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]
+ domain = self.request.form['update-domain-'+id]
+ language = self.request.form['update-language-'+id]
+ idents.append((msgid, domain, 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())
=== Zope3/src/zope/app/browser/services/translation/translate.pt 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:09 2002
+++ Zope3/src/zope/app/browser/services/translation/translate.pt Wed Dec 25 09:12:38 2002
@@ -0,0 +1,188 @@
+<html metal:use-macro="views/standard_macros/page">
+<head>
+ <title>Translation Service - Translate</title>
+</head>
+<body>
+
+<div metal:fill-slot="body">
+
+<span i18n:domain="Zope-I18n">
+
+<table cols="4" width="100%" border="0">
+ <tr>
+ <td width="25%">
+ <form action="./" method="post">
+ <div class="form-label" i18n:translate="">Select Languages:</div>
+ <div>
+ <select name="languages:list" size="3" style="width: 80%" multiple>
+ <tal:block repeat="language view/getAllLanguages">
+ <option value=""
+ tal:attributes="value language"
+ tal:content="language"
+ tal:condition="python: language not in
+ view.getEditLanguages()" ></option>
+ <option value="" selected="1"
+ tal:attributes="value language"
+ tal:content="language"
+ tal:condition="python: language in
+ view.getEditLanguages()" ></option>
+ </tal:block>
+ </select>
+ </div>
+ <div>
+ <input class="form-element" type="submit"
+ name="@@changeEditLanguages.html:method" value="Edit"
+ i18n:attributes="value">
+ <input class="form-element" type="submit"
+ name="@@deleteLanguages.html:method" value="Delete"
+ i18n:attributes="value">
+ </div>
+ </form>
+ </td>
+ <td width="25%">
+ <form action="./" method="post">
+ <div class="form-label" i18n:translate="">Select Domains:</div>
+ <div>
+ <select name="domains:list" size="3" style="width: 80%" multiple>
+ <tal:block repeat="domain view/getAllDomains">
+ <option value=""
+ tal:attributes="value domain"
+ tal:content="domain"
+ tal:condition="python: domain not in
+ view.getEditDomains()" ></option>
+ <option value="" selected="1"
+ tal:attributes="value domain"
+ tal:content="domain"
+ tal:condition="python: domain in
+ view.getEditDomains()" ></option>
+ </tal:block>
+ </select>
+ </div>
+ <div>
+ <input class="form-element" type="submit"
+ name="@@changeEditDomains.html:method" value="Edit"
+ i18n:attributes="value">
+ <input class="form-element" type="submit"
+ name="@@deleteDomains.html:method" value="Delete"
+ i18n:attributes="value">
+ </div>
+ </form>
+ </td>
+ <td width="25%" align="right" valign="top">
+ <form action="." method="post">
+ <div class="form-label" i18n:translate="">New Language:</div>
+ <div>
+ <input type="text" name="language" size="20" value="">
+ <input type="submit" name="@@addLanguage.html:method" value="Add">
+ </div>
+ <div class="form-label" i18n:translate="">New Domain:</div>
+ <div>
+ <input type="text" name="domain" size="20" value="">
+ <input type="submit" name="@@addDomain.html:method" value="Add">
+ </div>
+ </form>
+ </td>
+ <td width="25%" align="right" valign="top">
+ <form action="./" method="post">
+ <div class="form-label"
+ i18n:translate="">Filter (% - wildcard):</div>
+ <div>
+ <input type="text" name="filter" size="25" value=""
+ tal:attributes="value request/filter|default" />
+ </div>
+ <div>
+ <input type="submit" name="@@changeFilter.html:method"
+ value="Filter"
+ i18n:attributes="value"/>
+ </div>
+ </form>
+ </td>
+ </tr>
+ </table>
+
+ <form action="./" method="post">
+ <table width="100%" cellspacing="0" cellpadding="3" border="0"
+ class="listing">
+ <tr class="list-header" align="left">
+ <th width="16"> </th>
+ <th i18n:translate="">Message Id</th>
+ <th i18n:translate="">Domain</th>
+ <th tal:repeat="language python:view.getEditLanguages()"
+ tal:content="language">de</th>
+ </tr>
+ <tal:block repeat="message python: view.getMessages()">
+ <tr tal:define="oddrow repeat/message/odd"
+ tal:attributes="class python: oddrow and 'odd' or 'even'">
+ <td>
+ <input type="hidden"
+ tal:attributes="name python: 'edit-msg_id-%i' %message[2];
+ value python: message[0]">
+ <input type="hidden"
+ tal:attributes="name python: 'edit-domain-%i' %message[2];
+ value python: message[1]">
+ <input type="checkbox" name="message_ids:list"
+ tal:attributes="value python: message[2]">
+ </td>
+ <td>
+ <a href=""
+ tal:content="python: message[0]"
+ tal:attributes="
+ href python:'translateMessage.html?msgid=%s&domain=%s' %(
+ message[0], message[1])">message_id</a>
+ </td>
+ <td tal:content="python: message[1]">
+ default
+ </td>
+ <td tal:repeat="language python:view.getEditLanguages()">
+ <textarea cols="20" rows="2"
+ tal:attributes="name python: 'edit-%s-%i' %(language, message[2])"
+ tal:content="python: view.getTranslation(message[1],
+ message[0], language)"></textarea>
+ </td>
+ </tr>
+ </tal:block>
+ <tr><th colspan="3"
+ tal:attributes="colspan python:len(view.getEditLanguages())+3">
+ Add new messages
+ </th></tr>
+
+ <tal:block repeat="count python: range(5)">
+ <tr tal:define="oddrow repeat/count/odd"
+ tal:attributes="class python: oddrow and 'odd' or 'even'">
+ <td width="16"> </td>
+ <td>
+ <textarea cols="20" rows="2" name=""
+ tal:attributes="name string:new-msg_id-${count}"></textarea>
+ </td>
+ <td>
+ <select name=""
+ tal:attributes="name string:new-domain-${count}">
+ <option value=""
+ tal:repeat="domain python: view.getEditDomains()"
+ tal:content="domain"
+ tal:attributes="value domain">default</option>
+ </select>
+ </td>
+ <td tal:repeat="language python:view.getEditLanguages()">
+ <textarea cols="20" rows="2" name=""
+ tal:attributes="name string:new-${language}-${count}"></textarea>
+ </td>
+ </tr>
+ </tal:block>
+ </table>
+
+ <div>
+ <input class="form-element" type="submit"
+ name="@@editMessages.html:method" value="Edit Messages"
+ i18n:attributes="value">
+ <input class="form-element" type="submit"
+ name="@@deleteMessages.html:method" value="Delete Messages"
+ i18n:attributes="value">
+ </div>
+ </form>
+
+</span>
+</div>
+
+</body>
+</html>
=== Zope3/src/zope/app/browser/services/translation/translate.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:10 2002
+++ Zope3/src/zope/app/browser/services/translation/translate.py Wed Dec 25 09:12:38 2002
@@ -0,0 +1,144 @@
+##############################################################################
+#
+# 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 GUI
+
+$Id$
+"""
+from zope.app.browser.services.translation.basetranslationserviceview \
+ import BaseTranslationServiceView
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+
+
+class Translate(BaseTranslationServiceView):
+
+ index = ViewPageTemplateFile('translate.pt')
+ translateMessage = ViewPageTemplateFile('translatemessage.pt')
+
+ def getMessages(self):
+ """Get messages based on the domain selection"""
+ filter = self.request.get('filter', '%')
+ domains = self.getEditDomains()
+ messages = []
+ for domain in domains:
+ for msg_id in self.context.getMessageIdsOfDomain(domain, filter):
+ messages.append((msg_id, domain, len(messages)))
+
+ return messages
+
+
+ def getTranslation(self, domain, msgid, target_lang):
+ return self.context.translate(domain, 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 getEditDomains(self):
+ '''get the languages that are selected for editing'''
+ domains = self.request.cookies.get('edit_domains', '')
+ return filter(None, domains.split(','))
+
+
+ def editMessage(self):
+ domain = self.request['msg_domain']
+ msg_id = self.request['msg_id']
+ for language in self.getEditLanguages():
+ msg = self.request['msg_lang_%s' %language]
+ if msg != self.context.translate(domain, msg_id,
+ target_language=language):
+ self.context.updateMessage(domain, 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:
+ domain = self.request.get('new-domain-%i' %count, 'default')
+ for language in self.getEditLanguages():
+ msg = self.request.get('new-%s-%i' %(language, count),
+ msg_id)
+ self.context.addMessage(domain, 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]
+ domain = self.request['edit-domain-'+key]
+ for language in self.getEditLanguages():
+ msg = self.request['edit-%s-%s' %(language, key)]
+ if msg != self.context.translate(domain, msg_id,
+ target_language=language):
+ self.context.updateMessage(domain, msg_id, msg, language)
+
+ return self.request.response.redirect(self.request.URL[-1])
+
+
+ def deleteMessages(self, message_ids):
+ for id in message_ids:
+ domain = self.request.form['edit-domain-%s' %id]
+ msgid = self.request.form['edit-msg_id-%s' %id]
+ for language in self.context.getAvailableLanguages(domain):
+ # Some we edit a language, but no translation exists...
+ try:
+ self.context.deleteMessage(domain, 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 addDomain(self, domain):
+ self.context.addDomain(domain)
+ 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 changeEditDomains(self, domains=[]):
+ self.request.response.setCookie('edit_domains', ','.join(domains))
+ 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])
+
+
+ def deleteDomains(self, domains):
+ for domain in domains:
+ self.context.deleteDomain(domain)
+ return self.request.response.redirect(self.request.URL[-1])
=== Zope3/src/zope/app/browser/services/translation/translatemessage.pt 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:14:10 2002
+++ Zope3/src/zope/app/browser/services/translation/translatemessage.pt Wed Dec 25 09:12:38 2002
@@ -0,0 +1,41 @@
+<html metal:use-macro="views/standard_macros/page">
+<head>
+ <title>Translation Service - Translate</title>
+</head>
+<body>
+
+<div metal:fill-slot="body">
+
+<span i18n:domain="Zope-I18n">
+
+<form action="./" method="post">
+<input type="hidden" name="msg_domain" value=""
+ tal:attributes="value request/domain" />
+<input type="hidden" name="msg_id" value=""
+ tal:attributes="value request/msgid" />
+<table>
+ <tr>
+ <th i18n:translate="">Message Id</th>
+ <td tal:content="request/msgid">Message Id of the message.</td>
+ </tr>
+ <tr tal:repeat="language view/getEditLanguages">
+ <th tal:content="language">Language</th>
+ <td>
+ <textarea cols="80" rows="10" name=""
+ tal:attributes="name string:msg_lang_${language}"
+ tal:content="python: view.getTranslation(request['domain'],
+ request['msgid'], language)"
+ >Translation of Message</textarea>
+ </td>
+ </tr>
+</table>
+<input class="form-element" type="submit"
+ name="@@editMessage.html:method" value="Edit Message"
+ i18n:attributes="value">
+</form>
+
+</span>
+</div>
+
+</body>
+</html>