Segment extraction module
The segment extraction module is responsible for extracting translatable segments from source objects.
StreamFieldSegmentExtractor
A helper class to help traverse StreamField values and extract segments.
__init__(self, field, include_overridables=False)
special
Initialises a StreamFieldSegmentExtractor.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
field |
StreamField |
The StreamField to extract segments from. |
required |
include_overridables |
boolean |
Set this to True to extract overridable segments too. |
False |
Source code in wagtail_localize/segments/extract.py
def __init__(self, field, include_overridables=False):
"""
Initialises a StreamFieldSegmentExtractor.
Args:
field (StreamField): The StreamField to extract segments from.
include_overridables (boolean, optional): Set this to True to extract overridable segments too.
"""
self.field = field
self.include_overridables = include_overridables
extract_segments(instance)
Extracts segments from the given model instance.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
instance |
Model |
The model instance to extract segments from. |
required |
Returns:
Type | Description |
---|---|
list[StringSegmentValue, TemplateSegmentValue, RelatedObjectSegmentValue, or OverridableSegmentValue] |
The segment values that have been extracted. |
Source code in wagtail_localize/segments/extract.py
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):
value = field.value_from_object(instance)
if is_translatable:
template, strings = extract_strings(value)
# 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()
]
quote_path_component(text)
Puts quotes around the path compoenents, and escapes any special characters.
Source code in wagtail_localize/segments/extract.py
def quote_path_component(text):
"""
Puts quotes around the path compoenents, and escapes any special characters.
"""
return "'" + text.replace("\\", "\\\\").replace("'", "\\'") + "'"