[trans] Make SourceValueItem field type translatable with synchronized and asynchron translations

Created on 26 September 2025, 14 days ago

Problem/Motivation

The SourceValueItem field type currently supports asynchronous translations out of the box (default Drupal behavior).

We need synchronized translations for use cases where the field’s tree structure remains identical across languages and only selected values become language-specific.

Proposed resolution

  • Add a second storage column (translations) that stores language-specific payloads as JSON, keyed by a stable identifier.
  • Introduce a new sibling key source_uuid alongside existing source_id in the canonical tree:
    • source_id stays exactly as it is today (no behavior change).
    • source_uuid is assigned indirectly on save and remains stable/deterministic per element.
  • Do not make all fields translatable. Which values are translatable is decided by the configuration schema. Only values flagged by the schema are extracted into the translations column.
  • Canonical/default-language content:
    • The tree (default language) continues to be stored in the main tree column.
    • translations is a JSON map <source_uuid> => <source payload subset> for schema-marked fields only.
  • Modes:
    • Asynchronous (current default): the new translations column is ignored.
    • Synchronized: when the field is marked translatable, a storage setting enables synchronized mode so lookups prefer the language-specific payload from translations by source_uuid, with fallback to the canonical tree.
  • Backwards compatibility: existing data keeps working; source_id is untouched; source_uuid is additive.

Remaining tasks

  • Add the translations storage column.
  • On save, assign stable source_uuid next to every source_id.
  • Use the configuration schema to extract only schema-marked translatable values from the tree into translations.
  • Add storage setting to toggle synchronized mode (active only when the field is translatable).
  • Ensure read path resolves via source_uuid in synchronized mode, with fallback to the canonical tree.
  • Tests for multilingual scenarios (async vs. sync; schema-driven extraction; fallback behavior).

User interface changes

  • Field storage settings: new option to enable synchronized translations (only effective if the field is translatable).

API changes

  • Tree nodes gain a new sibling key source_uuid alongside existing source_id.
  • Lookup/renderers can resolve language-specific payloads via translations[source_uuid] when synchronized mode is enabled.

Data model changes

  • Add one additional database column translations (long text JSON) to SourceValueItem storage.

Example A — Canonical tree (default language) with source_uuid

Excerpt based on the provided UI Patterns structure. source_id is unchanged. New source_uuid is added as a sibling. UUIDs shown are examples.

ui_patterns:
  component_id: 'daisy_cms_daisyui:layout_columns'
  variant_id: null
  props:
    component_id: 'daisy_cms_daisyui:layout_columns'
    display_id: daisy_cms_daisyui.layout_columns.layout
    variant_id: null
    props:
      items_count:
        source:
          value: '1'
        source_id: enum_widget
        source_uuid: 'c8d7e8c2-1b22-4b5f-9a21-2b8198fb1f03'
      attributes:
        source:
          layout_layout: 'grid-1--sm-left container-md'
        source_id: ui_styles_css_widget
        source_uuid: 'a7b3d67e-0ab1-4ef1-9fbc-8d7c95fd2d90'
      display_header:
        source_id: checkbox
        source_uuid: 'f2244286-1c64-4a70-bcdd-62b2b6c8e9c1'
        source:
          value: false
      theme:
        source:
          value: light
        source_id: enum_widget
        source_uuid: '23b195e3-3c0a-4d39-8f70-0a77fcc86f2f'
      spacing_attributes:
        source:
          spacing_padding_top: pt-auto
          spacing_padding_bottom: pb-sm
          spacing_margin_bottom: mb-auto
        source_id: ui_styles_css_widget
        source_uuid: 'dd6a7a8a-4c9c-4f42-9f3d-0a5b2da8d8a1'
  slots:
    background:
      sources:
        - source:
            media:
              media_library_selection: ''
          source_id: media
          source_uuid: 'bbfae2a7-55a2-4d80-bb51-6cd4322e9c2f'

  items_count:
    source_id: enum_widget
    source_uuid: 'b1e3d2a4-0f3c-4fd6-9f33-cc0c1e20a6f4'
    source:
      value: '1'

  attributes:
    source_id: ui_styles_css_widget
    source_uuid: 'e5c59c55-0d0a-43a2-8fa9-34ee14f3e7e2'
    source:
      layout_layout: 'grid-1--sm-left container-md'

  display_header:
    source_id: checkbox
    source_uuid: '8b3f6a12-8c7e-4b6f-9c4a-9f5d7e8c6a2b'
    source:
      value: false

  theme:
    source_id: enum_widget
    source_uuid: 'f0d9cbe6-1a2f-4c5d-8b7e-19e7420b3f77'
    source:
      value: light

  spacing_attributes:
    source_id: ui_styles_css_widget
    source_uuid: 'a8d6f5c3-2e4a-45b1-9dcd-ef12a34b5678'
    source:
      spacing_padding_top: pt-auto
      spacing_padding_bottom: pb-sm
      spacing_margin_bottom: mb-auto

Example B — translations column (JSON, synchronized mode)


Only entries marked as translatable by the configuration schema are included here.
For illustration, assume the schema marks theme.value and the top-level items_count.value as translatable; others (e.g. CSS classes, booleans) are not.

{
  "f0d9cbe6-1a2f-4c5d-8b7e-19e7420b3f77": { "value": "light" },
  "b1e3d2a4-0f3c-4fd6-9f33-cc0c1e20a6f4": { "value": "1" }
}

In synchronized mode, renderers/widgets resolve values by source_uuid:
if a matching key exists in translations for the current language, that payload is used; otherwise the canonical tree.source value applies.
Asynchronous mode does not use the translations column at all.

Feature request
Status

Active

Version

2.0

Component

Code

Created by

🇩🇪Germany Christian.wiedemann

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • Merge request !440WIP 3548884 → (Open) created by sch4lly
  • Pipeline finished with Failed
    11 days ago
    Total: 665s
    #612462
  • Pipeline finished with Failed
    9 days ago
    Total: 658s
    #614873
  • Pipeline finished with Failed
    1 day ago
    Total: 677s
    #622695
Production build 0.71.5 2024