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 )
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!')
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 )
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 )
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)
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!')
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 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()
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 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()
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)
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())
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