• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TYPO3-Headless / headless / 29398229494

15 Jul 2026 07:42AM UTC coverage: 69.663% (-5.8%) from 75.459%
29398229494

Pull #893

github

web-flow
Merge ab993c965 into 79b7c5472
Pull Request #893: [TASK] Reintroduce missing features, extension cleanup

360 of 545 new or added lines in 33 files covered. (66.06%)

167 existing lines in 7 files now uncovered.

1364 of 1958 relevant lines covered (69.66%)

7.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/Classes/Form/Service/FormTranslationService.php
1
<?php
2

3
/*
4
 * This file is part of the "headless" Extension for TYPO3 CMS.
5
 *
6
 * For the full copyright and license information, please read the
7
 * LICENSE.md file that was distributed with this source code.
8
 */
9

10
declare(strict_types=1);
11

12
namespace FriendsOfTYPO3\Headless\Form\Service;
13

14
use InvalidArgumentException;
15
use TYPO3\CMS\Core\Utility\ArrayUtility;
16
use TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException;
17
use TYPO3\CMS\Core\Utility\GeneralUtility;
18
use TYPO3\CMS\Form\Service\TranslationService;
19

20
class FormTranslationService extends TranslationService
21
{
22
    /**
23
     * @return FormTranslationService
24
     */
25
    public static function getInstance(): self
26
    {
27
        return GeneralUtility::makeInstance(FormTranslationService::class);
×
28
    }
29

30
    /**
31
     * @param array<string,mixed> $element
32
     * @param array<int,mixed> $propertyParts
33
     * @param array<string,mixed> $formRuntime
34
     * @return string|array<int,string>
35
     * @throws InvalidArgumentException
36
     * @internal
37
     */
38
    public function translateElementValue(
39
        array $element,
40
        array $propertyParts,
41
        array $formRuntime
42
    ) {
43
        if (empty($propertyParts)) {
×
44
            throw new InvalidArgumentException('The argument "propertyParts" is empty', 1476216007);
×
45
        }
46

47
        $propertyType = 'properties';
×
48
        $property = implode('.', $propertyParts);
×
49
        $renderingOptions = $element['renderingOptions'] ?? [];
×
50
        $element['properties'] = $element['properties'] ?? [];
×
51

52
        if ($property === 'label') {
×
53
            $defaultValue = $element['label'] ?? '';
×
54
        } elseif (($element['type'] ?? '') !== 'Page') {
×
55
            try {
56
                $defaultValue = ArrayUtility::getValueByPath($element['properties'], $propertyParts, '.');
×
57
            } catch (MissingArrayPathException $exception) {
×
58
                $defaultValue = null;
×
59
            }
60
        } else {
61
            $propertyType = 'renderingOptions';
×
62
            try {
63
                $defaultValue = ArrayUtility::getValueByPath($renderingOptions, $propertyParts, '.');
×
64
            } catch (MissingArrayPathException $exception) {
×
65
                $defaultValue = null;
×
66
            }
67
        }
68

69
        $translatePropertyValueIfEmpty = $renderingOptions['translation']['translatePropertyValueIfEmpty'] ?? true;
×
70

71
        if (empty($defaultValue) && !$translatePropertyValueIfEmpty) {
×
72
            return $defaultValue;
×
73
        }
74

75
        $defaultValue = empty($defaultValue) ? '' : $defaultValue;
×
76
        $translationFiles = $renderingOptions['translation']['translationFiles'] ?? [];
×
77
        if (empty($translationFiles)) {
×
78
            $formRuntime['renderingOptions'] = $formRuntime['renderingOptions'] ?? [];
×
79
            $translationFiles = $formRuntime['renderingOptions']['translation']['translationFiles'];
×
80
        }
81

82
        $translationFiles = $this->sortArrayWithIntegerKeysDescending($translationFiles);
×
83
        $language = $renderingOptions['translation']['language'] ?? null;
×
84

85
        try {
86
            $arguments = ArrayUtility::getValueByPath(
×
87
                $renderingOptions['translation']['arguments'] ?? [],
×
88
                $propertyParts,
×
89
                '.'
×
90
            );
×
91
        } catch (MissingArrayPathException $e) {
×
92
            $arguments = [];
×
93
        }
94

95
        $originalFormIdentifier = null;
×
96
        if (isset($formRuntime['renderingOptions']['_originalIdentifier'])) {
×
97
            $originalFormIdentifier = $formRuntime['renderingOptions']['_originalIdentifier'];
×
98
        }
99

100
        if ($property === 'options' && is_array($defaultValue)) {
×
101
            foreach ($defaultValue as $optionValue => &$optionLabel) {
×
NEW
102
                $chain = $this->buildElementTranslationKeyChain(
×
NEW
103
                    $translationFiles,
×
NEW
104
                    $element,
×
NEW
105
                    $formRuntime,
×
NEW
106
                    $propertyType,
×
NEW
107
                    $property . '.' . $optionValue,
×
NEW
108
                    $originalFormIdentifier,
×
NEW
109
                );
×
NEW
110
                $translatedValue = $this->processTranslationChain($chain, $language, $arguments);
×
UNCOV
111
                $optionLabel = empty($translatedValue) ? $optionLabel : $translatedValue;
×
112
            }
NEW
113
            return $defaultValue;
×
114
        }
115

NEW
116
        if ($property === 'fluidAdditionalAttributes' && is_array($defaultValue)) {
×
NEW
117
            foreach ($defaultValue as $propertyName => &$propertyValue) {
×
NEW
118
                $chain = $this->buildElementTranslationKeyChain(
×
NEW
119
                    $translationFiles,
×
NEW
120
                    $element,
×
NEW
121
                    $formRuntime,
×
NEW
122
                    $propertyType,
×
NEW
123
                    (string)$propertyName,
×
NEW
124
                    $originalFormIdentifier,
×
NEW
125
                );
×
NEW
126
                $translatedValue = $this->processTranslationChain($chain, $language, $arguments);
×
UNCOV
127
                $propertyValue = empty($translatedValue) ? $propertyValue : $translatedValue;
×
128
            }
NEW
129
            return $defaultValue;
×
130
        }
131

NEW
132
        $chain = $this->buildElementTranslationKeyChain(
×
NEW
133
            $translationFiles,
×
NEW
134
            $element,
×
NEW
135
            $formRuntime,
×
NEW
136
            $propertyType,
×
NEW
137
            $property,
×
NEW
138
            $originalFormIdentifier,
×
NEW
139
        );
×
NEW
140
        $translatedValue = $this->processTranslationChain($chain, $language, $arguments);
×
141

NEW
142
        return empty($translatedValue) ? $defaultValue : $translatedValue;
×
143
    }
144

145
    /**
146
     * @param list<string> $translationFiles
147
     * @param array<string, mixed> $element
148
     * @param array<string, mixed> $formRuntime
149
     * @return list<string>
150
     */
151
    private function buildElementTranslationKeyChain(
152
        array $translationFiles,
153
        array $element,
154
        array $formRuntime,
155
        string $propertyType,
156
        string $leaf,
157
        ?string $originalFormIdentifier,
158
    ): array {
NEW
159
        $chain = [];
×
NEW
160
        foreach ($translationFiles as $translationFile) {
×
NEW
161
            if (!empty($originalFormIdentifier)) {
×
NEW
162
                $chain[] = sprintf(
×
163
                    '%s:%s.element.%s.%s.%s',
×
164
                    $translationFile,
×
NEW
165
                    $originalFormIdentifier,
×
166
                    $element['identifier'],
×
167
                    $propertyType,
×
NEW
168
                    $leaf,
×
169
                );
×
170
            }
NEW
171
            $chain[] = sprintf(
×
NEW
172
                '%s:%s.element.%s.%s.%s',
×
NEW
173
                $translationFile,
×
NEW
174
                $formRuntime['identifier'],
×
NEW
175
                $element['identifier'],
×
NEW
176
                $propertyType,
×
NEW
177
                $leaf,
×
NEW
178
            );
×
NEW
179
            $chain[] = sprintf(
×
NEW
180
                '%s:element.%s.%s.%s',
×
NEW
181
                $translationFile,
×
NEW
182
                $element['identifier'],
×
NEW
183
                $propertyType,
×
NEW
184
                $leaf,
×
NEW
185
            );
×
NEW
186
            $chain[] = sprintf(
×
NEW
187
                '%s:element.%s.%s.%s',
×
NEW
188
                $translationFile,
×
NEW
189
                $element['type'] ?? '',
×
NEW
190
                $propertyType,
×
NEW
191
                $leaf,
×
NEW
192
            );
×
193
        }
NEW
194
        return $chain;
×
195
    }
196

197
    /**
198
     * @param array<string,mixed> $element
199
     * @param int $code
200
     * @param array<string,mixed> $formRuntime
201
     * @param array<string,mixed> $arguments
202
     * @param string $defaultValue
203
     * @return string
204
     */
205
    public function translateElementError(
206
        array $element,
207
        int $code,
208
        array $formRuntime,
209
        array $arguments = [],
210
        string $defaultValue = ''
211
    ): string {
212
        if (empty($code)) {
×
213
            throw new InvalidArgumentException('The argument "code" is empty', 1489272978);
×
214
        }
215

216
        $renderingOptions = $element['renderingOptions'] ?? [];
×
217
        $translationFiles = $renderingOptions['translation']['translationFiles'] ?? [];
×
218
        if (empty($translationFiles)) {
×
219
            $translationFiles = $formRuntime['renderingOptions']['translation']['translationFiles'];
×
220
        }
221

222
        $translationFiles = $this->sortArrayWithIntegerKeysDescending($translationFiles);
×
223
        $language = $renderingOptions['language'] ?? null;
×
224
        $originalFormIdentifier = $formRuntime['renderingOptions']['_originalIdentifier'] ?? null;
×
225

226
        $translationKeyChain = [];
×
227
        foreach ($translationFiles as $translationFile) {
×
228
            if (!empty($originalFormIdentifier)) {
×
229
                $translationKeyChain[] = sprintf(
×
230
                    '%s:%s.validation.error.%s.%s',
×
231
                    $translationFile,
×
232
                    $originalFormIdentifier,
×
233
                    $element['identifier'],
×
234
                    $code
×
235
                );
×
236

237
                $translationKeyChain[] = sprintf(
×
238
                    '%s:%s.validation.error.%s',
×
239
                    $translationFile,
×
240
                    $originalFormIdentifier,
×
241
                    $code
×
242
                );
×
243
            }
244
            $translationKeyChain[] = sprintf(
×
245
                '%s:%s.validation.error.%s.%s',
×
246
                $translationFile,
×
247
                $formRuntime['identifier'],
×
248
                $element['identifier'],
×
249
                $code
×
250
            );
×
251
            $translationKeyChain[] = sprintf(
×
252
                '%s:%s.validation.error.%s',
×
253
                $translationFile,
×
254
                $formRuntime['identifier'],
×
255
                $code
×
256
            );
×
257
            $translationKeyChain[] = sprintf(
×
258
                '%s:validation.error.%s.%s',
×
259
                $translationFile,
×
260
                $element['identifier'],
×
261
                $code
×
262
            );
×
263
            $translationKeyChain[] = sprintf('%s:validation.error.%s', $translationFile, $code);
×
264
        }
265

266
        $translatedValue = $this->processTranslationChain($translationKeyChain, $language, $arguments);
×
267

268
        return empty($translatedValue) ? $defaultValue : $translatedValue;
×
269
    }
270
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc