Exemple #1
0
    def remove(self, user):
        """Remove translation from the VCS"""
        author = get_author_name(user)
        # Log
        self.log_info(
            'removing %s as %s',
            self.filename,
            author
        )

        # Remove file from VCS
        self.commit_message = '__delete__'
        with self.subproject.repository.lock:
            self.subproject.repository.remove(
                [self.filename],
                self.get_commit_message(),
                author,
            )

        # Delete from the database
        self.delete()

        # Record change
        Change.objects.create(
            subproject=self.subproject,
            action=Change.ACTION_REMOVE,
            target=self.filename,
            user=user,
            author=user
        )
Exemple #2
0
    def handle(self, *args, **options):
        # Check params
        if len(args) != 4:
            raise CommandError('Invalid number of parameters!')

        # Get translation object
        try:
            translation = Translation.objects.get(
                subproject__project__slug=args[0],
                subproject__slug=args[1],
                language__code=args[2],
            )
        except Translation.DoesNotExist:
            raise CommandError('No matching translation project found!')

        # Get user
        try:
            user = User.objects.get(email=options['author'])
        except User.DoesNotExist:
            raise CommandError('Import user does not exist!')

        # Create fake request object
        request = HttpRequest()
        request.user = user

        # Process import
        try:
            with open(args[3], 'r') as handle:
                translation.merge_upload(
                    request, handle, False, method='suggest',
                    author=get_author_name(user),
                )
        except IOError:
            raise CommandError('Failed to import translation file!')
    def handle(self, *args, **options):
        # Check params
        if len(args) != 4:
            raise CommandError('Invalid number of parameters!')

        # Get translation object
        translation = self.get_translation(args)

        # Get user
        try:
            user = User.objects.get(email=options['author'])
        except User.DoesNotExist:
            raise CommandError('Import user does not exist!')

        # Create fake request object
        request = HttpRequest()
        request.user = user

        # Process import
        try:
            with open(args[3], 'rb') as handle:
                translation.merge_upload(
                    request, handle, False, method='suggest',
                    author=get_author_name(user),
                )
        except IOError:
            raise CommandError('Failed to import translation file!')
Exemple #4
0
 def get_last_author(self, email=False):
     """Returns last autor of change done in Weblate."""
     if self.last_change_obj is None:
         return None
     return get_author_name(
         self.last_change_obj.author,
         email
     )
Exemple #5
0
    def add_new_language(self, language, request):
        '''
        Creates new language file.
        '''
        if self.new_lang != 'add':
            raise ValueError('Not supported operation!')

        if not self.file_format_cls.supports_new_language():
            raise ValueError('Not supported operation!')

        base_filename = self.get_new_base_filename()
        if not self.file_format_cls.is_valid_base_for_new(base_filename):
            raise ValueError('Not supported operation!')

        filename = self.file_format_cls.get_language_filename(
            self.filemask,
            language.code
        )
        fullname = os.path.join(self.get_path(), filename)

        self.file_format_cls.add_language(
            fullname,
            language.code,
            base_filename
        )

        translation = Translation.objects.create(
            subproject=self,
            language=language,
            filename=filename,
            language_code=language.code,
            commit_message='Created new translation.'
        )
        translation_post_add.send(
            sender=self.__class__,
            translation=translation
        )
        translation.git_commit(
            request,
            get_author_name(request.user),
            timezone.now(),
            force_commit=True,
            force_new=True,
        )
        translation.check_sync(
            force=True,
            request=request
        )
Exemple #6
0
    def merge_upload(self, request, fileobj, overwrite, author=None,
                     merge_header=True, method='translate', fuzzy=''):
        """Top level handler for file uploads."""
        filecopy = fileobj.read()
        fileobj.close()

        # Strip possible UTF-8 BOM
        if filecopy[:3] == codecs.BOM_UTF8:
            filecopy = filecopy[3:]

        # Load backend file
        store = try_load(
            fileobj.name,
            filecopy,
            self.subproject.file_format_cls,
            self.subproject.template_store
        )

        # Optionally set authorship
        if author is None:
            author = get_author_name(request.user)

        # Check valid plural forms
        if hasattr(store.store, 'parseheader'):
            header = store.store.parseheader()
            if 'Plural-Forms' in header and \
                    not self.language.same_plural(header['Plural-Forms']):
                raise Exception('Plural forms do not match the language.')

        if method in ('translate', 'fuzzy'):
            # Merge on units level
            with self.subproject.repository.lock:
                return self.merge_translations(
                    request,
                    store,
                    overwrite,
                    (method == 'fuzzy'),
                    fuzzy,
                    merge_header,
                )

        # Add as sugestions
        return self.merge_suggestions(request, store, fuzzy)
