def new_unit(request, project, component, lang): translation = get_translation(request, project, component, lang) if not request.user.has_perm("unit.add", translation): raise PermissionDenied() form = get_new_unit_form(translation, request.user, request.POST) if not form.is_valid(): show_form_errors(request, form) else: if form.unit_exists(translation): messages.error(request, _("This string seems to already exist.")) else: # This is slow way of detecting unit, add_units should directly # create the database units, return them and they should be saved to # file as regular pending ones. existing = list(translation.unit_set.values_list("pk", flat=True)) translation.add_units(request, [form.as_tuple()]) messages.success(request, _("New string has been added.")) new_units = translation.unit_set.exclude(pk__in=existing) if form.cleaned_data["variant"]: for new_unit in new_units: flags = Flags(new_unit.extra_flags) flags.set_value("variant", form.cleaned_data["variant"]) new_unit.extra_flags = flags.format() new_unit.save( update_fields=["extra_flags"], same_content=True, run_checks=False, ) return redirect(new_unit) return redirect(translation)
def validate_check_flags(val): """Validate check influencing flags.""" try: flags = Flags(val) except ParseException as error: raise ValidationError(_("Failed to parse flags: %s") % error) flags.validate()
def test_unicode(self): self.assertEqual( Flags("zkouška, Memóriakártya").items(), {"zkouška", "Memóriakártya"}) self.assertEqual( Flags("placeholder:'zkouška sirén'").items(), {("placeholder", "zkouška sirén")}, )
def test_quoted_values(self): flags = Flags(r"""placeholders:"bar: \"value\"":'baz \'value\''""") self.assertEqual( flags.get_value("placeholders"), ['bar: "value"', "baz 'value'"] ) self.assertEqual( flags.format(), r'''placeholders:"bar: \"value\"":"baz 'value'"''' )
def sync_terminology(self): try: unit_flags = Flags(self.flags) except ParseException: unit_flags = None new_flags = Flags(self.extra_flags, unit_flags) if "terminology" in new_flags: self.translation.component.schedule_sync_terminology()
def post_uninstall(self): try: target_translation = self.get_target_translation(self.instance.component) flags = Flags(target_translation.check_flags) flags.remove("ignore-all-checks") target_translation.check_flags = flags.format() target_translation.save(update_fields=["check_flags"]) except Translation.DoesNotExist: pass super().post_uninstall()
def post_configure(self, run: bool = True): try: target_translation = self.get_target_translation(self.instance.component) flags = Flags(target_translation.check_flags) flags.merge("ignore-all-checks") target_translation.check_flags = flags.format() target_translation.save(update_fields=["check_flags"]) except Translation.DoesNotExist: pass super().post_configure(run=run)
def bulk_edit(request, project, component=None, lang=None): obj, unit_set, context = parse_url(request, project, component, lang) if not request.user.has_perm('translation.auto', obj): raise PermissionDenied() form = BulkEditForm(request.user, obj, request.POST, project=context['project']) if not form.is_valid(): messages.error(request, _('Failed to process form!')) show_form_errors(request, form) return redirect(obj) target_state = int(form.cleaned_data['state']) add_flags = Flags(form.cleaned_data['add_flags']) remove_flags = Flags(form.cleaned_data['remove_flags']) add_labels = form.cleaned_data['add_labels'] remove_labels = form.cleaned_data['remove_labels'] matching = unit_set.search(form.cleaned_data['q']) updated = 0 with transaction.atomic(): for unit in matching.select_for_update(): if not request.user.has_perm('unit.edit', unit): continue if target_state != -1 and unit.state: unit.translate( request.user, unit.target, target_state, change_action=Change.ACTION_MASS_STATE, ) updated += 1 if add_flags or remove_flags: flags = Flags(unit.source_info.extra_flags) flags.merge(add_flags) flags.remove(remove_flags) unit.source_info.extra_flags = flags.format() unit.source_info.save(update_fields=['extra_flags']) updated += 1 if add_labels: unit.source_info.labels.add(*add_labels) updated += 1 if remove_labels: unit.source_info.labels.remove(*remove_labels) updated += 1 import_message( request, updated, _('Bulk edit completed, no strings were updated.'), ungettext( 'Bulk edit completed, %d string was updated.', 'Bulk edit completed, %d strings were updated.', updated, ), ) return redirect(obj)
def bulk_perform( user, unit_set, query, target_state, add_flags, remove_flags, add_labels, remove_labels, ): matching = unit_set.search(query) target_state = int(target_state) add_flags = Flags(add_flags) remove_flags = Flags(remove_flags) cleanups = {} preloaded_sources = False updated = 0 with transaction.atomic(): for unit in matching.select_for_update(): if not preloaded_sources: unit.translation.component.preload_sources() preloaded_sources = True if user is not None and not user.has_perm("unit.edit", unit): continue updated += 1 if (target_state != -1 and unit.state > STATE_EMPTY and unit.state < STATE_READONLY): unit.translate( user, unit.target, target_state, change_action=Change.ACTION_BULK_EDIT, propagate=False, ) if add_flags or remove_flags: flags = Flags(unit.source_info.extra_flags) flags.merge(add_flags) flags.remove(remove_flags) unit.source_info.is_bulk_edit = True unit.source_info.extra_flags = flags.format() unit.source_info.save(update_fields=["extra_flags"]) cleanups[ unit.translation.component.pk] = unit.translation.component if add_labels: unit.source_info.is_bulk_edit = True unit.source_info.labels.add(*add_labels) cleanups[ unit.translation.component.pk] = unit.translation.component if remove_labels: unit.source_info.is_bulk_edit = True unit.source_info.labels.remove(*remove_labels) cleanups[ unit.translation.component.pk] = unit.translation.component for component in cleanups.values(): component.invalidate_stats_deep() return updated
def update_variants(self): old_flags = Flags(self.old_unit.extra_flags, self.old_unit.flags) new_flags = Flags(self.extra_flags, self.flags) old_variant = None if old_flags.has_value("variant"): old_variant = old_flags.get_value("variant") new_variant = None if new_flags.has_value("variant"): new_variant = new_flags.get_value("variant") # Check for relevant changes if old_variant == new_variant: return # Delete stale variant if old_variant: for variant in self.defined_variants.all(): variant.defining_units.remove(self) if variant.defining_units.count() == 0: variant.delete() else: variant.unit_set.filter(id_hash=self.id_hash).update( variant=None) # Add new variant if new_variant: variant = Variant.objects.get_or_create( key=new_variant, component=self.translation.component)[0] variant.defining_units.add(self) # Update variant links self.translation.component.update_variants()
def test_whitespace(self): self.assertEqual(Flags(" foo , bar ").items(), {"foo", "bar"}) flags = Flags( "max-size:120:2,font-family:DIN next pro,font-spacing:2, priority:140" ) self.assertEqual( flags.items(), { ("font-family", "DIN next pro"), ("priority", "140"), ("max-size", "120", "2"), ("font-spacing", "2"), }, )
def test_remove(self): flags = Flags("placeholders:bar:baz, foo:1, bar") flags.remove("foo") self.assertEqual(flags.items(), {("placeholders", "bar", "baz"), "bar"}) flags.remove("bar") self.assertEqual(flags.items(), {("placeholders", "bar", "baz")})
def get_all_flags(self, override=None): """Return union of own and component flags.""" # Validate flags from the unit to avoid crash try: unit_flags = Flags(override or self.flags) except ParseException: unit_flags = None return Flags( self.translation.all_flags, self.extra_flags, # The source_unit is None before saving the object for the first time getattr(self.source_unit, "extra_flags", ""), unit_flags, )
def bulk_perform( user, unit_set, query, target_state, add_flags, remove_flags, add_labels, remove_labels, ): matching = unit_set.search(query) components = Component.objects.filter( id__in=matching.values_list("translation__component_id", flat=True)) target_state = int(target_state) add_flags = Flags(add_flags) remove_flags = Flags(remove_flags) updated = 0 for component in components: component.preload_sources() with transaction.atomic(), component.lock(): for unit in matching.filter( translation__component=component).select_for_update(): if user is not None and not user.has_perm("unit.edit", unit): continue updated += 1 if (target_state != -1 and unit.state > STATE_EMPTY and unit.state < STATE_READONLY): unit.translate( user, unit.target, target_state, change_action=Change.ACTION_BULK_EDIT, propagate=False, ) if add_flags or remove_flags: flags = Flags(unit.source_info.extra_flags) flags.merge(add_flags) flags.remove(remove_flags) unit.source_info.is_bulk_edit = True unit.source_info.extra_flags = flags.format() unit.source_info.save(update_fields=["extra_flags"]) if add_labels: unit.source_info.is_bulk_edit = True unit.source_info.labels.add(*add_labels) if remove_labels: unit.source_info.is_bulk_edit = True unit.source_info.labels.remove(*remove_labels) component.invalidate_stats_deep() return updated
def get_all_flags(self, override=None): """Return union of own and component flags.""" return Flags( self.translation.all_flags, self.extra_flags, override or self.flags, )
def get_all_flags(self, override=None): """Return union of own and component flags.""" return Flags( self.translation.component.all_flags, self.source_info.check_flags, override or self.flags, )
def all_flags(self): """Return union of own and component flags.""" return Flags( self.translation.component.all_flags, self.source_info.check_flags, self.flags, )
def flags(self): placeholders = self.mainunit.placeholders if not placeholders: return "" return "placeholders:{}".format(":".join( Flags.format_value("{{{}}}".format(key.upper())) for key in placeholders.keys()))
def test_description(self): unit = Unit(source="string URL", target="string") unit.__dict__["all_flags"] = Flags("regex:URL") check = Check(unit=unit) self.assertEqual( self.check.get_description(check), "Does not match regular expression <code>URL</code>.", )
def test_description(self): unit = Unit(source="string $URL$", target="string") unit.__dict__["all_flags"] = Flags("placeholders:$URL$") check = Check(unit=unit) self.assertEqual( self.check.get_description(check), "Translation is missing some placeholders: $URL$", )
def test_description(self): unit = Unit(source="string $URL$", target="string") unit.__dict__["all_flags"] = Flags("placeholders:$URL$") check = Check(unit=unit) self.assertEqual( self.check.get_description(check), "Following format strings are missing: $URL$", )
def get_all_flags(self, override=None): """Return union of own and component flags.""" return Flags( self.translation.all_flags, # The source_unit is None before saving the object for the first time self.source_unit.extra_flags if self.source_unit else self.extra_flags, override or self.flags, )
def edit_context(request, pk): unit = get_object_or_404(Unit, pk=pk) if not unit.is_source and not unit.translation.component.is_glossary: raise Http404("Non source unit!") do_add = "addflag" in request.POST if do_add or "removeflag" in request.POST: if not request.user.has_perm("unit.flag", unit.translation): raise PermissionDenied() flag = request.POST.get("addflag", request.POST.get("removeflag")) flags = Flags(unit.extra_flags) if do_add: flags.merge(flag) else: flags.remove(flag) new_flags = flags.format() if new_flags != unit.extra_flags: unit.extra_flags = new_flags unit.save(same_content=True, update_fields=["extra_flags"]) else: if not request.user.has_perm("source.edit", unit.translation): raise PermissionDenied() form = ContextForm(request.POST, instance=unit, user=request.user) if form.is_valid(): form.save() else: messages.error(request, _("Failed to change additional string info!")) show_form_errors(request, form) return redirect_next(request.POST.get("next"), unit.get_absolute_url())
def test_regexp(self): unit = Unit(source="string $URL$", target="string $FOO$") unit.__dict__["all_flags"] = Flags(r"""placeholders:r"\$[^$]*\$" """) check = Check(unit=unit) self.assertEqual( self.check.get_description(check), "Following format strings are missing: $URL$" "<br />Following format strings are extra: $FOO$", )
def ignore_check_source(request, check_id): obj = get_object_or_404(Check, pk=int(check_id)) unit = obj.unit.source_unit if not request.user.has_perm("unit.check", obj) or not request.user.has_perm( "source.edit", unit.translation.component ): raise PermissionDenied() # Mark check for ignoring ignore = obj.check_obj.ignore_string flags = Flags(unit.extra_flags) if ignore not in flags: flags.merge(ignore) unit.extra_flags = flags.format() unit.save(same_content=True) # response for AJAX return HttpResponse("ok")
def test_quoted_values(self): flags = Flags(r"""placeholders:"bar: \"value\"":'baz \'value\''""") self.assertEqual(flags.get_value("placeholders"), ['bar: "value"', "baz 'value'"]) self.assertEqual(flags.format(), r'''placeholders:"bar: \"value\"":"baz 'value'"''') flags = Flags(r'regex:"((?:@:\(|\{)[^\)\}]+(?:\)|\}))"') self.assertEqual(flags.format(), r'regex:"((?:@:\(|\{)[^\)\}]+(?:\)|\}))"')
def test_description(self): unit = Unit(source="string $URL$", target="string") unit.__dict__["all_flags"] = Flags("placeholders:$URL$") check = Check(unit=unit) self.assertHTMLEqual( self.check.get_description(check), """ Following format strings are missing: <span class="hlcheck" data-value="$URL$">$URL$</span> """, )
def __init__(self, id_hash=None, flags="", code="cs", source="", note=""): if id_hash is None: id_hash = random.randint(0, 65536) self.id_hash = id_hash self.flags = Flags(flags) self.translation = MockTranslation(code) self.source = source self.fuzzy = False self.translated = True self.state = 20 self.note = note
def ignore_check_source(request, check_id): obj = get_object_or_404(Check, pk=int(check_id)) unit = obj.unit.source_info project = unit.translation.component.project request.user.check_access(project) if (not request.user.has_perm('unit.check', project) or not request.user.has_perm('source.edit', unit.translation.component)): raise PermissionDenied() # Mark check for ignoring ignore = obj.check_obj.ignore_string flags = Flags(unit.extra_flags) if ignore not in flags: flags.merge(ignore) unit.extra_flags = flags.format() unit.save() # response for AJAX return HttpResponse('ok')
def __init__(self, id_hash=None, flags='', code='cs', source='', comment=''): if id_hash is None: id_hash = random.randint(0, 65536) self.id_hash = id_hash self.flags = Flags(flags) self.translation = MockTranslation(code) self.source = source self.fuzzy = False self.translated = True self.comment = comment