Translation memory models
These models are responsible for storing individual source strings and their translations.
String
Represents a unique string of translatable text.
Attributes:
Name | Type | Description |
---|---|---|
locale |
ForeignKey to Locale |
The locale of the string. |
data |
TextField |
The string. |
data_hash |
UUIDField |
A hash of the string, for more efficient indexing of long strings. |
_get_data_hash(data)
classmethod
private
Generates a UUID from the given string.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
string |
The string to generate a hash of. |
required |
Returns:
Type | Description |
---|---|
UUID |
The UUID hash. |
Source code in wagtail_localize/models.py
@classmethod
def _get_data_hash(cls, data):
"""
Generates a UUID from the given string.
Args:
data (string): The string to generate a hash of.
Returns:
UUID: The UUID hash.
"""
return uuid.uuid5(cls.UUID_NAMESPACE, data)
as_value(self)
Creates a StringValue object from the contents of this string.
Returns:
Type | Description |
---|---|
StringValue |
A StringValue instance with the content of this String. |
Source code in wagtail_localize/models.py
def as_value(self):
"""
Creates a StringValue object from the contents of this string.
Returns:
StringValue: A StringValue instance with the content of this String.
"""
return StringValue(self.data)
from_value(locale, stringvalue)
classmethod
Gets or creates a String instance from a StringValue object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
stringvalue |
StringValue |
The value of the string. |
required |
Returns:
Type | Description |
---|---|
String |
The String instance that corresponds with the given stringvalue and locale. |
Source code in wagtail_localize/models.py
@classmethod
def from_value(cls, locale, stringvalue):
"""
Gets or creates a String instance from a StringValue object.
Args:
locale (ForeignKey to Locale) The locale of the string.
stringvalue (StringValue): The value of the string.
Returns:
String: The String instance that corresponds with the given stringvalue and locale.
"""
string, created = cls.objects.get_or_create(
locale_id=pk(locale),
data_hash=cls._get_data_hash(stringvalue.data),
defaults={"data": stringvalue.data},
)
return string
StringTranslation
Represents a translation of a string.
Attributes:
Name | Type | Description |
---|---|---|
translation_of |
ForeignKey to String |
The String that this is a translation of. |
locale |
ForeignKey to Locale |
The Locale of this translation. |
context |
ForeignKey to TranslationContext |
The context that this translation was made in. This allows different fields/pages to have different translations of the same source string. |
data |
TextField |
The translation. |
translation_type |
CharField with choices 'manual' or 'machine' |
Whether the translationw as performed by a human or machine. |
tool_name |
CharField |
The name of the tool that was used to make this translation. |
last_translated_by |
ForeignKey to User |
The user who last updated this translation. |
created_at |
DateTimeField |
The date/time that this translation was first created. |
updated_at |
DateFimeField |
The date/time that this translation was last updated. |
has_error |
BooleanField |
Set to True if the value of this translation has an error. We store translations with errors in case they were edited from an external system. This allows us to display the error in Wagtail. |
field_error |
TextField |
If there was a database-level validation error while saving the translated object, that error is tored here. Note that this only makes sense if the context is not null. |
from_text(translation_of, locale, context, data)
classmethod
Gets or creates a StringTranslation instance from the given parameters.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
translation_of |
ForeignKey to String |
The String that this is a translation of. |
required |
locale |
ForeignKey to Locale |
The Locale of this translation. |
required |
context |
ForeignKey to TranslationContext |
The context that this translation was made in. This allows different fields/pages to have different translations of the same source string. |
required |
data |
TextField |
The translation. |
required |
Returns:
Type | Description |
---|---|
String |
The String instance that corresponds with the given stringvalue and locale. |
Source code in wagtail_localize/models.py
@classmethod
def from_text(cls, translation_of, locale, context, data):
"""
Gets or creates a StringTranslation instance from the given parameters.
Args:
translation_of (ForeignKey to String): The String that this is a translation of.
locale (ForeignKey to Locale): The Locale of this translation.
context (ForeignKey to TranslationContext): The context that this translation was made in. This allows different
fields/pages to have different translations of the same source string.
data (TextField): The translation.
Returns:
String: The String instance that corresponds with the given stringvalue and locale.
"""
segment, created = cls.objects.get_or_create(
translation_of=translation_of,
locale_id=pk(locale),
context_id=pk(context),
defaults={"data": data},
)
return segment
get_comment(self)
Returns a comment to display to the user containing info on how and when the string was translated.
Returns:
Type | Description |
---|---|
str |
A comment to display to the user. |
Source code in wagtail_localize/models.py
def get_comment(self):
"""
Returns a comment to display to the user containing info on how and when the string was translated.
Returns:
str: A comment to display to the user.
"""
if self.tool_name:
return _("Translated with {tool_name} on {date}").format(
tool_name=self.tool_name, date=self.updated_at.strftime(DATE_FORMAT)
)
elif self.translation_type == self.TRANSLATION_TYPE_MANUAL:
return _("Translated manually on {date}").format(
date=self.updated_at.strftime(DATE_FORMAT)
)
elif self.translation_type == self.TRANSLATION_TYPE_MACHINE:
return _("Machine translated on {date}").format(
date=self.updated_at.strftime(DATE_FORMAT)
)
get_error(self)
Returns a string containing any validation errors on the saved value.
Returns:
Type | Description |
---|---|
str |
The validation error if there is one. None: If there isn't an error. |
Source code in wagtail_localize/models.py
def get_error(self):
"""
Returns a string containing any validation errors on the saved value.
Returns:
str: The validation error if there is one.
None: If there isn't an error.
"""
if not self.has_error:
return
# Check for HTML validation errors
try:
StringValue.from_translated_html(self.data)
validate_translation_links(self.translation_of.data, self.data)
except ValueError as e:
return e.args[0]
# Check if a database error was raised when we last attempted to publish
if self.context is not None and self.field_error:
return self.field_error
set_field_error(self, error)
This sets the has_error
/field_error
fields to the value of the given ValidationError instance.
Note: If the given ValidationError contains multiple errors, only the first one is stored.
Note: This updates the database instance as well.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
error |
ValidationError |
The validation error to store. |
required |
Source code in wagtail_localize/models.py
def set_field_error(self, error):
"""
This sets the `has_error`/`field_error` fields to the value of the given ValidationError instance.
Note: If the given ValidationError contains multiple errors, only the first one is stored.
Note: This updates the database instance as well.
Args:
error (ValidationError): The validation error to store.
"""
self.has_error = True
# TODO (someday): We currently only support one error at a time
self.field_error = error[0].messages[0]
self.save(update_fields=["has_error", "field_error"])
Template
A Template stores the structure of a RichTextField or RichTextBlock.
When a RichTextField/RichTextBlock is converted into segments, all translatable segments are stripped out of the block and stored as String instances. The remaining HTML is saved as a Template and is used for recombining the translated strings back into a rich text value.
Attributes:
Name | Type | Description |
---|---|---|
template |
TextField |
The template value |
uuid |
UUIDField |
A hash of the template contents for efficient indexing. |
template_format |
CharField |
The format of the template (currently, only 'html' is supported). |
string_count |
PositiveIntegerField |
The number of translatable stirngs that were extracted from the template. |
from_value(template_value)
classmethod
Gets or creates a Template instance from a TemplateValue object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
template_value |
TemplateValue |
The value of the template. |
required |
Returns:
Type | Description |
---|---|
Template |
The Template instance that corresponds with the given template_value. |
Source code in wagtail_localize/models.py
@classmethod
def from_value(cls, template_value):
"""
Gets or creates a Template instance from a TemplateValue object.
Args:
template_value (TemplateValue): The value of the template.
Returns:
Template: The Template instance that corresponds with the given template_value.
"""
uuid_namespace = uuid.uuid5(cls.BASE_UUID_NAMESPACE, template_value.format)
template, created = cls.objects.get_or_create(
uuid=uuid.uuid5(uuid_namespace, template_value.template),
defaults={
"template": template_value.template,
"template_format": template_value.format,
"string_count": template_value.string_count,
},
)
return template
TranslationContext
Represents a context that a string may be translated in.
Strings can be translated differently in different contexts. A context is a combination of an object and content path.
Attributes:
Name | Type | Description |
---|---|---|
object |
ForeignKey to TranslatableObject |
The object. |
path |
TextField |
The content path. |
field_path |
TextField |
the field path. |
path_id |
UUIDField |
A hash of the path for efficient indexing of long content paths. |
_get_path_id(path)
classmethod
private
Generates a UUID from the given content path.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
path |
string |
The content path to generate a hash of. |
required |
Returns:
Type | Description |
---|---|
UUID |
The UUID hash. |
Source code in wagtail_localize/models.py
@classmethod
def _get_path_id(cls, path):
"""
Generates a UUID from the given content path.
Args:
path (string): The content path to generate a hash of.
Returns:
UUID: The UUID hash.
"""
return uuid.uuid5(uuid.UUID("fcab004a-2b50-11ea-978f-2e728ce88125"), path)
get_field_path(self, instance)
Gets the field path for this context
Field path's were introduced in version 1.0, any contexts that were created before that release won't have one.
Source code in wagtail_localize/models.py
def get_field_path(self, instance):
"""
Gets the field path for this context
Field path's were introduced in version 1.0, any contexts that were created before that release won't have one.
"""
if not self.field_path:
def get_field_path_from_field(instance, path_components):
field_name = path_components[0]
field = instance._meta.get_field(field_name)
if isinstance(field, StreamField):
def get_field_path_from_streamfield_block(value, path_components):
if isinstance(value, blocks.StructValue):
blocks_by_id = dict(value)
else:
if WAGTAIL_VERSION >= (2, 16) and isinstance(
value, ListValue
):
blocks_by_id = {
block.id: block for block in value.bound_blocks
}
else:
blocks_by_id = {block.id: block for block in value}
block_id = path_components[0]
block = blocks_by_id[block_id]
if isinstance(value, blocks.StructValue):
block_type = block_id
block_def = value.block.child_blocks[block_type]
block_value = block
else:
if WAGTAIL_VERSION >= (2, 16) and isinstance(
value, ListValue
):
block_type = "item"
block_def = value.list_block.child_block
else:
block_type = block.block_type
block_def = value.stream_block.child_blocks[block_type]
block_value = block.value
if isinstance(block_def, blocks.StructBlock):
return [block_type] + get_field_path_from_streamfield_block(
block_value, path_components[1:]
)
elif isinstance(block_def, blocks.StreamBlock):
return [block_type] + get_field_path_from_streamfield_block(
block_value, path_components[1:]
)
elif isinstance(
block_def, blocks.ListBlock
) and WAGTAIL_VERSION >= (2, 16):
return [block_type] + get_field_path_from_streamfield_block(
block_value, path_components[1:]
)
else:
return [block_type]
return [field_name] + get_field_path_from_streamfield_block(
field.value_from_object(instance), path_components[1:]
)
elif (
isinstance(field, models.ManyToOneRel)
and isinstance(field.remote_field, ParentalKey)
and issubclass(field.related_model, TranslatableMixin)
):
manager = getattr(instance, field_name)
child_instance = manager.get(translation_key=path_components[1])
return [field_name] + get_field_path_from_field(
child_instance, path_components[2:]
)
else:
return [field_name]
self.field_path = ".".join(
get_field_path_from_field(instance, self.path.split("."))
)
self.save(update_fields=["field_path"])
return self.field_path