Change record status: 
Project: 
Introduced in branch: 
1.x
Introduced in version: 
1.4.0
Description: 

To be able to translate configuration, the Drupal configuration translation system requires config to have a so-called "property path" pointing to the specific values being translated.

To make Canvas component trees stored in config entities symmetrically translatable, we then need to be able to point to specific inputs in specific component instances in the component tree.

For now: internal change, do not start using config translation yet!

⚠️ We first want to achieve both content and config translation before we start explicitly supporting this.

Update path

An automatic update path is provided for all Canvas config entity types that can store component trees (ContentTemplate, PageRegion, Pattern), as well as for the default value of a configurable field (FieldConfig) using the Canvas field type.

Change #1: no more JSON blobs (#3586342)

Before
The inputs for a component instance in a component tree are stored as a JSON blob:
component_tree:
  - 
    uuid: fd141b6e-c57a-4355-9885-a8b2e60627d6
    component_id: sdc.canvas_test_sdc.heading
    component_version: 8c01a2bdb897a810
    inputs: '{"text":"Hello there","style":"primary","element":"h1"}'

This makes it impossible to target specifically the text input.

This was due to the use of type: ignore in the config schema.

After
component_tree:
  -
    uuid: fd141b6e-c57a-4355-9885-a8b2e60627d6
    component_id: sdc.canvas_test_sdc.heading
    component_version: 8c01a2bdb897a810
    inputs:
      text: Hello there
      style: primary
      element: h1

Now it is possible to specify a "property path" (component_tree.0.inputs.text) to store the translation, which would store the following for the nl translation:

component_tree:
  -
    inputs:
      text: Hoi daar

💡 It's this property path that is used by the Config translation system to override only the translated values.

Change #2: unique sequence keys (#3582464)

The above made it possible to reliably store a symmetrical translation for a specific input. But as soon as the component instance would've been moved, it'd break.

For example: the above default (English) translation contains a single component instance. If a new component instance was added before it, then the translation would continue to target component_tree.0.inputs.text, but in reality it should be targeting component_tree.1.inputs.text now. This is a common pitfall in the design of Drupal configuration entities (even in core, e.g. #3382464: [Style] CKEditor 5 styles config storage is not compatible with config ovverides).

Before
Zero-indexed sequence keys that are not reliable to target for Config Translation:
component_tree:
  0:
    uuid: fd141b6e-c57a-4355-9885-a8b2e60627d6
    component_id: sdc.canvas_test_sdc.heading
    component_version: 8c01a2bdb897a810
    inputs:
      text: Hello there
      style: primary
      element: h1

its translation:

component_tree:
  0:
    inputs:
      text: Hoi daar

This makes it impossible to reliably target specifically this component instance: what if another component instance is inserted before that? Then the translation would end up targeting the new instance at sequence key zero!

(Actually … it was more complex. The root-level component instances were 0…n, but for instances in slots you'd have gotten sequence keys like 0:the_body:1 for the 2nd instance in the "the body" slot of the first root-level instance. But the same analysis applies: position alone is not a reliable target for config translation!)

After
component_tree:
  fd141b6e-c57a-4355-9885-a8b2e60627d6:
    uuid: fd141b6e-c57a-4355-9885-a8b2e60627d6
    component_id: sdc.canvas_test_sdc.heading
    component_version: 8c01a2bdb897a810
    inputs:
      text: Hello there
      style: primary
      element: h1

its translation:

component_tree:
  fd141b6e-c57a-4355-9885-a8b2e60627d6:
    inputs:
      text: Hoi daar

To ensure good config management DX, Canvas provides config import/export transformations (see \Drupal\canvas\EventSubscriber\ComponentTreeConfigEntityTransformer::export()) that encode position information to keep config diffs clear:

component_tree:
  0:fd141b6e-c57a-4355-9885-a8b2e60627d6:
    uuid: fd141b6e-c57a-4355-9885-a8b2e60627d6
    component_id: sdc.canvas_test_sdc.heading
    component_version: 8c01a2bdb897a810
    inputs:
      text: Hello there
      style: primary
      element: h1
  # or for the second component instance in the "the body" slot of the not-pictured 5th root-level component instance:
  4:the_body:1:19c5e30f-069a-46c7-b512-7b70f4d1a8e7
    uuid: 19c5e30f-069a-46c7-b512-7b70f4d1a8e7
    component_id: sdc.canvas_test_sdc.heading
    component_version: 8c01a2bdb897a810
    inputs:
      text: 👋 Hello there from somewhere deep in the component tree
      style: primary
      element: h1

👆 Note the position information is encoded in each sequence key; the actual sequence key is encoded after the last :, everything before it is to ensure sane config diffs.

Recipe maintainers

It is recommended to apply the update path and re-export your recipe's config, if it includes one of the aforementioned Canvas config entity types.

Impacts: 
Site builders, administrators, editors
Module developers
Site templates, recipes and distribution developers