def _get_user_perms(self, user, project, resource, language, team, checksum, is_maintainer): """ Get permissions for a user. Args: user: A User instance project: A Project instance resource: A Resource instance language: A Language instance team: A Team instance checksum: An md5 checksum representing a source entity is_maintiner: A boolean Returns: A dictionary containing various user permissions """ check = ProjectPermission(user) can_review = check.proofread(project, language) can_submit_translations = check.submit_translations( team or resource.project) accept_translations = resource.accept_translations return { 'can_review': can_review, 'can_submit_translations': can_submit_translations, 'accept_translations': accept_translations, 'is_maintainer': check.maintain(project), }
def cla_project_sign(request, project_slug): project = get_object_or_404(Project, slug=project_slug) cla = get_object_or_404(Cla, project=project) check = ProjectPermission(request.user) if not check.submit_translations(project, any_team=True): return permission_denied(request) try: signed_cla = request.user.cla_set.filter(project=project)[0] except IndexError: signed_cla = None if request.method == "POST" and not signed_cla: form = ClaForm(request.POST) if form.is_valid(): kwargs = {"cla_sign": True, "project": project, "user": request.user} handle_pre_team(None, **kwargs) messages.success(request, _("You have signed the CLA.")) return HttpResponseRedirect(reverse("cla_project_sign", args=[project_slug])) else: form = ClaForm() return render_to_response( "project_cla.html", {"project": project, "cla": cla, "signed_cla": signed_cla, "form": form}, context_instance=RequestContext(request), )
def _update(self, request, project_slug, resource_slug, lang_code=None): # Permissions handling try: resource = Resource.objects.get( slug=resource_slug, project__slug=project_slug ) except Resource.DoesNotExist: return rc.NOT_FOUND if lang_code == "source": language = resource.source_language else: try: language = Language.objects.by_code_or_alias(lang_code) except Language.DoesNotExist: logger.error("Weird! Selected language code (%s) does " "not match with any language in the database." % lang_code) return BAD_REQUEST( "Selected language code (%s) does not match with any" "language in the database." % lang_code ) team = Team.objects.get_or_none(resource.project, lang_code) check = ProjectPermission(request.user) if (not check.submit_translations(team or resource.project) or\ not resource.accept_translations) and not\ check.maintain(resource.project): return rc.FORBIDDEN try: t = Translation.get_object("create", request, resource, language) res = t.create() except BadRequestError, e: return BAD_REQUEST(unicode(e))
def lock_and_get_translation_file(request, project_slug, resource_slug, lang_code): """ Lock and download the translations file. View to lock a resource for the requested language and as a second step to download (export+download) the translations in a formatted file. """ resource = get_object_or_404(Resource, project__slug = project_slug, slug = resource_slug) # Permissions handling # Project should always be available project = get_object_or_404(Project, slug=project_slug) team = Team.objects.get_or_none(project, lang_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) or not \ resource.accept_translations: return permission_denied(request) language = get_object_or_404(Language, code=lang_code) lock = Lock.objects.get_valid(resource, language) can_lock = Lock.can_lock(resource, language, request.user) response = {} if not can_lock: #print_gray_text(You cannot assign this file to you) response['status'] = "FAILED" response['message'] = _("Sorry, you cannot lock this file!") else: # User can lock if not lock: try: # Lock the resource now Lock.objects.create_update(resource, language, request.user) response['status'] = 'OK' response['redirect'] = reverse('download_for_translation', args=[resource.project.slug, resource.slug, lang_code]) except: response['status'] = "FAILED" response['message'] = _("Failed to lock the resource!") else: if lock.owner == request.user: try: # File already locked by me, so extend the lock period. Lock.objects.create_update(resource, language, request.user) response['status'] = 'OK' response['redirect'] = reverse('download_for_translation', args=[resource.project.slug, resource.slug, lang_code]) except: response['status'] = "FAILED" response['message'] = _("Failed to extend lock period on " "the resource!") else: # File locked by someone else: response['status'] = "FAILED" response['message'] = _("You cannot lock it right now! (Locked " "by %s )" % (lock.owner,)) return HttpResponse(simplejson.dumps(response), mimetype='application/json')
def exit(request, project_slug, lang_code, resource_slug=None, *args, **kwargs): """ Exiting Lotte """ if request.method != 'POST': return HttpResponse(status=405) # Permissions handling # Project should always be available project = get_object_or_404(Project, slug=project_slug) team = Team.objects.get_or_none(project, lang_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) and not\ check.maintain(project): return permission_denied(request) language = Language.objects.by_code_or_alias(lang_code) resources = [] if resource_slug: resources = Resource.objects.filter(slug=resource_slug, project=project) if not resources: raise Http404 else: resources = Resource.objects.filter(project=project) data = simplejson.loads(request.raw_post_data) if data.get('updated'): modified = True # ActionLog & Notification for resource in resources: nt = 'project_resource_translated' context = {'project': project, 'resource': resource, 'language': language, 'sender': request.user} object_list = [project, resource, language] if team: object_list.append(team) action_logging(request.user, object_list, nt, context=context) else: modified = False lotte_done.send(None, request=request, resources=resources, language=language, modified=modified) redirect_url = reverse('team_detail', args=[project_slug, language.code]) if request.is_ajax(): json = simplejson.dumps(dict(redirect=redirect_url)) return HttpResponse(json, mimetype='application/json') return HttpResponseRedirect(redirect_url)
def can_lock(resource, language, user): """ Perform permission check whether 'user' can create a Lock. CAUTION: It does not perform lock counting check! """ perm = ProjectPermission(user) if resource.accept_translations and ( perm.submit_translations(resource.project, language) or perm.coordinate_team(project=resource.project, language=language)): return True return False
def update(self, request, project_slug, resource_slug, language_code, api_version=2): """ Update existing translations for multiple source entities of a resource at one go by permitted user(s). """ try: project, resource, language = \ self._requested_objects( project_slug, resource_slug, language_code) self._validate_language_is_not_source_language( project.source_language, language) translations = request.data self._validate_translations_json_data(translations) team = Team.objects.get_or_none(project, language.code) check = ProjectPermission(request.user) # User must be a member of the project is_maintainer = check.maintain(project) # Allow only project members to issue this update request if not is_maintainer and not (check.submit_translations( team or project) or check.proofread(project, language)): return FORBIDDEN_REQUEST( "You are not allowed to update translations.") trans_obj_dict = self._translations_as_dict( translations, resource, language) updated_translations = [] se_ids = [] for translation in translations: # All permission checks for a user is done here and # updated translations are collected in updated_tranlsations # and source_entity.id in se_ids self._process_translation_dict(translation, project, resource, language, team, check, is_maintainer, request.user, se_ids, updated_translations, trans_obj_dict) self._update_translations(updated_translations) keys = ['key', 'context', 'translation', 'reviewed', 'pluralized', 'wordcount', 'last_update', 'user', 'position', 'occurrences',] field_map, fields = self._get_update_fieldmap_and_fields(keys) return self._generate_translations_dict( Translation.objects.filter( source_entity__id__in=se_ids, language=language).values(*fields), field_map) except NotFoundError, e: return NOT_FOUND_REQUEST(unicode(e))
def exit(request, project_slug, lang_code, resource_slug=None, *args, **kwargs): """ Exiting Lotte """ # Permissions handling # Project should always be available project = get_object_or_404(Project, slug=project_slug) team = Team.objects.get_or_none(project, lang_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) and not\ check.maintain(project): return permission_denied(request) language = Language.objects.by_code_or_alias(lang_code) resources = [] if resource_slug: resources = Resource.objects.filter(slug=resource_slug, project=project) if not resources: raise Http404 url = reverse('resource_detail', args=[project_slug, resource_slug]) else: resources = Resource.objects.filter(project=project) url = reverse('project_detail', args=[project_slug]) if request.POST.get('updated', None) == 'true': modified = True # ActionLog & Notification for resource in resources: nt = 'project_resource_translated' context = {'project': project, 'resource': resource, 'language': language} object_list = [project, resource, language] action_logging(request.user, object_list, nt, context=context) if settings.ENABLE_NOTICES: txnotification.send_observation_notices_for(project, signal=nt, extra_context=context) else: modified = False lotte_done.send(None, request=request, resources=resources, language=language, modified=modified) if request.is_ajax(): json = simplejson.dumps(dict(redirect=url)) return HttpResponse(json, mimetype='application/json') return HttpResponseRedirect(url)
def update(self, request, project_slug, resource_slug, language_code, source_hash, api_version=2): """ Update existing translations for a source entity of a resource. """ try: project, resource, language = \ self._requested_objects(project_slug, resource_slug, language_code) # A translation in source language cannot be updated self._validate_language_is_not_source_language( project.source_language, language) try: source_entity = SourceEntity.objects.get( string_hash=source_hash, resource=resource) except SourceEntity.DoesNotExist, e: return rc.NOT_FOUND team = Team.objects.get_or_none(project, language.code) data = request.data # This is a hack to use the methods from TranslationObjectsHandler data['source_entity_hash'] = source_hash check = ProjectPermission(request.user) is_maintainer = check.maintain(project) # Allow only project members to issue this update request if not is_maintainer and not (check.submit_translations( team or project) or check.proofread(project, language)): return FORBIDDEN_REQUEST( "You are not allowed to update translations.") trans_obj_dict = self._translations_as_dict( [data], resource, language) if not trans_obj_dict: return rc.NOT_FOUND updated_translations = [] se_ids = [] # All permission checks for a user is done here and # updated translations are collected in updated_tranlsations # and source_entity.id in se_ids self._process_translation_dict(data, project, resource, language, team, check, is_maintainer, request.user, se_ids, updated_translations, trans_obj_dict) # Updated translations are saved to db self._update_translations(updated_translations) translations = Translation.objects.filter( source_entity=source_entity, language=language) field_map = self._get_fieldmap() fields = self._get_fields_for_translation_value_query_set(field_map) return self._generate_translations_dict( Translation.objects.filter( source_entity__id__in=se_ids, language=language).values(*fields), field_map, True)
def clone_language(request, project_slug=None, resource_slug=None, source_lang_code=None, target_lang_code=None): ''' Get a resource, a src lang and a target lang and clone all translation strings for the src to the target. The user is redirected to the online editor for the target language. ''' resource = get_object_or_404(Resource, slug=resource_slug, project__slug=project_slug) # Permissions handling # Project should always be available project = get_object_or_404(Project, slug=project_slug) team = Team.objects.get_or_none(project, target_lang_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) or not \ resource.accept_translations: return permission_denied(request) source_lang = get_object_or_404(Language, code=source_lang_code) target_lang = get_object_or_404(Language, code=target_lang_code) # get the strings which will be cloned strings = Translation.objects.filter(resource=resource, language=source_lang) # If the language we want to create, has the same plural rules with the # source, we also copy the pluralized translations! if not source_lang.get_pluralrules() == target_lang.get_pluralrules(): strings = strings.exclude(source_entity__pluralized=True) # clone them in new translation for s in strings: Translation.objects.get_or_create(language=target_lang, string=s.string, source_entity=s.source_entity, rule=s.rule, resource=s.resource) invalidate_stats_cache(resource, target_lang, user=request.user) return HttpResponseRedirect( reverse('translate_resource', args=[project_slug, resource_slug, target_lang_code]), )
def clone_language(request, project_slug=None, resource_slug=None, source_lang_code=None, target_lang_code=None): ''' Get a resource, a src lang and a target lang and clone all translation strings for the src to the target. The user is redirected to the online editor for the target language. ''' resource = get_object_or_404(Resource, slug=resource_slug, project__slug=project_slug) # Permissions handling # Project should always be available project = get_object_or_404(Project, slug=project_slug) team = Team.objects.get_or_none(project, target_lang_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) or not \ resource.accept_translations: return permission_denied(request) source_lang = get_object_or_404(Language, code=source_lang_code) target_lang = get_object_or_404(Language, code=target_lang_code) # get the strings which will be cloned strings = Translation.objects.filter( resource = resource, language = source_lang) # If the language we want to create, has the same plural rules with the # source, we also copy the pluralized translations! if not source_lang.get_pluralrules() == target_lang.get_pluralrules(): strings = strings.exclude(source_entity__pluralized = True) # clone them in new translation for s in strings: Translation.objects.get_or_create( language=target_lang, string=s.string, source_entity=s.source_entity, rule=s.rule, resource=s.resource ) invalidate_stats_cache(resource, target_lang, user=request.user) return HttpResponseRedirect(reverse('translate_resource', args=[project_slug, resource_slug, target_lang_code]),)
def update_translation(request, project_slug, resource_slug, lang_code=None): """Ajax view that gets an uploaded translation as a file and saves it. If the language is not specified, the translation does not exist yet. Othewise, this is an update. Returns: Either an error message, or nothing for success. """ resource = get_object_or_404( Resource.objects.select_related('project'), project__slug=project_slug, slug=resource_slug ) if lang_code is None: lang_code = request.POST.get('language_code', None) target_language = get_object_or_404(Language, code=lang_code) project = resource.project # Get the team if exists to use it for permissions and links team = Team.objects.get_or_none(project, lang_code) check = ProjectPermission(request.user) if (not check.submit_translations(team or resource.project) or\ not resource.accept_translations) and not\ check.maintain(resource.project): return HttpResponse( simplejson.dumps({ 'msg': _("You are not allowed to upload a translation."), 'status': 403, }), status=403, content_type='text/plain' ) content = content_from_uploaded_file(request.FILES) try: _save_translation(resource, target_language, request.user, content) except FormatsBackendError, e: return HttpResponse( simplejson.dumps({ 'msg': unicode(e), 'status': 400, }), status=400, content_type='text/plain' )
def update_translation(request, project_slug, resource_slug, lang_code=None): """Ajax view that gets an uploaded translation as a file and saves it. If the language is not specified, the translation does not exist yet. Othewise, this is an update. Returns: Either an error message, or nothing for success. """ resource = get_object_or_404(Resource.objects.select_related('project'), project__slug=project_slug, slug=resource_slug) if lang_code is None: lang_code = request.POST.get('language_code', None) target_language = get_object_or_404(Language, code=lang_code) project = resource.project # Get the team if exists to use it for permissions and links team = Team.objects.get_or_none(project, lang_code) check = ProjectPermission(request.user) if (not check.submit_translations(team or resource.project) or\ not resource.accept_translations) and not\ check.maintain(resource.project): return HttpResponse(simplejson.dumps({ 'msg': _("You are not allowed to upload a translation."), 'status': 403, }), status=403, content_type='text/plain') content = content_from_uploaded_file(request.FILES) try: _save_translation(resource, target_language, request.user, content) except FormatsBackendError, e: return HttpResponse(simplejson.dumps({ 'msg': unicode(e), 'status': 400, }), status=400, content_type='text/plain')
def cla_project_sign(request, project_slug): project = get_object_or_404(Project, slug=project_slug) cla = get_object_or_404(Cla, project=project) check = ProjectPermission(request.user) if not check.submit_translations(project, any_team=True): return permission_denied(request) try: signed_cla = request.user.cla_set.filter(project=project)[0] except IndexError: signed_cla = None if request.method == 'POST' and not signed_cla: form = ClaForm(request.POST) if form.is_valid(): kwargs = { 'cla_sign': True, 'project': project, 'user': request.user } handle_pre_team(None, **kwargs) messages.success(request, _("You have signed the CLA.")) return HttpResponseRedirect( reverse('cla_project_sign', args=[project_slug]), ) else: form = ClaForm() return render_to_response("project_cla.html", { 'project': project, 'cla': cla, 'signed_cla': signed_cla, 'form': form }, context_instance=RequestContext(request))
def _update(self, request, project_slug, resource_slug, lang_code=None): # Permissions handling try: resource = Resource.objects.select_related('project').get( slug=resource_slug, project__slug=project_slug) except Resource.DoesNotExist: return rc.NOT_FOUND source_push = False if lang_code == "source": language = resource.source_language source_push = True else: try: language = Language.objects.by_code_or_alias(lang_code) except Language.DoesNotExist: logger.error("Weird! Selected language code (%s) does " "not match with any language in the database." % lang_code) return BAD_REQUEST( "Selected language code (%s) does not match with any" "language in the database." % lang_code) team = Team.objects.get_or_none(resource.project, lang_code) check = ProjectPermission(request.user) if source_push and not check.maintain(resource.project): return rc.FORBIDDEN elif (not check.submit_translations(team or resource.project) or\ not resource.accept_translations) and not\ check.maintain(resource.project): return rc.FORBIDDEN try: t = Translation.get_object("create", request, resource, language) res = t.create() except BadRequestError, e: return BAD_REQUEST(unicode(e))
def translate(request, project_slug, lang_code, resource_slug=None, *args, **kwargs): """ Main lotte view. """ # Permissions handling # Project should always be available project = get_object_or_404(Project, slug=project_slug) team = Team.objects.get_or_none(project, lang_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) and not\ check.maintain(project): return permission_denied(request) resources = [] if resource_slug: resource_list = [ get_object_or_404(Resource, slug=resource_slug, project=project) ] else: resource_list = Resource.objects.filter(project=project) # Return a page explaining that the project has multiple source langs and # cannot be translated as a whole. if resource_list.values('source_language').distinct().count() > 1: messages.info( request, _("There are multiple source languages for this project. " "You will only be able to translate resources for one " "source language at a time.")) return HttpResponseRedirect( reverse('project_detail', args=[project_slug]), ) # Filter resources that are not accepting translations for resource in resource_list: if resource.accept_translations: resources.append(resource) # If no resource accepting translations, raise a 403 if not resources: return permission_denied(request) target_language = Language.objects.by_code_or_alias_or_404(lang_code) # If it is an attempt to edit the source language, redirect the user to # resource_detail and show him a message explaining the reason. if target_language == get_source_language(resources): messages.error( request, _("Cannot edit the source language because this would " "result in translation mismatches! If you want to " "update the source strings consider using the transifex " "command-line client.")) if resource_slug: return HttpResponseRedirect( reverse('resource_detail', args=[project_slug, resource_slug]), ) else: return HttpResponseRedirect( reverse('project_detail', args=[project_slug]), ) total_strings = SourceEntity.objects.filter(resource__in=resources).count() translated_strings = Translation.objects.filter( resource__in=resources, language=target_language, source_entity__pluralized=False, rule=5).count() reviewed_strings = Translation.objects.filter( resource__in=resources, language=target_language, source_entity__pluralized=False, rule=5, reviewed=True).count() # Include counting of pluralized entities for pluralized_entity in SourceEntity.objects.filter( resource__in=resources, pluralized=True): plurals_translated = Translation.objects.filter( language=target_language, source_entity=pluralized_entity).count() if plurals_translated == len(target_language.get_pluralrules()): translated_strings += 1 if len(resources) > 1: translation_resource = None else: translation_resource = resources[0] contributors = User.objects.filter(pk__in=Translation.objects.filter( resource__in=resources, language=target_language, rule=5).values_list( "user", flat=True)) lotte_init.send(None, request=request, resources=resources, language=target_language) if target_language in [team.language for team in project.available_teams]: team_language = True else: team_language = False GtModel = get_model('gtranslate', 'Gtranslate') try: auto_translate = GtModel.objects.get(project=project) except GtModel.DoesNotExist: auto_translate = None """ if cache.get('lotte_%s' % request.session.session_key, None): cache.delete('lotte_%s' % request.session.session_key) """ #Set rtl to True if target_language is an RTL language rtl = False if target_language.code in settings.RTL_LANGUAGE_CODES: rtl = True return render_to_response("translate.html", { 'project': project, 'resource': translation_resource, 'target_language': target_language, 'translated_strings': translated_strings, 'reviewed_strings': reviewed_strings, 'untranslated_strings': total_strings - translated_strings, 'contributors': contributors, 'resources': resources, 'resource_slug': resource_slug, 'languages': Language.objects.all(), 'auto_translate': auto_translate, 'spellcheck_supported_langs': SPELLCHECK_SUPPORTED_LANGS, 'team_language': team_language, 'RTL': rtl, }, context_instance=RequestContext(request))
def lock_and_get_translation_file(request, project_slug, resource_slug, lang_code): """ Lock and download the translations file. View to lock a resource for the requested language and as a second step to download (export+download) the translations in a formatted file. """ resource = get_object_or_404(Resource, project__slug=project_slug, slug=resource_slug) # Permissions handling # Project should always be available project = get_object_or_404(Project, slug=project_slug) team = Team.objects.get_or_none(project, lang_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) or not \ resource.accept_translations: return permission_denied(request) language = get_object_or_404(Language, code=lang_code) lock = Lock.objects.get_valid(resource, language) can_lock = Lock.can_lock(resource, language, request.user) response = {} if not can_lock: #print_gray_text(You cannot assign this file to you) response['status'] = "FAILED" response['message'] = _("Sorry, you cannot lock this file!") else: # User can lock if not lock: try: # Lock the resource now Lock.objects.create_update(resource, language, request.user) response['status'] = 'OK' response['redirect'] = reverse( 'download_for_translation', args=[resource.project.slug, resource.slug, lang_code]) except: response['status'] = "FAILED" response['message'] = _("Failed to lock the resource!") else: if lock.owner == request.user: try: # File already locked by me, so extend the lock period. Lock.objects.create_update(resource, language, request.user) response['status'] = 'OK' response['redirect'] = reverse( 'download_for_translation', args=[resource.project.slug, resource.slug, lang_code]) except: response['status'] = "FAILED" response['message'] = _("Failed to extend lock period on " "the resource!") else: # File locked by someone else: response['status'] = "FAILED" response['message'] = _( "You cannot lock it right now! (Locked " "by %s )" % (lock.owner, )) return HttpResponse(simplejson.dumps(response), mimetype='application/json')
def update(self, request, project_slug, resource_slug, language_code=None, api_version=1): """ Update resource translations of a project by the UUID of a StorageFile. """ try: project = Project.objects.get(slug=project_slug) resource = Resource.objects.get(slug=resource_slug, project=project) except (Project.DoesNotExist, Resource.DoesNotExist): return rc.NOT_FOUND # Permissions handling team = Team.objects.get_or_none(project, language_code) check = ProjectPermission(request.user) if (not check.submit_translations(team or project) or not resource.accept_translations) and not check.maintain( project ): return rc.FORBIDDEN if "application/json" in request.content_type: if "uuid" in request.data: uuid = request.data["uuid"] storagefile = StorageFile.objects.get(uuid=uuid) language = storagefile.language logger.debug( "Going to insert strings from %s (%s) to %s/%s" % (storagefile.name, storagefile.uuid, project_slug, resource.slug) ) strings_added, strings_updated = 0, 0 parser = storagefile.find_parser() language = storagefile.language fhandler = parser(filename=storagefile.get_storage_path()) fhandler.set_language(language) fhandler.bind_resource(resource) fhandler.contents_check(fhandler.filename) try: fhandler.parse_file() strings_added, strings_updated = fhandler.save2db(user=request.user) except Exception, e: logger.error(e.message, exc_info=True) return BAD_REQUEST("Error importing file: %s" % e) else: messages = [] if strings_added > 0: messages.append(_("%i strings added") % strings_added) if strings_updated > 0: messages.append(_("%i strings updated") % strings_updated) retval = { "strings_added": strings_added, "strings_updated": strings_updated, "redirect": reverse("resource_detail", args=[project_slug, resource.slug]), } logger.debug("Extraction successful, returning: %s" % retval) # Set StorageFile to 'bound' status, which means that it is # bound to some translation resource storagefile.bound = True storagefile.save() # If any string added/updated if retval["strings_added"] > 0 or retval["strings_updated"] > 0: modified = True else: modified = False post_submit_translation.send( None, request=request, resource=resource, language=language, modified=modified ) return HttpResponse(simplejson.dumps(retval), mimetype="application/json") else: return BAD_REQUEST("Missing request data.")
def exit(request, project_slug, lang_code, resource_slug=None, *args, **kwargs): """ Exiting Lotte """ if request.method != 'POST': return HttpResponse(status=405) # Permissions handling # Project should always be available project = get_object_or_404(Project, slug=project_slug) team = Team.objects.get_or_none(project, lang_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) and not\ check.maintain(project): return permission_denied(request) language = Language.objects.by_code_or_alias(lang_code) resources = [] if resource_slug: resources = Resource.objects.filter(slug=resource_slug, project=project) if not resources: raise Http404 else: resources = Resource.objects.filter(project=project) data = simplejson.loads(request.raw_post_data) if data.get('updated'): modified = True # ActionLog & Notification for resource in resources: nt = 'project_resource_translated' context = { 'project': project, 'resource': resource, 'language': language, 'sender': request.user } object_list = [project, resource, language] if team: object_list.append(team) action_logging(request.user, object_list, nt, context=context) else: modified = False lotte_done.send(None, request=request, resources=resources, language=language, modified=modified) redirect_url = reverse('team_detail', args=[project_slug, language.code]) if request.is_ajax(): json = simplejson.dumps(dict(redirect=redirect_url)) return HttpResponse(json, mimetype='application/json') return HttpResponseRedirect(redirect_url)
def resource_translation_toggle_watch(request, project_slug, resource_slug, language_code): """Add/Remove a TranslationWatch for a specific user.""" if request.method != 'POST': return json_error(_('Must use POST to activate')) if not settings.ENABLE_NOTICES: return json_error(_('Notification is not enabled')) resource = get_object_or_404(Resource, slug=resource_slug, project__slug=project_slug) project = resource.project language = get_object_or_404(Language, code=language_code) team = Team.objects.get_or_none(project, language_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) and not \ check.maintain(project) and not \ request.user.has_perm('watches.add_translationwatch') and not \ request.user.has_perm('watches.delete_translationwatch'): return permission_denied(request) url = reverse('resource_translation_toggle_watch', args=(project_slug, resource_slug, language_code)) try: twatch = TranslationWatch.objects.get(resource=resource, language=language) result = { 'style': 'watch_add', 'title': _('Watch it'), 'id': twatch.id, 'url': url, 'error': None, } notification.stop_observing(twatch, request.user, signal='project_resource_translation_changed') except (TranslationWatch.DoesNotExist, notification.ObservedItem.DoesNotExist): try: twatch = TranslationWatch.objects.get_or_create(resource=resource, language=language)[0] result = { 'style': 'watch_remove', 'title': _('Stop watching'), 'id': twatch.id, 'url': url, 'error': None, } notification.observe(twatch, request.user, 'project_resource_translation_changed', signal='project_resource_translation_changed') except WatchException, e: return json_error(e.message, result)
def translate(request, project_slug, lang_code, resource_slug=None, *args, **kwargs): """ Main lotte view. """ # Permissions handling # Project should always be available project = get_object_or_404(Project, slug=project_slug) team = Team.objects.get_or_none(project, lang_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) and not\ check.maintain(project): return permission_denied(request) resources = [] if resource_slug: resource_list = [get_object_or_404(Resource, slug=resource_slug, project=project)] else: resource_list = Resource.objects.filter(project=project) # Return a page explaining that the project has multiple source langs and # cannot be translated as a whole. if resource_list.values('source_language').distinct().count() > 1: messages.info(request,_( "There are multiple source languages for this project. " "You will only be able to translate resources for one " "source language at a time.")) return HttpResponseRedirect(reverse('project_detail', args=[project_slug]),) # Filter resources that are not accepting translations for resource in resource_list: if resource.accept_translations: resources.append(resource) # If no resource accepting translations, raise a 403 if not resources: return permission_denied(request) target_language = Language.objects.by_code_or_alias_or_404(lang_code) # If it is an attempt to edit the source language, redirect the user to # resource_detail and show him a message explaining the reason. if target_language == get_source_language(resources): messages.error(request,_( "Cannot edit the source language because this would " "result in translation mismatches! If you want to " "update the source strings consider using the transifex " "command-line client.")) if resource_slug: return HttpResponseRedirect(reverse('resource_detail', args=[project_slug, resource_slug]),) else: return HttpResponseRedirect(reverse('project_detail', args=[project_slug]),) total_strings = SourceEntity.objects.filter( resource__in = resources).count() translated_strings = Translation.objects.filter( resource__in = resources, language = target_language, source_entity__pluralized=False, rule = 5).count() # Include counting of pluralized entities for pluralized_entity in SourceEntity.objects.filter(resource__in = resources, pluralized=True): plurals_translated = Translation.objects.filter( language=target_language, source_entity=pluralized_entity).count() if plurals_translated == len(target_language.get_pluralrules()): translated_strings += 1 if len(resources) > 1: translation_resource = None else: translation_resource = resources[0] contributors = User.objects.filter(pk__in=Translation.objects.filter( resource__in = resources, language = target_language, rule = 5).values_list("user", flat=True)) lotte_init.send(None, request=request, resources=resources, language=target_language) if target_language in [team.language for team in project.available_teams]: team_language = True else: team_language = False GtModel = get_model('gtranslate', 'Gtranslate') try: auto_translate = GtModel.objects.get(project=project) except GtModel.DoesNotExist: auto_translate = None return render_to_response("translate.html", { 'project' : project, 'resource' : translation_resource, 'target_language' : target_language, 'translated_strings': translated_strings, 'untranslated_strings': total_strings - translated_strings, 'contributors': contributors, 'resources': resources, 'resource_slug': resource_slug, 'languages': Language.objects.all(), 'auto_translate': auto_translate, 'spellcheck_supported_langs' : SPELLCHECK_SUPPORTED_LANGS, 'team_language': team_language }, context_instance = RequestContext(request))
def push_translation(request, project_slug, lang_code, *args, **kwargs): """ Client pushes an id and a translation string. Id is considered to be of the source translation string and the string is in the target_lang. FIXME: Document in detail the form of the 'strings' POST variable. """ logger.debug("POST data when saving translation: %s" % request.POST) # Permissions handling # Project should always be available project = get_object_or_404(Project, slug=project_slug) team = Team.objects.get_or_none(project, lang_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) and not\ check.maintain(project): return permission_denied(request) if not request.POST: return HttpResponseBadRequest() data = simplejson.loads(request.raw_post_data) strings = data["strings"] try: target_language = Language.objects.by_code_or_alias(lang_code) except Language.DoesNotExist: raise Http404 # This dictionary will hold the results of the save operation and will map # status code for each translation pushed, to indicate the result on each # translation push separately. push_response_dict = {} # Form the strings dictionary, get as Json object # The fields are the following: # id-> source_entity id # translations-> translation strings (includes all plurals) # context-> source_entity context # occurrence-> occurrence (not yet well supported) # Iterate through all the row data that have been sent. for row in strings: source_id = int(row['id']) try: source_string = Translation.objects.select_related(depth=1).get( id=source_id ) except Translation.DoesNotExist: # TODO: Log or inform here push_response_dict[source_id] = { 'status':400, 'message':_("Source string cannot be identified in the DB")} # If the source_string cannot be identified in the DB then go to next # translation pair. continue if not source_string.resource.accept_translations: push_response_dict[source_id] = { 'status':400, 'message':_("The resource of this source string is not " "accepting translations.") } # If the translated source string is pluralized check that all the # source language supported rules have been filled in, else return error # and donot save the translations. if source_string.source_entity.pluralized: error_flag = False for rule in target_language.get_pluralrules(): if rule in row['translations'] and row['translations'][rule] != "": continue else: error_flag = True if error_flag: error_flag = False # Check also if all of them are "". If yes, delete all the plurals! for rule in target_language.get_pluralrules(): if rule in row['translations'] and row['translations'][rule] == "": continue else: error_flag = True if error_flag: push_response_dict[source_id] = { 'status':400, 'message':(_("Cannot save unless plural translations are either " "completely specified or entirely empty!"))} # Skip the save as we hit on an error. continue try: msgs = _save_translation( source_string, row['translations'], target_language, request.user ) if not msgs: push_response_dict[source_id] = {'status': 200} else: push_response_dict[source_id] = { 'status': 200, 'message': msgs[-1] } except LotteBadRequestError, e: push_response_dict[source_id] = { 'status': 400, 'message': e.message } except Exception, e: logger.error( "Unexpected exception raised: %s" % e.message, exc_info=True ) push_response_dict[source_id] = { 'status': 400, 'message': e.message }
def push_translation(request, project_slug, lang_code, *args, **kwargs): """ Client pushes an id and a translation string. Id is considered to be of the source translation string and the string is in the target_lang. FIXME: Document in detail the form of the 'strings' POST variable. """ logger.debug("POST data when saving translation: %s" % request.POST) # Permissions handling # Project should always be available project = get_object_or_404(Project, slug=project_slug) team = Team.objects.get_or_none(project, lang_code) check = ProjectPermission(request.user) if not check.submit_translations(team or project) and not\ check.maintain(project): return permission_denied(request) if not request.POST: return HttpResponseBadRequest() data = simplejson.loads(request.raw_post_data) strings = data["strings"] try: target_language = Language.objects.by_code_or_alias(lang_code) except Language.DoesNotExist: raise Http404 # This dictionary will hold the results of the save operation and will map # status code for each translation pushed, to indicate the result on each # translation push separately. push_response_dict = {} # Form the strings dictionary, get as Json object # The fields are the following: # id-> source_entity id # translations-> translation strings (includes all plurals) # context-> source_entity context # occurrence-> occurrence (not yet well supported) # Iterate through all the row data that have been sent. for row in strings: source_id = int(row['id']) try: source_string = Translation.objects.select_related(depth=1).get( id=source_id) except Translation.DoesNotExist: # TODO: Log or inform here push_response_dict[source_id] = { 'status': 400, 'message': _("Source string cannot be identified in the DB") } # If the source_string cannot be identified in the DB then go to next # translation pair. continue if not source_string.resource.accept_translations: push_response_dict[source_id] = { 'status': 400, 'message': _("The resource of this source string is not " "accepting translations.") } # If the translated source string is pluralized check that all the # source language supported rules have been filled in, else return error # and donot save the translations. if source_string.source_entity.pluralized: error_flag = False for rule in target_language.get_pluralrules(): if rule in row[ 'translations'] and row['translations'][rule] != "": continue else: error_flag = True if error_flag: error_flag = False # Check also if all of them are "". If yes, delete all the plurals! for rule in target_language.get_pluralrules(): if rule in row['translations'] and row['translations'][ rule] == "": continue else: error_flag = True if error_flag: push_response_dict[source_id] = { 'status': 400, 'message': (_("Cannot save unless plural translations are either " "completely specified or entirely empty!")) } # Skip the save as we hit on an error. continue try: msgs = _save_translation(source_string, row['translations'], target_language, request.user) if not msgs: push_response_dict[source_id] = {'status': 200} else: push_response_dict[source_id] = { 'status': 200, 'message': msgs[-1] } except LotteBadRequestError, e: push_response_dict[source_id] = { 'status': 400, 'message': e.message } except Exception, e: logger.error("Unexpected exception raised: %s" % e.message, exc_info=True) push_response_dict[source_id] = { 'status': 400, 'message': e.message }