def setUp(self): self.login() self.en_locale = Locale.objects.get() self.fr_locale = Locale.objects.create(language_code="fr") self.de_locale = Locale.objects.create(language_code="de") self.en_snippet = TestSnippet.objects.create(field="Test snippet") self.en_homepage = Page.objects.get(depth=2) self.fr_homepage = self.en_homepage.copy_for_translation( self.fr_locale) self.de_homepage = self.fr_homepage.copy_for_translation( self.de_locale) self.en_blog_index = make_test_page(self.en_homepage, title="Blog", slug="blog") self.en_blog_post = make_test_page(self.en_blog_index, title="Blog post", slug="blog-post") self.snippet_translation = Translation.objects.create( source=TranslationSource.get_or_create_from_instance( self.en_snippet)[0], target_locale=self.fr_locale, ) self.homepage_translation = Translation.objects.create( source=TranslationSource.get_or_create_from_instance( self.en_homepage)[0], target_locale=self.fr_locale, ) self.de_homepage_translation = Translation.objects.create( source=TranslationSource.get_or_create_from_instance( self.fr_homepage)[0], target_locale=self.de_locale, ) self.blog_index_translation = Translation.objects.create( source=TranslationSource.get_or_create_from_instance( self.en_blog_index)[0], target_locale=self.fr_locale, ) self.blog_post_translation = Translation.objects.create( source=TranslationSource.get_or_create_from_instance( self.en_blog_post)[0], target_locale=self.fr_locale, )
def test_post_submit_page_translation_reactivates_deleted_translation(self): # Create a disabled translation record # This simulates the case where the page was previously translated into that locale but later deleted source, created = TranslationSource.get_or_create_from_instance( self.en_blog_index ) translation = Translation.objects.create( source=source, target_locale=self.fr_locale, enabled=False, ) response = self.client.post( reverse( "wagtail_localize:submit_page_translation", args=[self.en_blog_index.id], ), {"locales": [self.fr_locale.id]}, ) # Check that the translation was reactivated # Note, .get() here tests that another translation record wasn't created translation = Translation.objects.get() self.assertEqual(translation.source, source) self.assertEqual(translation.target_locale, self.fr_locale) self.assertTrue(translation.enabled) # The translated page should've been created and published translated_page = self.en_blog_index.get_translation(self.fr_locale) self.assertTrue(translated_page.live) self.assertRedirects( response, reverse("wagtailadmin_pages:edit", args=[translated_page.id]) )
def test_update(self): source = TranslationSource.objects.create( object_id=self.snippet.translation_key, specific_content_type=ContentType.objects.get_for_model( TestSnippet), locale=self.snippet.locale, content_json=json.dumps({ "pk": self.snippet.pk, "field": "Some different content", # Changed "translation_key": str(self.snippet.translation_key), "locale": self.snippet.locale_id, }), last_updated_at=timezone.now(), ) new_source, created = TranslationSource.get_or_create_from_instance( self.snippet) self.assertEqual(source, new_source) self.assertEqual( json.loads(source.content_json)["field"], "Some different content") self.assertEqual( json.loads(new_source.content_json)["field"], "Some different content")
def setUp(self): self.snippet = TestSnippet.objects.create( field="Test snippet content", small_charfield="Small text" ) self.source, created = TranslationSource.get_or_create_from_instance( self.snippet ) self.source_locale = Locale.objects.get(language_code="en") self.dest_locale = Locale.objects.create(language_code="fr") # Add translation for field self.string = String.from_value( self.source_locale, StringValue.from_plaintext("Test snippet content") ) self.translation = StringTranslation.objects.create( translation_of=self.string, locale=self.dest_locale, context=TranslationContext.objects.get( object_id=self.snippet.translation_key, path="field" ), data="Tester le contenu de l'extrait", ) # Add translation for small_charfield self.small_string = String.from_value( self.source_locale, StringValue.from_plaintext("Small text") ) self.small_translation = StringTranslation.objects.create( translation_of=self.small_string, locale=self.dest_locale, context=TranslationContext.objects.get( object_id=self.snippet.translation_key, path="small_charfield" ), data="Petit text", # Truncated to fit because the field is limited to 10 characters )
def test_sync_view_restrictions_raises_exception_for_snippets(self): snippet = TestSnippet.objects.create(field="Test content") source, created = TranslationSource.get_or_create_from_instance( snippet) with self.assertRaises(NoViewRestrictionsError): source.sync_view_restrictions(snippet, snippet)
def setUp(self): self.snippet = TestSnippet.objects.create(field="Test snippet content") self.page = create_test_page( title="Test page", slug="test-page", test_charfield="This is some test content", test_snippet=self.snippet, ) self.source, created = TranslationSource.get_or_create_from_instance( self.page) self.source_locale = Locale.objects.get(language_code="en") self.dest_locale = Locale.objects.create(language_code="fr") # Translate the snippet self.translated_snippet = self.snippet.copy_for_translation( self.dest_locale) self.translated_snippet.field = "Tester le contenu de l'extrait" self.translated_snippet.save() # Add translation for test_charfield self.string = String.from_value( self.source_locale, StringValue.from_plaintext("This is some test content")) self.translation = StringTranslation.objects.create( translation_of=self.string, locale=self.dest_locale, context=TranslationContext.objects.get( object_id=self.page.translation_key, path="test_charfield"), data="Ceci est du contenu de test", )
def test_snippet(self): snippet = TestSnippet.objects.create(field="Test content") source, created = TranslationSource.get_or_create_from_instance(snippet) fr_translation = Translation.objects.create( source=source, target_locale=self.fr_locale, ) fr_translation.save_target() # Create a separate spanish translation to make sure that isn't disabled es_translation = Translation.objects.create( source=source, target_locale=self.es_locale, ) es_translation.save_target() fr_translation.refresh_from_db() es_translation.refresh_from_db() self.assertTrue(fr_translation.enabled) self.assertTrue(es_translation.enabled) snippet.get_translation(self.fr_locale).delete() fr_translation.refresh_from_db() es_translation.refresh_from_db() self.assertFalse(fr_translation.enabled) self.assertTrue(es_translation.enabled)
def test_post_submit_page_translation_doesnt_reactivate_deactivated_translation( self, ): # Like the previous test, this creates a disabled translation record, but this # time, the translation has not been deleted. It should not reactivate in this case source, created = TranslationSource.get_or_create_from_instance( self.en_blog_index ) translation = Translation.objects.create( source=source, target_locale=self.fr_locale, ) translation.save_target() translation.enabled = False translation.save(update_fields=["enabled"]) response = self.client.post( reverse( "wagtail_localize:submit_page_translation", args=[self.en_blog_index.id], ), {"locales": [self.fr_locale.id]}, ) # Form error self.assertEqual(response.status_code, 200) # Note, .get() here tests that another translation record wasn't created translation = Translation.objects.get() self.assertFalse(translation.enabled) # The translated page should've been created and published translated_page = self.en_blog_index.get_translation(self.fr_locale) self.assertTrue(translated_page.live)
def test_create_child(self): child_page = create_test_page( title="Child page", slug="child-page", parent=self.page, test_charfield="This is some test content", ) child_source = TranslationSource.from_instance(child_page)[0] translated_parent = self.page.copy_for_translation(self.dest_locale) # Create a translation for the new context StringTranslation.objects.create( translation_of=self.string, locale=self.dest_locale, context=TranslationContext.objects.get( object_id=child_page.translation_key, path="test_charfield"), data="Ceci est du contenu de test", ) new_page, created = child_source.create_or_update_translation( self.dest_locale) self.assertTrue(created) self.assertEqual(new_page.get_parent(), translated_parent) self.assertEqual(new_page.title, "Child page") self.assertEqual(new_page.test_charfield, "Ceci est du contenu de test") self.assertEqual(new_page.translation_key, child_page.translation_key) self.assertEqual(new_page.locale, self.dest_locale) self.assertTrue( child_source.translation_logs.filter( locale=self.dest_locale).exists())
def setUp(self): self.page = create_test_page( title="Test page", slug="test-page", test_charfield="This is some test content") self.source, created = TranslationSource.get_or_create_from_instance( self.page)
def setUp(self): self.page = create_test_page( title="Test page", slug="test-page", test_charfield="This is some test content") self.source = TranslationSource.from_instance(self.page)[0] self.source.extract_segments()
def test_creates_new_source_if_forced(self): source = TranslationSource.objects.create( object_id=self.snippet.translation_key, specific_content_type=ContentType.objects.get_for_model( TestSnippet), locale=self.snippet.locale, content_json=json.dumps({ "pk": self.snippet.pk, "field": "This is some test content", "translation_key": str(self.snippet.translation_key), "locale": self.snippet.locale_id, }), created_at=timezone.now(), ) new_source, created = TranslationSource.from_instance(self.snippet, force=True) self.assertTrue(created) self.assertNotEqual(source, new_source) self.assertEqual( json.loads(source.content_json)["field"], "This is some test content") self.assertEqual( json.loads(new_source.content_json)["field"], "This is some test content")
def create_test_page(**kwargs): parent = kwargs.pop("parent", None) or Page.objects.get(id=1) page = parent.add_child(instance=TestPage(**kwargs)) revision = page.save_revision() revision.publish() source, created = TranslationSource.get_or_create_from_instance(page) return page, source
def test_update_target_restrictions_ignores_snippets( self, get_translated_instance): snippet = TestSnippet.objects.create(field="Test content") source, created = TranslationSource.get_or_create_from_instance( snippet) source.update_target_view_restrictions(self.fr_locale) self.assertEqual(get_translated_instance.call_count, 0)
def prepare_source(source): # Recurse into any related objects for segment in source.relatedobjectsegment_set.all(): if not isinstance(segment, RelatedObjectSegmentValue): continue related_source, created = TranslationSource.get_or_create_from_instance( segment.get_instance(source.locale)) prepare_source(related_source)
def test_update_synchronised_fields(self): translated = self.page.copy_for_translation(self.dest_locale) self.page.test_synchronized_charfield = "Test synchronised content" self.page.test_synchronized_textfield = "Test synchronised content" self.page.test_synchronized_emailfield = "*****@*****.**" self.page.test_synchronized_slugfield = "test-synchronised-content" self.page.test_synchronized_urlfield = "https://test.synchronised/content" self.page.test_synchronized_richtextfield = "<p>Test synchronised content</p>" # self.page.test_synchronized_streamfield = "" synchronized_snippet = TestSnippet.objects.create( field="Synchronised snippet") self.page.test_synchronized_snippet = synchronized_snippet self.page.test_synchronized_customfield = "Test synchronised content" # Save the page revision = self.page.save_revision() revision.publish() self.page.refresh_from_db() source_with_translated_content = TranslationSource.from_instance( self.page)[0] # Check translation hasn't been updated yet translated.refresh_from_db() self.assertEqual(translated.test_synchronized_charfield, "") # Update the original page again. This will make sure it's taking the content from the translation source and not the live version self.page.test_synchronized_charfield = ( "Test synchronised content updated again") self.page.save_revision().publish() ( new_page, created, ) = source_with_translated_content.create_or_update_translation( self.dest_locale) self.assertFalse(created) self.assertEqual(new_page, translated) self.assertEqual(new_page.test_synchronized_charfield, "Test synchronised content") self.assertEqual(new_page.test_synchronized_charfield, "Test synchronised content") self.assertEqual(new_page.test_synchronized_textfield, "Test synchronised content") self.assertEqual(new_page.test_synchronized_emailfield, "*****@*****.**") self.assertEqual(new_page.test_synchronized_slugfield, "test-synchronised-content") self.assertEqual(new_page.test_synchronized_urlfield, "https://test.synchronised/content") self.assertEqual(new_page.test_synchronized_richtextfield, "<p>Test synchronised content</p>") self.assertEqual(new_page.test_synchronized_snippet, synchronized_snippet) self.assertEqual(new_page.test_synchronized_customfield, "Test synchronised content")
def setUp(self): self.en_locale = Locale.objects.get(language_code="en") self.fr_locale = Locale.objects.create(language_code="fr") self.page = create_test_page(title="Test page", slug="test-page", test_charfield="This is some test content") self.source, created = TranslationSource.get_or_create_from_instance(self.page) self.translation = Translation.objects.create( source=self.source, target_locale=self.fr_locale, )
def setUp(self): self.login() self.en_locale = Locale.objects.get() self.fr_locale = Locale.objects.create(language_code="fr") self.de_locale = Locale.objects.create(language_code="de") self.en_homepage = Page.objects.get(depth=2) self.fr_homepage = self.en_homepage.copy_for_translation( self.fr_locale) self.de_homepage = self.en_homepage.copy_for_translation( self.de_locale) self.en_blog_index = make_test_page(self.en_homepage, title="Blog", slug="blog") self.en_blog_post = make_test_page( self.en_blog_index, title="Blog post", slug="blog-post", test_charfield="Test content", test_richtextfield="<p>rich text</p>", ) self.en_snippet = TestSnippet.objects.create(field="Test snippet") # Create translation of page. This creates the FR version self.page_source, created = TranslationSource.get_or_create_from_instance( self.en_blog_post) self.page_translation = Translation.objects.create( source=self.page_source, target_locale=self.fr_locale) self.page_translation.save_target(publish=True) self.fr_blog_post = self.en_blog_post.get_translation(self.fr_locale) # Create translation of snippet. This creates the FR version self.snippet_source, created = TranslationSource.get_or_create_from_instance( self.en_snippet) self.snippet_translation = Translation.objects.create( source=self.snippet_source, target_locale=self.fr_locale) self.snippet_translation.save_target(publish=True) self.fr_snippet = self.en_snippet.get_translation(self.fr_locale)
def test_import_po(self): obsolete_string = String.from_value(self.en_locale, StringValue("This is an obsolete string")) StringTranslation.objects.create( translation_of=obsolete_string, context=TranslationContext.objects.get(path="test_charfield"), locale=self.fr_locale, data="Ceci est une chaîne obsolète", ) # Create a translation source to represent a past source that had the above string past_source = TranslationSource.from_instance(self.page, force=True)[0] past_source.extract_segments() past_source.stringsegment_set.update(string=obsolete_string) po = polib.POFile(wrapwidth=200) po.metadata = { "POT-Creation-Date": str(timezone.now()), "MIME-Version": "1.0", "Content-Type": "text/plain; charset=utf-8", "X-WagtailLocalize-TranslationID": str(self.translation.uuid), } po.append( polib.POEntry( msgid="This is some test content", msgctxt="test_charfield", msgstr="Contenu de test", ) ) po.append( polib.POEntry( msgid="This is an obsolete string", msgctxt="test_charfield", msgstr="C'est encore une chaîne obsolète", obsolete=True ) ) warnings = list(self.translation.import_po(po)) self.assertEqual(warnings, []) translation = StringTranslation.objects.get(translation_of__data="This is some test content") self.assertEqual(translation.context, TranslationContext.objects.get(path="test_charfield")) self.assertEqual(translation.locale, self.fr_locale) self.assertEqual(translation.data, "Contenu de test") # Obsolete strings still get updated translation = StringTranslation.objects.get(translation_of__data="This is an obsolete string") self.assertEqual(translation.context, TranslationContext.objects.get(path="test_charfield")) self.assertEqual(translation.locale, self.fr_locale) self.assertEqual(translation.data, "C'est encore une chaîne obsolète",)
def prepare_source(source): # Extract segments from source and save them into translation memory segments = extract_segments(source.as_instance()) insert_segments(source, source.locale_id, segments) # Recurse into any related objects for segment in segments: if not isinstance(segment, RelatedObjectSegmentValue): continue related_source, created = TranslationSource.from_instance( segment.get_instance(source.locale)) prepare_source(related_source)
def test_update_streamfields(self): # Streamfields are special in that they contain content that needs to be synchronised as well as # translatable content. # Copy page for translation, this will have a blank streamfield translated = self.page.copy_for_translation(self.dest_locale) # Set streamfield value on original self.page.test_streamfield = StreamValue( TestPage.test_streamfield.field.stream_block, [ { "id": "id", "type": "test_charblock", "value": "This is some test content", } ], is_lazy=True, ) # Save the page revision = self.page.save_revision() revision.publish() self.page.refresh_from_db() ( source_with_streamfield, created, ) = TranslationSource.update_or_create_from_instance(self.page) # Create a translation for the new context StringTranslation.objects.create( translation_of=self.string, locale=self.dest_locale, context=TranslationContext.objects.get( object_id=self.page.translation_key, path="test_streamfield.id" ), data="Ceci est du contenu de test", ) new_page, created = source_with_streamfield.create_or_update_translation( self.dest_locale ) self.assertFalse(created) self.assertEqual(new_page, translated) # Check the block was copied into translation self.assertEqual(new_page.test_streamfield[0].id, "id") self.assertEqual( new_page.test_streamfield[0].value, "Ceci est du contenu de test" )
def create_translations(self, instance, include_related_objects=True): if isinstance(instance, Page): instance = instance.specific if instance.translation_key in self.seen_objects: return self.seen_objects.add(instance.translation_key) source, created = TranslationSource.get_or_create_from_instance( instance) # Add related objects # Must be before translation records or those translation records won't be able to create # the objects because the dependencies haven't been created if include_related_objects: for related_object_segment in source.relatedobjectsegment_set.all( ): related_instance = related_object_segment.object.get_instance( instance.locale) # Limit to one level of related objects, since this could potentially pull in a lot of stuff self.create_translations(related_instance, include_related_objects=False) # Support disabling the out of the box translation mode. # The value set on the model takes precendence over the global setting. if hasattr(instance, "localize_default_translation_mode"): translation_mode = instance.localize_default_translation_mode else: translation_mode = getattr( settings, "WAGTAIL_LOCALIZE_DEFAULT_TRANSLATION_MODE", "synced") translation_enabled = translation_mode == "synced" # Set up translation records for target_locale in self.target_locales: # Create translation if it doesn't exist yet, re-enable if translation was disabled # Note that the form won't show this locale as an option if the translation existed # in this langauge, so this shouldn't overwrite any unmanaged translations. translation, created = Translation.objects.update_or_create( source=source, target_locale=target_locale, defaults={"enabled": translation_enabled}, ) self.mappings[source].append(translation) try: translation.save_target(user=self.user) except ValidationError: pass
def setUp(self): self.login() self.en_locale = Locale.objects.get() self.fr_locale = Locale.objects.create(language_code="fr") self.de_locale = Locale.objects.create(language_code="de") self.en_snippet = TestSnippet.objects.create(field="Test snippet") self.fr_snippet = self.en_snippet.copy_for_translation(self.fr_locale) self.fr_snippet.save() self.source, created = TranslationSource.get_or_create_from_instance( self.en_snippet) self.translation = Translation.objects.create( source=self.source, target_locale=self.fr_locale)
def test_snippet(self): snippet = TestSnippet.objects.create(field="Test content") source, created = TranslationSource.get_or_create_from_instance(snippet) translation = Translation.objects.create( source=source, target_locale=self.fr_locale, ) translation.refresh_from_db() self.assertTrue(translation.enabled) snippet.delete() translation.refresh_from_db() self.assertFalse(translation.enabled)
def test_create(self): source, created = TranslationSource.get_or_create_from_instance( self.snippet) self.assertTrue(created) self.assertEqual(source.object_id, self.snippet.translation_key) self.assertEqual(source.locale, self.snippet.locale) self.assertEqual( json.loads(source.content_json), { "pk": self.snippet.pk, "field": "This is some test content", "translation_key": str(self.snippet.translation_key), "locale": self.snippet.locale_id, }, ) self.assertTrue(source.created_at)
def test_save_target_cant_save_snippet_as_draft(self): snippet = TestSnippet.objects.create(field="Test content") source, created = TranslationSource.get_or_create_from_instance(snippet) translation = Translation.objects.create( source=source, target_locale=self.fr_locale, ) field_context = TranslationContext.objects.get(path="field") StringTranslation.objects.create( translation_of=self.test_content_string, context=field_context, locale=self.fr_locale, data="Contenu de test", ) with self.assertRaises(CannotSaveDraftError): translation.save_target(publish=False)
def setUp(self): self.page = create_test_page( title="Test page", slug="test-page", test_charfield="This is some test content", test_textfield="This is some more test content", ) self.source, created = TranslationSource.get_or_create_from_instance(self.page) self.source_locale = Locale.objects.get(language_code="en") self.dest_locale = Locale.objects.create(language_code="fr") # Translate the page self.translated_page = self.page.copy_for_translation(self.dest_locale) # Add a test child object and update the test_textfield. Then update the translation source self.page.test_childobjects.add( TestChildObject(field="This is a test child object") ) self.page.test_textfield = "Updated textfield" self.page.save_revision().publish() self.source.update_from_db() # Add translation for test_charfield self.translation = StringTranslation.objects.create( translation_of=String.objects.get(data="This is some test content"), locale=self.dest_locale, context=TranslationContext.objects.get( object_id=self.page.translation_key, path="test_charfield" ), data="Ceci est du contenu de test", ) # Add translation for child object self.translation = StringTranslation.objects.create( translation_of=String.objects.get(data="This is a test child object"), locale=self.dest_locale, context=TranslationContext.objects.get( object_id=self.page.translation_key, path="test_childobjects.{}.field".format( self.page.test_childobjects.get().translation_key ), ), data="Ceci est un objet enfant de test", )
def test_save_target_snippet(self): snippet = TestSnippet.objects.create(field="Test content") source, created = TranslationSource.get_or_create_from_instance(snippet) translation = Translation.objects.create( source=source, target_locale=self.fr_locale, ) field_context = TranslationContext.objects.get(path="field") StringTranslation.objects.create( translation_of=self.test_content_string, context=field_context, locale=self.fr_locale, data="Contenu de test", ) translation.save_target() translated_snippet = snippet.get_translation(self.fr_locale) self.assertEqual(translated_snippet.field, "Contenu de test")
def setUp(self): self.login() self.en_locale = Locale.objects.get() self.fr_locale = Locale.objects.create(language_code="fr") self.de_locale = Locale.objects.create(language_code="de") self.en_homepage = Page.objects.get(depth=2) self.fr_homepage = self.en_homepage.copy_for_translation( self.fr_locale) self.de_homepage = self.en_homepage.copy_for_translation( self.de_locale) self.en_blog_index = make_test_page(self.en_homepage, title="Blog", slug="blog") self.source, created = TranslationSource.get_or_create_from_instance( self.en_blog_index) self.translation = Translation.objects.create( source=self.source, target_locale=self.fr_locale)
def create_translations(self, instance, include_related_objects=True): if isinstance(instance, Page): instance = instance.specific if instance.translation_key in self.seen_objects: return self.seen_objects.add(instance.translation_key) source, created = TranslationSource.get_or_create_from_instance( instance) # Add related objects # Must be before translation records or those translation records won't be able to create # the objects because the dependencies haven't been created if include_related_objects: for related_object_segment in source.relatedobjectsegment_set.all( ): related_instance = related_object_segment.object.get_instance( instance.locale) # Limit to one level of related objects, since this could potentially pull in a lot of stuff self.create_translations(related_instance, include_related_objects=False) # Set up translation records for target_locale in self.target_locales: # Create translation if it doesn't exist yet, re-enable if translation was disabled # Note that the form won't show this locale as an option if the translation existed # in this langauge, so this shouldn't overwrite any unmanaged translations. translation, created = Translation.objects.update_or_create( source=source, target_locale=target_locale, defaults={'enabled': True}) try: translation.save_target(user=self.user) except ValidationError: pass