This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
glasnost/servers/TranslationsServer/TranslationsServer.py

818 lines
36 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
# Romain Chantereau <rchantereau@entrouvert.com>
# Nicolas Clapiès <nclapies@easter-eggs.org>
# Pierre-Antoine Dejace <padejace@entrouvert.be>
# Thierry Dulieu <tdulieu@easter-eggs.com>
# Florent Monnier <monnier@codelutin.com>
# Cédric Musso <cmusso@easter-eggs.org>
# Frédéric Péters <fpeters@entrouvert.be>
# Benjamin Poussin <poussin@codelutin.com>
# Emmanuel Raviart <eraviart@entrouvert.com>
# Sébastien Régnier <regnier@codelutin.com>
# Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
# Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
# Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
__doc__ = """Glasnost Translations Server"""
__version__ = '$Revision$'[11:-2]
import difflib
import md5
import sys
import time
glasnostPythonDir = '/usr/local/lib/glasnost-devel' # changed on make install
sys.path.insert(0, glasnostPythonDir)
import glasnost
import glasnost.common.faults as faults
from glasnost.common.TranslationsCommon import *
import glasnost.common.xhtmlgenerator as X
from glasnost.server.ObjectsServer import register, AdministrableServerMixin, \
AdminServerWithoutWritersMixin, ObjectServerMixin, Server, \
AdministrableVirtualServer
from glasnost.server.tools import *
from glasnost.proxy.CacheProxy import invalidateKeyStart
from glasnost.proxy.tools import getProxy
applicationName = 'TranslationsServer'
applicationRole = 'translations'
dispatcher = None
class AdminTranslations(AdminServerWithoutWritersMixin,
AdminTranslationsCommon):
def __init__(self):
AdminTranslationsCommon.__init__(self)
self.translatorsSets = {}
def modify(self, changes, givenSlotNames = None):
AdminServerWithoutWritersMixin.modify(
self, changes, givenSlotNames = givenSlotNames)
if self.translatorsSets is None:
self.translatorsSets = {}
register(AdminTranslations)
class Localization(LocalizationCommon):
pass
register(Localization)
class Translation(ObjectServerMixin, ObjectCommon):
creationTimes = None
creationTimes_kind_keyKind_valueName = 'String'
creationTimes_kind_valueKind_valueName = 'Time'
creationTimes_kindName = 'Mapping'
destinationStrings = None
destinationStrings_kind_keyKind_valueName = 'String'
destinationStrings_kind_valueKind_valueName = 'String'
destinationStrings_kindName = 'Mapping'
fuzzyLocalizations = None
fuzzyLocalizations_kind_itemKind_valueName = 'String'
fuzzyLocalizations_kindName = 'Sequence'
previousVersionSigns = None
previousVersionSigns_kind_keyKind_valueName = 'Source'
previousVersionSigns_kind_valueKind_valueName = 'String'
previousVersionSigns_kindName = 'Mapping'
sourceLanguage = None
sourceLanguage_kindName = 'Choice'
sources = None
sources_kind_itemKind_valueName = 'Source'
sources_kindName = 'Sequence'
sourceString = None
sourceString_kindName = 'String'
sourceStringDigest = None
sourceStringDigest_kindName = 'String'
translatorIds = None
translatorIds_kind_keyKind_valueName = 'String'
translatorIds_kind_valueKind_valueName = 'Id'
translatorIds_kindName = 'Mapping'
untranslatableLocalizations = None
untranslatableLocalizations_kind_itemKind_valueName = 'String'
untranslatableLocalizations_kindName = 'Sequence'
def addTranslator(self, destinationLanguage, userId):
if not self.translatorIds:
self.translatorIds = {}
if self.translatorIds.has_key(destinationLanguage):
if userId in self.translatorIds[destinationLanguage]:
pass
else:
self.translatorIds[destinationLanguage].append(userId)
else:
self.translatorIds[destinationLanguage] = [userId]
def checkLocalizationState(self, destinationLanguage, possibleStates):
if not possibleStates:
return 1
if not self.sources:
state = 'obsolete'
elif destinationLanguage == self.sourceLanguage:
state = 'original'
elif self.untranslatableLocalizations is not None \
and destinationLanguage in self.untranslatableLocalizations:
state = 'untranslatable'
elif not self.hasDestinationString(destinationLanguage):
state = 'untranslated'
elif self.fuzzyLocalizations is not None \
and destinationLanguage in self.fuzzyLocalizations:
state = 'fuzzy'
else:
state = 'translated'
return state in possibleStates
def getDestinationString(self, destinationLanguage):
if destinationLanguage == self.sourceLanguage:
return self.sourceString
elif self.destinationStrings is not None \
and self.destinationStrings.has_key(destinationLanguage):
return self.destinationStrings[destinationLanguage]
else:
return None
def getTranslatorsSet(self, destinationLanguage):
if not self.translatorIds or \
not self.translatorIds.has_key(destinationLanguage):
return []
return self.translatorIds[destinationLanguage]
def getLabel(self):
label = self.getTitle()
if label is None:
return ''
return label
def getTitle(self):
title = self.sourceString
if len(title) > 80:
title = title[:60] + '...'
return title
def hasDestinationString(self, destinationLanguage):
return destinationLanguage == self.sourceLanguage \
or self.destinationStrings is not None \
and self.destinationStrings.has_key(destinationLanguage)
def isPreviousTranslation(self, translation, visitedTranslations):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getServer().getVirtualServer(virtualServerId)
if self.previousVersionSigns is None:
return 0
for previousVersionSign in self.previousVersionSigns.values():
if not virtualServer.translations.has_key(previousVersionSign):
continue
previousTranslation = virtualServer.translations[
previousVersionSign]
if previousTranslation in visitedTranslations:
return 0
if previousTranslation == translation:
return 1
visitedTranslations.append(previousTranslation)
if previousTranslation.isPreviousTranslation(
translation, visitedTranslations):
return 1
return 0
def setDestinationString(self, destinationLanguage, isTranslatable,
destinationString, isFuzzy):
if isTranslatable:
if self.untranslatableLocalizations is not None and \
destinationLanguage in self.untranslatableLocalizations:
self.untranslatableLocalizations.remove(destinationLanguage)
if not self.untranslatableLocalizations:
del self.untranslatableLocalizations
else:
if self.untranslatableLocalizations is None:
self.untranslatableLocalizations = []
if not destinationLanguage in self.untranslatableLocalizations:
self.untranslatableLocalizations.append(destinationLanguage)
destinationString = None
isFuzzy = 0
if not destinationString:
if self.destinationStrings is not None and \
self.destinationStrings.has_key(destinationLanguage):
del self.destinationStrings[destinationLanguage]
if not self.destinationStrings:
del self.destinationStrings
if self.fuzzyLocalizations is not None and \
destinationLanguage in self.fuzzyLocalizations:
self.fuzzyLocalizations.remove(destinationLanguage)
if not self.fuzzyLocalizations:
del self.fuzzyLocalizations
else:
if self.destinationStrings is None:
self.destinationStrings = {}
if self.creationTimes is None:
self.creationTimes = {}
self.destinationStrings[destinationLanguage] = destinationString
self.creationTimes[destinationLanguage] = time.time()
if isFuzzy:
if self.fuzzyLocalizations is None:
self.fuzzyLocalizations = []
if not destinationLanguage in self.fuzzyLocalizations:
self.fuzzyLocalizations.append(destinationLanguage)
elif self.fuzzyLocalizations is not None and \
destinationLanguage in self.fuzzyLocalizations:
self.fuzzyLocalizations.remove(destinationLanguage)
if not self.fuzzyLocalizations:
del self.fuzzyLocalizations
register(Translation)
class TranslationsVirtualServer(AdministrableVirtualServer):
translations = None
translationsBySource = None
def convertIds(self, sourceDispatcherId, destinationDispatcherId):
AdministrableVirtualServer.convertIds(
self, sourceDispatcherId, destinationDispatcherId)
for sign, translation in self.translations.items():
translation.convertIds(sourceDispatcherId, destinationDispatcherId)
for source, translation in self.translationsBySource.items():
newSource = source.replace(
sourceDispatcherId, destinationDispatcherId)
if newSource != source:
del self.translationsBySource[source]
self.translationsBySource[newSource] = translation
def init(self):
AdministrableVirtualServer.init(self)
self.translations = {}
self.translationsBySource = {}
def initFromOldData(self, data):
AdministrableVirtualServer.initFromOldData(self, data)
(self.translations,
self.translationsBySource,
self.admin,
) = data
def removeIds(self, rolesToKeep):
import glasnost.common.tools_new as commonTools
AdministrableVirtualServer.removeIds(self, rolesToKeep)
for sign, translation in self.translations.items():
translation.removeIds(rolesToKeep)
for source, translation in self.translationsBySource.items():
if not commonTools.extractRole(source) in rolesToKeep:
del self.translationsBySource[source]
class TranslationsServer(TranslationsCommonMixin, AdministrableServerMixin,
Server):
VirtualServer = TranslationsVirtualServer
def canDeleteLocalization(self, localizationKey, sourceStringDigest):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
if virtualServer.admin.translatorsSets.has_key(localizationKey):
translatorsSet = virtualServer.admin.translatorsSets[
localizationKey]
else:
translatorsSet = None
result = self.isAdmin() \
or getProxyForServerRole('authentication').setContainsUser(
translatorsSet)
return result
def canModifyLocalization(self, localizationKey, sourceStringDigest):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
if not virtualServer.admin.translatorsSets.has_key(localizationKey):
return 0
translatorsSet = virtualServer.admin.translatorsSets[localizationKey]
authenticationProxy = getProxyForServerRole('authentication')
return self.isAdmin() or \
authenticationProxy.setContainsUser(translatorsSet)
def getLanguagesForObjectId(self, objectId):
#languages = self.getPossibleLanguages()
languages = translation.languageKeys
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
t = objectId + ' '
translations = [
virtualServer.translationsBySource[k]
for k in virtualServer.translationsBySource.keys()
if k.startswith(t)]
l = len(translations)
result = []
for lang in languages:
if len( [x for x in translations \
if x.sourceLanguage == lang] ) == l:
result.append(lang)
continue
if len([x for x in translations
if (x.destinationStrings and
x.destinationStrings.has_key(lang)) or (
lang in (x.untranslatableLocalizations or []))]) == l:
result.append(lang)
continue
return result
def getLastDigestsAndLabelsXmlRpc(
self, localizationKey, digestsAndLabelsCount, possibleStates):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
if virtualServer.admin.translatorsSets.has_key(localizationKey):
translatorsSet = virtualServer.admin.translatorsSets[
localizationKey]
else:
translatorsSet = None
if not self.isAdmin() \
and not getProxyForServerRole('authentication'
).setContainsUser(translatorsSet):
raise faults.UserAccessDenied()
digestsAndLabels = []
for sign, translation in virtualServer.translations.items():
if not sign.startswith(localizationKey[:2]):
continue
if not translation.checkLocalizationState(
localizationKey[2:], possibleStates):
continue
digestsAndLabels.append(
[translation.sourceStringDigest,
utf8(translation.getLabel()),
len(translation.sourceString.split())])
if len(digestsAndLabels) >= digestsAndLabelsCount:
break
return digestsAndLabels
def getLocalizationXmlRpc(self, localizationKey, sourceStringDigest):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
sign = localizationKey[:2] + sourceStringDigest
if not virtualServer.translations.has_key(sign):
raise faults.MissingItem(sign)
translation = virtualServer.translations[sign]
if virtualServer.admin.translatorsSets.has_key(localizationKey):
translatorsSet = virtualServer.admin.translatorsSets[
localizationKey]
else:
translatorsSet = None
if not self.isAdmin() \
and not getProxyForServerRole('authentication'
).setContainsUser(translatorsSet):
raise faults.UserAccessDenied()
destinationLanguage = localizationKey[2:]
localization = Localization()
localization.version = translation.version
localization.destinationLanguage = destinationLanguage
if translation.sources:
sourceIds = [ source.split(' ', 1)[0]
for source in translation.sources]
localization.sourceIds = []
for sourceId in sourceIds:
if not sourceId in localization.sourceIds:
localization.sourceIds.append(sourceId)
localization.sourceLanguage = translation.sourceLanguage
localization.sourceString = translation.sourceString
localization.sourceStringDigest = translation.sourceStringDigest
localization.isTranslatable = (
translation.untranslatableLocalizations is None
or not destinationLanguage in \
translation.untranslatableLocalizations)
# not translatable
if not localization.isTranslatable:
return localization.exportToXmlRpc()
# already translated
if translation.hasDestinationString(destinationLanguage):
localization.translatorsSet = \
translation.getTranslatorsSet(destinationLanguage)
localization.destinationString = \
translation.getDestinationString(destinationLanguage)
localization.isFuzzy = (
translation.fuzzyLocalizations is not None
and destinationLanguage in translation.fuzzyLocalizations)
print ' returning good translation'
return localization.exportToXmlRpc()
# not translated
if translation.sources:
possibleTranslations = []
for source in translation.sources:
for trans in virtualServer.translations.values():
if source in trans.sources:
possibleTranslations.append(trans)
if not trans.previousVersionSigns:
continue
for src, sign in trans.previousVersionSigns.items():
if not source == src:
continue
possibleTranslations.append(
virtualServer.translations[sign])
print [x.__dict__ for x in possibleTranslations]
oldResults = []
for trans in possibleTranslations:
if not trans.getDestinationString(destinationLanguage):
print trans.getDestinationString(destinationLanguage)
continue
if not trans.creationTimes or \
not trans.creationTimes.has_key(destinationLanguage):
oldResults.append( (0, trans) )
else:
oldResults.append(
(trans.creationTimes[destinationLanguage],
trans) )
oldResults.sort()
if oldResults:
# it once was translated; we return the last known translation
# for the same sourcePath
translation = oldResults[-1][1]
localization.isFuzzy = 1
localization.similarString = translation.sourceString
localization.destinationString = \
translation.destinationStrings[destinationLanguage]
print ' returning possibly previous translation'
return localization.exportToXmlRpc()
# we try to return a translation matching what's asked
sequenceMatcher = difflib.SequenceMatcher(None)
sequenceMatcher.set_seq1(localization.sourceString)
bestRatio = 0.8
for similarSign, similarTranslation in \
virtualServer.translations.items():
if not similarSign.startswith(localizationKey[:2]):
continue
if similarTranslation == translation:
continue
if similarTranslation.destinationStrings is None or \
not similarTranslation.destinationStrings.has_key(
destinationLanguage):
continue
if similarTranslation.fuzzyLocalizations is not None \
and destinationLanguage in \
similarTranslation.fuzzyLocalizations:
continue
sequenceMatcher.set_seq2(similarTranslation.sourceString)
ratio = sequenceMatcher.quick_ratio()
if ratio <= bestRatio:
continue
if not translation.isPreviousTranslation(
similarTranslation, []):
for source in similarTranslation.sources:
id, path = source.split(' ', 1)
try:
getProxy(id).getObjectStringFromDigest(
id, path,
similarTranslation.sourceStringDigest)
except faults.Fault, fault:
pass
else:
# The translator has read access to the similar
# string in the current source.
break
else:
# The translator has no read access to the similar
# string.
continue
bestRatio = ratio
localization.similarString = \
similarTranslation.sourceString
localization.destinationString = \
similarTranslation.destinationStrings[
destinationLanguage]
localization.isFuzzy = 1
print ' returning really fuzzy translation'
return localization.exportToXmlRpc()
def getPossibleLanguages(self):
translatorsSets = self.getAdminCore().translatorsSets
if not translatorsSets:
return []
languages = {}
for k in translatorsSets.keys():
languages[k[:2]] = None
languages[k[2:]] = None
return languages.keys()
def getTranslationInfos(
self, sourceStringDigest, sourceId, sourcePath, sourceLanguage,
destinationLanguages, ignoreNew = 0):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
if splitId(sourceId)[1] == 'virtualhosts':
try:
virtualHost = getProxy(sourceId).getObject(sourceId)
except faults.UnknownDispatcherInId:
return ('', '', 'ignored')
fakeSourceId = virtualHost.defaultDispatcherId + '/foo/bar'
virtualServerId = self.computeVirtualServerId(fakeSourceId)
try:
virtualServer = self.getVirtualServer(virtualServerId)
except KeyError:
# The virtual host is not running or doesn't exist anymore.
return ('', '', 'ignored')
source = sourceId + ' ' + sourcePath
sign = sourceLanguage + sourceStringDigest
if virtualServer.translations.has_key(sign):
translation = virtualServer.translations[sign]
if not source in translation.sources and not ignoreNew:
# Check that the string exists on the server before creating
# its translation, to avoid the creation of fake translations
# by any user.
# If getObjectStringFromDigest() raises an exception, it is
# propagated to the caller of getTranslation().
sourceString = getProxy(sourceId).getObjectStringFromDigest(
sourceId, sourcePath, sourceStringDigest)
virtualServer.lock.acquire()
translation.sources.append(source)
if virtualServer.translationsBySource.has_key(source):
previousTranslation = virtualServer.translationsBySource[
source]
previousTranslation.sources.remove(source)
if previousTranslation.sourceLanguage == sourceLanguage:
if translation.previousVersionSigns is None:
translation.previousVersionSigns = {}
translation.previousVersionSigns[source] = \
sourceLanguage \
+ previousTranslation.sourceStringDigest
virtualServer.translationsBySource[source] = translation
virtualServer.lock.release()
virtualServer.markCoreAsDirty()
elif not ignoreNew:
if virtualServerId == 'glasnost://system':
return ('', '', 'ignored') # or use gettext ?
# Check that the string exists on the server before creating its
# translation, to avoid the creation of fake translations by any
# user.
# If getObjectStringFromDigest() raises an exception, it is
# propagated to the caller of getTranslation().
sourceString = getProxy(sourceId).getObjectStringFromDigest(
sourceId, sourcePath, sourceStringDigest)
translation = Translation()
translation.sourceLanguage = sourceLanguage
translation.sourceString = sourceString
translation.sourceStringDigest = sourceStringDigest
translation.sources = [source]
virtualServer.lock.acquire()
virtualServer.translations[sign] = translation
if virtualServer.translationsBySource.has_key(source):
previousTranslation = virtualServer.translationsBySource[
source]
previousTranslation.sources.remove(source)
if previousTranslation.sourceLanguage == sourceLanguage:
translation.previousVersionSigns = {
source: sourceLanguage \
+ previousTranslation.sourceStringDigest,
}
virtualServer.translationsBySource[source] = translation
virtualServer.lock.release()
virtualServer.markCoreAsDirty()
else:
return ('', '', 'ignored')
state = 'invariant'
if destinationLanguages:
# Look for an up to date translation.
destinationLanguage = destinationLanguages[0]
if destinationLanguage == sourceLanguage:
return translation.sourceString, sourceLanguage, 'original'
if translation.untranslatableLocalizations is not None and \
destinationLanguage in translation.untranslatableLocalizations:
return (translation.sourceString,
sourceLanguage,
'untranslatable')
if translation.fuzzyLocalizations is not None and \
destinationLanguage in translation.fuzzyLocalizations:
state = 'fuzzy'
else:
destinationString = translation.getDestinationString(
destinationLanguage)
if destinationString is not None:
return destinationString, destinationLanguage, 'translated'
state = 'untranslated'
# Look for an obsolete translation.
currentTranslation = translation
visitedTranslations = []
while currentTranslation.previousVersionSigns is not None and \
currentTranslation.previousVersionSigns.has_key(source):
previousVersionSign = currentTranslation.previousVersionSigns[
source]
if not virtualServer.translations.has_key(previousVersionSign):
break
visitedTranslations.append(currentTranslation)
currentTranslation = virtualServer.translations[
previousVersionSign]
if currentTranslation in visitedTranslations:
# Vicious circle in the translation history.
break
# We make the assumption that the reader has the right to read
# the previous version of the sourceString.
if currentTranslation.untranslatableLocalizations is not None \
and destinationLanguage in \
currentTranslation.untranslatableLocalizations:
return currentTranslation.sourceString, sourceLanguage, \
'obsolete'
if currentTranslation.fuzzyLocalizations is not None \
and destinationLanguage in \
currentTranslation.fuzzyLocalizations:
continue
destinationString = currentTranslation.getDestinationString(
destinationLanguage)
if destinationString is None:
continue
return destinationString, destinationLanguage, 'obsolete'
# Look for a translation in another language.
for destinationLanguage in destinationLanguages[1:]:
if destinationLanguage == sourceLanguage:
return translation.sourceString, sourceLanguage, state
if translation.untranslatableLocalizations is not None \
and destinationLanguage in \
translation.untranslatableLocalizations:
return translation.sourceString, sourceLanguage, state
if translation.fuzzyLocalizations is not None and \
destinationLanguage in translation.fuzzyLocalizations:
continue
destinationString = translation.getDestinationString(
destinationLanguage)
if destinationString is None:
continue
return destinationString, destinationLanguage, state
return translation.sourceString, sourceLanguage, state
def getTranslationInfosXmlRpc(
self, sourceStringDigest, sourceId, sourcePath, sourceLanguage,
destinationLanguages, ignoreNew):
infos = list(self.getTranslationInfos(
sourceStringDigest, sourceId, sourcePath, sourceLanguage,
destinationLanguages, ignoreNew))
infos[0] = utf8(infos[0])
return infos
def getTranslationXmlRpc(
self, sourceStringDigest, sourceId, sourcePath, sourceLanguage,
destinationLanguages):
result = utf8(self.getTranslationInfos(
sourceStringDigest, sourceId, sourcePath, sourceLanguage,
destinationLanguages)[0])
return result
def getTranslatorLocalizationKeys(self):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
userToken = context.getVar('userToken')
if not userToken:
return []
localizationKeys = []
for localizationKey, translatorsSet in \
virtualServer.admin.translatorsSets.items():
if getProxyForServerRole('authentication').setContainsUser(
translatorsSet):
localizationKeys.append(localizationKey)
return localizationKeys
def hasLocalization( self, localizationKey, sourceStringDigest):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
sign = localizationKey[:2] + sourceStringDigest
if not virtualServer.translations.has_key(sign):
return 0
translation = virtualServer.translations[sign]
return translation.hasDestinationString(localizationKey[2:])
def hasSourceString(self, localizationKey, sourceStringDigest):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
sign = localizationKey[:2] + sourceStringDigest
return virtualServer.translations.has_key(sign)
def modifyLocalizationXmlRpc(self, localizationImport):
virtualServerId = context.getVar('applicationId')
virtualServer = self.getVirtualServer(virtualServerId)
localization = commonTools.importThing(localizationImport)
sign = localization.sourceLanguage \
+ localization.sourceStringDigest
if not virtualServer.translations.has_key(sign):
raise faults.MissingItem(sign)
translation = virtualServer.translations[sign]
if not translation.canBeModified():
raise faults.ReadOnlyObject()
if virtualServer.admin.translatorsSets.has_key(
localization.getKey()):
translatorsSet = virtualServer.admin.translatorsSets[
localization.getKey()]
else:
translatorsSet = None
if not self.isAdmin() \
and not getProxyForServerRole('authentication'
).setContainsUser(translatorsSet):
raise faults.UserAccessDenied()
assert translation.sourceLanguage == localization.sourceLanguage
virtualServer.lock.acquire()
# Check once again, now that the thread is locked.
if not virtualServer.translations.has_key(sign):
virtualServer.lock.release()
raise faults.MissingItem(sign)
translation.version += 1
translation.setDestinationString(
localization.destinationLanguage, localization.isTranslatable,
localization.destinationString, localization.isFuzzy)
userId = getProxyForServerRole('authentication').getUserId()
translation.addTranslator(localization.destinationLanguage, userId)
if not translation.destinationStrings and not translation.sources:
del virtualServer.translations[sign]
virtualServer.lock.release()
virtualServer.markCoreAsDirty()
cacheKey = '_' .join([localization.sourceStringDigest,
localization.sourceLanguage,
''])
invalidateKeyStart(cacheKey)
return translation.version
def registerPublicMethods(self):
Server.registerPublicMethods(self)
AdministrableServerMixin.registerPublicMethods(self)
self.registerPublicMethod('canDeleteLocalization')
self.registerPublicMethod('canModifyLocalization')
self.registerPublicMethod('getLanguagesForObjectId')
self.registerPublicMethod('getLastDigestsAndLabels',
self.getLastDigestsAndLabelsXmlRpc)
self.registerPublicMethod('getPossibleLanguages',
self.getPossibleLanguages)
self.registerPublicMethod('getLocalization',
self.getLocalizationXmlRpc)
self.registerPublicMethod('getTranslation',
self.getTranslationXmlRpc)
self.registerPublicMethod('getTranslationInfos',
self.getTranslationInfosXmlRpc)
self.registerPublicMethod('getTranslatorLocalizationKeys')
self.registerPublicMethod('hasLocalization')
self.registerPublicMethod('hasSourceString')
self.registerPublicMethod('modifyLocalization',
self.modifyLocalizationXmlRpc)
def repairVirtualServer(self, virtualServer, version):
changed = 0
if version < 4000:
changed = virtualServer.admin.repair(4000) or changed
for sign, translation in virtualServer.translations.items():
changed = translation.repair(4000) or changed
if version < 5004:
changed = virtualServer.admin.repair(5004) or changed
for sign, translation in virtualServer.translations.items():
changed = translation.repair(5004) or changed
if version <= 1012000:
admin = virtualServer.admin
if admin.id is None:
changed = 1
admin.id = '%s/__admin__' % virtualServer.virtualServerId
if changed:
virtualServer.markAllAsDirtyFIXME()
translationsServer = TranslationsServer()
if __name__ == "__main__":
translationsServer.launch(applicationName, applicationRole)