Exemple #7
0
    def handle(self, *args, **options):
        # Get translation object
        translation = self.get_translation(**options)

        # Get user
        try:
            user = User.objects.get(email=options['author'])
        except User.DoesNotExist:
            raise CommandError('Import user does not exist!')

        # Create fake request object
        request = HttpRequest()
        request.user = user

        # Process import
        try:
            translation.merge_upload(
                request, options['file'], False, method='suggest',
                author=get_author_name(user),
            )
        except IOError:
            raise CommandError('Failed to import translation file!')
Exemple #8
0
    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
Exemple #9
0
    def merge_upload(self, request, fileobj, overwrite, author=None,
                     merge_header=True, method='', fuzzy='',
                     merge_comments=False):
        '''
        Top level handler for file uploads.
        '''
        filecopy = fileobj.read()
        fileobj.close()

        # Strip possible UTF-8 BOM
        if filecopy[:3] == codecs.BOM_UTF8:
            filecopy = filecopy[3:]

        # Load backend file
        try:
            # First try using own loader
            store = self.subproject.file_format_cls.parse(
                StringIOMode(fileobj.name, filecopy),
                self.subproject.template_store
            )
        except Exception:
            # Fallback to automatic detection
            store = AutoFormat.parse(
                StringIOMode(fileobj.name, filecopy),
            )

        # Optionally set authorship
        if author is None:
            author = get_author_name(request.user)

        # List translations we should process
        # Filter out those who don't want automatic update, but keep ourselves
        translations = Translation.objects.filter(
            language=self.language,
            subproject__project=self.subproject.project
        ).filter(
            Q(pk=self.pk) | Q(subproject__allow_translation_propagation=True)
        )

        ret = False

        if method in ('', 'fuzzy'):
            # Do actual merge
            if self.subproject.has_template():
                # Merge on units level
                ret = self.merge_translations(
                    request,
                    store,
                    overwrite,
                    (method == 'fuzzy'),
                    fuzzy
                )
            else:
                # Merge on file level
                for translation in translations:
                    ret |= translation.merge_store(
                        request,
                        author,
                        store,
                        overwrite,
                        merge_header,
                        (method == 'fuzzy'),
                        fuzzy,
                        merge_comments=merge_comments,
                    )
        else:
            # Add as sugestions
            ret = self.merge_suggestions(request, store, fuzzy)

        return ret, store.count_units()
Exemple #10
0
    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
Exemple #11
0
    def merge_upload(self, request, fileobj, overwrite, author=None,
                     merge_header=True, method='translate', fuzzy='',
                     merge_comments=False):
        """Top level handler for file uploads."""
        filecopy = fileobj.read()
        fileobj.close()

        # Strip possible UTF-8 BOM
        if filecopy[:3] == codecs.BOM_UTF8:
            filecopy = filecopy[3:]

        # Load backend file
        try:
            # First try using own loader
            store = self.store.parse(
                StringIOMode(fileobj.name, filecopy),
                self.subproject.template_store
            )
        except Exception:
            # Fallback to automatic detection
            store = AutoFormat.parse(
                StringIOMode(fileobj.name, filecopy),
            )

        # Optionally set authorship
        if author is None:
            author = get_author_name(request.user)

        # Check valid plural forms
        if hasattr(store.store, 'parseheader'):
            header = store.store.parseheader()
            if 'Plural-Forms' in header and \
                    self.language.get_plural_form() != header['Plural-Forms']:
                raise Exception('Plural forms do not match the language.')

        # List translations we should process
        # Filter out those who don't want automatic update, but keep ourselves
        translations = Translation.objects.filter(
            language=self.language,
            subproject__project=self.subproject.project
        ).filter(
            Q(pk=self.pk) | Q(subproject__allow_translation_propagation=True)
        )

        ret = False

        if method in ('translate', 'fuzzy'):
            # Do actual merge
            if self.subproject.has_template():
                # Merge on units level
                ret = self.merge_translations(
                    request,
                    store,
                    overwrite,
                    (method == 'fuzzy'),
                    fuzzy
                )
            else:
                # Merge on file level
                for translation in translations:
                    ret |= translation.merge_store(
                        request,
                        author,
                        store,
                        overwrite,
                        merge_header,
                        (method == 'fuzzy'),
                        fuzzy,
                        merge_comments=merge_comments,
                    )
        else:
            # Add as sugestions
            ret = self.merge_suggestions(request, store, fuzzy)

        return ret, store.count_units()
