Skip to content

IBX-10684: Document translation management#3249

Draft
dabrt wants to merge 4 commits into
5.0from
translations-management
Draft

IBX-10684: Document translation management#3249
dabrt wants to merge 4 commits into
5.0from
translations-management

Conversation

@dabrt

@dabrt dabrt commented Jun 18, 2026

Copy link
Copy Markdown
Contributor
Question Answer
JIRA Ticket IBX-10684
Versions 5.0 and up
Edition all

Document translation management

Checklist

  • Text renders correctly
  • Text has been checked with vale
  • Description metadata is up to date
  • Code samples are working
  • PHP code samples have been fixed with PHP CS fixer
  • Added link to this PR in relevant JIRA ticket or code PR

@adriendupuis adriendupuis marked this pull request as draft June 19, 2026 07:12
@github-actions

Copy link
Copy Markdown

code_samples/ change report

Before (on target branch)After (in current PR)

code_samples/translations_management/config/services.yaml


code_samples/translations_management/config/services.yaml

docs/multisite/translations_management/extend_translations_management.md@29:``` yaml
docs/multisite/translations_management/extend_translations_management.md@30:[[= include_code('code_samples/translations_management/config/services.yaml', 1, 6) =]]
docs/multisite/translations_management/extend_translations_management.md@31:```

001⫶services:
002⫶ App\TranslationsManagement\MyCustomProvider:
003⫶ tags:
004⫶ - name: 'ibexa.translations_management.auto_translate.provider'
005⫶ identifier: 'my_custom_provider'
006⫶ validation_profile: 'ai_generic'

docs/multisite/translations_management/extend_translations_management.md@44:``` yaml
docs/multisite/translations_management/extend_translations_management.md@45:[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]]
docs/multisite/translations_management/extend_translations_management.md@46:[[= include_code('code_samples/translations_management/config/services.yaml', 7, 10) =]]
docs/multisite/translations_management/extend_translations_management.md@47:```

001⫶services:
002⫶ App\TranslationsManagement\MyProviderValidator:
003⫶ tags:
004⫶ - name: 'ibexa.translations_management.auto_translate.provider.validator'
005⫶ profile: 'my_custom_profile'

docs/multisite/translations_management/extend_translations_management.md@78:``` yaml
docs/multisite/translations_management/extend_translations_management.md@79:[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]]
docs/multisite/translations_management/extend_translations_management.md@80:[[= include_code('code_samples/translations_management/config/services.yaml', 14, 17) =]]
docs/multisite/translations_management/extend_translations_management.md@81:```

001⫶services:
002⫶ App\TranslationsManagement\ImageAltTextTransformer:
003⫶ tags:
004⫶ - name: 'ibexa.translations_management.auto_translate.field_value_transformer'
005⫶ field_type_identifier: 'ibexa_image'

docs/multisite/translations_management/extend_translations_management.md@102:``` yaml
docs/multisite/translations_management/extend_translations_management.md@103:[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]]
docs/multisite/translations_management/extend_translations_management.md@104:[[= include_code('code_samples/translations_management/config/services.yaml', 18, 20) =]]
docs/multisite/translations_management/extend_translations_management.md@105:```

001⫶services:
002⫶ App\TranslationsManagement\MyCustomExclusionRule:
003⫶ tags:
004⫶ - { name: 'ibexa.translations_management.side_by_side.exclusion_rule' }

docs/multisite/translations_management/extend_translations_management.md@114:``` yaml
docs/multisite/translations_management/extend_translations_management.md@115:[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]]
docs/multisite/translations_management/extend_translations_management.md@116:[[= include_code('code_samples/translations_management/config/services.yaml', 21, 26) =]]
docs/multisite/translations_management/extend_translations_management.md@117:```

001⫶services:
002⫶ app.translations_management.exclusion_rule.custom_field_types:
003⫶ class: Ibexa\TranslationsManagement\SideBySide\Service\UnsupportedFieldTypeExclusionRule
004⫶ arguments:
005⫶ $excludedFieldTypeIdentifiers: ['custom_blog_post', 'custom_landing_page']
006⫶ tags:
007⫶ - { name: 'ibexa.translations_management.side_by_side.exclusion_rule' }

