diff --git a/.gitignore b/.gitignore
index fa0fdd7a..b816031e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
/.php_cs.cache
node_modules/
yarn.lock
+/var
diff --git a/src/bundle/DependencyInjection/IbexaFieldTypeRichTextExtension.php b/src/bundle/DependencyInjection/IbexaFieldTypeRichTextExtension.php
index f67cc30f..0da004ce 100644
--- a/src/bundle/DependencyInjection/IbexaFieldTypeRichTextExtension.php
+++ b/src/bundle/DependencyInjection/IbexaFieldTypeRichTextExtension.php
@@ -184,7 +184,10 @@ private function prependJMSTranslation(ContainerBuilder $container): void
'output_dir' => __DIR__ . '/../Resources/translations/',
'output_format' => 'xliff',
'excluded_dirs' => ['Behat', 'Tests', 'node_modules'],
- 'extractors' => [],
+ 'extractors' => [
+ 'ibexa.translation_extractor.field_type.ezrichtext.custom_tags',
+ 'ibexa.translation_extractor.field_type.ezrichtext.custom_tags.choices',
+ ],
],
],
]);
diff --git a/src/bundle/Resources/config/translation.yaml b/src/bundle/Resources/config/translation.yaml
index 60afbec6..42c800cf 100644
--- a/src/bundle/Resources/config/translation.yaml
+++ b/src/bundle/Resources/config/translation.yaml
@@ -5,7 +5,26 @@ services:
public: false
Ibexa\FieldTypeRichText\Translation\Extractor\OnlineEditorCustomAttributesExtractor:
+ deprecated: 'Since ibexa/fieldtype-richtext 4.6.7 the "%service_id%" service is deprecated, will be removed in 5.0.0'
arguments:
$siteAccessList: '%ibexa.site_access.list%'
tags:
- { name: jms_translation.extractor, alias: ez_online_editor_attributes }
+
+ Ibexa\FieldTypeRichText\Translation\Extractor\CustomTagExtractor:
+ arguments:
+ $customTags: '%ibexa.field_type.richtext.custom_tags%'
+ $domain: '%ibexa.field_type.richtext.custom_tags.translation_domain%'
+ $allowlist: ['ezyoutube', 'eztwitter', 'ezfacebook']
+ tags:
+ - name: jms_translation.extractor
+ alias: ibexa.translation_extractor.field_type.ezrichtext.custom_tags
+
+ Ibexa\FieldTypeRichText\Translation\Extractor\ChoiceAttributeExtractor:
+ arguments:
+ $customTags: '%ibexa.field_type.richtext.custom_tags%'
+ $domain: '%ibexa.field_type.richtext.custom_tags.translation_domain%'
+ $allowlist: ['ezyoutube', 'eztwitter', 'ezfacebook']
+ tags:
+ - name: jms_translation.extractor
+ alias: ibexa.translation_extractor.field_type.ezrichtext.custom_tags.choices
diff --git a/src/bundle/Resources/translations/custom_tags.en.xliff b/src/bundle/Resources/translations/custom_tags.en.xliff
new file mode 100644
index 00000000..59b3afc5
--- /dev/null
+++ b/src/bundle/Resources/translations/custom_tags.en.xliff
@@ -0,0 +1,131 @@
+
+
+
+
+
+ The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.
+
+
+
+ Post URL
+ Post URL
+ key: ezrichtext.custom_tags.ezfacebook.attributes.post_url.label
+
+
+ Width
+ Width
+ key: ezrichtext.custom_tags.ezfacebook.attributes.width.label
+
+
+ Embed Facebook post
+ Embed Facebook post
+ key: ezrichtext.custom_tags.ezfacebook.description
+
+
+ Facebook
+ Facebook
+ key: ezrichtext.custom_tags.ezfacebook.label
+
+
+ Hidden
+ Hidden
+ key: ezrichtext.custom_tags.eztwitter.attributes.cards.choice.hidden.label
+
+
+ Cards
+ Cards
+ key: ezrichtext.custom_tags.eztwitter.attributes.cards.label
+
+
+ None
+ None
+ key: ezrichtext.custom_tags.eztwitter.attributes.conversation.choice.none.label
+
+
+ Conversation
+ Conversation
+ key: ezrichtext.custom_tags.eztwitter.attributes.conversation.label
+
+
+ Don't target
+ Don't target
+ key: ezrichtext.custom_tags.eztwitter.attributes.dnt.label
+
+
+ Language code
+ Language code
+ key: ezrichtext.custom_tags.eztwitter.attributes.lang.label
+
+
+ Link color
+ Link color
+ key: ezrichtext.custom_tags.eztwitter.attributes.link_color.label
+
+
+ Dark
+ Dark
+ key: ezrichtext.custom_tags.eztwitter.attributes.theme.choice.dark.label
+
+
+ Light
+ Light
+ key: ezrichtext.custom_tags.eztwitter.attributes.theme.choice.light.label
+
+
+ Theme
+ Theme
+ key: ezrichtext.custom_tags.eztwitter.attributes.theme.label
+
+
+ Tweet URL
+ Tweet URL
+ key: ezrichtext.custom_tags.eztwitter.attributes.tweet_url.label
+
+
+ Width
+ Width
+ key: ezrichtext.custom_tags.eztwitter.attributes.width.label
+
+
+ Embed X post
+ Embed X post
+ key: ezrichtext.custom_tags.eztwitter.description
+
+
+ X
+ X
+ key: ezrichtext.custom_tags.eztwitter.label
+
+
+ Autoplay
+ Autoplay
+ key: ezrichtext.custom_tags.ezyoutube.attributes.autoplay.label
+
+
+ Height
+ Height
+ key: ezrichtext.custom_tags.ezyoutube.attributes.height.label
+
+
+ Video URL
+ Video URL
+ key: ezrichtext.custom_tags.ezyoutube.attributes.video_url.label
+
+
+ Width
+ Width
+ key: ezrichtext.custom_tags.ezyoutube.attributes.width.label
+
+
+ Embed YouTube video
+ Embed YouTube video
+ key: ezrichtext.custom_tags.ezyoutube.description
+
+
+ YouTube
+ YouTube
+ key: ezrichtext.custom_tags.ezyoutube.label
+
+
+
+
diff --git a/src/lib/Translation/Extractor/ChoiceAttributeExtractor.php b/src/lib/Translation/Extractor/ChoiceAttributeExtractor.php
new file mode 100644
index 00000000..81d2f272
--- /dev/null
+++ b/src/lib/Translation/Extractor/ChoiceAttributeExtractor.php
@@ -0,0 +1,81 @@
+ */
+ private array $customTags;
+
+ private string $domain;
+
+ /** @var string[] */
+ private array $allowlist;
+
+ /**
+ * @param array $customTags Custom tags definitions
+ * @param string $domain Target translation domain
+ * @param string[] $allowlist Whitelist of custom tags to extract
+ */
+ public function __construct(array $customTags, string $domain, array $allowlist = [])
+ {
+ $this->customTags = $customTags;
+ $this->domain = $domain;
+ $this->allowlist = $allowlist;
+ }
+
+ public function extract(): MessageCatalogue
+ {
+ $catalogue = new MessageCatalogueBuilder($this->domain);
+ foreach ($this->customTags as $tagName => $customTag) {
+ if (!in_array($tagName, $this->allowlist, true)) {
+ continue;
+ }
+
+ $attributes = $customTag['attributes'] ?? [];
+ foreach ($attributes as $attributeName => $attribute) {
+ $type = $attribute['type'] ?? null;
+ if ($type !== self::CHOICE_ATTRIBUTE_TYPE) {
+ continue;
+ }
+
+ foreach ($attribute['choices'] as $choice) {
+ if (empty($choice)) {
+ continue;
+ }
+
+ $this->addChoiceLabelMessage($catalogue, $tagName, $attributeName, $choice);
+ }
+ }
+ }
+
+ return $catalogue->getCatalogue();
+ }
+
+ private function addChoiceLabelMessage(
+ MessageCatalogueBuilder $catalogue,
+ string $tagName,
+ string $attributeName,
+ string $choice
+ ): void {
+ $catalogue->addMessage(
+ sprintf(self::CHOICE_LABEL_KEY, $tagName, $attributeName, $choice),
+ $choice
+ );
+ }
+}
diff --git a/src/lib/Translation/Extractor/CustomTagExtractor.php b/src/lib/Translation/Extractor/CustomTagExtractor.php
new file mode 100644
index 00000000..599a4b2b
--- /dev/null
+++ b/src/lib/Translation/Extractor/CustomTagExtractor.php
@@ -0,0 +1,84 @@
+ */
+ private array $customTags;
+
+ private string $domain;
+
+ /** @var string[] */
+ private array $allowlist;
+
+ /**
+ * @param array $customTags Custom tags definitions
+ * @param string $domain Target translation domain
+ * @param string[] $allowlist Whitelist of custom tags to extract
+ */
+ public function __construct(array $customTags, string $domain, array $allowlist = [])
+ {
+ $this->customTags = $customTags;
+ $this->domain = $domain;
+ $this->allowlist = $allowlist;
+ }
+
+ public function extract(): MessageCatalogue
+ {
+ $catalogue = new MessageCatalogueBuilder($this->domain);
+ foreach ($this->customTags as $tagName => $config) {
+ if (!in_array($tagName, $this->allowlist, true)) {
+ continue;
+ }
+
+ $this->addCustomTagLabelMessage($catalogue, $tagName);
+ $this->addCustomTagDescriptionMessage($catalogue, $tagName);
+
+ /** @var string[] $attributes */
+ $attributes = array_keys($config['attributes'] ?? []);
+ foreach ($attributes as $attributeName) {
+ $this->addAttributeLabelMessage($catalogue, $tagName, $attributeName);
+ }
+ }
+
+ return $catalogue->getCatalogue();
+ }
+
+ private function addCustomTagLabelMessage(MessageCatalogueBuilder $catalogue, string $tagName): void
+ {
+ $catalogue->addMessage(sprintf(self::CUSTOM_TAG_LABEL, $tagName), $tagName);
+ }
+
+ private function addCustomTagDescriptionMessage(MessageCatalogueBuilder $catalogue, string $tagName): void
+ {
+ $catalogue->addMessage(sprintf(self::CUSTOM_TAG_DESCRIPTION, $tagName), $tagName);
+ }
+
+ private function addAttributeLabelMessage(
+ MessageCatalogueBuilder $catalogue,
+ string $tagName,
+ string $attributeName
+ ): void {
+ $catalogue->addMessage(
+ sprintf(self::ATTRIBUTE_LABEL, $tagName, $attributeName),
+ $attributeName
+ );
+ }
+}
diff --git a/src/lib/Translation/Extractor/MessageCatalogueBuilder.php b/src/lib/Translation/Extractor/MessageCatalogueBuilder.php
new file mode 100644
index 00000000..8355afea
--- /dev/null
+++ b/src/lib/Translation/Extractor/MessageCatalogueBuilder.php
@@ -0,0 +1,60 @@
+domain = $domain;
+ $this->catalogue = new MessageCatalogue();
+ }
+
+ public function getDomain(): string
+ {
+ return $this->domain;
+ }
+
+ public function reset(): void
+ {
+ $this->catalogue = new MessageCatalogue();
+ }
+
+ public function getCatalogue(): MessageCatalogue
+ {
+ return $this->catalogue;
+ }
+
+ public function addMessage(string $id, string $desc): void
+ {
+ $this->catalogue->add($this->createMessage($id, $desc));
+ }
+
+ private function createMessage(string $id, string $desc): XliffMessage
+ {
+ $message = new XliffMessage($id, $this->domain);
+ $message->setNew(false);
+ $message->setMeaning($desc);
+ $message->setDesc($desc);
+ $message->setLocaleString($desc);
+ $message->addNote('key: ' . $id);
+
+ return $message;
+ }
+}
diff --git a/src/lib/Translation/Extractor/OnlineEditorCustomAttributesExtractor.php b/src/lib/Translation/Extractor/OnlineEditorCustomAttributesExtractor.php
index 63f64479..fdca10a6 100644
--- a/src/lib/Translation/Extractor/OnlineEditorCustomAttributesExtractor.php
+++ b/src/lib/Translation/Extractor/OnlineEditorCustomAttributesExtractor.php
@@ -15,7 +15,7 @@
use JMS\TranslationBundle\Translation\ExtractorInterface;
/**
- * Generates translation strings for limitation types.
+ * @deprecated 4.6.7 The "OnlineEditorCustomAttributesExtractor" class is deprecated, will be removed in 5.0.
*/
final class OnlineEditorCustomAttributesExtractor implements ExtractorInterface
{
diff --git a/tests/integration/IbexaTestKernel.php b/tests/integration/IbexaTestKernel.php
index 1c26428a..d41662d5 100644
--- a/tests/integration/IbexaTestKernel.php
+++ b/tests/integration/IbexaTestKernel.php
@@ -76,7 +76,7 @@ public function registerContainerConfiguration(LoaderInterface $loader): void
{
parent::registerContainerConfiguration($loader);
- $loader->load(__DIR__ . '/../lib/_settings/common.yaml');
+ $loader->load(__DIR__ . '/Resources/override.yaml');
$loader->load(__DIR__ . '/Resources/config.yaml');
$loader->load(static function (ContainerBuilder $container): void {
$container->setDefinition(
diff --git a/tests/integration/Resources/override.yaml b/tests/integration/Resources/override.yaml
new file mode 100644
index 00000000..3a0c61ed
--- /dev/null
+++ b/tests/integration/Resources/override.yaml
@@ -0,0 +1,5 @@
+parameters:
+ ibexa.field_type.richtext.resources: 'src/bundle/Resources/richtext'
+ ibexa.field_type.richtext.validator.docbook.resources:
+ - '%ibexa.field_type.richtext.resources%/schemas/docbook/ezpublish.rng'
+ - '%ibexa.field_type.richtext.resources%/schemas/docbook/docbook.iso.sch.xsl'