Wagtail Localize

repository·main·Indexed 42 days ago

https://github.com/wagtail/wagtail-localize

A translation plugin for the Wagtail CMS that enables users to translate pages and snippets directly within the Wagtail admin interface. It supports PO file workflows and integrates with external translation services such as Pontoon and DeepL.

Tokens
29.2K
Snippets
83
Records
129
Agent score
53%

What's inside Wagtail Localize

  1. Template Segment

    main

    A Template Segment is used to manage the structure of rich text fields and blocks. It is an HTML blob that preserves the layout while marking where translated text should be inserted.

    Instead of translating the HTML directly, Wagtail localize extracts the text into String Segments and replaces them in the template with <text> tags containing a position attribute. This allows the system to recombine the translated strings with the original HTML structure.

    Key behaviors:

    • Block tags (e.g., <p>, <li>, <h1>) are left in the template.
    • Inline tags (e.g., <b>, <a>) are extracted along with the string segments. However, if an inline tag completely encapsulates a string segment, that tag remains in the template.
    • Non-translatable elements like images or embeds are preserved in the template.
    <h1><text position="0"></h1>
    <p>
        <text position="1">
        <ul>
            <li><b><text position="2"></b></li>
        </ul>
    </p>
  2. Understand benchmark scope and limitations

    main

    When interpreting benchmark results, be aware of the following constraints:

    • Synthetic Data: The fixtures are fixed and synthetic; results describe specific workloads, not all possible sites or content models.
    • Database Environment: SQLite is used for cheap, reproducible local runs, but production database behavior and query costs may differ.
    • Query Count Metric: A 'query count' refers to the number of entries in Django's query log. It is not a measure of database statement count or individual statement cost (e.g., a commit counts as one entry, as does an executemany regardless of row count).
    • Timing: Measurements include cold Python and framework state; they do not model concurrent traffic or warmed application workers.
    • Attribution: run.py can detect scaling issues but cannot attribute their cause. To find the cause, use run_attribution.py (to see where a flow's growth comes from) or run_query_doctor.py (for an external tool's opinion).
  3. How to change the benchmark catalog

    main

    The benchmark catalog is defined in catalog.py. Each Flow in the catalog represents a specific measurement scenario and must implement three distinct responsibilities to ensure measurement accuracy:

    1. setup: Asserts or establishes the pre-measurement scenario (e.g., creating data).
    2. run: Performs only the specific operation being measured.
    3. verify: Proves the operation occurred and returns the observed workload.

    Best Practices:

    • Keep fixture construction and verification logic outside of the run method.
    • When writing tests for the catalog, prefer asserting properties like stable workload or a flat small-to-large query slope rather than asserting absolute query counts.
    # Conceptual structure of a Flow in catalog.py
    class MyFlow:
        def setup(self):
            # Establish pre-measurement scenario
            pass
    
        def run(self):
            # Perform ONLY the operation being measured
            pass
    
        def verify(self):
            # Prove operation happened and return observed workload
            pass
  4. How Wagtail Localize auto-generates translatable fields

    main

    When you do not explicitly define a translatable_fields attribute on a model, Wagtail Localize uses an automatic discovery process to determine which fields should be translatable (translated per language) and which should be synchronised (copied from the source language to all translations).

    The Discovery Process

    1. Manual Override Check: If the model has a translatable_fields attribute defined, the auto-generation process is completely bypassed.
    2. Field Discovery: The system inspects Django ORM fields. It excludes auto-fields (id), non-editable fields (editable=False), ManyToManyField, ParentalKey, parent link fields (page_ptr), and specific inherited fields (like MP_Node or Page metadata).
      • Text Fields: RichTextField and StreamField are marked as translatable. However, URLField, EmailField, and CharField with choices are marked as synchronised.
      • Relationships: ForeignKey and OneToOneField are translatable if the target model inherits from TranslatableMixin; otherwise, they are synchronised.
      • Custom Logic: Any field defining a get_translatable_segments method is marked as translatable.
      • Default: All other valid fields are marked as synchronised.
    3. Child Relationship Discovery: The system identifies relationships created via ParentalKey (often used for inline panels). If the child model inherits from TranslatableMixin, the relationship is translatable. Otherwise, it is synchronised. (Note: For Page models, the comments relation is always excluded).
    4. Override Application: Finally, the system checks for an override_translatable_fields attribute on the model to apply developer-defined adjustments to the automatic decisions.
  5. Understand translatable segment models

    main

    Wagtail Localize uses specific models to store and manage details about translatable segments within a TranslationSource. These segments represent the individual pieces of content that can be translated.

    There are three primary types of segments:

    • StringSegment: Represents a piece of text (a String) that can be translated.
    • TemplateSegment: Represents a part of a Django template (a Template) that can be translated.
    • RelatedObjectSegment: Represents a related object that needs translation.

    All segments are associated with a TranslationSource and a TranslationContext. Additionally, segments can be categorized under OverridableSegment and managed via SegmentOverride to handle specific translation overrides.

  6. Use the segment extraction module to extract translatable segments

    main
    The wagtail_localize.segments.extract module is responsible for identifying and extracting translatable segments from source objects. This is a core component of the localization process, used to break down content into smaller units that can be translated independently.
  7. Understand the types of translatable fields

    main

    Wagtail Localize categorizes fields into three distinct behaviors that determine how content is handled during translation:

    1. Translatable:
      • Text fields: Content is extracted for manual translation by editors.
      • Foreign keys: The referenced model is also translatable. When a translation is created/updated, the field automatically links to the translation of the referenced object.
      • StreamFields: Translatable fields within blocks are extracted, while some blocks may remain synchronised.
      • Child relations (ParentalKey): The child model is translatable and contains its own translatable fields.
    2. Synchronised: The value is copied from the source to the translation whenever the translation is updated. Depending on the field type, these may be overridable (editable on the translation, but stops receiving source updates until 'Revert to source version' is clicked) or non-overridable.
    3. Neither / excluded: The field is not updated after the initial translation creation. This is typically used for internal fields like id or page paths.
  8. Understand overridable segments models

    main

    In wagtail-localize, overridable segments allow non-text data (such as images, specific settings, or other non-translatable fields) to be modified independently for each locale.

    This is achieved through two primary models:

    • OverridableSegment: Represents a specific part of a translation source that is marked as capable of being overridden.
    • SegmentOverride: Stores the actual overridden data for a specific locale.

    These models work together to link a segment to its original TranslationSource and its specific TranslationContext, while the SegmentOverride links the new data to a specific wagtail.Locale.

  9. Content Path formats for different model structures

    main

    Wagtail Localize generates content paths based on the complexity of the data structure. The format changes depending on whether you are targeting a simple field, an inline child, or a complex StreamField:

    • Model Fields: The field name itself.
    • Inline Child Objects: <child relation name>.<translation key of child object>.<field name>.
    • StreamField Blocks: <streamfield field name>.<block id>.
    • StructBlock Fields: <streamfield field name>.<block id>.<structblock field name>.
    • ListBlock (Nested): <streamfield field name>.<block id>.<item id> (where the item ID is derived from the block structure).
  10. Related Object Segment

    main

    A Related Object Segment represents a translatable object referenced via ForeignKey, OneToOneField, or SnippetChooserBlocks.

    When a page is submitted for translation, any translatable related objects are automatically submitted for translation alongside the page. The translated page is then automatically linked to the translated version of that related object, allowing translators to track progress and edit the related object directly from the page translation interface.