docs/multisite/translations_management/extend_translations_management.md@139:``` yaml
docs/multisite/translations_management/extend_translations_management.md@140:[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]]
docs/multisite/translations_management/extend_translations_management.md@141:[[= include_code('code_samples/translations_management/config/services.yaml', 27, 31) =]]
docs/multisite/translations_management/extend_translations_management.md@142:```

001⫶services:
002⫶ App\TranslationsManagement\TwigComponent\MyTranslationModalFooter:
003⫶ tags:
004⫶ - name: ibexa.twig.component
005⫶ group: 'admin-ui-content-translation-modal-footer'
006⫶ priority: 10

docs/multisite/translations_management/extend_translations_management.md@163:``` yaml
docs/multisite/translations_management/extend_translations_management.md@164:[[= include_code('code_samples/translations_management/config/services.yaml', 1, 1) =]]
docs/multisite/translations_management/extend_translations_management.md@165:[[= include_code('code_samples/translations_management/config/services.yaml', 11, 13) =]]
docs/multisite/translations_management/extend_translations_management.md@166:```

001⫶services:
002⫶ App\TranslationsManagement\MyTranslationAddExtension:
003⫶ tags:
004⫶ - { name: form.type_extension }


code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php


code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php

docs/multisite/translations_management/extend_translations_management.md@179:``` php hl_lines="35 36"
docs/multisite/translations_management/extend_translations_management.md@180:[[= include_code('code_samples/translations_management/src/TranslationsManagement/ContentProxyTranslateSubscriber.php') =]]
docs/multisite/translations_management/extend_translations_management.md@181:```

001⫶<?php declare(strict_types=1);
002⫶
003⫶namespace App\TranslationsManagement\EventSubscriber;
004⫶
005⫶use Ibexa\Contracts\AdminUi\Event\ContentProxyTranslateEvent;
006⫶use Symfony\Component\EventDispatcher\EventSubscriberInterface;
007⫶use Symfony\Component\HttpFoundation\RedirectResponse;
008⫶use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
009⫶
010⫶final readonly class ContentProxyTranslateSubscriber implements EventSubscriberInterface
011⫶{
012⫶ public function __construct(
013⫶ private UrlGeneratorInterface $urlGenerator,
014⫶ ) {
015⫶ }
016⫶
017⫶ public static function getSubscribedEvents(): array
018⫶ {
019⫶ return [
020⫶ ContentProxyTranslateEvent::class => ['onProxyTranslate', 200],
021⫶ ];
022⫶ }
023⫶
024⫶ public function onProxyTranslate(ContentProxyTranslateEvent $event): void
025⫶ {
026⫶ // Read the translation context:
027⫶ $event->getContentId();
028⫶ $event->getFromLanguageCode(); // ?string — null when no source language exists
029⫶ $event->getToLanguageCode();
030⫶ $event->getLocationId(); // ?int — null when no location context is available
031⫶
032⫶ $url = $this->urlGenerator->generate('your_custom_route', [
033⫶ 'contentId' => $event->getContentId(),
034⫶ ]);
035❇️
036❇️ $event->setResponse(new RedirectResponse($url));
037⫶ $event->stopPropagation();
038⫶ }
039⫶}


code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php


code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php

