def test_urlblock(self):
        block_id = uuid.uuid4()
        page = make_test_page_with_streamfield_block(
            str(block_id), "test_urlblock", "http://test-content.com/foo")

        translated_page = page.copy_for_translation(self.locale)

        ingest_segments(
            page,
            translated_page,
            self.src_locale,
            self.locale,
            [
                StringSegmentValue(f"test_streamfield.{block_id}",
                                   "http://test-content.fr/foo")
            ],
        )

        translated_page.save()
        translated_page.refresh_from_db()

        self.assertEqual(
            translated_page.test_streamfield.stream_data,
            [{
                "id": str(block_id),
                "type": "test_urlblock",
                "value": "http://test-content.fr/foo",
            }],
        )
    def test_childobjects(self):
        page = make_test_page()
        page.test_childobjects.add(TestChildObject(field="Test content"))
        page.save()

        child_translation_key = TestChildObject.objects.get().translation_key

        translated_page = page.copy_for_translation(self.locale)

        ingest_segments(
            page,
            translated_page,
            self.src_locale,
            self.locale,
            [
                StringSegmentValue(
                    f"test_childobjects.{child_translation_key}.field",
                    "Tester le contenu",
                )
            ],
        )

        old_child_object = page.test_childobjects.get()
        new_child_object = translated_page.test_childobjects.get()

        self.assertNotEqual(old_child_object.id, new_child_object.id)
        self.assertEqual(old_child_object.locale, self.src_locale)
        self.assertEqual(new_child_object.locale, self.locale)
        self.assertEqual(old_child_object.translation_key,
                         new_child_object.translation_key)

        self.assertEqual(new_child_object.field, "Tester le contenu")
Beispiel #3
0
    def test_blockquoteblock(self):
        block_id = uuid.uuid4()
        page = make_test_page_with_streamfield_block(str(block_id),
                                                     "test_blockquoteblock",
                                                     "Test content")

        translated_page = page.copy_for_translation(self.locale)

        ingest_segments(
            page,
            translated_page,
            self.src_locale,
            self.locale,
            [
                StringSegmentValue(f"test_streamfield.{block_id}",
                                   "Tester le contenu")
            ],
        )

        translated_page.save()
        translated_page.refresh_from_db()

        self.assertEqual(
            list(translated_page.test_streamfield.stream_data),
            [{
                "id": str(block_id),
                "type": "test_blockquoteblock",
                "value": "Tester le contenu",
            }],
        )
Beispiel #4
0
    def test_raises_typeerror_if_string_is_none(self):
        with self.assertRaises(TypeError) as e:
            StringSegmentValue("foo.bar", None)

        self.assertEqual(
            str(e.exception),
            "`string` must be either a `StringValue` or a `str`. Got `NoneType`",
        )
Beispiel #5
0
    def test_listblock(self):
        block_id = uuid.uuid4()
        page = make_test_page_with_streamfield_block(
            str(block_id), "test_listblock",
            ["Test content", "Some more test content"])

        segments = extract_segments(page)

        self.assertEqual(
            segments,
            [
                StringSegmentValue(f"test_streamfield.{block_id}",
                                   "Test content"),
                StringSegmentValue(f"test_streamfield.{block_id}",
                                   "Some more test content"),
            ],
        )
Beispiel #6
0
    def test_urlfield(self):
        page = make_test_page(test_urlfield="http://test-content.com/foo")
        segments = extract_segments(page)

        self.assertEqual(
            segments,
            [
                StringSegmentValue("test_urlfield",
                                   "http://test-content.com/foo")
            ],
        )
Beispiel #7
0
    def test_blockquoteblock(self):
        block_id = uuid.uuid4()
        page = make_test_page_with_streamfield_block(str(block_id),
                                                     "test_blockquoteblock",
                                                     "Test content")

        segments = extract_segments(page)

        self.assertEqual(segments, [
            StringSegmentValue(f"test_streamfield.{block_id}", "Test content")
        ])
    def test_structblock(self):
        block_id = uuid.uuid4()
        page = make_test_page_with_streamfield_block(
            str(block_id),
            "test_structblock",
            {"field_a": "Test content", "field_b": "Some more test content"},
        )

        translated_page = page.copy_for_translation(self.locale)

        ingest_segments(
            page,
            translated_page,
            self.src_locale,
            self.locale,
            [
                StringSegmentValue(
                    f"test_streamfield.{block_id}.field_a", "Tester le contenu"
                ),
                StringSegmentValue(
                    f"test_streamfield.{block_id}.field_b", "Encore du contenu de test"
                ),
            ],
        )

        translated_page.save()
        translated_page.refresh_from_db()

        self.assertEqual(
            translated_page.test_streamfield.stream_data,
            [
                {
                    "id": str(block_id),
                    "type": "test_structblock",
                    "value": {
                        "field_a": "Tester le contenu",
                        "field_b": "Encore du contenu de test",
                    },
                }
            ],
        )
    def test_replace_html_attrs(self):
        segment = StringSegmentValue.from_html(
            "foo.bar",
            'This is some text. &lt;foo&gt; <b>Bold text</b> <a id="a1">A link and some more <b>Bold text</b></a>',
        )

        segment.attrs = {"a1": {"href": "http://changed-example.com"}}

        self.assertEqual(
            segment.render_html(),
            'This is some text. &lt;foo&gt; <b>Bold text</b> <a href="http://changed-example.com">A link and some more <b>Bold text</b></a>',
        )
Beispiel #10
0
    def test_customfield(self):
        page = make_test_page(test_customfield="Test content")

        segments = extract_segments(page)

        self.assertEqual(
            segments,
            [
                StringSegmentValue("test_customfield.foo",
                                   "Test content and some extra")
            ],
        )
Beispiel #11
0
    def test_emailblock(self):
        block_id = uuid.uuid4()
        page = make_test_page_with_streamfield_block(str(block_id),
                                                     "test_emailblock",
                                                     "*****@*****.**")

        segments = extract_segments(page)

        self.assertEqual(segments, [
            StringSegmentValue(f"test_streamfield.{block_id}",
                               "*****@*****.**")
        ])
    def test_emailfield(self):
        page = make_test_page(test_emailfield="*****@*****.**")
        translated_page = page.copy_for_translation(self.locale)

        ingest_segments(
            page,
            translated_page,
            self.src_locale,
            self.locale,
            [StringSegmentValue("test_emailfield", "*****@*****.**")],
        )

        self.assertEqual(translated_page.test_emailfield, "*****@*****.**")
    def test_textfield(self):
        page = make_test_page(test_textfield="Test content")
        translated_page = page.copy_for_translation(self.locale)

        ingest_segments(
            page,
            translated_page,
            self.src_locale,
            self.locale,
            [StringSegmentValue("test_textfield", "Tester le contenu")],
        )

        self.assertEqual(translated_page.test_textfield, "Tester le contenu")
    def test_urlfield(self):
        page = make_test_page(test_urlfield="http://test-content.com/foo")
        translated_page = page.copy_for_translation(self.locale)

        ingest_segments(
            page,
            translated_page,
            self.src_locale,
            self.locale,
            [StringSegmentValue("test_urlfield", "http://test-content.fr/foo")],
        )

        self.assertEqual(translated_page.test_urlfield, "http://test-content.fr/foo")
Beispiel #15
0
    def handle_block(self, block_type, block_value):
        if hasattr(block_type, "get_translatable_segments"):
            return block_type.get_translatable_segments(block_value)

        elif isinstance(block_type, (blocks.URLBlock, blocks.EmailBlock)):
            if self.include_overridables:
                return [OverridableSegmentValue("", block_value)]
            else:
                return []

        elif isinstance(
                block_type,
            (blocks.CharBlock, blocks.TextBlock, blocks.BlockQuoteBlock)):
            return [StringSegmentValue("", block_value)]

        elif isinstance(block_type, blocks.RichTextBlock):
            template, strings = extract_strings(block_value.source)

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

        elif isinstance(block_type, blocks.ChooserBlock):
            return self.handle_related_object_block(block_value)

        elif isinstance(block_type, blocks.StructBlock):
            return self.handle_struct_block(block_value)

        elif isinstance(block_type, blocks.ListBlock):
            return self.handle_list_block(block_value)

        elif isinstance(block_type, blocks.StreamBlock):
            return self.handle_stream_block(block_value)

        # Ignore everything else
        return []
Beispiel #16
0
    def test_urlblock(self):
        block_id = uuid.uuid4()
        page = make_test_page_with_streamfield_block(
            str(block_id), "test_urlblock", "http://test-content.com/foo")

        segments = extract_segments(page)

        self.assertEqual(
            segments,
            [
                StringSegmentValue(f"test_streamfield.{block_id}",
                                   "http://test-content.com/foo")
            ],
        )
Beispiel #17
0
    def test_childobjects(self):
        page = make_test_page()
        page.test_childobjects.add(TestChildObject(field="Test content"))
        page.save()

        child_translation_key = TestChildObject.objects.get().translation_key

        segments = extract_segments(page)

        self.assertEqual(
            segments,
            [
                StringSegmentValue(
                    f"test_childobjects.{child_translation_key}.field",
                    "Test content")
            ],
        )
    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")
    def test_segment_value(self):
        segment = StringSegmentValue.from_html(
            "foo.bar",
            'This is some text. &lt;foo&gt; <b>Bold text</b> <a href="http://example.com">A link and some more <b>Bold text</b></a>',
        )

        self.assertEqual(segment.path, "foo.bar")
        self.assertEqual(segment.order, 0)
        self.assertEqual(
            segment.attrs, {"a1": {"href": "http://example.com"}}
        )
        self.assertEqual(
            segment.render_text(),
            "This is some text. <foo> Bold text A link and some more Bold text",
        )
        self.assertEqual(
            segment.render_html(),
            'This is some text. &lt;foo&gt; <b>Bold text</b> <a href="http://example.com">A link and some more <b>Bold text</b></a>',
        )

        # .with_order()
        orderred = segment.with_order(123)
        self.assertEqual(segment.order, 0)
        self.assertEqual(orderred.order, 123)
        self.assertEqual(orderred.path, "foo.bar")
        self.assertEqual(orderred.string, segment.string)
        self.assertEqual(orderred.attrs, segment.attrs)

        # .wrap()
        wrapped = segment.wrap("baz")
        self.assertEqual(segment.path, "foo.bar")
        self.assertEqual(wrapped.path, "baz.foo.bar")
        self.assertEqual(wrapped.order, segment.order)
        self.assertEqual(wrapped.string, segment.string)
        self.assertEqual(wrapped.attrs, segment.attrs)

        # .unwrap()
        path_component, unwrapped = segment.unwrap()
        self.assertEqual(segment.path, "foo.bar")
        self.assertEqual(path_component, "foo")
        self.assertEqual(unwrapped.path, "bar")
        self.assertEqual(unwrapped.order, segment.order)
        self.assertEqual(unwrapped.string, segment.string)
        self.assertEqual(unwrapped.attrs, segment.attrs)
Beispiel #20
0
    def test_customstructblock(self):
        block_id = uuid.uuid4()
        page = make_test_page_with_streamfield_block(
            str(block_id),
            "test_customstructblock",
            {
                "field_a": "Test content",
                "field_b": "Some more test content"
            },
        )

        segments = extract_segments(page)

        self.assertEqual(
            segments,
            [
                StringSegmentValue(
                    f"test_streamfield.{block_id}.foo",
                    "Test content / Some more test content",
                )
            ],
        )
Beispiel #21
0
    def test_nestedstreamblock(self):
        block_id = uuid.uuid4()
        nested_block_id = uuid.uuid4()
        page = make_test_page_with_streamfield_block(
            str(block_id),
            "test_nestedstreamblock",
            [{
                "id": str(nested_block_id),
                "type": "block_a",
                "value": "Test content"
            }],
        )

        segments = extract_segments(page)

        self.assertEqual(
            segments,
            [
                StringSegmentValue(
                    f"test_streamfield.{block_id}.{nested_block_id}",
                    "Test content")
            ],
        )
Beispiel #22
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()
    ]
Beispiel #23
0
    def test_slugfield(self):
        page = make_test_page(test_slugfield="test-content")
        segments = extract_segments(page)

        self.assertEqual(
            segments, [StringSegmentValue("test_slugfield", "test-content")])
    root_page = Page.objects.get(id=1)
    kwargs.setdefault("title", "Test page")
    return root_page.add_child(instance=TestPage(**kwargs))


RICH_TEXT_TEST_INPUT = '<h1>This is a heading</h1><p>This is a paragraph. &lt;foo&gt; <b>Bold text</b></p><ul><li><a href="http://example.com">This is a link</a></li></ul>'

