def log_action( action, user, translation=None, entity=None, locale=None, ): """Save a new action in the database. :arg string action: The type of action that was performed. See models.ActionLog.ACTIONS_TYPES for choices. :arg User user: The User who performed the action. :arg Translation translation: The Translation the action was performed on. :arg Entity entity: The Entity the action was performed on. Only used for the "translation:deleted" action. :arg Locale locale: The Locale the action was performed on. Only used for the "translation:deleted" action. :returns: None """ action = ActionLog( action_type=action, performed_by=user, translation=translation, entity=entity, locale=locale, ) action.save()
def approve_translations(form, user, translations, locale): """Approve a series of translations. For documentation, refer to the `batch_action_template` function. """ invalid_translation_pks = list( translations.filter( approved=False, errors__isnull=False, ).values_list("pk", flat=True) ) translations = translations.filter( approved=False, errors__isnull=True, ) changed_translation_pks = list(translations.values_list("pk", flat=True)) latest_translation_pk = None if changed_translation_pks: latest_translation_pk = translations.last().pk count, translated_resources, changed_entities = utils.get_translations_info( translations, locale, ) # Log approving actions actions_to_log = [ ActionLog( action_type=ActionLog.ActionType.TRANSLATION_APPROVED, performed_by=user, translation=t, ) for t in translations ] ActionLog.objects.bulk_create(actions_to_log) # Approve translations. translations.update( approved=True, approved_user=user, approved_date=timezone.now(), rejected=False, rejected_user=None, rejected_date=None, pretranslated=False, fuzzy=False, ) return { "count": count, "translated_resources": translated_resources, "changed_entities": changed_entities, "latest_translation_pk": latest_translation_pk, "changed_translation_pks": changed_translation_pks, "invalid_translation_pks": invalid_translation_pks, }
def bulk_create_translations(self): Translation.objects.bulk_create(self.translations_to_create) for translation in self.translations_to_create: self.actions_to_log.append( ActionLog( action_type=ActionLog.ActionType.TRANSLATION_CREATED, created_at=translation.date, performed_by=translation.user or self.sync_user, translation=translation, ))
def bulk_create_translations(self): Translation.objects.bulk_create(self.translations_to_create) for translation in self.translations_to_create: self.actions_to_log.append( ActionLog( action_type="translation:created", created_at=translation.date, performed_by=translation.user or self.sync_user, translation=translation, ))
def reject_translations(form, user, translations, locale): """Reject a series of translations. Note that this function doesn't use the `translations` parameter, as it needs to impact non-active translations. Hence it will generate its own list of suggested translations to work on. For documentation, refer to the `batch_action_template` function. """ suggestions = Translation.objects.filter( locale=locale, entity__pk__in=form.cleaned_data["entities"], approved=False, rejected=False, ) count, translated_resources, changed_entities = utils.get_translations_info( suggestions, locale, ) TranslationMemoryEntry.objects.filter(translation__in=suggestions).delete() # Log rejecting actions actions_to_log = [ ActionLog( action_type=ActionLog.ActionType.TRANSLATION_REJECTED, performed_by=user, translation=t, ) for t in translations ] ActionLog.objects.bulk_create(actions_to_log) # Reject translations. suggestions.update( active=False, rejected=True, rejected_user=user, rejected_date=timezone.now(), approved=False, approved_user=None, approved_date=None, pretranslated=False, fuzzy=False, ) return { "count": count, "translated_resources": translated_resources, "changed_entities": changed_entities, "latest_translation_pk": None, "changed_translation_pks": [], "invalid_translation_pks": [], }
def replace_translations(form, user, translations, locale): """Replace characters in a series of translations. Replaces all occurences of the content of the `find` parameter with the content of the `replace` parameter. For documentation, refer to the `batch_action_template` function. """ find = form.cleaned_data["find"] replace = form.cleaned_data["replace"] latest_translation_pk = None ( old_translations, translations_to_create, invalid_translation_pks, ) = utils.find_and_replace(translations, find, replace, user) count, translated_resources, changed_entities = utils.get_translations_info( old_translations, locale, ) # Log rejecting actions actions_to_log = [ ActionLog( action_type=ActionLog.ActionType.TRANSLATION_REJECTED, performed_by=user, translation=t, ) for t in old_translations ] ActionLog.objects.bulk_create(actions_to_log) # Deactivate and unapprove old translations old_translations.update( active=False, approved=False, approved_user=None, approved_date=None, rejected=True, rejected_user=user, rejected_date=timezone.now(), fuzzy=False, ) # Create new translations changed_translations = Translation.objects.bulk_create( translations_to_create, ) # Log creating actions actions_to_log = [ ActionLog( action_type=ActionLog.ActionType.TRANSLATION_CREATED, performed_by=user, translation=t, ) for t in changed_translations ] ActionLog.objects.bulk_create(actions_to_log) changed_translation_pks = [c.pk for c in changed_translations] if changed_translation_pks: latest_translation_pk = max(changed_translation_pks) return { "count": count, "translated_resources": translated_resources, "changed_entities": changed_entities, "latest_translation_pk": latest_translation_pk, "changed_translation_pks": changed_translation_pks, "invalid_translation_pks": invalid_translation_pks, }
def update_entity_translations_from_vcs( self, db_entity, locale_code, vcs_translation, user=None, db_translations=None, db_translations_approved_before_sync=None, ): if db_translations is None: db_translations = db_entity.translation_set.filter( locale__code=locale_code, ) if db_translations_approved_before_sync is None: db_translations_approved_before_sync = db_translations.filter( approved_date__lte=self.now) approved_translations = [] fuzzy_translations = [] for plural_form, string in vcs_translation.strings.items(): db_translation = match_attr(db_translations, plural_form=plural_form, string=string) # Modify existing translation. if db_translation: new_action = None if not db_translation.approved and not vcs_translation.fuzzy: new_action = ActionLog( action_type=ActionLog.ActionType.TRANSLATION_APPROVED, performed_by=user or self.sync_user, translation=db_translation, ) db_translation.approved = True db_translation.approved_user = user db_translation.approved_date = self.now db_translation.rejected = False db_translation.fuzzy = vcs_translation.fuzzy db_translation.extra = vcs_translation.extra if db_translation.is_dirty(): self.translations_to_update[ db_translation.pk] = db_translation if new_action: self.actions_to_log.append(new_action) if db_translation.fuzzy: fuzzy_translations.append(db_translation) else: approved_translations.append(db_translation) # Create new translation. else: self.translations_to_create.append( Translation( entity=db_entity, locale=self.locales[locale_code], string=string, plural_form=plural_form, approved=not vcs_translation.fuzzy, approved_user=user, approved_date=self.now if not vcs_translation.fuzzy else None, user=user, fuzzy=vcs_translation.fuzzy, extra=vcs_translation.extra, )) # Unapprove translations that were approved before the sync job started unless sync # resolves them as active approved translations. # Note: If translations get approved after the sync starts, duplicate approvals can arise. # We take care of that at the and of the sync job in tasks.py. for translation in db_translations_approved_before_sync: if translation not in approved_translations: # Use the translation instance already set for update if it exists. translation = self.translations_to_update.get( translation.pk, translation) translation.approved = False translation.approved_user = None translation.approved_date = None # Reject translations unless they became fuzzy during sync. Condition is sufficient # because they were approved previously. if not translation.fuzzy: new_action = ActionLog( action_type=ActionLog.ActionType.TRANSLATION_REJECTED, performed_by=user or self.sync_user, translation=translation, ) translation.rejected = True translation.rejected_user = user translation.rejected_date = self.now else: new_action = ActionLog( action_type=ActionLog.ActionType. TRANSLATION_UNAPPROVED, performed_by=user or self.sync_user, translation=translation, ) if translation.is_dirty(): self.translations_to_update[translation.pk] = translation self.actions_to_log.append(new_action) # Unfuzzy existing translations unless sync resolves them as active fuzzy translations. # Note: Translations cannot get fuzzy after the sync job starts, because they cannot be # made fuzzy in Pontoon. for translation in db_translations: if translation not in fuzzy_translations: # Use the translation instance already set for update if it exists. translation = self.translations_to_update.get( translation.pk, translation) translation.fuzzy = False if translation.is_dirty(): self.translations_to_update[translation.pk] = translation