def handle_block(self, block_type, block_value, raw_value=None): # 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 if isinstance(block_type, EmbedBlock): if self.include_overridables: return [OverridableSegmentValue("", block_value.url)] else: return [] 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) # 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"]) ret = ( [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) ]) return ret 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, raw_value) elif isinstance(block_type, blocks.StreamBlock): return self.handle_stream_block(block_value) # Ignore everything else return []
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.CharBlock, blocks.TextBlock)): 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) elif isinstance(block_type, (blocks.ChoiceBlock, EmbedBlock)): return [] else: raise Exception( "Unrecognised StreamField block type '{}'. Have you implemented get_translatable_segments on this class?" .format(block_type.__class__.__name__))
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 []
TestSnippet, ) 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. <foo> <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. <foo> <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"),
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() ]
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() ]