Extend translations management¶
By extending Translations management, you can adapt the package's behavior to your specific requirements. The package is designed to be extended in multiple ways. You can create custom translation providers, field type transformers, exclusion rules, and UI components. In all cases, you follow the same pattern: implement an interface first, then register the service with a service tag. The package discovers and registers tagged services automatically.
Add custom translation provider¶
Before you build a custom translation provider, if your provider uses the AI Actions framework, make sure that the ibexa/connector-ai package is configured in your system.
REST API-based provider¶
To connect a translation service that calls a REST API directly, implement TranslationProviderInterface.
For providers that store API keys and other required settings, you can rely on ConfigurableProviderInterface.
It extends TranslationProviderInterface and adds getConfiguration() and isConfigured() methods.
The translate() method receives a TranslationDataInterface object that carries the text to translate along with the source and target language codes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | |
Register the provider with the ibexa.translations_management.auto_translate.provider tag.
Both identifier and validation_profile attributes are required.
1 2 3 4 5 6 | |
AI-based provider¶
To connect a translation service that uses the AI Actions framework, implement AiTranslationProviderInterface.
This interface extends ConfigurableProviderInterface and serves as a type marker for AI-based providers.
The system uses the getConfiguration() and isConfigured() methods to determine whether the provider is available before displaying selectable options in the Create a new translation modal:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | |
Register the provider with the ibexa.translations_management.auto_translate.provider tag, with ai_generic as the validation profile.
The ai_generic validation profile is meant to be used by default for AI providers, but you can implement your own.
1 2 3 4 5 6 | |
If your custom provider integrates with the AI Actions framework, isConfigured() should check whether the actionConfigurationIdentifier resolves to an existing and enabled Action Configuration.
The validation_profile, supportedLanguageCodes, and languageCodesMap options work the same way as for REST API-based providers.
Language code normalizer¶
If your provider uses language codes that differ from the ones used by Ibexa DXP and the languageCodesMap configuration is insufficient, implement a custom LanguageNormalizerInterface to handle the conversion:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |
The supports() method is a way to bind the normalizer to a provider.
When a translation is triggered, the system checks the registered normalizers, and it uses the first one whose supports() method returns true for the current provider.
Register the normalizer with the ibexa.translations_management.auto_translate.provider.language_normalizer tag:
1 2 3 4 5 | |
If multiple normalizers are registered, use priority to control the order in which they're checked.
Validation profiles¶
The validation_profile attribute links the provider to a validator that checks language codes and payload size before each translation request.
By default, three profiles are available:
| Profile | Used by |
|---|---|
google |
Google Translate provider |
deepl |
DeepL provider |
ai_generic |
All built-in AI providers. Suitable for custom AI providers. |
To define a custom validation profile, implement ProviderValidatorInterface and register it:
1 2 3 4 5 | |
You can reuse the DefaultProviderValidator class if it meets your requirements or implement your own.
It exposes configurable maximum payload size and language code regex patterns.
Add support for custom field types¶
The translation engine works by extracting translatable text from fields, sending it to the provider, and writing the translated text back.
Field value transformers handle this encode/decode cycle, one per field type.
The package includes transformers for text, RichText, and ibexa_landing_page fields.
To add support for a custom or non-standard field type, implement FieldValueTransformerInterface:
getFieldTypeIdentifier()- returns the field type identifier that this transformer handlesencode(Field $field): EncodedFieldValue- extracts the translatable string from the field and wraps it in anEncodedFieldValue. The constructor takes the extracted string as its first argument and an optional metadata array as the second.decode(string $value, mixed $previousFieldValue, array $metadata): Value- receives the translated string, the previous field value, and any metadata. Returns the updated field value.
The following example adds support for automatically translating the alternative text of an image:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |
Register the new transformer with the ibexa.translations_management.auto_translate.field_value_transformer tag.
The field_type_identifier attribute is required.
It must match the value that getFieldTypeIdentifier() returns:
1 2 3 4 5 | |
Advanced metadata handling
When metadata is required for decoding or when you need to control what happens if metadata encoding fails, implement MetadataAwareFieldValueTransformerInterface.
With this interface, you can fail the translation when metadata encoding fails and indicate that metadata is required for decoding.
Without it, the field is skipped instead.
Define custom exclusion rules¶
Use exclusion rules to identify content that cannot use the side-by-side view.
The Translations management package ships with one rule that excludes content types that contain ibexa_landing_page or ibexa_form fields.
Exclude with custom class¶
To exclude content from side-by-side view, for example, content types whose fields render incorrectly in the side-by-side layout, implement SideBySideExclusionRuleInterface.
The isExcluded() method receives a ContentInfo object, which gives you access to different criteria, including content type, section, owner, main language, publication status, visibility, and main location of the content item.
If the content item should be excluded, the method should return true.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Register the rule with the ibexa.translations_management.side_by_side.exclusion_rule tag.
This interface is not registered for Symfony autoconfiguration, so the tag is required.
1 2 3 4 5 | |
Use Twig component extension points¶
Two Twig component groups allow you to inject custom UI elements into the translation interface without the need to override their templates.
Such custom element could be, for example, a disclaimer or policy notice that the editor must acknowledge before a translation is created.
The two groups behave differently:
admin-ui-content-translation-modal-footer— if any of the components renders output that is not empty, it entirely replaces the default footer buttons. Your component template must therefore include its own action buttons.admin-ui-content-edit-translation-select-footer— component output is inserted between the existing Edit and Discard buttons of the content edit confirmation screen.
Register a component with the ibexa.twig.component tag:
1 2 3 4 5 6 | |
Note
The admin-ui-content-translation-modal-footer group receives a location variable that may be null for an unpublished draft.
Always check for null before you access location properties in your component template.