Exemple #12
0
 def get_last_author(self, email=False):
     """Return last autor of change done in Weblate."""
     if self.last_change_obj is None:
         return None
     return get_author_name(self.last_change_obj.author, email)
Exemple #13
0
    def merge_translations(self, request, store2, overwrite, add_fuzzy,
                           fuzzy, merge_header):
        """Merge translation unit wise

        Needed for template based translations to add new strings.
        """
        not_found = 0
        skipped = 0
        accepted = 0

        # Are there any translations to propagate?
        # This is just an optimalization to avoid doing that for every unit.
        propagate = Translation.objects.filter(
            language=self.language,
            subproject__project=self.subproject.project
        ).filter(
            subproject__allow_translation_propagation=True
        ).exclude(
            pk=self.pk
        ).exists()

        author = get_author_name(request.user)

        # Commit possible prior changes
        self.commit_pending(request, author)
        # Avoid committing while we're importing
        self._skip_commit = True

        for set_fuzzy, unit2 in store2.iterate_merge(fuzzy):
            try:
                unit = self.unit_set.get_unit(unit2)
            except Unit.DoesNotExist:
                not_found += 1
                continue

            if unit.translated and not overwrite:
                skipped += 1
                continue

            accepted += 1

            unit.translate(
                request,
                split_plural(unit2.get_target()),
                add_fuzzy or set_fuzzy,
                change_action=Change.ACTION_UPLOAD,
                propagate=propagate
            )

        self._skip_commit = False

        if accepted > 0:
            self.update_stats()

            if merge_header:
                self.store.merge_header(store2)
                self.store.save()

            self.git_commit(
                request, author, timezone.now(),
                force_commit=True, sync=True
            )

        return (not_found, skipped, accepted, store2.count_units())
Exemple #14
0
    def save_backend(self,
                     request,
                     propagate=True,
                     gen_change=True,
                     change_action=None,
                     user=None):
        """
        Stores unit to backend.

        Optional user parameters defines authorship of a change.

        This should be always called in a trasaction with updated unit
        locked for update.
        """
        # For case when authorship specified, use user from request
        if user is None or user.is_anonymous:
            user = request.user

        # Commit possible previous changes by other author
        self.translation.commit_pending(request, get_author_name(user))

        # Return if there was no change
        # We have to explicitly check for fuzzy flag change on monolingual
        # files, where we handle it ourselves without storing to backend
        if (self.old_unit.state == self.state
                and self.old_unit.target == self.target):
            # Propagate if we should
            if propagate:
                self.propagate(request, change_action)
            return False

        # Propagate to other projects
        # This has to be done before changing source/content_hash for template
        if propagate:
            self.propagate(request, change_action)

        if self.translation.is_template:
            self.source = self.target
            self.content_hash = calculate_hash(self.source, self.context)

        # Unit is pending for write
        self.pending = True
        # Update translated flag (not fuzzy and at least one translation)
        translation = bool(max(self.get_target_plurals()))
        if self.state == STATE_TRANSLATED and not translation:
            self.state = STATE_EMPTY
        elif self.state == STATE_EMPTY and translation:
            self.state = STATE_TRANSLATED

        # Save updated unit to database
        self.save(backend=True)

        # Update translation stats
        old_translated = self.translation.stats.translated
        if change_action != Change.ACTION_UPLOAD:
            self.translation.invalidate_cache()
            self.translation.store_hash()

        # Notify subscribed users about new translation
        notify_new_translation(self, self.old_unit, user)

        # Update user stats
        user.profile.translated += 1
        user.profile.save()

        # Generate Change object for this change
        if gen_change:
            self.generate_change(request, user, change_action)

        # Force commiting on completing translation
        translated = self.translation.stats.translated
        if (old_translated < translated
                and translated == self.translation.stats.all):
            Change.objects.create(translation=self.translation,
                                  action=Change.ACTION_COMPLETE,
                                  user=user,
                                  author=user)
            self.translation.commit_pending(request)

        # Update related source strings if working on a template
        if self.translation.is_template:
            self.update_source_units(self.old_unit.source, user)

        return True