def update(self): """ It's only for AT on factory so we check """ if self.context.portal_factory.isTemporary(self.context): if ITranslatable.providedBy(self.context): self.lang = ILanguage(self.context).get_language() else: self.lang = 'NaN'
def __init__(self, context, request, view, manager): super(CookiePolicyViewlet, self).__init__(context, request, view, manager) registry = getUtility(IRegistry) self.proxy = registry.forInterface(ICookiePolicySchema) if self.proxy: self.enabled = self.proxy.enabled self.cookies_document_id = self.proxy.cookies_document_id portal = api.portal.get() try: cookies_document = portal.restrictedTraverse(str(self.cookies_document_id)) except: cookies_document = None if cookies_document: if multilingual_enabled: try: language = ILanguage(context).get_language() except: language = "en" try: if ITranslatable.providedBy(cookies_document): cookies_document_translated=ITranslationManager(cookies_document).get_translation(language) if cookies_document_translated: cookies_document=cookies_document_translated except: pass self.title = cookies_document.description self.message = cookies_document.text.output
def getMenuItems(self, context, request): menu = super(TranslateMenu, self).getMenuItems(context, request) url = context.absolute_url() is_neutral_content = ( ILanguage(context).get_language() == LANGUAGE_INDEPENDENT or is_language_independent(context) ) if not is_neutral_content and not INavigationRoot.providedBy(context): if ITranslatable.providedBy(context) and getSecurityManager().checkPermission('Manage portal', context): menu.append({ "title": _( u"title_mirror_content", default=u"Mirror this object to other languages" ), "description": _( u"description_mirror_content", default=u"" ), "action": url + "/mirror_content", "selected": False, "icon": None, "extra": { "id": "_mirror_content", "separator": None, "class": "" }, "submenu": None, }) return menu
def is_translatable(content): """Checks if content is translatable. :param content: Content to be translated. :type content: Content object :returns: Boolean """ return ITranslatable.providedBy(content)
def link_translations(request, registration): if not IPloneAppMultilingualInstalled.providedBy(request): return if not IRegistration.providedBy(registration): return if not ITranslatable.providedBy(registration): return registry = getUtility(IRegistry) langs = list(registry["plone.available_languages"]) current_lang = api.portal.get_current_language()[:2] langs.remove(current_lang) types = ["EasyForm", "Event"] for lang in langs: trans_registration = ITranslationManager(registration).get_translation( lang) if not trans_registration: continue for portal_type in types: brains = api.content.find(context=registration, portal_type=portal_type) if len(brains) != 1: continue obj = brains[0].getObject() if not ITranslatable.providedBy(obj): continue trans = ITranslationManager(obj).get_translation(lang) if trans: continue trans_brains = api.content.find( context=trans_registration, portal_type=portal_type, ) if len(trans_brains) != 1: continue trans_obj = trans_brains[0].getObject() ITranslationManager(obj).register_translation(lang, trans_obj) ILanguage(trans_obj).set_language(lang)
def objectTranslated(ob, event): if ob: if ITranslatable.providedBy(ob): if getattr(ob, 'language', None) == "en" and getattr( ob, 'portal_type', None) in [ "Document", "Event", "News Item" ] and getattr(ob, 'id', '') not in ['slideshow']: createdEvent(ob, event) if not hasattr(ob, 'slideshow'): if ITranslationManager(ob).has_translation('nl'): original_ob = ITranslationManager(ob).get_translation( 'nl') if hasattr(original_ob, 'slideshow'): slideshow = original_ob['slideshow'] ITranslationManager(slideshow).add_translation( 'en') slideshow_trans = ITranslationManager( slideshow).get_translation('en') slideshow_trans.title = slideshow.title slideshow_trans.portal_workflow.doActionFor( slideshow_trans, "publish", comment="Slideshow published") for sitem in slideshow: if slideshow[sitem].portal_type == "Image": ITranslationManager( slideshow[sitem]).add_translation('en') trans = ITranslationManager( slideshow[sitem]).get_translation('en') trans.image = slideshow[sitem].image addCropToTranslation( slideshow[sitem], trans) ob.reindexObject() ob.reindexObject(idxs=["hasMedia"]) ob.reindexObject(idxs=["leadMedia"]) else: # no slideshow folder pass else: # no translation pass else: # has slideshow pass else: # wrong language pass else: # invalid object pass return
def get_translations(self): cts = [] if ITranslatable.providedBy(self.context): t_langs = translated_languages(self.context) context_translations = ITranslationManager(self.context).get_translations() for lang in t_langs: cts.append(dict(lang_native=lang.title, url=context_translations[lang.value].absolute_url())) return cts
def get_translations(self): cts = [] if ITranslatable.providedBy(self.context): t_langs = translated_languages(self.context) context_translations = ITranslationManager( self.context).get_translations() for lang in t_langs: cts.append( dict(lang_native=lang.title, url=context_translations[lang.value].absolute_url())) return cts
def set_default_language_content(self): """ Set default language on root to language independent """ portal = getSite() defaultLanguage = LANGUAGE_INDEPENDENT for id in portal.objectIds(): if id not in _languagelist and \ id not in _combinedlanguagelist and \ ITranslatable.providedBy(portal[id]): set_recursive_language(portal[id], defaultLanguage)
def set_recursive_language(obj, language): """ Set the language at this object and recursive """ if ILanguage(obj).get_language() != language: ILanguage(obj).set_language(language) ITranslationManager(obj).update() reindex_object(obj) if IFolderish.providedBy(obj): for item in obj.items(): if ITranslatable.providedBy(item): set_recursive_language(item, language)
def _update_deferred(self): for path, canonicalpath, language in self.deferred: obj = self._traverse(path) if obj is None: continue canonical = self._traverse(canonicalpath) if canonical is None: continue if (ITranslatable.providedBy(obj) and ITranslatable.providedBy(canonical)): try: translation_group = IMutableTG(canonical).get() IMutableTG(obj).set(translation_group) manager = ITranslationManager(obj) manager.register_translation(language, obj) except KeyError: # put obj in a separate translation group when registration # fails IMutableTG(obj).set(self.uuid_generator())
def set_default_language_content(self): """Set default language on root to language independent """ portal = getSite() defaultLanguage = LANGUAGE_INDEPENDENT for id_ in portal.objectIds(): if all([id_ not in _languagelist, id_ not in _combinedlanguagelist, ITranslatable.providedBy(portal[id_])]): set_recursive_language(portal[id_], defaultLanguage)
def update(self): try: tg = self.request.translation_info['tg'] except AttributeError: return self.available = True if ITranslatable.providedBy(self.context): self.lang = ILanguage(self.context).get_language() else: self.lang = 'NaN' catalog = getToolByName(self.context, 'portal_catalog') query = {'TranslationGroup': tg, 'Language': 'all'} self.origin = catalog.searchResults(query)
def createdEvent(obj, event): """ Subscriber to set language on the child folder It can be a - IObjectRemovedEvent - don't do anything - IObjectMovedEvent - IObjectAddedEvent - IObjectCopiedEvent """ if IObjectRemovedEvent.providedBy(event): return request = getattr(event.object, 'REQUEST', getRequest()) if not IPloneAppMultilingualInstalled.providedBy(request): return # On ObjectCopiedEvent and ObjectMovedEvent aq_parent(event.object) is # always equal to event.newParent. parent = aq_parent(event.object) # special parent handling if not ITranslatable.providedBy(parent): set_recursive_language(obj, LANGUAGE_INDEPENDENT) return # Normal use case # We set the tg, linking language = ILanguage(parent).get_language() set_recursive_language(obj, language) request = getattr(event.object, 'REQUEST', getRequest()) try: ti = request.translation_info except AttributeError: return # AT check portal = getSite() portal_factory = getToolByName(portal, 'portal_factory', None) if ( not IDexterityContent.providedBy(obj) and portal_factory is not None and not portal_factory.isTemporary(obj) ): return IMutableTG(obj).set(ti['tg']) modified(obj) tm = ITranslationManager(obj) old_obj = tm.get_translation(ti['source_language']) ILanguageIndependentFieldsManager(old_obj).copy_fields(obj)
def update(self): sdm = self.context.session_data_manager session = sdm.getSessionData(create=True) if ITranslatable.providedBy(self.context): self.lang = ILanguage(self.context).get_language() else: self.lang = 'NaN' if 'tg' in session.keys(): tg = session['tg'] self.available = True ptool = getToolByName(self.context, 'portal_catalog') query = {'TranslationGroup': tg, 'Language': 'all'} results = ptool.searchResults(query) self.origin = results
def createdEvent(obj, event): """ Subscriber to set language on the child folder It can be a - IObjectRemovedEvent - don't do anything - IObjectMovedEvent - IObjectAddedEvent - IObjectCopiedEvent """ if IObjectRemovedEvent.providedBy(event): return request = getattr(event.object, 'REQUEST', getRequest()) if not IPloneAppMultilingualInstalled.providedBy(request): return # On ObjectCopiedEvent and ObjectMovedEvent aq_parent(event.object) is # always equal to event.newParent. parent = aq_parent(event.object) # special parent handling if not ITranslatable.providedBy(parent): set_recursive_language(obj, LANGUAGE_INDEPENDENT) return # Normal use case # We set the tg, linking language = ILanguage(parent).get_language() set_recursive_language(obj, language) request = getattr(event.object, 'REQUEST', getRequest()) try: ti = request.translation_info except AttributeError: return # AT check portal = getSite() portal_factory = getToolByName(portal, 'portal_factory', None) if (not IDexterityContent.providedBy(obj) and portal_factory is not None and not portal_factory.isTemporary(obj)): return IMutableTG(obj).set(ti['tg']) modified(obj) tm = ITranslationManager(obj) old_obj = tm.get_translation(ti['source_language']) ILanguageIndependentFieldsManager(old_obj).copy_fields(obj)
def set_recursive_language(ob, language): """Set the language for this object and its children in a recursive manner """ if is_language_independent(ob): ILanguage(ob).set_language(None) elif ILanguage(ob).get_language() != language: ILanguage(ob).set_language(language) ITranslationManager(ob).update() reindex_object(ob) for child in (IFolderish.providedBy(ob) and ob.items() or ()): if ITranslatable.providedBy(child): set_recursive_language(child, language)
def update(self): """ It's only for AT on factory so we check """ factory = getToolByName(self.context, 'portal_factory', None) if factory is not None and factory.isTemporary(self.context): sdm = self.context.session_data_manager session = sdm.getSessionData(create=True) if ITranslatable.providedBy(self.context): self.lang = ILanguage(self.context).get_language() else: self.lang = 'NaN' if 'tg' in session.keys(): tg = session['tg'] self.available = True ptool = getToolByName(self.context, 'portal_catalog') query = {'TranslationGroup': tg, 'Language': 'all'} results = ptool.searchResults(query) self.origin = results
def createdEvent(obj, event): """ It can be a IObjectRemovedEvent - don't do anything IObjectMovedEvent IObjectAddedEvent IObjectCopiedEvent """ if IObjectRemovedEvent.providedBy(event): return # On ObjectCopiedEvent and ObjectMovedEvent aq_parent(event.object) is # always equal to event.newParent. parent = aq_parent(event.object) if ITranslatable.providedBy(parent): # Normal use case # We set the tg, linking language = ILanguage(parent).get_language() set_recursive_language(obj, language) sdm = obj.session_data_manager session = sdm.getSessionData() portal = getSite() portal_factory = getToolByName(portal, 'portal_factory', None) request = getattr(event.object, 'REQUEST', getRequest()) has_pam_old_lang_in_form = ( request and 'form.widgets.pam_old_lang' not in request.form ) if (not has_pam_old_lang_in_form and 'tg' in session.keys() and 'old_lang' in session.keys() and (portal_factory is None or not portal_factory.isTemporary(obj))): IMutableTG(obj).set(session['tg']) modified(obj) del session['tg'] old_obj = ITranslationManager(obj)\ .get_translation(session['old_lang']) ILanguageIndependentFieldsManager(old_obj).copy_fields(obj) del session['old_lang'] else: set_recursive_language(obj, LANGUAGE_INDEPENDENT)
def recursively_bind_translation(source, target, language, keep_workflow_states): if ITranslatable.providedBy(source): tm_source = ITranslationManager(source) tm_source.register_translation(language=language, content=target) if keep_workflow_states: try: api.content.transition(target, to_state=api.content.get_state(source)) except WorkflowException: pass if IFolderish.providedBy(source) and IFolderish.providedBy(target): for source_obj_id, source_obj in source.objectItems(): target_obj = target[source_obj_id] recursively_bind_translation(source_obj, target_obj, language, keep_workflow_states)
def __iter__(self): for item in self.previous: pathkey = self.pathkey(*item.keys())[0] if not pathkey: yield item continue path = item[pathkey] if isinstance(path, unicode): path = path.encode('ascii') obj = self._traverse(path) if obj is None: yield item continue canonicalkey = self.canonicalkey(*item.keys())[0] translationkey = self.translationkey(*item.keys())[0] if not canonicalkey: yield item continue canonicalpath = item[translationkey] if isinstance(canonicalpath, unicode): canonicalpath = canonicalpath.encode('ascii') language = item['language'] if ITranslatable.providedBy(obj): ILanguage(obj).set_language(language) if item[canonicalkey]: IMutableTG(obj).set(self.uuid_generator()) manager = ITranslationManager(obj) manager.register_translation(language, obj) else: self.deferred.append((path, canonicalpath, language)) yield item self._update_deferred()
def createdEvent(obj, event): """ It can be a IObjectRemovedEvent - don't do anything IObjectMovedEvent IObjectAddedEvent IObjectCopiedEvent """ if IObjectRemovedEvent.providedBy(event): return portal = getSite() # On ObjectCopiedEvent and ObjectMovedEvent aq_parent(event.object) is # always equal to event.newParent. parent = aq_parent(event.object) if ITranslatable.providedBy(parent): # Normal use case # We set the tg, linking language = ILanguage(parent).get_language() set_recursive_language(obj, language) sdm = obj.session_data_manager session = sdm.getSessionData() portal = getSite() if 'tg' in session.keys() and \ 'old_lang' in session.keys() and \ not portal.portal_factory.isTemporary(obj): IMutableTG(obj).set(session['tg']) modified(obj) del session['tg'] old_obj = ITranslationManager(obj)\ .get_translation(session['old_lang']) ILanguageIndependentFieldsManager(old_obj).copy_fields(obj) del session['old_lang'] else: set_recursive_language(obj, LANGUAGE_INDEPENDENT)
def run(self, resource, *args, **kwds): """Change the rdf resource """ context = self.context # ZZZ: should watch for availability of plone.app.multilingual if has_plone_multilingual and ITranslatable.providedBy(context): tm = ITranslationManager(context) translations = tm.get_translated_languages() if translations: translations_objs = filter( None, [tm.get_translation(o) for o in translations]) resource.eea_hasTranslation = \ [rdflib.URIRef(o.absolute_url()) for o in translations_objs if o.absolute_url() != context.absolute_url()] else: resource.eea_isTranslationOf = \ rdflib.URIRef(context.absolute_url()) else: resource.eea_hasTranslation = ['No Translation'] return
def getClosestDestination(self): """Get the "closest translated object" URL. """ # We should 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 site = getSite() root = getToolByName(site, 'portal_url') ltool = getToolByName(site, 'portal_languages') # We are using 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 preferred language translation # Otherwise we get the first as context to look for translation prefered = ltool.getPreferredLanguage(self.request) 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) \ and not ILanguageRootFolder.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 getMenuItems(self, context, request): """Return menu item entries in a TAL-friendly form. """ # Settings site_url = getSite().absolute_url() language_tool = getToolByName(context, "portal_languages") show_flags = language_tool.showFlags try: lang_names = request.locale.displayNames.languages except AttributeError: lang_names = {} registry = getUtility(IRegistry) settings = registry.forInterface(IMultiLanguageExtraOptionsSchema, prefix="plone") if settings.redirect_babel_view: translation_view = 'babel_edit' else: translation_view = 'edit' # Content content = context content_url = context.absolute_url() content_language = ILanguage(content).get_language() content_translatable = not ( content_language == LANGUAGE_INDEPENDENT or is_language_independent(content) or ILanguageRootFolder.providedBy(content) ) content_translated = translated_languages(content) content_untranslated = untranslated_languages(content) content_translation_group = ITG(content, '') if not ITranslatable.providedBy(content): content = None # Folder when content is default page folder = aq_parent(context) if not is_default_page(folder, context): folder = None if folder and ITranslatable.providedBy(folder): # noqa folder_url = folder.absolute_url() folder_language = ILanguage(folder).get_language() folder_translatable = not ( folder_language == LANGUAGE_INDEPENDENT or is_language_independent(folder) or ILanguageRootFolder.providedBy(folder) ) folder_translated = translated_languages(folder) folder_untranslated = untranslated_languages(folder) folder_translation_group = ITG(folder, '') else: folder_url = '' folder_language = '' folder_translatable = False folder_translated = [] folder_untranslated = [] folder_translation_group = '' # Assets folder assets_folder_url = None assets_folder_title = None pc = getToolByName(getSite(), 'portal_catalog') results = pc.unrestrictedSearchResults( portal_type='LIF', Language=ILanguage(context).get_language()) for brain in results: assets_folder_url = brain.getURL() + '/folder_contents' assets_folder_title = safe_unicode(brain.Title) break # Menu items results = [] results_folder = [] results_content = [] if folder_translatable: # Folder translation view lang_name = lang_names.get(folder_language, folder_language) results_folder.append({ "title": _( u'edit_translation', default=u"Edit ${lang_name}", mapping={"lang_name": lang_name} ), "description": _( u"description_babeledit_menu", default=u"Edit {lang_name} with the two-column translation view", # noqa mapping={"lang_name": lang_name} ), "action": folder_url + "/" + translation_view, "selected": False, "icon": None, "extra": { "id": "_edit_folder_babel_edit", "separator": None, "class": "", }, "submenu": None, }) if folder and folder_untranslated and False: # disabled in favor of cut & paste # noqa # Set folder language results_folder.append({ "title": _( u'title_set_language', default=u"Change content language" ), "description": _( u"description_set_language", default=u"Move the translation under another language folder" # noqa ), "action": folder_url + "/update_language", "selected": False, "icon": None, "extra": { "id": "_set_folder_language", "separator": None, "class": "" }, "submenu": None, }) if folder_translatable: for idx, lang in enumerate(folder_untranslated): lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = show_flags and language_tool.getFlagForLanguageCode(lang_id) or None # noqa results_folder.append({ "title": _( u'create_translation', default=u"Create ${lang_name}", mapping={"lang_name": lang_name} ), "description": _( u"description_translate_into", default=u"Translate into ${lang_name}", mapping={"lang_name": lang_name} ), "action": "%s/@@create_translation?language=%s" % ( folder_url, lang_id), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": {"id": "translate_folder_into_%s" % lang_id, "separator": None, "class": "contentmenuflags"}, "submenu": None, }) urls = translated_urls(folder) for lang in folder_translated: if lang.value not in urls.by_token: # omit if translation is not permitted to access. continue lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = show_flags and language_tool.getFlagForLanguageCode(lang_id) or None # noqa results_folder.append({ "title": _( u'edit_translation', default=u"Edit ${lang_name}", mapping={"lang_name": lang_name} ), "description": _( u"description_babeledit_menu", default=u"Edit {lang_name} with the two-column translation view", # noqa mapping={"lang_name": lang_name} ), "action": (urls.getTerm(lang_id).title + "/" + translation_view), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": {"id": "babel_edit_%s" % lang_id, "separator": None, "class": "contentmenuflags"}, "submenu": None, }) # Manage folder translations results_folder.append({ "title": _( u"title_modify_translations", default=u"Manage translations" ), "description": _( u"description_modify_translations", default=u"Add or delete translations" ), "action": folder_url + "/modify_translations", "selected": False, "icon": None, "extra": { "id": "_modify_folder_translations", "separator": None, "class": "" }, "submenu": None, }) # Universal link if folder_translation_group: results_folder.append({ "title": _( u"universal_link", default=u"Universal link" ), "description": _( u"description_universal_link", default=u"Universal link to the content in user's preferred language" # noqa ), "action": "%s/@@multilingual-universal-link/%s" % ( site_url, folder_translation_group), "selected": False, "icon": None, "extra": { "id": "_universal_folder_link", "separator": None, "class": "" }, "submenu": None, }) if results_folder: # Folder translation separator results.append({ 'title': _( u'title_translate_current_folder', default=u'Folder translation' ), 'description': '', 'action': None, 'selected': False, 'icon': None, 'extra': {'id': 'translateFolderHeader', 'separator': 'actionSeparator', 'class': 'plone-toolbar-submenu-header'}, 'submenu': None, }) results.extend(results_folder) lang_name = lang_names.get(content_language, content_language) # Content language if content_untranslated and False: # disabled in favor of cut & paste results_content.append({ "title": _( u"title_set_language", default=u"Change content language" ), "description": _( u"description_set_language", default=u"Move the translation under another language folder" # noqa ), "action": content_url + "/update_language", "selected": False, "icon": None, "extra": { "id": "_set_language", "separator": None, "class": "" }, "submenu": None, }) if content_translatable: # Content translation view results_content.append({ "title": _( u'edit_translation', default=u"Edit ${lang_name}", mapping={"lang_name": lang_name} ), "description": _( u"description_babeledit_menu", default=u"Edit {lang_name} with the two-column translation view", # noqa mapping={"lang_name": lang_name} ), "action": content_url + "/" + translation_view, "selected": False, "icon": None, "extra": { "id": "_edit_babel_edit", "separator": None, "class": "", }, "submenu": None, }) if content_translatable: for idx, lang in enumerate(content_untranslated): lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = show_flags and language_tool.getFlagForLanguageCode(lang_id) or None # noqa results_content.append({ "title": _( u'create_translation', default=u"Create ${lang_name}", mapping={"lang_name": lang_name} ), "description": _( u"description_translate_into", default=u"Translate into ${lang_name}", mapping={"lang_name": lang_name} ), "action": "%s/@@create_translation?language=%s" % ( content_url, lang_id), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": {"id": "translate_into_%s" % lang_id, "separator": None, "class": "contentmenuflags"}, "submenu": None, }) urls = translated_urls(content) for lang in content_translated: if lang.value not in urls.by_token: # omit if translation is not permitted to access. continue lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = show_flags and language_tool.getFlagForLanguageCode(lang_id) or None # noqa results_content.append({ "title": _( u'edit_translation', default=u"Edit ${lang_name}", mapping={"lang_name": lang_name} ), "description": _( u"description_babeledit_menu", default=u"Edit {lang_name} with the two-column translation view", # noqa mapping={"lang_name": lang_name} ), "action": (urls.getTerm(lang_id).title + "/" + translation_view), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": {"id": "babel_edit_%s" % lang_id, "separator": None, "class": "contentmenuflags"}, "submenu": None, }) # Manage content translations results_content.append({ "title": _(u"title_modify_translations", default=u"Manage translations"), "description": _( u"description_modify_translations", default=u"Add or delete translations" ), "action": content_url + "/modify_translations", "selected": False, "icon": None, "extra": { "id": "_modify_translations", "separator": None, "class": "" }, "submenu": None, }) # Universal link if content_translation_group: results_content.append({ "title": _( u"universal_link", default=u"Universal link" ), "description": _( u"description_universal_link", default=u"Universal link to the content in user's preferred language" # noqa ), "action": "%s/@@multilingual-universal-link/%s" % ( site_url, content_translation_group), "selected": False, "icon": None, "extra": { "id": "_universal_link", "separator": None, "class": "" }, "submenu": None, }) if results_folder and results_content: # Item translations separator results.append({ 'title': _( u'title_translate_current_item', default=u'Item translation' ), 'description': '', 'action': None, 'selected': False, 'icon': None, 'extra': {'id': 'translateItemHeader', 'separator': 'actionSeparator', 'class': ''}, 'submenu': None, }) results.extend(results_content) # Language independent assets folder if assets_folder_url: results.append({ "title": _( u"shared_folder", default=u"Open ${title} folder", mapping={"title": assets_folder_title} ), "description": _( u"description_shared_folder", default=u"Open the language independent assets folder" ), "action": assets_folder_url, "selected": False, "icon": None, "extra": { "id": "_shared_folder", "separator": results and 'actionSeparator' or None, "class": ""}, "submenu": None, }) # User preferred language root folder if not folder_translatable and not content_translatable: results.append({ "title": _( u"language_folder", default=u"Return to language folder" ), "description": _( u"description_language_folder", default=u"Go to the user's browser preferred language " u"related folder" ), "action": site_url + '/' + language_tool.getPreferredLanguage(), # noqa "selected": False, "icon": None, "extra": { "id": "_language_folder", "separator": ( (results and not assets_folder_url) and 'actionSeparator' or None ), "class": "" }, "submenu": None, }) return results
def test_archetype_provides_interface_when_located_in_lrf(self): sample_id = self.lrf_de.invokeFactory('Document', 'd1') sample = self.lrf_de[sample_id] self.assertTrue(ITranslatable.providedBy(sample))
def getMenuItems(self, context, request): """Return menu item entries in a TAL-friendly form. """ # Settings site_url = getSite().absolute_url() language_tool = getToolByName(context, "portal_languages") show_flags = language_tool.showFlags try: lang_names = request.locale.displayNames.languages except AttributeError: lang_names = {} registry = getUtility(IRegistry) settings = registry.forInterface(IMultiLanguageExtraOptionsSchema, prefix="plone") if settings.redirect_babel_view: translation_view = 'babel_edit' else: translation_view = 'edit' # Content content = context content_url = context.absolute_url() content_language = ILanguage(content).get_language() content_translatable = not (content_language == LANGUAGE_INDEPENDENT or is_language_independent(content) or ILanguageRootFolder.providedBy(content)) content_translated = translated_languages(content) content_untranslated = untranslated_languages(content) content_translation_group = ITG(content, '') if not ITranslatable.providedBy(content): content = None # Folder when content is default page folder = aq_parent(context) if not is_default_page(folder, context): folder = None if folder and ITranslatable.providedBy(folder): # noqa folder_url = folder.absolute_url() folder_language = ILanguage(folder).get_language() folder_translatable = not (folder_language == LANGUAGE_INDEPENDENT or is_language_independent(folder) or ILanguageRootFolder.providedBy(folder)) folder_translated = translated_languages(folder) folder_untranslated = untranslated_languages(folder) folder_translation_group = ITG(folder, '') else: folder_url = '' folder_language = '' folder_translatable = False folder_translated = [] folder_untranslated = [] folder_translation_group = '' # Assets folder assets_folder_url = None assets_folder_title = None pc = getToolByName(getSite(), 'portal_catalog') results = pc.unrestrictedSearchResults( portal_type='LIF', Language=ILanguage(context).get_language()) for brain in results: assets_folder_url = brain.getURL() + '/folder_contents' assets_folder_title = safe_unicode(brain.Title) break # Menu items results = [] results_folder = [] results_content = [] if folder_translatable: # Folder translation view lang_name = lang_names.get(folder_language, folder_language) results_folder.append({ "title": _(u'edit_translation', default=u"Edit ${lang_name}", mapping={"lang_name": lang_name}), "description": _( u"description_babeledit_menu", default= u"Edit {lang_name} with the two-column translation view", # noqa mapping={"lang_name": lang_name}), "action": folder_url + "/" + translation_view, "selected": False, "icon": None, "extra": { "id": "_edit_folder_babel_edit", "separator": None, "class": "", }, "submenu": None, }) if folder and folder_untranslated and False: # disabled in favor of cut & paste # noqa # Set folder language results_folder.append({ "title": _(u'title_set_language', default=u"Change content language"), "description": _( u"description_set_language", default= u"Move the translation under another language folder" # noqa ), "action": folder_url + "/update_language", "selected": False, "icon": None, "extra": { "id": "_set_folder_language", "separator": None, "class": "" }, "submenu": None, }) if folder_translatable: for idx, lang in enumerate(folder_untranslated): lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = show_flags and language_tool.getFlagForLanguageCode( lang_id) or None # noqa results_folder.append({ "title": _(u'create_translation', default=u"Create ${lang_name}", mapping={"lang_name": lang_name}), "description": _(u"description_translate_into", default=u"Translate into ${lang_name}", mapping={"lang_name": lang_name}), "action": "%s/@@create_translation?language=%s" % (folder_url, lang_id), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": { "id": "translate_folder_into_%s" % lang_id, "separator": None, "class": "contentmenuflags" }, "submenu": None, }) urls = translated_urls(folder) for lang in folder_translated: if lang.value not in urls.by_token: # omit if translation is not permitted to access. continue lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = show_flags and language_tool.getFlagForLanguageCode( lang_id) or None # noqa results_folder.append({ "title": _(u'edit_translation', default=u"Edit ${lang_name}", mapping={"lang_name": lang_name}), "description": _( u"description_babeledit_menu", default= u"Edit {lang_name} with the two-column translation view", # noqa mapping={"lang_name": lang_name}), "action": (urls.getTerm(lang_id).title + "/" + translation_view), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": { "id": "babel_edit_%s" % lang_id, "separator": None, "class": "contentmenuflags" }, "submenu": None, }) # Manage folder translations results_folder.append({ "title": _(u"title_modify_translations", default=u"Manage translations"), "description": _(u"description_modify_translations", default=u"Add or delete translations"), "action": folder_url + "/modify_translations", "selected": False, "icon": None, "extra": { "id": "_modify_folder_translations", "separator": None, "class": "" }, "submenu": None, }) # Universal link if folder_translation_group: results_folder.append({ "title": _(u"universal_link", default=u"Universal link"), "description": _( u"description_universal_link", default= u"Universal link to the content in user's preferred language" # noqa ), "action": "%s/@@multilingual-universal-link/%s" % (site_url, folder_translation_group), "selected": False, "icon": None, "extra": { "id": "_universal_folder_link", "separator": None, "class": "" }, "submenu": None, }) if results_folder: # Folder translation separator results.append({ 'title': _(u'title_translate_current_folder', default=u'Folder translation'), 'description': '', 'action': None, 'selected': False, 'icon': None, 'extra': { 'id': 'translateFolderHeader', 'separator': 'actionSeparator', 'class': 'plone-toolbar-submenu-header' }, 'submenu': None, }) results.extend(results_folder) lang_name = lang_names.get(content_language, content_language) # Content language if content_untranslated and False: # disabled in favor of cut & paste results_content.append({ "title": _(u"title_set_language", default=u"Change content language"), "description": _( u"description_set_language", default= u"Move the translation under another language folder" # noqa ), "action": content_url + "/update_language", "selected": False, "icon": None, "extra": { "id": "_set_language", "separator": None, "class": "" }, "submenu": None, }) if content_translatable: # Content translation view results_content.append({ "title": _(u'edit_translation', default=u"Edit ${lang_name}", mapping={"lang_name": lang_name}), "description": _( u"description_babeledit_menu", default= u"Edit {lang_name} with the two-column translation view", # noqa mapping={"lang_name": lang_name}), "action": content_url + "/" + translation_view, "selected": False, "icon": None, "extra": { "id": "_edit_babel_edit", "separator": None, "class": "", }, "submenu": None, }) if content_translatable: for idx, lang in enumerate(content_untranslated): lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = show_flags and language_tool.getFlagForLanguageCode( lang_id) or None # noqa results_content.append({ "title": _(u'create_translation', default=u"Create ${lang_name}", mapping={"lang_name": lang_name}), "description": _(u"description_translate_into", default=u"Translate into ${lang_name}", mapping={"lang_name": lang_name}), "action": "%s/@@create_translation?language=%s" % (content_url, lang_id), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": { "id": "translate_into_%s" % lang_id, "separator": None, "class": "contentmenuflags" }, "submenu": None, }) urls = translated_urls(content) for lang in content_translated: if lang.value not in urls.by_token: # omit if translation is not permitted to access. continue lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = show_flags and language_tool.getFlagForLanguageCode( lang_id) or None # noqa results_content.append({ "title": _(u'edit_translation', default=u"Edit ${lang_name}", mapping={"lang_name": lang_name}), "description": _( u"description_babeledit_menu", default= u"Edit {lang_name} with the two-column translation view", # noqa mapping={"lang_name": lang_name}), "action": (urls.getTerm(lang_id).title + "/" + translation_view), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": { "id": "babel_edit_%s" % lang_id, "separator": None, "class": "contentmenuflags" }, "submenu": None, }) # Manage content translations results_content.append({ "title": _(u"title_modify_translations", default=u"Manage translations"), "description": _(u"description_modify_translations", default=u"Add or delete translations"), "action": content_url + "/modify_translations", "selected": False, "icon": None, "extra": { "id": "_modify_translations", "separator": None, "class": "" }, "submenu": None, }) # Universal link if content_translation_group: results_content.append({ "title": _(u"universal_link", default=u"Universal link"), "description": _( u"description_universal_link", default= u"Universal link to the content in user's preferred language" # noqa ), "action": "%s/@@multilingual-universal-link/%s" % (site_url, content_translation_group), "selected": False, "icon": None, "extra": { "id": "_universal_link", "separator": None, "class": "" }, "submenu": None, }) if results_folder and results_content: # Item translations separator results.append({ 'title': _(u'title_translate_current_item', default=u'Item translation'), 'description': '', 'action': None, 'selected': False, 'icon': None, 'extra': { 'id': 'translateItemHeader', 'separator': 'actionSeparator', 'class': '' }, 'submenu': None, }) results.extend(results_content) # Language independent assets folder if assets_folder_url: results.append({ "title": _(u"shared_folder", default=u"Open ${title} folder", mapping={"title": assets_folder_title}), "description": _(u"description_shared_folder", default=u"Open the language independent assets folder"), "action": assets_folder_url, "selected": False, "icon": None, "extra": { "id": "_shared_folder", "separator": results and 'actionSeparator' or None, "class": "" }, "submenu": None, }) # User preferred language root folder if not folder_translatable and not content_translatable: results.append({ "title": _(u"language_folder", default=u"Return to language folder"), "description": _(u"description_language_folder", default=u"Go to the user's browser preferred language " u"related folder"), "action": site_url + '/' + language_tool.getPreferredLanguage(), # noqa "selected": False, "icon": None, "extra": { "id": "_language_folder", "separator": ((results and not assets_folder_url) and 'actionSeparator' or None), "class": "" }, "submenu": None, }) return results
def getClosestDestination(self): """Get the "closest translated object" URL. """ # We should 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 site = getSite() root = getToolByName(site, 'portal_url') ltool = getToolByName(site, 'portal_languages') # We are using TranslationManager to get the translations of a # string tg try: manager = TranslationManager(self.tg) languages = manager.get_translations() except AttributeError: languages = [] 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 preferred language translation # Otherwise we get the first as context to look for translation prefered = ltool.getPreferredLanguage(self.request) if prefered in languages: context = languages[prefered] else: context = languages[list(languages.keys())[0]] checkPermission = getSecurityManager().checkPermission chain = self.getParentChain(context) for item in chain: if ISiteRoot.providedBy(item) \ and not ILanguageRootFolder.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 getMenuItems(self, context, request): """Return menu item entries in a TAL-friendly form. """ try: lang_names = request.locale.displayNames.languages except AttributeError: lang_names = {} menu = [] url = context.absolute_url() lt = getToolByName(context, "portal_languages") site_url = getSite().absolute_url() showflags = lt.showFlags context_id = ITranslationManager(context).tg registry = getUtility(IRegistry) settings = registry.forInterface(IMultiLanguageExtraOptionsSchema, prefix="plone") edit_view = 'babel_edit' if settings.redirect_babel_view else 'edit' # In case is neutral language show set language menu only is_neutral_content = (ILanguage(context).get_language() == LANGUAGE_INDEPENDENT or is_language_independent(context)) shared_folder_url = site_url + '/folder_contents' pc = getToolByName(getSite(), 'portal_catalog') results = pc.unrestrictedSearchResults( portal_type='LIF', Language=ILanguage(context).get_language()) for brain in results: shared_folder_url = brain.getURL() + '/folder_contents' if not is_neutral_content and not INavigationRoot.providedBy(context): menu.append({ "title": _(u"title_babel_edit", default=u"Edit with babel view"), "description": _(u"description_babel_edit", default=u"Edit with the babel_edit"), "action": url + "/" + edit_view, "selected": False, "icon": None, "extra": { "id": "_edit_babel_edit", "separator": None, "class": "", }, "submenu": None, }) if ITranslatable.providedBy(context): contexts = [ context, ] else: contexts = [] prt = aq_parent(context) if is_default_page(prt, context) and ITranslatable.providedBy(prt): contexts.append(prt) for idx, context in enumerate(contexts): url = context.absolute_url() ulangs = untranslated_languages(context) for lang in ulangs: lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = showflags and lt.getFlagForLanguageCode(lang_id)\ or None item = { "description": _(u"description_translate_into", default=u"Translate into ${lang_name}", mapping={"lang_name": lang_name}), "action": "%s/@@create_translation?language=%s" % (url, lang_id), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": { "id": "translate_into_%s" % lang_id, "separator": None, "class": "contentmenuflags" }, "submenu": None, } item['title'] = idx and _( u'create_translation_folder', default=u"Create ${lang_name} folder", mapping={"lang_name": lang_name}) or _( u'create_translation', default=u"Create ${lang_name}", mapping={"lang_name": lang_name}) menu.append(item) langs = translated_languages(context) urls = translated_urls(context) for lang in langs: if lang.value not in urls.by_token: # omit if translation is not permitted to access. continue lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = showflags and lt.getFlagForLanguageCode(lang_id)\ or None item = { "description": _(u"description_babeledit_menu", default=u"Babel edit ${lang_name}", mapping={"lang_name": lang_name}), "action": (urls.getTerm(lang_id).title + "/" + edit_view), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": { "id": "babel_edit_%s" % lang_id, "separator": None, "class": "contentmenuflags" }, "submenu": None, } item['title'] = idx and _( u'edit_translation_folder', default=u"Edit ${lang_name} folder", mapping={"lang_name": lang_name}) or _( u'edit_translation', default=u"Edit ${lang_name}", mapping={"lang_name": lang_name}) menu.append(item) item = { "description": _(u"description_add_translations", default=u"Add existing content as translation"), "action": url + "/add_translations", "selected": False, "icon": None, "extra": { "id": "_add_translations", "separator": langs and "actionSeparator" or None, "class": "" }, "submenu": None, } item['title'] = idx and _( u"title_add_translations_folder", default=u"Add translations for folder...") or _( u"title_add_translations", default=u"Add translations...") menu.append(item) item = { "title": _(u"title_remove_translations", default=u"Remove translations..."), "description": _(u"description_remove_translations", default=u"Delete translations or remove the relations"), "action": url + "/remove_translations", "selected": False, "icon": None, "extra": { "id": "_remove_translations", "separator": langs and "actionSeparator" or None, "class": "" }, "submenu": None, } menu.append(item) elif is_neutral_content: menu.append({ "title": _(u"language_folder", default=u"Return to language folder"), "description": _(u"description_language_folder", default=u"Go to the user's browser preferred language " u"related folder"), "action": site_url + '/' + lt.getPreferredLanguage(), "selected": False, "icon": None, "extra": { "id": "_shared_folder", "separator": None, "class": "" }, "submenu": None, }) if not is_neutral_content: menu.append({ "title": _(u"universal_link", default=u"Universal Link"), "description": _(u"description_universal_link", default=u"Universal Language content link"), "action": "%s/@@multilingual-universal-link/%s" % (site_url, context_id), "selected": False, "icon": None, "extra": { "id": "_universal_link", "separator": None, "class": "" }, "submenu": None, }) menu.append({ "title": _(u"shared_folder", default=u"Go to shared folder"), "description": _(u"description_shared_folder", default=u"Show the language shared (neutral language) " u"folder"), "action": shared_folder_url, "selected": False, "icon": None, "extra": { "id": "_shared_folder", "separator": None, "class": "" }, "submenu": None, }) menu.append({ "title": _(u"title_set_language", default=u"Set content language"), "description": _(u"description_set_language", default=u"Set or change the current content language"), "action": url + "/update_language", "selected": False, "icon": None, "extra": { "id": "_set_language", "separator": None, "class": "" }, "submenu": None, }) return menu
def getMenuItems(self, context, request): """Return menu item entries in a TAL-friendly form. """ try: lang_names = request.locale.displayNames.languages except AttributeError: lang_names = {} menu = [] url = context.absolute_url() lt = getToolByName(context, "portal_languages") site_url = getSite().absolute_url() showflags = lt.showFlags context_id = ITranslationManager(context).tg registry = getUtility(IRegistry) settings = registry.forInterface(IMultiLanguageExtraOptionsSchema, prefix="plone") edit_view = 'babel_edit' if settings.redirect_babel_view else 'edit' # In case is neutral language show set language menu only is_neutral_content = ( ILanguage(context).get_language() == LANGUAGE_INDEPENDENT or is_language_independent(context) ) shared_folder_url = site_url + '/folder_contents' pc = getToolByName(getSite(), 'portal_catalog') results = pc.unrestrictedSearchResults( portal_type='LIF', Language=ILanguage(context).get_language()) for brain in results: shared_folder_url = brain.getURL() + '/folder_contents' if not is_neutral_content and not INavigationRoot.providedBy(context): menu.append({ "title": _( u"title_babel_edit", default=u"Edit with babel view" ), "description": _( u"description_babel_edit", default=u"Edit with the babel_edit" ), "action": url + "/" + edit_view, "selected": False, "icon": None, "extra": { "id": "_edit_babel_edit", "separator": None, "class": "", }, "submenu": None, }) if ITranslatable.providedBy(context): contexts = [context, ] else: contexts = [] prt = aq_parent(context) if isDefaultPage(prt, context) and ITranslatable.providedBy(prt): contexts.append(prt) for idx, context in enumerate(contexts): url = context.absolute_url() ulangs = untranslated_languages(context) for lang in ulangs: lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = showflags and lt.getFlagForLanguageCode(lang_id)\ or None item = { "description": _( u"description_translate_into", default=u"Translate into ${lang_name}", mapping={"lang_name": lang_name} ), "action": "%s/@@create_translation?language=%s" % ( url, lang_id), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": {"id": "translate_into_%s" % lang_id, "separator": None, "class": "contentmenuflags"}, "submenu": None, } item['title'] = idx and _( u'create_translation_folder', default=u"Create ${lang_name} folder", mapping={"lang_name": lang_name} ) or _( u'create_translation', default=u"Create ${lang_name}", mapping={"lang_name": lang_name} ) menu.append(item) langs = translated_languages(context) urls = translated_urls(context) for lang in langs: if lang.value not in urls.by_token: # omit if translation is not permitted to access. continue lang_name = lang_names.get(lang.value, lang.title) lang_id = lang.value icon = showflags and lt.getFlagForLanguageCode(lang_id)\ or None item = { "description": _( u"description_babeledit_menu", default=u"Babel edit ${lang_name}", mapping={"lang_name": lang_name} ), "action": (urls.getTerm(lang_id).title + "/" + edit_view), "selected": False, "icon": icon, "width": "14", "height": "11", "extra": {"id": "babel_edit_%s" % lang_id, "separator": None, "class": "contentmenuflags"}, "submenu": None, } item['title'] = idx and _( u'edit_translation_folder', default=u"Edit ${lang_name} folder", mapping={"lang_name": lang_name} ) or _( u'edit_translation', default=u"Edit ${lang_name}", mapping={"lang_name": lang_name} ) menu.append(item) item = { "description": _( u"description_add_translations", default=u"Add existing content as translation"), "action": url + "/add_translations", "selected": False, "icon": None, "extra": { "id": "_add_translations", "separator": langs and "actionSeparator" or None, "class": "" }, "submenu": None, } item['title'] = idx and _( u"title_add_translations_folder", default=u"Add translations for folder..." ) or _( u"title_add_translations", default=u"Add translations..." ) menu.append(item) item = { "title": _( u"title_remove_translations", default=u"Remove translations..." ), "description": _( u"description_remove_translations", default=u"Delete translations or remove the relations" ), "action": url + "/remove_translations", "selected": False, "icon": None, "extra": { "id": "_remove_translations", "separator": langs and "actionSeparator" or None, "class": "" }, "submenu": None, } menu.append(item) elif is_neutral_content: menu.append({ "title": _( u"language_folder", default=u"Return to language folder" ), "description": _( u"description_language_folder", default=u"Go to the user's browser preferred language " u"related folder" ), "action": site_url + '/' + lt.getPreferredLanguage(), "selected": False, "icon": None, "extra": { "id": "_shared_folder", "separator": None, "class": "" }, "submenu": None, }) if not is_neutral_content: menu.append({ "title": _( u"universal_link", default=u"Universal Link" ), "description": _( u"description_universal_link", default=u"Universal Language content link" ), "action": "%s/@@multilingual-universal-link/%s" % ( site_url, context_id), "selected": False, "icon": None, "extra": { "id": "_universal_link", "separator": None, "class": "" }, "submenu": None, }) menu.append({ "title": _( u"shared_folder", default=u"Go to shared folder" ), "description": _( u"description_shared_folder", default=u"Show the language shared (neutral language) " u"folder" ), "action": shared_folder_url, "selected": False, "icon": None, "extra": { "id": "_shared_folder", "separator": None, "class": ""}, "submenu": None, }) menu.append({ "title": _( u"title_set_language", default=u"Set content language" ), "description": _( u"description_set_language", default=u"Set or change the current content language" ), "action": url + "/update_language", "selected": False, "icon": None, "extra": { "id": "_set_language", "separator": None, "class": "" }, "submenu": None, }) return menu