Synctree module
The synctree module implements the logic that keeps locale trees in sync.
PageIndex
An in-memory index of pages to remove the need to query the database.
Each entry in the index is a unique page by translation key, so a page that has been translated into different languages appears only once.
Entry
Represents a page in the index.
from_page_instance(page)
classmethod
Initialises an Entry from the given page instance.
Source code in wagtail_localize/synctree.py
@classmethod
def from_page_instance(cls, page):
"""
Initialises an Entry from the given page instance.
"""
# Get parent, but only if the parent is not the root page. We consider the
# homepage of each langauge tree to be the roots
if page.depth > 2:
parent_page = page.get_parent()
else:
parent_page = None
return cls(
page.content_type,
page.translation_key,
page.locale,
parent_page.translation_key if parent_page else None,
list(
Page.objects.filter(
translation_key=page.translation_key,
alias_of__isnull=True,
).values_list("locale", flat=True)
),
list(
Page.objects.filter(
translation_key=page.translation_key,
alias_of__isnull=False,
).values_list("locale", flat=True)
),
)
from_database()
classmethod
Populates the index from the database.
Source code in wagtail_localize/synctree.py
@classmethod
def from_database(cls):
"""
Populates the index from the database.
"""
pages = []
for page in Page.objects.filter(alias_of__isnull=True, depth__gt=1).only(
*PageIndex.Entry.REQUIRED_PAGE_FIELDS
):
pages.append(PageIndex.Entry.from_page_instance(page))
return PageIndex(pages)
not_translated_into(self, locale)
Returns an index of pages that are not translated into the specified locale. This includes pages that have and don't have a placeholder
Source code in wagtail_localize/synctree.py
def not_translated_into(self, locale):
"""
Returns an index of pages that are not translated into the specified locale.
This includes pages that have and don't have a placeholder
"""
pages = [page for page in self.pages if locale.id not in page.locales]
return PageIndex(pages)
sort_by_tree_position(self)
Returns a new index with the pages sorted in depth-first-search order using their parent in their respective source locale.
Source code in wagtail_localize/synctree.py
def sort_by_tree_position(self):
"""
Returns a new index with the pages sorted in depth-first-search order
using their parent in their respective source locale.
"""
remaining_pages = {page.translation_key for page in self.pages}
new_pages = []
def _walk(translation_key):
for page in self.by_parent_translation_key.get(translation_key, []):
if page.translation_key not in remaining_pages:
continue
remaining_pages.remove(page.translation_key)
new_pages.append(page)
_walk(page.translation_key)
_walk(None)
if remaining_pages:
print("Warning: {} orphaned pages!".format(len(remaining_pages)))
return PageIndex(new_pages)
synchronize_tree(source_locale, target_locale, *, page_index=None)
Synchronises a locale tree with an other locale.
This creates alias pages for pages that are not translated yet.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
source_locale |
Locale |
The Locale to sync from. |
required |
target_locale |
Locale |
The Locale to sync into |
required |
page_index |
PageIndex |
The Page index to reuse for performance. Otherwise will generate a new one. |
None |
Source code in wagtail_localize/synctree.py
def synchronize_tree(source_locale, target_locale, *, page_index=None):
"""
Synchronises a locale tree with an other locale.
This creates alias pages for pages that are not translated yet.
Args:
source_locale (Locale): The Locale to sync from.
target_locale (Locale): The Locale to sync into
page_index (PageIndex, optional): The Page index to reuse for performance. Otherwise will generate a new one.
"""
# Build a page index
if not page_index:
page_index = PageIndex.from_database().sort_by_tree_position()
# Find pages that are not translated for this locale
# This includes locales that have a placeholder, it only excludes locales that have an actual translation
pages_not_in_locale = page_index.not_translated_into(target_locale)
for page in pages_not_in_locale:
# Skip pages that do not exist in the source
if (
source_locale.id not in page.locales
and source_locale.id not in page.aliased_locales
):
continue
# Fetch source from database
model = page.content_type.model_class()
source_page = model.objects.get(
translation_key=page.translation_key, locale=source_locale
)
if target_locale.id not in page.aliased_locales:
source_page.copy_for_translation(
target_locale, copy_parents=True, alias=True
)