def translate_this( context, attrs=[], translation_exists=False, target_languages=[]): """ Translates the current object into all languages and transfers the given attributes """ info = list() warnings = list() errors = list() # if context is language-neutral, it must receive a language before # it is translated lang_support = ILanguage(context) manager = ITranslationManager(context) if lang_support.get_language() == '': lang_support.set_language( context.portal_languages.getPreferredLanguage()) canLang = lang_support.get_language() # if the user didn't select target languages, get all supported languages # from the language tool if not target_languages: portal_languages = getToolByName(context, 'portal_languages') target_languages = portal_languages.getSupportedLanguages() content_helper = IContentHelper(context) for lang in target_languages: if lang == canLang: continue res = list() if not manager.get_translation(lang): if not translation_exists: # need to make lang a string. It can be unicode so checkid will # freak out and lead to an infinite recursion manager.add_translation(str(lang)) res.append("Added Translation for %s" % lang) # For a new translation, make sure the title is copied as well attrs = content_helper.check_for_title_attr(attrs) else: warnings.append( u'Translation in language %s does not exist, ' 'skipping' % lang) continue else: if not translation_exists: warnings.append( u'Translation for language %s already ' 'exists, skipping' % lang) continue res.append(u"Found translation for %s " % lang) trans = manager.get_translation(lang) content_results = content_helper.copy_attributes(trans, attrs) res.extend(content_results['res']) warnings.extend(content_results['warnings']) info.append(u"\n".join(res)) return (info, warnings, errors)
def test_content_is_linked(self): items = self._run_transmogrifier() self.assertEqual(4, len(items)) manager = ITranslationManager(self.folder_en) self.assertEqual(self.folder_de, manager.get_translation('de'), 'English and German content should be linked.') self.assertEqual(2, len(manager.get_translations())) manager = ITranslationManager(self.file_de) self.assertEqual(self.file_en, manager.get_translation('en'), 'English and German content should be linked.') self.assertEqual(2, len(manager.get_translations()))
def __call__(self): if (self.request.method != 'POST' and not ('field' in self.request.form.keys() and 'lang_source' in self.request.form.keys())): return _("Need a field") else: manager = ITranslationManager(self.context) registry = getUtility(IRegistry) settings = registry.forInterface(IMultiLanguageExtraOptionsSchema) lang_target = ILanguage(self.context).get_language() lang_source = self.request.form['lang_source'] orig_object = manager.get_translation(lang_source) try: question = orig_object.getField( self.request.form['field']).get(orig_object) except AttributeError: return _("Invalid field") if len(question) > 1600: return _("Too long field") data = {'key': settings.google_translation_key, 'target': lang_target, 'source': lang_source, 'q': question} params = urllib.urlencode(data) url = 'https://www.googleapis.com/language/translate/v2' retorn = urllib.urlopen(url + '?' + params) return retorn.read()
def _at_back_references(source_object, relationship, translation=None): lang = queryAdapter(source_object, ILanguage).get_language() if translation: lang = queryAdapter(translation, ILanguage).get_language() refs = IReferenceable(source_object).getBRefs(relationship=relationship) gsm = getSecurityManager() result = [] for obj in refs: if ITranslatable.providedBy(obj): trans_manager = ITranslationManager(aq_inner(obj)) try: trans_obj = trans_manager.get_translation(lang) except Unauthorized: continue if trans_obj: result.append(trans_obj) continue if gsm.checkPermission('zope2.View', obj): result.append(obj) return result
def _back_references(source_object, attribute_name, translation=None): catalog = getUtility(ICatalog) intids = getUtility(IIntIds) lang = queryAdapter(source_object, ILanguage).get_language() if translation: lang = queryAdapter(translation, ILanguage).get_language() gsm = getSecurityManager() result = [] for rel in catalog.findRelations({ 'to_id': intids.getId(aq_inner(source_object)), 'from_attribute':attribute_name }): obj = intids.queryObject(rel.from_id) if obj is not None and checkPermission('zope2.View', obj): if ITranslatable.providedBy(obj): trans_manager = ITranslationManager(aq_inner(obj)) try: trans_obj = trans_manager.get_translation(lang) except Unauthorized, e: continue if trans_obj: result.append(trans_obj) continue if gsm.checkPermission('zope2.View', obj): result.append(obj)
def __call__(self): if (self.request.method != 'POST' and not ('field' in self.request.form.keys() and 'lang_source' in self.request.form.keys())): return _("Need a field") else: manager = ITranslationManager(self.context) registry = getUtility(IRegistry) settings = registry.forInterface(IMultiLanguageExtraOptionsSchema) lang_target = ILanguage(self.context).get_language() lang_source = self.request.form['lang_source'] orig_object = manager.get_translation(lang_source) try: question = orig_object.getField( self.request.form['field']).get(orig_object) except AttributeError: return _("Invalid field") if len(question) > 1600: return _("Too long field") data = { 'key': settings.google_translation_key, 'target': lang_target, 'source': lang_source, 'q': question } params = urllib.urlencode(data) url = 'https://www.googleapis.com/language/translate/v2' retorn = urllib.urlopen(url + '?' + params) return retorn.read()
def handle_modified(self, content): fieldmanager = ILanguageIndependentFieldsManager(content) if not fieldmanager.has_independent_fields(): return sm = getSecurityManager() try: # Do we have permission to sync language independent fields? if self.bypass_security_checks(): # Clone the current user and assign a new editor role to # allow edition of all translated objects even if the # current user whould not have permission to do that. tmp_user = UnrestrictedUser( sm.getUser().getId(), '', ['Editor', ], '') # Wrap the user in the acquisition context of the portal # and finally switch the user to our new editor acl_users = getToolByName(content, 'acl_users') tmp_user = tmp_user.__of__(acl_users) newSecurityManager(None, tmp_user) # Copy over all language independent fields transmanager = ITranslationManager(content) for translation in self.get_all_translations(content): trans_obj = transmanager.get_translation(translation) if trans_obj and fieldmanager.copy_fields(trans_obj): self.reindex_translation(trans_obj) finally: # Restore the old security manager setSecurityManager(sm)
def delete_this(ob, *args, **kw): err = list() lang = kw.get('lang', '') id_to_delete = kw['id_to_delete'] name = '' if id_to_delete in ob.objectIds(): name = id_to_delete else: # look for a translation of the item in the current language target_object = kw.get('target_object', None) if target_object: manager = ITranslationManager(target_object) trans_object = manager.get_translation(lang) if trans_object: name = trans_object.getId() if not name: err.append(u'No translation for language %s found' % lang) else: try: ob._delObject(name) except Exception, e: err.append( u'Could not delete %s for language %s. Message: %s' % (id_to_delete, lang, str(e)))
def renamer(ob, *args, **kw): """ rename one object within context from oldid to newid """ err = list() oldid = kw['oldid'] newid = kw['newid'] if not oldid: err.append(u'Current id must not be empty') else: oldid = oldid.encode('utf-8') if not newid: err.append(u'New id must not be empty') else: newid = newid.encode('utf-8') if not err: if oldid not in ob.objectIds(): manager = ITranslationManager(kw['target_object']) trans = manager.get_translation(kw['lang']) if trans: oldid = trans.getId() if oldid in ob.objectIds(): ob.manage_renameObjects([oldid], [newid]) else: err.append( 'No translation for %s in language %s found in ' 'folder %s' % (oldid, kw['lang'], '/'.join(ob.getPhysicalPath()))) return err
def handle_remove(self, action): data, errors = self.extractData() manager = ITranslationManager(self.context) if not errors: for language in data["languages"]: content = manager.get_translation(language) manager.remove_translation(language) aq_parent(content).manage_delObjects([content.getId()]) return self.request.response.redirect(self.context.absolute_url() + "/remove_translations")
def test_multilingual_content_is_linked(self): english_content = self.portal.get('en').get('accessibility') self.assertTrue(english_content, 'Missing page /en/accessibility') german_content = self.portal.get('de').get('barrierefreiheit') self.assertTrue(german_content, 'Missing page /de/barrierefreiheit') manager = ITranslationManager(english_content) self.assertEquals(german_content, manager.get_translation('de'), 'English and German content should be linked.')
def handle_remove(self, action): data, errors = self.extractData() manager = ITranslationManager(self.context) if not errors: for language in data['languages']: content = manager.get_translation(language) manager.remove_translation(language) aq_parent(content).manage_delObjects([content.getId()]) return self.request.response.redirect(self.context.absolute_url() \ + '/remove_translations')
def translated_urls(context): manager = ITranslationManager(context) translated_languages = manager.get_translated_languages() content_language = ILanguage(context).get_language() if content_language in translated_languages: translated_languages.remove(content_language) languages = [] for lang in translated_languages: languages.append(SimpleVocabulary.createTerm(lang, lang, \ manager.get_translation(lang).absolute_url())) return SimpleVocabulary(languages)
def back_references(source_object, attribute_name): """ Return back references from source object on specified attribute_name """ language_tool = getToolByName(source_object, 'portal_languages') default_language = language_tool.getDefaultLanguage() default_rels = [] # if this object is translatable, we should get the back relationship from the # default language of this object if ITranslatable.providedBy(source_object): trans_manager = ITranslationManager(aq_inner(source_object)) default_lang_obj = trans_manager.get_translation(default_language) if default_lang_obj: default_rels = _back_references(default_lang_obj, attribute_name, source_object) return list(set(default_rels + _back_references(source_object, attribute_name)))
def at_back_references(source_object, relationship): language_tool = getToolByName(source_object, 'portal_languages') default_language = language_tool.getDefaultLanguage() # if this object is translatable, we should get the back relationship from the # default language of this object default_rels = [] if ITranslatable.providedBy(source_object): trans_manager = ITranslationManager(aq_inner(source_object)) default_lang_obj = trans_manager.get_translation(default_language) if default_lang_obj: default_rels = _at_back_references(default_lang_obj, relationship, source_object) return list(set(default_rels + _at_back_references(source_object, relationship)))
def __call__(self, language): """ Look for the closest translated folder or siteroot """ parent = aq_parent(self.context) translated_parent = parent found = False while not IPloneSiteRoot.providedBy(parent) and not found: parent_translation = ITranslationManager(parent) if parent_translation.has_translation(language): translated_parent = parent_translation.get_translation( language) found = True parent = aq_parent(parent) return translated_parent
def handle_create(self, action): data, errors = self.extractData() if not errors: language = data['language'] translation_manager = ITranslationManager(aq_inner(self.context)) if ILanguage(self.context).get_language() == LANGUAGE_INDEPENDENT: language_tool = getToolByName(self.context, 'portal_languages') default_language = language_tool.getDefaultLanguage() ILanguage(self.context).set_language(default_language) translation_manager.update() self.context.reindexObject(idxs='language') translation_manager.add_translation(language) translated = translation_manager.get_translation(language) return self.request.response.redirect(translated.absolute_url() \ + '/edit')
def __call__(self): if (self.request.method != 'POST' and not ('field' in self.request.form.keys() and 'lang_source' in self.request.form.keys())): return _("Need a field") else: manager = ITranslationManager(self.context) registry = getUtility(IRegistry) settings = registry.forInterface(IMultiLanguageExtraOptionsSchema) lang_target = ILanguage(self.context).get_language() lang_source = self.request.form['lang_source'] orig_object = manager.get_translation(lang_source) try: question = orig_object.getField( self.request.form['field']).get(orig_object) except AttributeError: return _("Invalid field") return google_translate(question, settings.google_translation_key, lang_target, lang_source)
def __call__(self): if (self.request.method != 'POST' and not ('field' in self.request.form.keys() and 'lang_source' in self.request.form.keys())): return _("Need a field") else: manager = ITranslationManager(self.context) registry = getUtility(IRegistry) settings = registry.forInterface(IMultiLanguageExtraOptionsSchema) lang_target = ILanguage(self.context).get_language() lang_source = self.request.form['lang_source'] orig_object = manager.get_translation(lang_source) field = self.request.form['field'].split('.')[-1] if hasattr(orig_object, field): question = getattr(orig_object, field, '') if hasattr(question, 'raw'): question = question.raw else: return _("Invalid field") return google_translate(question, settings.google_translation_key, lang_target, lang_source)
def handle_create(self, action): data, errors = self.extractData() if not errors: language = data['language'] translation_manager = ITranslationManager(aq_inner(self.context)) if ILanguage(self.context).get_language() == LANGUAGE_INDEPENDENT: language_tool = getToolByName(self.context, 'portal_languages') default_language = language_tool.getDefaultLanguage() ILanguage(self.context).set_language(default_language) translation_manager.update() self.context.reindexObject(idxs='language') translation_manager.add_translation(language) translated = translation_manager.get_translation(language) registry = getUtility(IRegistry) settings = registry.forInterface(IMultiLanguageExtraOptionsSchema) if settings.redirect_babel_view: return self.request.response.redirect( translated.absolute_url() + '/babel_edit') else: return self.request.response.redirect( translated.absolute_url() + '/edit?set_language=%s' % language)
def handle_create(self, action): data, errors = self.extractData() if not errors: language = data['language'] translation_manager = ITranslationManager(aq_inner(self.context)) if ILanguage(self.context).get_language() == LANGUAGE_INDEPENDENT: language_tool = getToolByName(self.context, 'portal_languages') default_language = language_tool.getDefaultLanguage() ILanguage(self.context).set_language(default_language) translation_manager.update() self.context.reindexObject(idxs='language') translation_manager.add_translation(language) translated = translation_manager.get_translation(language) registry = getUtility(IRegistry) settings = registry.forInterface(IMultiLanguageExtraOptionsSchema) if settings.redirect_babel_view: return self.request.response.redirect( translated.absolute_url() + '/babel_edit?set_language=%s' % language) else: return self.request.response.redirect( translated.absolute_url() + '/edit?set_language=%s' % language)
def _setXLIFF(self, data, target_language=''): """ Set the data on one object """ site = getSite() uid_catalog = getToolByName(site, 'uid_catalog') if target_language == '': target_language = data['target-language'].encode('ascii') # nothing to do if there is no target language if not target_language: return try: oid = data['oid'].encode('ascii') results = uid_catalog(UID=oid) if len(results) != 1: #raise ValueError, "Uid catalog should return exactly one #result but returned %s." % len(results) raise KeyError, "Invalid OID %s" % oid source_ob = results[0].getObject() except KeyError: # old style xliff file. Using path #print "Using path to find target object" path = data['original'].encode('utf-8') source_ob = site.restrictedTraverse(path, None) if source_ob is None: raise ValueError( "%s not found, can not add translation." % data['original'].encode('utf-8')) # If the source object is language-neutral, it must receive a language # prior to translation # XXXX What to do if the source_ob HAS a language, but it differs # from the source-language inside the data? if source_ob.Language() == '': # Get the source language from the data source_language = data.get('source-language') # No source language present in the section, use site default if not source_language: langtool = getToolByName(site, 'portal_languages') source_language = langtool.getPreferredLanguage() source_ob.setLanguage(source_language) tm = ITranslationManager(source_ob) if not tm.has_translation(target_language): tm.add_translation(target_language) self.new_translations += 1 target_ob = tm.get_translation(target_language) if IBaseObject.providedBy(target_ob): # We dont want the id to get renamed to match the title target_ob.unmarkCreationFlag() values = {} for unit in data.findAll('trans-unit'): fieldname = unit['id'].encode('utf-8') value = unit.find('target').renderContents('utf-8').strip() # Note: We don't use xliff to remove values, so no value means no # translation and no change to the original # XXX: This doesn't handle values other than strings, this may be # a problem. if not value: continue # convert HTML entities value = safe_unicode(value) value = html_parser.unescape(value) values[fieldname] = value if IDexterityContent.providedBy(target_ob): # Dexterity schema = get_dx_schema(target_ob) for name, field in schema.items(): if ILanguageIndependentField.providedBy(field): # Copy from the original: field.set(target_ob, field.get(source_ob)) pass elif name in values: value = values[name] if IRichText.providedBy(field): value = RichTextValue(value) schema[name].set(target_ob, value) else: # Archetypes target_ob.processForm(data=1, metadata=1, values=values) # Set the correct format if shasattr(source_ob, 'text_format'): target_ob.setFormat(source_ob.text_format) self.total += 1
def getClosestDestination(self): """Get the "closest translated object" URL. """ # We sould travel the parent chain using the catalog here, # but I think using the acquisition chain is faster # (or well, __parent__ pointers) because the catalog # would require a lot of queries, while technically, # having done traversal up to this point you should # have the objects in memory already # As we don't have any content object we are going to look # for the best option root = getToolByName(self.context, 'portal_url') ltool = getToolByName(self.context, 'portal_languages') # We are useing TranslationManager to get the translations of a string tg manager = TranslationManager(self.tg) context = None languages = manager.get_translations() if len(languages) == 0: # If there is no results there are no translations # we move to portal root return self.wrapDestination(root(), postpath=False) # We are going to see if there is the prefered language translation # Otherwise we get the first as context to look for translation prefered = ltool.getPreferredLanguage() if prefered in languages: context = languages[prefered] else: context = languages[languages.keys()[0]] checkPermission = getSecurityManager().checkPermission chain = self.getParentChain(context) for item in chain: if ISiteRoot.providedBy(item): # We do not care to get a permission error # if the whole of the portal cannot be viewed. # Having a permission issue on the root is fine; # not so much for everything else so that is checked there return self.wrapDestination(item.absolute_url()) elif IFactoryTempFolder.providedBy(item) or \ IFactoryTool.providedBy(item): # TempFolder or portal_factory, can't have a translation continue try: canonical = ITranslationManager(item) except TypeError: if not ITranslatable.providedBy(item): # In case there it's not translatable go to parent # This solves the problem when a parent is not ITranslatable continue else: raise translation = canonical.get_translation(self.lang) if translation and ( INavigationRoot.providedBy(translation) or bool(checkPermission('View', translation)) ): # Not a direct translation, therefore no postpath # (the view might not exist on a different context) return self.wrapDestination(translation.absolute_url(), postpath=False) # Site root's the fallback return self.wrapDestination(root(), postpath=False)
def makeTranslation(content, language='en'): manager = ITranslationManager(content) manager.add_translation(language) import transaction; transaction.commit() return manager.get_translation(language)
def exec_for_all_langs(context, method, *args, **kw): """ helper method. Takes a method and executes it on all language versions of the context """ info = [] warnings = [] errors = [] changed_languages = [] skipped_languages = [] portal_url = getToolByName(context, 'portal_url') portal_path = portal_url.getPortalPath() manager = ITranslationManager(context) translations = manager.get_translations() content_language = ILanguage(context).get_language() langs = [x for x in translations.keys() if x != content_language] langs.append(content_language) kw['content_language'] = content_language context_path = context.getPhysicalPath() dynamic_path = portal_path + '/%s/' + \ "/".join(context_path[len(portal_path) + 1:]) if dynamic_path[-1] == "/": dynamic_path = dynamic_path[:-1] # if the special keyword 'target_id' is passed, try to retrieve an object # of that name from the current context and save it in the kw arguments. # This object can the used in the method for retrieving translations. # Needed when we are not working directly on translations of the current # context, but items contained in translations of the current context. if kw.get('target_id', None): target_object = getattr(context, kw.get('target_id'), None) if target_object: kw['target_object'] = target_object if kw.get('target_path', None): targetpath = safe_unicode(kw['target_path']).encode('utf-8') if targetpath.startswith('/'): if not targetpath.startswith(portal_path): targetpath = portal_path + targetpath target_base = context.restrictedTraverse(targetpath, None) kw['target_base'] = target_base # add the portal_path to the keywords kw['portal_path'] = portal_path for lang in langs: base = manager.get_translation(lang) if base is None: log.info("Break for lang %s, no translation present" % lang) skipped_languages.append(lang) continue kw['lang'] = lang err = method(base, *args, **kw) log.info("Executing for language %s" % lang) if err: errors.extend(err) else: changed_languages.append(lang) if changed_languages: info.append( 'Executed for the following languages: %s' % ' '.join(changed_languages)) if skipped_languages: warnings.append( 'No translations for the following languages: %s' % ' '.join(skipped_languages)) return info, warnings, errors
def cut_and_paste(ob, *args, **kw): """ Uses OFS to cut and paste an object. """ err = list() if not kw['target_path']: err.append('You must specify a target path') id = kw['id_to_move'] if not id: err.append(u'You must select an object to move') id = safe_unicode(id) if len(err): return err lang = kw['lang'] target_base = kw['target_base'] if target_base is None: err.append( u'No object was found at the given taget path %s' % kw['target_path']) return err if ITranslatable.providedBy(target_base): target_manager = ITranslationManager(target_base) target = target_manager.get_translation(lang) else: err.append( u'The target object is not translatable. Please ' 'choose a different target that is translatable.') return err if target is None: err.append( u'No translation in language "%s" was found of ' 'the target %s' % (lang, kw['target_path'])) return err if not IBaseFolder.providedBy(target): err.append( u'The target object is not folderish - pasting is ' 'not possible.') return err name = None if id in ob.objectIds(): name = id trans_object = getattr(ob, name) else: # look for translation via get_translation manager = ITranslationManager(kw['target_object']) trans_object = manager.get_translation(lang) if trans_object: if Acquisition.aq_parent(trans_object) == ob: name = trans_object.getId() if name is None: err.append( u'No translation of the requested object for language ' '%s found in %s' % (lang, '/'.join(ob.getPhysicalPath()))) return err if target == trans_object: err.append( u'The target cannot be identical to the object you want to move') return err # we need to pass a string name = safe_unicode(name).encode('utf-8') try: cut = ob.manage_cutObjects(name) except ResourceLockedError: lockable = ILockable(trans_object) lockable.unlock() cut = ob.manage_cutObjects(name) try: target.manage_pasteObjects(cut) except Exception, error: err.append( u'Not possible to paste item in language %s to target %s.' 'Error message: %s' % (lang, target.absolute_url(), error))
def makeTranslation(content, language='en'): manager = ITranslationManager(content) manager.add_translation(language) import transaction transaction.commit() return manager.get_translation(language)
def _setXLIFF(self, data, target_language=''): """ Set the data on one object """ site = getSite() uid_catalog = getToolByName(site, 'uid_catalog') if target_language == '': target_language = data['target-language'].encode('ascii') # nothing to do if there is no target language if not target_language: return try: oid = data['oid'].encode('ascii') results = uid_catalog(UID=oid) if len(results) != 1: #raise ValueError, "Uid catalog should return exactly one #result but returned %s." % len(results) raise KeyError, "Invalid OID %s" % oid source_ob = results[0].getObject() except KeyError: # old style xliff file. Using path #print "Using path to find target object" path = data['original'].encode('utf-8') source_ob = site.restrictedTraverse(path, None) if source_ob is None: raise ValueError( "%s not found, can not add translation." % data['original'].encode('utf-8')) # If the source object is language-neutral, it must receive a language # prior to translation # XXXX What to do if the source_ob HAS a language, but it differs # from the source-language inside the data? if source_ob.Language() == '': # Get the source language from the data source_language = data.get('source-language') # No source language present in the section, use site default if not source_language: langtool = getToolByName(site, 'portal_languages') source_language = langtool.getPreferredLanguage() source_ob.setLanguage(source_language) tm = ITranslationManager(source_ob) if not tm.has_translation(target_language): tm.add_translation(target_language) self.new_translations += 1 target_ob = tm.get_translation(target_language) if IBaseObject.providedBy(target_ob): # We dont want the id to get renamed to match the title target_ob.unmarkCreationFlag() values = {} for unit in data.findAll('trans-unit'): fieldname = unit['id'].encode('utf-8') value = unit.find('target').renderContents('utf-8').strip() # Note: We don't use xliff to remove values, so no value means no # translation and no change to the original # XXX: This doesn't handle values other than strings, this may be # a problem. if not value: continue # convert HTML entities value = safe_unicode(value) value = html_parser.unescape(value) values[fieldname] = value if IDexterityContent.providedBy(target_ob): # Dexterity schema = get_dx_schema(target_ob) for name, field in schema.items(): if ILanguageIndependentField.providedBy(field): # Copy from the original: field.set(target_ob, field.get(source_ob)) pass elif name == 'header_links': value = eval(values[name]) schema[name].set(target_ob, value) elif name in values: value = values[name] if IRichText.providedBy(field): value = RichTextValue(value,'text/html', 'text/x-html-safe') schema[name].set(target_ob, value) ######### set SEO Properties #### for seo_value in values: if seo_value.startswith('qSEO_'): if target_ob.hasProperty(seo_value): target_ob.manage_changeProperties({seo_value: values[seo_value].encode('utf-8')}) else: target_ob.manage_addProperty(seo_value, values[seo_value.encode('utf-8')], 'string') else: # Archetypes target_ob.processForm(data=1, metadata=1, values=values) # Set the correct format if shasattr(source_ob, 'text_format'): target_ob.setFormat(source_ob.text_format) self.total += 1