Exemple #1
0
    def test_snippet(self):
        test_snippet = TestSnippet.objects.create(field="Test content")
        page = make_test_page(test_snippet=test_snippet)
        segments = extract_segments(page)

        self.assertEqual(segments, [
            RelatedObjectSegmentValue.from_instance("test_snippet",
                                                    test_snippet)
        ])
Exemple #2
0
    def handle_related_object_block(self, related_object):
        if related_object is None:
            return []

        if isinstance(related_object, TranslatableMixin):
            return [
                RelatedObjectSegmentValue.from_instance("", related_object)
            ]
        else:
            return [OverridableSegmentValue("", related_object.pk)]
Exemple #3
0
    def handle_related_object_block(self, related_object):
        if related_object is None:
            return []

        # All FKs to translatable models should be translatable.
        # With the exception of pages that are special because we can localize them at runtime easily.
        # TODO: Perhaps we need a special type for pages where it links to the translation if availabe,
        # but falls back to the source if it isn't translated yet?
        # Note: This exact same decision was made for regular foreign keys in fields.py
        if isinstance(related_object, TranslatableMixin) and not isinstance(
                related_object, Page):
            return [
                RelatedObjectSegmentValue.from_instance("", related_object)
            ]
        else:
            return [OverridableSegmentValue("", related_object.pk)]
    def test_snippet(self):
        test_snippet = TestSnippet.objects.create(field="Test content")
        translated_snippet = test_snippet.copy_for_translation(self.locale)
        translated_snippet.save()

        # Ingest segments into the snippet
        ingest_segments(
            test_snippet,
            translated_snippet,
            self.src_locale,
            self.locale,
            [StringSegmentValue("field", "Tester le contenu")],
        )

        translated_snippet.save()

        self.assertEqual(translated_snippet.field, "Tester le contenu")

        # Now ingest a RelatedObjectSegmentValue into the page
        page = make_test_page(test_snippet=test_snippet)
        translated_page = page.copy_for_translation(self.locale)

        ingest_segments(
            page,
            translated_page,
            self.src_locale,
            self.locale,
            [
                RelatedObjectSegmentValue.from_instance(
                    "test_snippet", test_snippet)
            ],
        )

        # Check the translated snippet was linked to the translated page
        self.assertNotEqual(page.test_snippet_id,
                            translated_page.test_snippet_id)
        self.assertEqual(page.test_snippet.locale, self.src_locale)
        self.assertEqual(translated_page.test_snippet.locale, self.locale)
        self.assertEqual(
            page.test_snippet.translation_key,
            translated_page.test_snippet.translation_key,
        )

        self.assertEqual(translated_page.test_snippet.field,
                         "Tester le contenu")