RICH_TEXT_TEST_FRENCH_SEGMENTS = [
    TemplateSegmentValue(
        "",
        "html",
        '<h1><text position="0"></text></h1><p><text position="1"></text></p><ul><li><text position="2"></text></li></ul>',
        3,
        order=9,
    ),
    StringSegmentValue("", "Ceci est une rubrique", order=10),
    StringSegmentValue.from_source_html(
        "",
        'Ceci est un paragraphe. &lt;foo&gt; <b>Texte en gras</b>',
        order=11,
    ),
    StringSegmentValue(
        "",
        StringValue('<a id="a1">Ceci est un lien</a>'),
        attrs={
            "a1": {"href": "http://example.com"}
        },
        order=12,
    ),
]
Beispiel #25
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()
    ]
Beispiel #26
0
 def get_translatable_segments(self, value):
     return [
         StringSegmentValue(
             "foo", "{} / {}".format(value["field_a"], value["field_b"]))
     ]
Beispiel #27
0
def make_test_page(**kwargs):
    root_page = Page.objects.get(id=1)
    kwargs.setdefault("title", "Test page")
    return root_page.add_child(instance=TestPage(**kwargs))


RICH_TEXT_TEST_INPUT = '<h1>This is a heading</h1><p>This is a paragraph. &lt;foo&gt; <b>Bold text</b></p><ul><li><a href="http://example.com">This is a link</a>.</li></ul>'

RICH_TEXT_TEST_OUTPUT = [
    TemplateSegmentValue(
        "",
        "html",
        '<h1><text position="0"></text></h1><p><text position="1"></text></p><ul><li><text position="2"></text></li></ul>',
        3,
    ),
    StringSegmentValue("", "This is a heading"),
    StringSegmentValue.from_source_html(
        "",
        "This is a paragraph. &lt;foo&gt; <b>Bold text</b>",
    ),
    StringSegmentValue(
        "",
        StringValue('<a id="a1">This is a link</a>.'),
        attrs={"a1": {
            "href": "http://example.com"
        }},
    ),
    OverridableSegmentValue("'http://example.com'", "http://example.com"),
]

Beispiel #28
0
    def get_translatable_segments(self, value):
        if not value:
            # Don't disrupt other tests
            return []

        return [StringSegmentValue("foo", "{} and some extra".format(value))]
Beispiel #29
0
def machine_translate(request, translation_id):
    translation = get_object_or_404(Translation, id=translation_id)

    instance = translation.get_target_instance()
    if not user_can_edit_instance(request.user, instance):
        raise PermissionDenied

    translator = get_machine_translator()
    if translator is None:
        raise Http404

    if not translator.can_translate(translation.source.locale,
                                    translation.target_locale):
        raise Http404

    # Get segments
    segments = defaultdict(list)
    for string_segment in translation.source.stringsegment_set.all(
    ).select_related("context", "string"):
        segment = StringSegmentValue(
            string_segment.context.path,
            string_segment.string.as_value()).with_order(string_segment.order)
        if string_segment.attrs:
            segment.attrs = json.loads(string_segment.attrs)

        # Don't translate if there already is a translation
        if StringTranslation.objects.filter(
                translation_of_id=string_segment.string_id,
                locale=translation.target_locale,
                context_id=string_segment.context_id,
        ).exists():
            continue

        segments[segment.string].append(
            (string_segment.string_id, string_segment.context_id))

    if segments:
        translations = translator.translate(translation.source.locale,
                                            translation.target_locale,
                                            segments.keys())

        with transaction.atomic():
            for string, contexts in segments.items():
                for string_id, context_id in contexts:
                    StringTranslation.objects.get_or_create(
                        translation_of_id=string_id,
                        locale=translation.target_locale,
                        context_id=context_id,
                        defaults={
                            'data': translations[string].data,
                            'translation_type':
                            StringTranslation.TRANSLATION_TYPE_MACHINE,
                            'tool_name': translator.display_name,
                            'last_translated_by': request.user,
                            'has_error': False,
                            'field_error': "",
                        })

        messages.success(
            request,
            _("Successfully translated with {}.").format(
                translator.display_name))

    else:
        messages.warning(request, _("There isn't anything left to translate."))

    # Work out where to redirect to
    next_url = get_valid_next_url_from_request(request)
    if not next_url:
        # Note: You should always provide a next URL when using this view!
        next_url = reverse('wagtailadmin_home')

    return redirect(next_url)