def handle_block(self, block_type, block_value, segments): # Need to check if the app is installed before importing EmbedBlock # See: https://github.com/wagtail/wagtail-localize/issues/309 if apps.is_installed("wagtail.embeds"): from wagtail.embeds.blocks import EmbedBlock, EmbedValue if isinstance(block_type, EmbedBlock): if len(segments) > 1: raise ValueError( "EmbedBlock can only have a single segment. Found {}". format(len(segments))) segment = segments[0] if isinstance(segment, OverridableSegmentValue): return EmbedValue(segment.data) if hasattr(block_type, "restore_translated_segments"): return block_type.restore_translated_segments( block_value, segments) elif isinstance( block_type, (blocks.CharBlock, blocks.TextBlock, blocks.URLBlock, blocks.EmailBlock), ): if len(segments) > 1: raise ValueError( "TextBlock/CharBlock can only have a single segment. Found {}" .format(len(segments))) segment = segments[0] if isinstance(segment, OverridableSegmentValue): return segment.data else: # Assume it's a StringSegmentValue return segment.render_text() elif isinstance(block_type, blocks.RichTextBlock): format, template, strings = organise_template_segments(segments) assert format == "html" return RichText(restore_strings(template, strings)) elif isinstance(block_type, blocks.ChooserBlock): return self.handle_related_object_block(block_value, segments) elif isinstance(block_type, blocks.StructBlock): return self.handle_struct_block(block_value, segments) elif isinstance(block_type, blocks.ListBlock): return self.handle_list_block(block_value, segments) elif isinstance(block_type, blocks.StreamBlock): return self.handle_stream_block(block_value, segments) else: raise Exception( "Unrecognised StreamField block type '{}'. Have you implemented restore_translated_segments() on this class?" .format(block_type.__class__.__name__))
def handle_block(self, block_type, block_value, segments): if hasattr(block_type, "restore_translated_segments"): return block_type.restore_translated_segments( block_value, segments) elif isinstance(block_type, (blocks.CharBlock, blocks.TextBlock)): return segments[0].render_text() elif isinstance(block_type, blocks.RichTextBlock): format, template, strings = organise_template_segments(segments) assert format == "html" return RichText(restore_strings(template, strings)) elif isinstance(block_type, blocks.ChooserBlock): return self.handle_related_object_block(block_value, segments) elif isinstance(block_type, blocks.StructBlock): return self.handle_struct_block(block_value, segments) elif isinstance(block_type, blocks.ListBlock): return self.handle_list_block(block_value, segments) elif isinstance(block_type, blocks.StreamBlock): return self.handle_stream_block(block_value, segments) else: raise Exception( "Unrecognised StreamField block type '{}'. Have you implemented restore_translated_segments() on this class?" .format(block_type.__class__.__name__))
def handle_block(self, block_type, block_value, segments): if hasattr(block_type, "restore_translated_segments"): return block_type.restore_translated_segments(block_value, segments) elif isinstance(block_type, (blocks.CharBlock, blocks.TextBlock, blocks.URLBlock, blocks.EmailBlock)): if len(segments) > 1: raise ValueError("TextBlock/CharBlock can only have a single segment. Found {}".format(len(segments))) segment = segments[0] if isinstance(segment, OverridableSegmentValue): return segment.data else: # Assume it's a StringSegmentValue return segment.render_text() elif isinstance(block_type, blocks.RichTextBlock): format, template, strings = organise_template_segments(segments) assert format == "html" return RichText(restore_strings(template, strings)) elif isinstance(block_type, blocks.ChooserBlock): return self.handle_related_object_block(block_value, segments) elif isinstance(block_type, blocks.StructBlock): return self.handle_struct_block(block_value, segments) elif isinstance(block_type, blocks.ListBlock): return self.handle_list_block(block_value, segments) elif isinstance(block_type, blocks.StreamBlock): return self.handle_stream_block(block_value, segments) else: raise Exception( "Unrecognised StreamField block type '{}'. Have you implemented restore_translated_segments() on this class?".format( block_type.__class__.__name__ ) )
def test_restore_strings(self): html = restore_strings( """ <p><text position="0"></text></p> <p><text position="1"></text></p> """, [ StringValue.from_html( '<b>Bread</b>\xa0is a\xa0<a href="https://en.wikipedia.org/wiki/Staple_food">staple food</a>\xa0prepared from a\xa0<a href="https://en.wikipedia.org/wiki/Dough">dough</a>\xa0of\xa0<a href="https://en.wikipedia.org/wiki/Flour">flour</a>\xa0and\xa0<a href="https://en.wikipedia.org/wiki/Water">water</a>, usually by\xa0<a href="https://en.wikipedia.org/wiki/Baking">baking</a>. Throughout recorded history it has been popular around the world and is one of the oldest artificial foods, having been of importance since the dawn of\xa0<a href="https://en.wikipedia.org/wiki/Agriculture#History">agriculture</a>.' ), StringValue.from_html( 'Proportions of types of flour and other ingredients vary widely, as do modes of preparation. As a result, types, shapes, sizes, and textures of breads differ around the world. Bread may be\xa0<a href="https://en.wikipedia.org/wiki/Leaven">leavened</a>\xa0by processes such as reliance on naturally occurring\xa0<a href="https://en.wikipedia.org/wiki/Sourdough">sourdough</a>\xa0microbes, chemicals, industrially produced yeast, or high-pressure aeration. Some bread is cooked before it can leaven, including for traditional or religious reasons. Non-cereal ingredients such as fruits, nuts and fats may be included. Commercial bread commonly contains additives to improve flavor, texture, color, shelf life, and ease of manufacturing.' ), ], ) self.assertHTMLEqual( """ <p><b>Bread</b>\xa0is a\xa0<a href="https://en.wikipedia.org/wiki/Staple_food">staple food</a>\xa0prepared from a\xa0<a href="https://en.wikipedia.org/wiki/Dough">dough</a>\xa0of\xa0<a href="https://en.wikipedia.org/wiki/Flour">flour</a>\xa0and\xa0<a href="https://en.wikipedia.org/wiki/Water">water</a>, usually by\xa0<a href="https://en.wikipedia.org/wiki/Baking">baking</a>. Throughout recorded history it has been popular around the world and is one of the oldest artificial foods, having been of importance since the dawn of\xa0<a href="https://en.wikipedia.org/wiki/Agriculture#History">agriculture</a>.</p> <p>Proportions of types of flour and other ingredients vary widely, as do modes of preparation. As a result, types, shapes, sizes, and textures of breads differ around the world. Bread may be\xa0<a href="https://en.wikipedia.org/wiki/Leaven">leavened</a>\xa0by processes such as reliance on naturally occurring\xa0<a href="https://en.wikipedia.org/wiki/Sourdough">sourdough</a>\xa0microbes, chemicals, industrially produced yeast, or high-pressure aeration. Some bread is cooked before it can leaven, including for traditional or religious reasons. Non-cereal ingredients such as fruits, nuts and fats may be included. Commercial bread commonly contains additives to improve flavor, texture, color, shelf life, and ease of manufacturing.</p> """, html, )
def test_restore_strings_2(self): html = restore_strings( """ <h1><text position="0"></text></h1> <p><text position="1"></text></p> <p><text position="2"></text></p> <ul> <li><text position="3"></text></li> <li><text position="4"></text></li> </ul> <img alt="This bit isn\'t translatable" src="foo"> """, [ StringValue.from_html("Foo bar baz"), StringValue.from_html( "This is a paragraph. <b>This is some bold <i>and now italic</i></b> text" ), StringValue.from_html( "<script> this should be interpreted as text."), StringValue.from_html("List item one"), StringValue.from_html("<b>List item two</b>"), ], ) self.assertHTMLEqual( """ <h1>Foo bar baz</h1> <p>This is a paragraph. <b>This is some bold <i>and now italic</i></b> text</p> <p><script> this should be interpreted as text.</p> <ul> <li>List item one</li> <li><b>List item two</li> </ul> <img src="foo" alt="This bit isn't translatable"> """, html, )
def ingest_segments(original_obj, translated_obj, src_locale, tgt_locale, segments): # Get segments by field name segments_by_field_name = defaultdict(list) for segment in segments: field_name, segment = segment.unwrap() segments_by_field_name[field_name].append(segment) for field_name, field_segments in segments_by_field_name.items(): field = translated_obj.__class__._meta.get_field(field_name) if hasattr(field, "restore_translated_segments"): value = field.value_from_object(original_obj) new_value = field.restore_translated_segments(value, field_segments) setattr(translated_obj, field_name, new_value) elif isinstance(field, StreamField): data = field.value_from_object(original_obj) StreamFieldSegmentsWriter( field, src_locale, tgt_locale ).handle_stream_block(data, field_segments) setattr(translated_obj, field_name, data) elif isinstance(field, RichTextField): format, template, strings = organise_template_segments(field_segments) assert format == "html" html = restore_strings(template, strings) setattr(translated_obj, field_name, html) elif isinstance(field, (models.TextField, models.CharField)): if len(field_segments) > 1: raise ValueError("TextField/CharField can only have a single segment. Found {}".format(len(field_segments))) segment = field_segments[0] if isinstance(segment, OverridableSegmentValue): setattr(translated_obj, field_name, segment.data) else: # Assume it's a StringSegmentValue setattr(translated_obj, field_name, segment.render_text()) elif isinstance(field, models.ForeignKey): related_translated = handle_related_object( field.related_model, src_locale, tgt_locale, field_segments ) setattr(translated_obj, field_name, related_translated) elif isinstance(field, (models.ManyToOneRel)): original_manager = getattr(original_obj, field_name) translated_manager = getattr(translated_obj, field_name) segments_by_child = defaultdict(list) for segment in field_segments: child_translation_key, segment = segment.unwrap() segments_by_child[child_translation_key].append(segment) for child_translation_key, child_segments in segments_by_child.items(): # The child objects must be synchronised before calling this function, so we # can assume that both exist original_child_object = original_manager.get( translation_key=child_translation_key ) translated_child_object = translated_manager.get( translation_key=child_translation_key ) ingest_segments( original_child_object, translated_child_object, src_locale, tgt_locale, child_segments, )