Exemple #5
0
def extract_segments(instance):
    """
    Extracts segments from the given model instance.

    Args:
        instance (Model): The model instance to extract segments from.

    Returns:
        list[StringSegmentValue, TemplateSegmentValue, RelatedObjectSegmentValue, or OverridableSegmentValue]: The
            segment values that have been extracted.
    """
    segments = []

    for translatable_field in get_translatable_fields(instance.__class__):
        field = translatable_field.get_field(instance.__class__)
        is_translatable = translatable_field.is_translated(instance)
        is_synchronized = translatable_field.is_synchronized(instance)
        is_overridable = translatable_field.is_overridable(instance)
        extract_overridables = is_synchronized and is_overridable

        if hasattr(field, "get_translatable_segments"):
            if is_translatable:
                segments.extend(
                    segment.wrap(field.name)
                    for segment in field.get_translatable_segments(
                        field.value_from_object(instance)))

        elif isinstance(field, StreamField):
            if is_translatable:
                segments.extend(
                    segment.wrap(field.name)
                    for segment in StreamFieldSegmentExtractor(
                        field, include_overridables=extract_overridables).
                    handle_stream_block(field.value_from_object(instance)))

        elif isinstance(field, RichTextField):
            if is_translatable:
                template, strings = extract_strings(
                    field.value_from_object(instance))

                # Find all unique href values
                hrefs = set()
                for _string, attrs in strings:
                    for tag_attrs in attrs.values():
                        if "href" in tag_attrs:
                            hrefs.add(tag_attrs["href"])

                field_segments = ([
                    TemplateSegmentValue("", "html", template, len(strings))
                ] + [
                    StringSegmentValue("", string, attrs=attrs)
                    for string, attrs in strings
                ] + [
                    OverridableSegmentValue(quote_path_component(href), href)
                    for href in sorted(hrefs)
                ])

                segments.extend(
                    segment.wrap(field.name) for segment in field_segments)

            if extract_overridables:
                pass  # TODO: Extract images and links

        elif isinstance(field, (models.TextField, models.CharField)):
            if not field.choices:
                value = field.value_from_object(instance)

                if value is None:
                    continue

                if is_translatable:
                    segments.append(StringSegmentValue(field.name, value))

                elif extract_overridables:
                    segments.append(OverridableSegmentValue(field.name, value))

        elif isinstance(field, (models.ForeignKey)):
            if is_translatable:
                if not issubclass(field.related_model, TranslatableMixin):
                    raise ImproperlyConfigured(
                        "The foreign key `{}.{}.{}` was registered as a translatable "
                        "field but the model it points to `{}.{}` is not translatable"
                        .format(
                            field.model._meta.app_label,
                            field.model.__name__,
                            field.name,
                            field.related_model._meta.app_label,
                            field.related_model.__name__,
                        ))

                related_instance = getattr(instance, field.name)

                if related_instance:
                    segments.append(
                        RelatedObjectSegmentValue.from_instance(
                            field.name, related_instance))

            elif extract_overridables:
                related_instance = getattr(instance, field.name)

                if related_instance:
                    segments.append(
                        OverridableSegmentValue(field.name,
                                                related_instance.pk))
        elif (isinstance(field, (models.ManyToOneRel))
              and isinstance(field.remote_field, ParentalKey)
              and issubclass(field.related_model, TranslatableMixin)):
            manager = getattr(instance, field.name)

            if is_translatable:
                for child_instance in manager.all():
                    segments.extend(
                        segment.wrap(str(child_instance.translation_key)).wrap(
                            field.name)
                        for segment in extract_segments(child_instance))

            elif extract_overridables:
                pass  # TODO

    class Counter:
        def __init__(self):
            self.value = 0

        def next(self):
            self.value += 1
            return self.value

    counter = Counter()

    return [
        segment.with_order(counter.next()) for segment in segments
        if not segment.is_empty()
    ]
Exemple #6
0
def extract_segments(instance):
    segments = []

    for translatable_field in get_translatable_fields(instance.__class__):
        if not translatable_field.is_translated(instance):
            continue

        field = translatable_field.get_field(instance.__class__)

        if hasattr(field, "get_translatable_segments"):
            segments.extend(
                segment.wrap(field.name)
                for segment in field.get_translatable_segments(
                    field.value_from_object(instance)))

        elif isinstance(field, StreamField):
            segments.extend(
                segment.wrap(field.name)
                for segment in StreamFieldSegmentExtractor(field).
                handle_stream_block(field.value_from_object(instance)))

        elif isinstance(field, RichTextField):
            template, strings = extract_strings(
                field.value_from_object(instance))

            field_segments = [
                TemplateSegmentValue("", "html", template, len(strings))
            ] + [
                StringSegmentValue("", string, attrs=attrs)
                for string, attrs in strings
            ]

            segments.extend(
                segment.wrap(field.name) for segment in field_segments)

        elif isinstance(field, (models.TextField, models.CharField)):
            if not field.choices:
                segments.append(
                    StringSegmentValue(field.name,
                                       field.value_from_object(instance)))

        elif isinstance(field, (models.ForeignKey)) and issubclass(
                field.related_model, TranslatableMixin):
            related_instance = getattr(instance, field.name)

            if related_instance:
                segments.append(
                    RelatedObjectSegmentValue.from_instance(
                        field.name, related_instance))

        elif (isinstance(field, (models.ManyToOneRel))
              and isinstance(field.remote_field, ParentalKey)
              and issubclass(field.related_model, TranslatableMixin)):
            manager = getattr(instance, field.name)

            for child_instance in manager.all():
                segments.extend(
                    segment.wrap(str(child_instance.translation_key)).wrap(
                        field.name)
                    for segment in extract_segments(child_instance))

    class Counter:
        def __init__(self):
            self.value = 0

        def next(self):
            self.value += 1
            return self.value

    counter = Counter()

    return [
        segment.with_order(counter.next()) for segment in segments
        if not segment.is_empty()
    ]
Exemple #7
0
    def handle_related_object_block(self, related_object):
        if related_object is None or not isinstance(related_object,
                                                    TranslatableMixin):
            return []

        return [RelatedObjectSegmentValue.from_instance("", related_object)]