[FEATURE] EXT:form - support translation arguments 51/52951/12
authorMathias Brodala <mbrodala@pagemachine.de>
Mon, 29 May 2017 11:08:48 +0000 (13:08 +0200)
committerSusanne Moog <susanne.moog@typo3.org>
Thu, 7 Dec 2017 19:37:27 +0000 (20:37 +0100)
Form element properties and finisher options can now use arguments
in their translations.

This is especially useful to pass values created dynamically via
formDefinitionOverrides in TypoScript.

Resolves: #81363
Releases: master
Change-Id: Ie205ebc62bcf807e6740c54bbda0115435317604
Reviewed-on: https://review.typo3.org/52951
Reviewed-by: Daniel Lorenz <daniel.lorenz@extco.de>
Tested-by: Daniel Lorenz <daniel.lorenz@extco.de>
Reviewed-by: Carlos Meyer <cm@davitec.de>
Tested-by: Carlos Meyer <cm@davitec.de>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
typo3/sysext/core/Documentation/Changelog/master/Feature-81363-AcceptFormElementTranslationArguments.rst [new file with mode: 0644]
typo3/sysext/form/Classes/Service/TranslationService.php
typo3/sysext/form/Tests/Unit/Service/Fixtures/locallang_form.xlf
typo3/sysext/form/Tests/Unit/Service/TranslationServiceTest.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-81363-AcceptFormElementTranslationArguments.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-81363-AcceptFormElementTranslationArguments.rst
new file mode 100644 (file)
index 0000000..9676da8
--- /dev/null
@@ -0,0 +1,92 @@
+.. include:: ../../Includes.txt
+
+=======================================================================
+Feature: #81363 - EXT:form - support form element translation arguments
+=======================================================================
+
+See :issue:`81363`
+
+Description
+===========
+
+Passing arguments to form element property translations is now supported to enrich
+translations with variable values:
+
+.. code-block:: yaml
+
+    renderables:
+      fieldWithTranslationArguments:
+        identifier: field-with-translation-arguments
+        type: Checkbox
+        label: This is a %s feature
+        renderingOptions:
+          translation:
+            translationFile: path/to/locallang.xlf
+            arguments:
+              label:
+                - useful
+
+Alternatively, translation arguments can be set via :typoscript:`formDefinitionOverrides`
+in TypoScript:
+
+.. code-block: typoscript
+
+    plugin.tx_form {
+      settings {
+        formDefinitionOverrides {
+          <form-id> {
+            renderables {
+              0 { # Page
+                renderables {
+                  fieldWithTranslationArguments {
+                    renderingOptions {
+                      translation {
+                        arguments {
+                          label {
+                            0 = TEXT
+                            0.typolink {
+                              parameter = 42
+                              returnLast = url
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+.. important::
+   There must be at least one translation file with a translation for the configured form element property. Arguments are not inserted into default values defined in a form definition.
+
+The same goes for finisher options:
+
+.. code-block:: yaml
+
+
+    finishers:
+      finisherWithTranslationArguments:
+        identifier: EmailToReceiver
+        options:
+          subject: My %s subject
+          recipientAddress: foo@example.org
+          senderAddress: bar@example.org
+          translation:
+            translationFile: path/to/locallang.xlf
+            arguments:
+              subject:
+                - awesome
+
+
+Impact
+======
+
+Form element property translations and finisher option translations can now use placeholders
+to output translation arguments.
+
+.. index:: Frontend, TypoScript, NotScanned
index b87956a..99be366 100644 (file)
@@ -258,13 +258,19 @@ class TranslationService implements SingletonInterface
             $language = $renderingOptions['language'];
         }
 
+        try {
+            $arguments = ArrayUtility::getValueByPath($renderingOptions['arguments'] ?? [], $optionKey, '.');
+        } catch (\RuntimeException $e) {
+            $arguments = [];
+        }
+
         $translationKeyChain = [];
         foreach ($translationFiles as $translationFile) {
             $translationKeyChain[] = sprintf('%s:%s.finisher.%s.%s', $translationFile, $formRuntime->getIdentifier(), $finisherIdentifier, $optionKey);
             $translationKeyChain[] = sprintf('%s:finisher.%s.%s', $translationFile, $finisherIdentifier, $optionKey);
         }
 
-        $translatedValue = $this->processTranslationChain($translationKeyChain, $language);
+        $translatedValue = $this->processTranslationChain($translationKeyChain, $language, $arguments);
         $translatedValue = (empty($translatedValue)) ? $optionValue : $translatedValue;
 
         return $translatedValue;
@@ -337,6 +343,12 @@ class TranslationService implements SingletonInterface
             $language = $renderingOptions['translation']['language'];
         }
 
+        try {
+            $arguments = ArrayUtility::getValueByPath($renderingOptions['translation']['arguments'] ?? [], $propertyParts, '.');
+        } catch (\RuntimeException $e) {
+            $arguments = [];
+        }
+
         if ($property === 'options' && is_array($defaultValue)) {
             foreach ($defaultValue as $optionValue => &$optionLabel) {
                 $translationKeyChain = [];
@@ -346,7 +358,7 @@ class TranslationService implements SingletonInterface
                     $translationKeyChain[] = sprintf('%s:element.%s.%s.%s.%s', $translationFile, $element->getType(), $propertyType, $property, $optionValue);
                 }
 
-                $translatedValue = $this->processTranslationChain($translationKeyChain, $language);
+                $translatedValue = $this->processTranslationChain($translationKeyChain, $language, $arguments);
                 $optionLabel = (empty($translatedValue)) ? $optionLabel : $translatedValue;
             }
             $translatedValue = $defaultValue;
@@ -359,7 +371,7 @@ class TranslationService implements SingletonInterface
                     $translationKeyChain[] = sprintf('%s:element.%s.%s.%s', $translationFile, $element->getType(), $propertyType, $propertyName);
                 }
 
-                $translatedValue = $this->processTranslationChain($translationKeyChain, $language);
+                $translatedValue = $this->processTranslationChain($translationKeyChain, $language, $arguments);
                 $propertyValue = (empty($translatedValue)) ? $propertyValue : $translatedValue;
             }
             $translatedValue = $defaultValue;
@@ -371,7 +383,7 @@ class TranslationService implements SingletonInterface
                 $translationKeyChain[] = sprintf('%s:element.%s.%s.%s', $translationFile, $element->getType(), $propertyType, $property);
             }
 
-            $translatedValue = $this->processTranslationChain($translationKeyChain, $language);
+            $translatedValue = $this->processTranslationChain($translationKeyChain, $language, $arguments);
             $translatedValue = (empty($translatedValue)) ? $defaultValue : $translatedValue;
         }
 
index 898bde4..94e8e2d 100644 (file)
                 <source>my-form-runtime-identifier my-form-element-identifier LABEL EN</source>
             </trans-unit>
 
+            <trans-unit id="element.my-form-element-with-translation-arguments.properties.label" xml:space="preserve">
+                <source>See %s or %s</source>
+            </trans-unit>
+
             <trans-unit id="my-form-runtime-identifier.finisher.SaveToDatabase.subject" xml:space="preserve">
                 <source>my-form-runtime-identifier form-element-identifier SaveToDatabase subject EN</source>
             </trans-unit>
+
+            <trans-unit id="finisher.EmailToReceiverWithTranslationArguments.subject" xml:space="preserve">
+                <source>My %s subject</source>
+            </trans-unit>
         </body>
     </file>
 </xliff>
index 76377e9..2077ced 100644 (file)
@@ -21,6 +21,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
 use TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement;
 use TYPO3\CMS\Form\Domain\Model\FormElements\Page;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
 use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
 use TYPO3\CMS\Form\Service\TranslationService;
 
@@ -879,6 +880,47 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
     /**
      * @test
      */
+    public function supportsArgumentsForFormElementValueTranslations()
+    {
+        $formRuntimeXlfPath = 'EXT:form/Tests/Unit/Service/Fixtures/locallang_form.xlf';
+
+        $this->store->flushData($formRuntimeXlfPath);
+
+        /** @var FormRuntime|\Prophecy\Prophecy\ObjectProphecy */
+        $formRuntime = $this->prophesize(FormRuntime::class);
+        $formRuntime->getIdentifier()->willReturn('my-form-runtime-identifier');
+        $formRuntime->getRenderingOptions()->willReturn([
+            'translation' => [
+                'translationFile' => $formRuntimeXlfPath,
+                'translatePropertyValueIfEmpty' => true,
+            ],
+        ]);
+
+        /** @var RootRenderableInterface|\Prophecy\Prophecy\ObjectProphecy */
+        $element = $this->prophesize(RootRenderableInterface::class);
+        $element->getIdentifier()->willReturn('my-form-element-with-translation-arguments');
+        $element->getType()->willReturn(RootRenderableInterface::class);
+        $element->getLabel()->willReturn('See %s or %s');
+        $element->getRenderingOptions()->willReturn([
+            'translation' => [
+                'arguments' => [
+                        'label' => [
+                            'this',
+                            'that',
+                        ],
+                ],
+            ],
+        ]);
+
+        $expected = 'See this or that';
+        $result = $this->mockTranslationService->_call('translateFormElementValue', $element->reveal(), ['label'], $formRuntime->reveal());
+
+        $this->assertEquals($expected, $result);
+    }
+
+    /**
+     * @test
+     */
     public function translateFinisherOptionTranslateOptionForConcreteFormFromFormRuntimeIfFinisherTranslationOptionsContainsNoTranslationFileAndFinisherOptionIsNotEmptyAndPropertyShouldBeTranslatedAndTranslationExists()
     {
         $formRuntimeXlfPath = 'EXT:form/Tests/Unit/Service/Fixtures/locallang_form.xlf';
@@ -911,6 +953,38 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
     /**
      * @test
      */
+    public function supportsArgumentsForFinisherOptionTranslations()
+    {
+        $formRuntimeXlfPath = 'EXT:form/Tests/Unit/Service/Fixtures/locallang_form.xlf';
+
+        $this->store->flushData($formRuntimeXlfPath);
+
+        /** @var FormRuntime|\Prophecy\Prophecy\ObjectProphecy */
+        $formRuntime = $this->prophesize(FormRuntime::class);
+        $formRuntime->getIdentifier()->willReturn('my-form-runtime-identifier');
+        $formRuntime->getRenderingOptions()->willReturn([
+            'translation' => [
+                'translationFile' => $formRuntimeXlfPath,
+                'translatePropertyValueIfEmpty' => true,
+            ],
+        ]);
+        $renderingOptions = [
+            'arguments' => [
+                'subject' => [
+                    'awesome',
+                ],
+            ],
+        ];
+
+        $expected = 'My awesome subject';
+        $result = $this->mockTranslationService->_call('translateFinisherOption', $formRuntime->reveal(), 'EmailToReceiverWithTranslationArguments', 'subject', 'My %s subject', $renderingOptions);
+
+        $this->assertEquals($expected, $result);
+    }
+
+    /**
+     * @test
+     */
     public function translateFormElementValueTranslateLabelFromAdditionalTranslationForConcreteFormAndConcreteElementIfElementRenderingOptionsContainsATranslationFileAndElementLabelIsNotEmptyAndPropertyShouldBeTranslatedAndTranslationExists()
     {
         $formRuntimeXlfPath = 'EXT:form/Tests/Unit/Service/Fixtures/locallang_form.xlf';