docs/multisite/translations_management/extend_translations_management.md@71:``` php hl_lines="19 24"
docs/multisite/translations_management/extend_translations_management.md@72:[[= include_code('code_samples/translations_management/src/TranslationsManagement/ImageAltTextTransformer.php') =]]
docs/multisite/translations_management/extend_translations_management.md@73:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\TranslationsManagement;
006⫶
007⫶use Ibexa\Contracts\Core\Repository\Values\Content\Field;
008⫶use Ibexa\Contracts\TranslationsManagement\AutoTranslate\Transformer\Field\EncodedFieldValue;
009⫶use Ibexa\Contracts\TranslationsManagement\AutoTranslate\Transformer\Field\FieldValueTransformerInterface;
010⫶use Ibexa\Core\FieldType\Value;
011⫶
012⫶final class ImageAltTextTransformer implements FieldValueTransformerInterface
013⫶{
014⫶ public function getFieldTypeIdentifier(): string
015⫶ {
016⫶ return 'ibexa_image';
017⫶ }
018⫶
019❇️ public function encode(Field $field): EncodedFieldValue
020⫶ {
021⫶ return new EncodedFieldValue($field->getValue()->alternativeText ?? '');
022⫶ }
023⫶
024❇️ public function decode(string $value, mixed $previousFieldValue, array $metadata): Value
025⫶ {
026⫶ $previousFieldValue->alternativeText = $value;
027⫶
028⫶ return $previousFieldValue;
029⫶ }
030⫶}


code_samples/translations_management/src/TranslationsManagement/MyCustomExclusionRule.php


code_samples/translations_management/src/TranslationsManagement/MyCustomExclusionRule.php

docs/multisite/translations_management/extend_translations_management.md@96:``` php
docs/multisite/translations_management/extend_translations_management.md@97:[[= include_code('code_samples/translations_management/src/TranslationsManagement/MyCustomExclusionRule.php') =]]
docs/multisite/translations_management/extend_translations_management.md@98:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\TranslationsManagement;
006⫶
007⫶use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo;
008⫶use Ibexa\Contracts\TranslationsManagement\SideBySide\Service\SideBySideExclusionRuleInterface;
009⫶
010⫶final class MyCustomExclusionRule implements SideBySideExclusionRuleInterface
011⫶{
012⫶ public function isExcluded(ContentInfo $contentInfo): bool
013⫶ {
014⫶ return $contentInfo->getContentType()->identifier === 'my_excluded_type';
015⫶ }
016⫶}


code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php


code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php

docs/multisite/translations_management/extend_translations_management.md@22:``` php hl_lines="31-44"
docs/multisite/translations_management/extend_translations_management.md@23:[[= include_code('code_samples/translations_management/src/TranslationsManagement/MyCustomProvider.php') =]]
docs/multisite/translations_management/extend_translations_management.md@24:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\TranslationsManagement;
006⫶
007⫶use Ibexa\Contracts\TranslationsManagement\AutoTranslate\Provider\TranslationProviderInterface;
008⫶use Ibexa\Contracts\TranslationsManagement\AutoTranslate\TranslationDataInterface;
009⫶
010⫶final readonly class MyCustomProvider implements TranslationProviderInterface
011⫶{
012⫶ public function __construct(
013⫶ private MyApiClient $apiClient,
014⫶ ) {
015⫶ }
016⫶
017⫶ public function getIdentifier(): string
018⫶ {
019⫶ return 'my_custom_provider';
020⫶ }
021⫶
022⫶ public function getName(): string
023⫶ {
024⫶ return 'My Translation Service';
025⫶ }
026⫶
027⫶ public function getVendorName(): string
028⫶ {
029⫶ return 'My Company Ltd';
030⫶ }
031❇️
032❇️ public function translate(TranslationDataInterface $translationData): string
033❇️ {
034❇️ return $this->apiClient->translate(
035❇️ $translationData->getText(),
036❇️ $translationData->getSourceLanguage(),
037❇️ $translationData->getTargetLanguage()
038❇️ );
039❇️ }
040❇️
041❇️ /** @return array<string> */
042❇️ public function getSupportedLanguageCodes(): array
043❇️ {
044❇️ return ['en_GB', 'de_DE', 'fr_FR'];
045⫶ }
046⫶}


code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php


code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php

docs/multisite/translations_management/extend_translations_management.md@157:``` php
docs/multisite/translations_management/extend_translations_management.md@158:[[= include_code('code_samples/translations_management/src/TranslationsManagement/MyTranslationAddExtension.php') =]]
docs/multisite/translations_management/extend_translations_management.md@159:```

001⫶<?php declare(strict_types=1);
002⫶
003⫶use Ibexa\AdminUi\Form\Type\Content\Translation\TranslationAddType;
004⫶use Symfony\Component\Form\AbstractTypeExtension;
005⫶use Symfony\Component\Form\FormBuilderInterface;
006⫶
007⫶final class MyTranslationAddExtension extends AbstractTypeExtension
008⫶{
009⫶ public static function getExtendedTypes(): iterable
010⫶ {
011⫶ return [TranslationAddType::class];
012⫶ }
013⫶
014⫶ public function buildForm(FormBuilderInterface $builder, array $options): void
015⫶ {
016⫶ $builder->add('my_custom_field'/* ... */);
017⫶ }
018⫶}

Download colorized diff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant