def widgets(request, project): obj = get_project(request, project) # Parse possible language selection form = EngageForm(obj, request.GET) lang = None component = None if form.is_valid(): if form.cleaned_data['lang']: lang = Language.objects.get(code=form.cleaned_data['lang']).code if form.cleaned_data['component']: component = SubProject.objects.get( slug=form.cleaned_data['component'], project=obj).slug kwargs = {'project': obj.slug} if lang is not None: kwargs['lang'] = lang engage_url = get_site_url(reverse('engage', kwargs=kwargs)) engage_url_track = '{0}?utm_source=widget'.format(engage_url) widget_base_url = get_site_url( reverse('widgets', kwargs={'project': obj.slug})) widget_list = [] for widget_name in sorted(WIDGETS, key=widgets_sorter): widget_class = WIDGETS[widget_name] if not widget_class.show: continue color_list = [] for color in widget_class.colors: kwargs = { 'project': obj.slug, 'widget': widget_name, 'color': color, 'extension': widget_class.extension, } if lang is not None: kwargs['lang'] = lang if component is not None: kwargs['subproject'] = component color_url = reverse('widget-image', kwargs=kwargs) color_list.append({ 'name': color, 'url': get_site_url(color_url), }) widget_list.append({ 'name': widget_name, 'colors': color_list, }) return render( request, 'widgets.html', { 'engage_url': engage_url, 'engage_url_track': engage_url_track, 'widget_list': widget_list, 'widget_base_url': widget_base_url, 'object': obj, 'project': obj, 'image_src': widget_list[0]['colors'][0]['url'], 'form': form, })
def get_widgets_url(self): """Return absolute URL for widgets.""" return get_site_url('{0}?lang={1}'.format( reverse('widgets', kwargs={ 'project': self.subproject.project.slug, }), self.language.code))
def download_dictionary(request, project, lang): """Export dictionary into various formats.""" prj = get_project(request, project) lang = get_object_or_404(Language, code=lang) # Parse parameters export_format = None if 'format' in request.GET: export_format = request.GET['format'] if export_format not in ('csv', 'po', 'tbx', 'xliff'): export_format = 'csv' # Grab all words words = Dictionary.objects.filter(project=prj, language=lang).order_by('source') # Translate toolkit based export exporter = get_exporter(export_format)( prj, lang, get_site_url( reverse('show_dictionary', kwargs={ 'project': prj.slug, 'lang': lang.code })), fieldnames=('source', 'target'), ) # Add words for word in words.iterator(): exporter.add_dictionary(word) # Save to response return exporter.get_response('glossary-{project}-{language}.{extension}')
def get_widgets_url(self): """ Returns absolute URL for widgets. """ return get_site_url( reverse('widgets', kwargs={'project': self.slug}) )
def get_commit_message(self): """Format commit message based on project configuration.""" template = self.subproject.commit_message if self.commit_message == '__add__': template = self.subproject.add_message self.commit_message = '' self.save() elif self.commit_message == '__delete__': template = self.subproject.delete_message self.commit_message = '' self.save() msg = template % { 'language': self.language_code, 'language_name': self.language.name, 'subproject': self.subproject.name, 'resource': self.subproject.name, 'component': self.subproject.name, 'project': self.subproject.project.name, 'url': get_site_url(self.get_absolute_url()), 'total': self.total, 'fuzzy': self.fuzzy, 'fuzzy_percent': self.get_fuzzy_percent(), 'translated': self.translated, 'translated_percent': self.get_translated_percent(), } if self.commit_message: msg = '{0}\n\n{1}'.format(msg, self.commit_message) self.commit_message = '' self.save() return msg
def get_share_url(self): """ Returns absolute URL usable for sharing. """ return get_site_url( reverse('engage', kwargs={'project': self.slug}) )
def get_absolute_url(self): return get_site_url( reverse( 'show_language', kwargs={'lang': self.code} ) )
def json_req(self, url, http_post=False, skip_auth=False, raw=False, **kwargs): """Perform JSON request.""" # Encode params if len(kwargs) > 0: params = urlencode( {key: val.encode('utf-8') for key, val in kwargs.items()}) else: params = '' # Store for exception handling self.request_url = url self.request_params = params # Append parameters if len(params) > 0 and not http_post: url = '?'.join((url, params)) # Create request object with custom headers request = Request(url) request.timeout = 0.5 request.add_header('User-Agent', USER_AGENT) request.add_header('Referer', get_site_url()) # Optional authentication if not skip_auth: self.authenticate(request) # Fire request if http_post: handle = urlopen(request, params.encode('utf-8')) else: handle = urlopen(request) # Read and possibly convert response text = handle.read() # Needed for Microsoft if text[:3] == b'\xef\xbb\xbf': text = text.decode('UTF-8-sig') else: text = text.decode('utf-8') # Replace literal \t text = text.strip().replace('\t', '\\t').replace('\r', '\\r') # Needed for Google while ',,' in text or '[,' in text: text = text.replace(',,', ',null,').replace('[,', '[') if raw: return text # Parse JSON response = json.loads(text) # Return data return response
def get_share_url(self): """Returns absolute URL usable for sharing.""" return get_site_url( reverse('engage-lang', kwargs={ 'project': self.subproject.project.slug, 'lang': self.language.code }))
def download_dictionary_ttkit(export_format, prj, lang, words): ''' Translate-toolkit builder for dictionary downloads. ''' # Use translate-toolkit for other formats if export_format == 'po': # Construct store from translate.storage.po import pofile store = pofile() # Export parameters content_type = 'text/x-po' extension = 'po' has_lang = False # Set po file header store.updateheader(add=True, language=lang.code, x_generator='Weblate %s' % weblate.VERSION, project_id_version='%s (%s)' % (lang.name, prj.name), language_team='%s <%s>' % ( lang.name, get_site_url( reverse('show_dictionary', kwargs={ 'project': prj.slug, 'lang': lang.code })), )) else: # Construct store from translate.storage.tbx import tbxfile store = tbxfile() # Export parameters content_type = 'application/x-tbx' extension = 'tbx' has_lang = True # Setup response and headers response = HttpResponse(content_type='%s; charset=utf-8' % content_type) filename = 'glossary-%s-%s.%s' % (prj.slug, lang.code, extension) response['Content-Disposition'] = 'attachment; filename=%s' % filename # Add words for word in words.iterator(): unit = store.UnitClass(word.source) if has_lang: unit.settarget(word.target, lang.code) else: unit.target = word.target store.addunit(unit) # Save to response response.write(str(store)) return response
def weblate_context(request): """ Context processor to inject various useful variables into context. """ if 'next' in request.GET: login_redirect_url = request.GET['next'] else: login_redirect_url = request.get_full_path() projects = Project.objects.all_acl(request.user) # Load user translations if user is authenticated subscribed_projects = None if request.user.is_authenticated: subscribed_projects = request.user.profile.subscriptions.all() if settings.OFFER_HOSTING: description = _( 'Hosted Weblate, the place to translate your software project.') else: description = _( 'This site runs Weblate for translating various software projects.' ) if (hasattr(settings, 'ROLLBAR') and 'client_token' in settings.ROLLBAR and 'environment' in settings.ROLLBAR): rollbar_token = settings.ROLLBAR['client_token'] rollbar_environment = settings.ROLLBAR['environment'] else: rollbar_token = None rollbar_environment = None return { 'version': weblate.VERSION, 'description': description, 'weblate_url': URL_BASE % weblate.VERSION, 'donate_url': URL_DONATE % weblate.VERSION, 'site_title': settings.SITE_TITLE, 'site_url': get_site_url(), 'offer_hosting': settings.OFFER_HOSTING, 'demo_server': settings.DEMO_SERVER, 'enable_avatars': settings.ENABLE_AVATARS, 'enable_sharing': settings.ENABLE_SHARING, 'piwik_site_id': settings.PIWIK_SITE_ID, 'piwik_url': settings.PIWIK_URL, 'google_analytics_id': settings.GOOGLE_ANALYTICS_ID, 'current_date': datetime.utcnow().strftime('%Y-%m-%d'), 'current_year': datetime.utcnow().strftime('%Y'), 'current_month': datetime.utcnow().strftime('%m'), 'login_redirect_url': login_redirect_url, 'hooks_enabled': settings.ENABLE_HOOKS, 'has_ocr': weblate.screenshots.views.HAS_OCR, 'registration_open': settings.REGISTRATION_OPEN, 'acl_projects': projects, 'subscribed_projects': subscribed_projects, 'rollbar_token': rollbar_token, 'rollbar_environment': rollbar_environment, }
def get_widgets_url(self): """Returns absolute URL for widgets.""" return get_site_url('%s?lang=%s' % ( reverse('widgets', kwargs={ 'project': self.subproject.project.slug, }), self.language.code, ))
def get_export_url(component): """Return Git export URL for component""" return get_site_url( reverse('git-export', kwargs={ 'project': component.project.slug, 'subproject': component.slug, 'path': '', }))
def reverse_url(self, name=None): """ Generic reverser for URL. """ if name is None: urlname = self._reverse_url_name() else: urlname = '%s_%s' % (name, self._reverse_url_name()) return get_site_url(reverse(urlname, kwargs=self._reverse_url_kwargs()))
def export_stats(request, project, subproject): ''' Exports stats in JSON format. ''' subprj = get_subproject(request, project, subproject, True) jsonp = None if 'jsonp' in request.GET and request.GET['jsonp']: jsonp = request.GET['jsonp'] response = [] for trans in subprj.translation_set.all(): response.append({ 'code': trans.language.code, 'name': trans.language.name, 'total': trans.total, 'total_words': trans.total_words, 'last_change': trans.last_change, 'last_author': trans.get_last_author(), 'translated': trans.translated, 'translated_words': trans.translated_words, 'translated_percent': trans.get_translated_percent(), 'fuzzy': trans.fuzzy, 'fuzzy_percent': trans.get_fuzzy_percent(), 'failing': trans.failing_checks, 'failing_percent': trans.get_failing_checks_percent(), 'url': trans.get_share_url(), 'url_translate': get_site_url(trans.get_absolute_url()), }) if jsonp: return HttpResponse('{0}({1})'.format( jsonp, json.dumps( response, cls=DjangoJSONEncoder, )), content_type='application/javascript') return JsonResponse(data=response, safe=False)
def weblate_context(request): """ Context processor to inject various useful variables into context. """ if 'next' in request.GET: login_redirect_url = request.GET['next'] else: login_redirect_url = request.get_full_path() projects = Project.objects.all_acl(request.user) # Load user translations if user is authenticated usertranslations = None if request.user.is_authenticated(): usertranslations = Translation.objects.filter( language__in=request.user.profile.languages.all(), subproject__project__in=projects, ).order_by( 'subproject__project__name', 'subproject__name' ).select_related() return { 'version': weblate.VERSION, 'weblate_url': URL_BASE % weblate.VERSION, 'donate_url': URL_DONATE % weblate.VERSION, 'site_title': appsettings.SITE_TITLE, 'site_url': get_site_url(), 'offer_hosting': appsettings.OFFER_HOSTING, 'demo_server': appsettings.DEMO_SERVER, 'enable_avatars': appsettings.ENABLE_AVATARS, 'enable_sharing': appsettings.ENABLE_SHARING, 'piwik_site_id': appsettings.PIWIK_SITE_ID, 'piwik_url': appsettings.PIWIK_URL, 'google_analytics_id': appsettings.GOOGLE_ANALYTICS_ID, 'current_date': datetime.utcnow().strftime('%Y-%m-%d'), 'current_year': datetime.utcnow().strftime('%Y'), 'current_month': datetime.utcnow().strftime('%m'), 'login_redirect_url': login_redirect_url, 'hooks_enabled': appsettings.ENABLE_HOOKS, 'registration_open': appsettings.REGISTRATION_OPEN, 'acl_projects': projects, 'usertranslations': usertranslations, }
def is_spam(text, request): """Generic spam checker interface.""" if settings.AKISMET_API_KEY: from akismet import Akismet akismet = Akismet( settings.AKISMET_API_KEY, get_site_url() ) return akismet.comment_check( get_ip_address(request), request.META.get('HTTP_USER_AGENT', ''), comment_content=text, comment_type='comment' ) return False
def download_translation_format(request, project, subproject, lang, fmt): obj = get_translation(request, project, subproject, lang) try: exporter = get_exporter(fmt)(obj.subproject.project, obj.language, get_site_url(obj.get_absolute_url())) except KeyError: raise Http404('File format not supported') for unit in obj.unit_set.iterator(): exporter.add_unit(unit) # Save to response return exporter.get_response( '{{project}}-{0}-{{language}}.{{extension}}'.format(subproject))
def render(self): translations = [] offset = 30 color = self.COLOR_MAP[self.color] for data in get_per_language_stats(self.obj): language, translated, total = data[:3] if total == 0: percent = 0 else: percent = int(100 * translated / total) if self.color == 'auto': if percent >= 90: color = '#4c1' elif percent >= 75: color = '#dfb317' else: color = '#e05d44' translations.append(( # Language name language.name, # Translation percent percent, # Text y offset offset, # Bar y offset offset - 10, # Bar width int(percent * 1.5), # Bar color color, # Row URL get_site_url( reverse('project-language', kwargs={ 'lang': language.code, 'project': self.obj.slug })), # Bounding box y offset offset - 15, )) offset += 20 self.image = render_to_string( 'multi-language-badge.svg', { 'height': len(translations) * 20 + 20, 'boxheight': len(translations) * 20 + 10, 'translations': translations, })
def __init__(self, project=None, language=None, url=None, translation=None): if translation is not None: self.project = translation.subproject.project self.language = translation.language self.url = get_site_url(translation.get_absolute_url()) else: self.project = project self.language = language self.url = url self.storage = self.get_storage() self.storage.setsourcelanguage(self.project.source_language.code) self.storage.settargetlanguage(self.language.code)
def download_dictionary_ttkit(export_format, prj, lang, words): """Translate-toolkit builder for dictionary downloads.""" exporter = get_exporter(export_format)(prj, lang, get_site_url( reverse('show_dictionary', kwargs={ 'project': prj.slug, 'lang': lang.code }))) # Add words for word in words.iterator(): exporter.add_dictionary(word) # Save to response return exporter.get_response('glossary-{project}-{language}.{extension}')
def get_stats(self): """Return stats dictionary""" return { 'code': self.language.code, 'name': self.language.name, 'total': self.total, 'total_words': self.total_words, 'last_change': self.last_change, 'last_author': self.get_last_author(), 'translated': self.translated, 'translated_words': self.translated_words, 'translated_percent': self.get_translated_percent(), 'fuzzy': self.fuzzy, 'fuzzy_percent': self.get_fuzzy_percent(), 'failing': self.failing_checks, 'failing_percent': self.get_failing_checks_percent(), 'url': self.get_share_url(), 'url_translate': get_site_url(self.get_absolute_url()), }
def get_notification_email(language, email, notification, translation_obj=None, context=None, headers=None, user=None, info=None): ''' Renders notification email. ''' cur_language = django_translation.get_language() context = context or {} headers = headers or {} references = None if 'unit' in context: unit = context['unit'] references = '{0}/{1}/{2}/{3}'.format( unit.translation.subproject.project.slug, unit.translation.subproject.slug, unit.translation.language.code, unit.id) if references is not None: references = '<{0}@{1}>'.format(references, get_site_domain()) headers['In-Reply-To'] = references headers['References'] = references try: if info is None: info = force_text(translation_obj) LOGGER.info('sending notification %s on %s to %s', notification, info, email) # Load user language if language is not None: django_translation.activate(language) # Template name context['subject_template'] = 'mail/{0}_subject.txt'.format( notification) # Adjust context context['current_site_url'] = get_site_url() if translation_obj is not None: context['translation'] = translation_obj context['translation_url'] = get_site_url( translation_obj.get_absolute_url()) context['site_title'] = settings.SITE_TITLE # Render subject subject = render_to_string(context['subject_template'], context).strip() # Render body body = render_to_string('mail/{0}.txt'.format(notification), context) html_body = render_to_string('mail/{0}.html'.format(notification), context) # Define headers headers['Auto-Submitted'] = 'auto-generated' headers['X-AutoGenerated'] = 'yes' headers['Precedence'] = 'bulk' headers['X-Mailer'] = 'Weblate {0}'.format(VERSION) # Reply to header if user is not None: headers['Reply-To'] = user.email # List of recipients if email == 'ADMINS': emails = [a[1] for a in settings.ADMINS] else: emails = [email] # Create message email = EmailMultiAlternatives( settings.EMAIL_SUBJECT_PREFIX + subject, body, to=emails, headers=headers, ) email.attach_alternative(html_body, 'text/html') # Return the mail return email finally: django_translation.activate(cur_language)
def export_stats(request, project, subproject): ''' Exports stats in JSON format. ''' subprj = get_subproject(request, project, subproject) try: indent = int(request.GET['indent']) except (ValueError, KeyError): indent = None jsonp = None if 'jsonp' in request.GET and request.GET['jsonp']: jsonp = request.GET['jsonp'] response = [] for trans in subprj.translation_set.all(): response.append({ 'code': trans.language.code, 'name': trans.language.name, 'total': trans.total, 'total_words': trans.total_words, 'last_change': trans.last_change, 'last_author': trans.get_last_author(), 'translated': trans.translated, 'translated_words': trans.translated_words, 'translated_percent': trans.get_translated_percent(), 'fuzzy': trans.fuzzy, 'fuzzy_percent': trans.get_fuzzy_percent(), 'failing': trans.failing_checks, 'failing_percent': trans.get_failing_checks_percent(), 'url': trans.get_share_url(), 'url_translate': get_site_url(trans.get_absolute_url()), }) json_data = json.dumps( response, default=json_dt_handler, indent=indent, ) if jsonp: return HttpResponse('{0}({1})'.format( jsonp, json_data, ), content_type='application/javascript') return HttpResponse(json_data, content_type='application/json')
def get_attribute(self, instance): value = super(AbsoluteURLField, self).get_attribute(instance) if 'http:/' not in value and 'https:/' not in value: return get_site_url(value) return value
def update_unit(self, unit, request, user=None): ''' Updates backend file and unit. ''' if user is None: user = request.user # Save with lock acquired with self.subproject.repository_lock: src = unit.get_source_plurals()[0] add = False pounit, add = self.store.find_unit(unit.context, src) # Bail out if we have not found anything if pounit is None or pounit.is_obsolete(): return False, None # Check for changes if ((not add or unit.target == '') and unit.target == pounit.get_target() and unit.fuzzy == pounit.is_fuzzy()): return False, pounit # Store translations if unit.is_plural(): pounit.set_target(unit.get_target_plurals()) else: pounit.set_target(unit.target) # Update fuzzy flag pounit.mark_fuzzy(unit.fuzzy) # Optionally add unit to translation file if add: self.store.add_unit(pounit) # We need to update backend now author = get_author_name(user) # Update po file header now = timezone.now() if not timezone.is_aware(now): now = timezone.make_aware(now, timezone.utc) # Prepare headers to update headers = { 'add': True, 'last_translator': author, 'plural_forms': self.language.get_plural_form(), 'language': self.language_code, 'PO_Revision_Date': now.strftime('%Y-%m-%d %H:%M%z'), } # Optionally store language team with link to website if self.subproject.project.set_translation_team: headers['language_team'] = '%s <%s>' % ( self.language.name, get_site_url(self.get_absolute_url()), ) # Optionally store email for reporting bugs in source report_source_bugs = self.subproject.report_source_bugs if report_source_bugs != '': headers['report_msgid_bugs_to'] = report_source_bugs # Update genric headers self.store.update_header( **headers ) # commit possible previous changes (by other author) self.commit_pending(request, author) # save translation changes self.store.save() # commit VCS repo if needed self.git_commit(request, author, timezone.now(), sync=True) return True, pounit
def update_units(self, author): """Update backend file and unit.""" updated = False for unit in self.unit_set.filter(pending=True): src = unit.get_source_plurals()[0] add = False pounit, add = self.store.find_unit(unit.context, src) unit.pending = False # Bail out if we have not found anything if pounit is None or pounit.is_obsolete(): self.log_error('message %s disappeared!', unit) unit.save(backend=True, update_fields=['pending']) continue # Check for changes if ((not add or unit.target == '') and unit.target == pounit.get_target() and unit.fuzzy == pounit.is_fuzzy()): unit.save(backend=True, update_fields=['pending']) continue updated = True # Optionally add unit to translation file. # This has be done prior setting tatget as some formats # generate content based on target language. if add: self.store.add_unit(pounit) # Store translations if unit.is_plural(): pounit.set_target(unit.get_target_plurals()) else: pounit.set_target(unit.target) # Update fuzzy flag pounit.mark_fuzzy(unit.fuzzy) # Update comments as they might have been changed (eg, fuzzy flag # removed) translated = pounit.is_translated() flags = pounit.get_flags() if translated != unit.translated or flags != unit.flags: unit.translated = translated unit.flags = flags unit.save( backend=True, update_fields=['translated', 'flags', 'pending'] ) # Did we do any updates? if not updated: return # Update po file header now = timezone.now() if not timezone.is_aware(now): now = timezone.make_aware(now, timezone.utc) # Prepare headers to update headers = { 'add': True, 'last_translator': author, 'plural_forms': self.language.get_plural_form(), 'language': self.language_code, 'PO_Revision_Date': now.strftime('%Y-%m-%d %H:%M%z'), } # Optionally store language team with link to website if self.subproject.project.set_translation_team: headers['language_team'] = '{0} <{1}>'.format( self.language.name, get_site_url(self.get_absolute_url()) ) # Optionally store email for reporting bugs in source report_source_bugs = self.subproject.report_source_bugs if report_source_bugs != '': headers['report_msgid_bugs_to'] = report_source_bugs # Update genric headers self.store.update_header( **headers ) # save translation changes self.store.save() # Update stats (the translated flag might have changed) self.update_stats()
def widgets(request, project): obj = get_project(request, project) # Parse possible language selection form = EnageLanguageForm(obj, request.GET) lang = None if form.is_valid() and form.cleaned_data['lang'] != '': lang = Language.objects.get(code=form.cleaned_data['lang']) if lang is None: engage_base = reverse('engage', kwargs={'project': obj.slug}) else: engage_base = reverse( 'engage-lang', kwargs={'project': obj.slug, 'lang': lang.code} ) engage_url = get_site_url(engage_base) engage_url_track = '{0}?utm_source=widget'.format(engage_url) widget_base_url = get_site_url( reverse('widgets', kwargs={'project': obj.slug}) ) widget_list = [] for widget_name in sorted(WIDGETS, key=widgets_sorter): widget_class = WIDGETS[widget_name] color_list = [] for color in widget_class.colors: if lang is None: color_url = reverse( 'widget-image', kwargs={ 'project': obj.slug, 'widget': widget_name, 'color': color, 'extension': widget_class.extension, } ) else: color_url = reverse( 'widget-image-lang', kwargs={ 'project': obj.slug, 'widget': widget_name, 'color': color, 'lang': lang.code, 'extension': widget_class.extension, } ) color_list.append({ 'name': color, 'url': get_site_url(color_url), }) widget_list.append({ 'name': widget_name, 'colors': color_list, }) return render( request, 'widgets.html', { 'engage_url': engage_url, 'engage_url_track': engage_url_track, 'widget_list': widget_list, 'widget_base_url': widget_base_url, 'object': obj, 'project': obj, 'image_src': widget_list[0]['colors'][0]['url'], 'form': form, } )