From bf11b23ae8fea7aadee81d04588145b92062d151 Mon Sep 17 00:00:00 2001 From: Frederick Mixell Date: Sun, 17 Dec 2023 20:56:58 -0500 Subject: [PATCH 1/5] allow list of include blocks to override --- wagtail_localize/segments/extract.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wagtail_localize/segments/extract.py b/wagtail_localize/segments/extract.py index c7bf532d5..136557abc 100644 --- a/wagtail_localize/segments/extract.py +++ b/wagtail_localize/segments/extract.py @@ -123,7 +123,15 @@ def handle_related_object_block(self, related_object): def handle_struct_block(self, struct_block, raw_value=None): segments = [] + translatable_blocks = getattr(struct_block.block, "translateable_blocks", None) + for field_name, block_value in struct_block.items(): + if ( + translatable_blocks is not None + and field_name not in translatable_blocks + ): + continue + block_type = struct_block.block.child_blocks[field_name] try: block_raw_value = raw_value["value"].get(field_name) From 00644b1cb5ebefc6c0f678ea2326be4a4165e79b Mon Sep 17 00:00:00 2001 From: Frederick Mixell Date: Sun, 24 Dec 2023 09:28:38 -0500 Subject: [PATCH 2/5] match other override syntax --- wagtail_localize/segments/extract.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/wagtail_localize/segments/extract.py b/wagtail_localize/segments/extract.py index 136557abc..9b045d656 100644 --- a/wagtail_localize/segments/extract.py +++ b/wagtail_localize/segments/extract.py @@ -123,12 +123,14 @@ def handle_related_object_block(self, related_object): def handle_struct_block(self, struct_block, raw_value=None): segments = [] - translatable_blocks = getattr(struct_block.block, "translateable_blocks", None) + override_translatable_blocks = getattr( + struct_block.block, "override_translatable_blocks", None + ) for field_name, block_value in struct_block.items(): if ( - translatable_blocks is not None - and field_name not in translatable_blocks + override_translatable_blocks is not None + and field_name not in override_translatable_blocks ): continue From ecadd52c8a85a6bc16787acc8e747e8c10f4f3f4 Mon Sep 17 00:00:00 2001 From: Frederick Mixell Date: Sun, 24 Dec 2023 09:30:14 -0500 Subject: [PATCH 3/5] adding test cases --- .../segments/tests/test_segment_extraction.py | 34 +++++++++++++++++++ wagtail_localize/test/models.py | 16 +++++++++ 2 files changed, 50 insertions(+) diff --git a/wagtail_localize/segments/tests/test_segment_extraction.py b/wagtail_localize/segments/tests/test_segment_extraction.py index c19a068bb..087b38940 100644 --- a/wagtail_localize/segments/tests/test_segment_extraction.py +++ b/wagtail_localize/segments/tests/test_segment_extraction.py @@ -533,6 +533,40 @@ def test_customstructblock(self): ], ) + def test_structblockwithoverrides(self): + block_id = uuid.uuid4() + page = make_test_page_with_streamfield_block( + str(block_id), + "test_structblockwithoverrides", + {"field_a": "Test content", "field_b": "Non-translatable content"}, + ) + + segments = extract_segments(page) + + self.assertEqual( + segments, + [ + StringSegmentValue( + f"test_streamfield.{block_id}.field_a", + "Test content", + ) + ], + ) + + def test_structblockignoreall(self): + block_id = uuid.uuid4() + page = make_test_page_with_streamfield_block( + str(block_id), + "test_structblockignoreall", + { + "field_a": "Non-translatable content", + "field_b": "Non-translatable content", + }, + ) + + segments = extract_segments(page) + self.assertEqual(segments, []) + def test_customblockwithoutextractmethod(self): block_id = uuid.uuid4() page = make_test_page_with_streamfield_block( diff --git a/wagtail_localize/test/models.py b/wagtail_localize/test/models.py index 4ff6fc9d8..83b4ee870 100644 --- a/wagtail_localize/test/models.py +++ b/wagtail_localize/test/models.py @@ -119,6 +119,20 @@ class TestNestedStreamBlock(blocks.StreamBlock): chooser_in_list = blocks.ListBlock(blocks.PageChooserBlock()) +class TestStructBlockOverride(blocks.StructBlock): + field_a = blocks.TextBlock() + field_b = blocks.TextBlock() + + override_translatable_blocks = ["field_a"] + + +class TestStructBlockIgnoreAll(blocks.StructBlock): + field_a = blocks.TextBlock() + field_b = blocks.TextBlock() + + override_translatable_blocks = [] + + class TestNestedChooserStructBlock(blocks.StructBlock): nested_page = TestChooserStructBlock() @@ -196,6 +210,8 @@ class TestStreamBlock(blocks.StreamBlock): test_nestedstreamblock = TestNestedStreamBlock() test_streamblock_in_structblock = TestStreamBlockInStructBlock() test_customstructblock = CustomStructBlock() + test_structblockwithoverrides = TestStructBlockOverride() + test_structblockignoreall = TestStructBlockIgnoreAll() test_customblockwithoutextractmethod = CustomBlockWithoutExtractMethod() test_pagechooserblock = blocks.PageChooserBlock() test_pagechooserblock_with_restricted_types = blocks.PageChooserBlock( From dea103e06f969429fe33db39f5325d19d60aba8d Mon Sep 17 00:00:00 2001 From: Frederick Mixell Date: Thu, 4 Jan 2024 12:50:18 -0500 Subject: [PATCH 4/5] revert naming --- wagtail_localize/segments/extract.py | 8 +++----- wagtail_localize/test/models.py | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/wagtail_localize/segments/extract.py b/wagtail_localize/segments/extract.py index 9b045d656..10287cc6f 100644 --- a/wagtail_localize/segments/extract.py +++ b/wagtail_localize/segments/extract.py @@ -123,14 +123,12 @@ def handle_related_object_block(self, related_object): def handle_struct_block(self, struct_block, raw_value=None): segments = [] - override_translatable_blocks = getattr( - struct_block.block, "override_translatable_blocks", None - ) + translatable_blocks = getattr(struct_block.block, "translatable_blocks", None) for field_name, block_value in struct_block.items(): if ( - override_translatable_blocks is not None - and field_name not in override_translatable_blocks + translatable_blocks is not None + and field_name not in translatable_blocks ): continue diff --git a/wagtail_localize/test/models.py b/wagtail_localize/test/models.py index 83b4ee870..790ff99d5 100644 --- a/wagtail_localize/test/models.py +++ b/wagtail_localize/test/models.py @@ -123,14 +123,14 @@ class TestStructBlockOverride(blocks.StructBlock): field_a = blocks.TextBlock() field_b = blocks.TextBlock() - override_translatable_blocks = ["field_a"] + translatable_blocks = ["field_a"] class TestStructBlockIgnoreAll(blocks.StructBlock): field_a = blocks.TextBlock() field_b = blocks.TextBlock() - override_translatable_blocks = [] + translatable_blocks = [] class TestNestedChooserStructBlock(blocks.StructBlock): From 5fb32e5fd4b3fc34e5320e7f59bf2efb88b5dd17 Mon Sep 17 00:00:00 2001 From: Frederick Mixell Date: Thu, 4 Jan 2024 13:41:04 -0500 Subject: [PATCH 5/5] adding docs --- docs/how-to/field-configuration.md | 49 +++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/docs/how-to/field-configuration.md b/docs/how-to/field-configuration.md index 7ae543c00..e77286ccb 100644 --- a/docs/how-to/field-configuration.md +++ b/docs/how-to/field-configuration.md @@ -1,9 +1,5 @@ # Configuring translatable fields -!!! attention - - It is not currently possible to configure `StructBlock` translatable fields. See [Issue #307](https://github.com/wagtail/wagtail-localize/issues/307) for more details. - By default, Wagtail Localize will decide for you which fields are translatable and which fields should just be synchronised. This is decided by some simple rules described in the [Auto-generation of Translatable Fields](/concept/translatable-fields-autogen) explanation. @@ -105,3 +101,48 @@ class BlogPage(Page): SynchronizedField("slug"), ] ``` + +## Specifying Translatable Fields within a StructBlock + +**By default, all sub-fields within a StructBlock are included for translation.** However, there may be instances where certain fields within the StructBlock should be excluded from translation. To facilitate this, we've introduced the **`translatable_blocks`** parameter. + +The **`translatable_blocks`** parameter allows you to specify a list of block names that should be processed for translation. Any fields within the StructBlock that are not included in this list will be excluded from translation. + +For instance, consider a YouTubeBlock that contains a CharBlock for a video ID and a TextBlock for a video description. The video ID is not something we'd want to send for translation, but the description is. To exclude the video ID from translation, we would use the **`translatable_blocks`** parameter as follows: + +```python +class YouTubeBlock(blocks.StructBlock): + video_id = blocks.CharBlock( + required=True, help_text="Add a YouTube video ID. You can find this in the url." + ) + description = blocks.TextBlock( + required=False, help_text="Add a description for the video." + ) + + translatable_blocks = ["description"] +``` + +In this example, only the description field will be included for translation. The video_id field will be excluded from both the translation UI in Wagtail and the exported PO file. + +##### Managing Images and Overrideable Segments within a StructBlock + +When dealing with overrideable segments such as images within a StructBlock, it's important to note that ignoring these segments could result in losing the ability to use a different image for different languages. If you want to maintain the ability to override an image, include it in the list of translatable_blocks to preserve the default behavior. + +Consider the following example of a **`LocationImageBlock`** that contains an **`ImageChooserBlock`** for an image and a **`TextBlock`** for a caption, along with a **`TextBlock`** for an address: + +```python +class LocationImageBlock(blocks.StructBlock): + """Location image block with caption.""" + + image = ImageChooserBlock(required=True, help_text="Add a banner image.") + caption = blocks.TextBlock( + required=False, help_text="Add a description for the image." + ) + address = blocks.TextBlock( + required=True, help_text="Enter the address for this location." + ) + + translatable_blocks = ["caption", "image"] +``` + +In this example, the image is still overrideable, but the address, which is unique to this location, is locked in by translatable_blocks. This allows you to maintain the flexibility of using different images for different languages, while ensuring that certain unique information remains consistent across all translations.