From 23ac67816b0e8050008e149d3a75be8b0d2a1998 Mon Sep 17 00:00:00 2001 From: Jose Reyero <consulting@reyero.net> Date: Wed, 30 Apr 2025 19:20:17 +0200 Subject: [PATCH 1/4] Introduce 'translate' yaml tag, first try 3313863#6 --- .../Drupal/Component/Serialization/Yaml.php | 37 +++++++++++++++++++ core/lib/Drupal/Core/Recipe/Recipe.php | 16 +++++++- core/recipes/feedback_contact_form/recipe.yml | 10 ++--- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/core/lib/Drupal/Component/Serialization/Yaml.php b/core/lib/Drupal/Component/Serialization/Yaml.php index 5cff6dd53f1e..3c0f278505fb 100644 --- a/core/lib/Drupal/Component/Serialization/Yaml.php +++ b/core/lib/Drupal/Component/Serialization/Yaml.php @@ -5,6 +5,7 @@ use Drupal\Component\Serialization\Exception\InvalidDataTypeException; use Symfony\Component\Yaml\Dumper; use Symfony\Component\Yaml\Parser; +use Symfony\Component\Yaml\Tag\TaggedValue; use Symfony\Component\Yaml\Yaml as SymfonyYaml; /** @@ -51,4 +52,40 @@ public static function getFileExtension() { return 'yml'; } + /** + * Parses custom YAML tags and convert values to primitive types. + * + * Tag objects will be replaced by their raw value or, if a callback + * exists for that tag it will be used. + * + * @param mixed $data + * Parsed yaml data + * @param callable[] $tall_callbacks + * Optional callbacks for tag value, indexed by tag. + * + * @return mixed + * Parsed data with parsed tag values. + */ + public static function decodeTags($data, $tag_callbacks = []) { + if (is_array($data)) { + foreach ($data as $key => $value) { + if (is_object($value) && $value instanceof TaggedValue) { + if (isset($tag_callbacks[$value->getTag()])) { + $data[$key] = call_user_func($tag_callbacks[$value->getTag()], $value->getValue()); + } + else { + $data[$key] = $value->getValue(); + } + } + elseif (is_array($value)) { + $data[$key] = static::decodeTags($value, $tag_callbacks); + } + } + return $data; + } + else { + return $data; + } + } + } diff --git a/core/lib/Drupal/Core/Recipe/Recipe.php b/core/lib/Drupal/Core/Recipe/Recipe.php index 888f54e4f42c..1d6b5178c3ea 100644 --- a/core/lib/Drupal/Core/Recipe/Recipe.php +++ b/core/lib/Drupal/Core/Recipe/Recipe.php @@ -11,6 +11,7 @@ use Drupal\Core\Extension\ThemeExtensionList; use Drupal\Component\Serialization\Yaml; use Drupal\Core\Render\Element; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\Validation\Plugin\Validation\Constraint\RegexConstraint; use Symfony\Component\Validator\Constraints\All; @@ -308,12 +309,24 @@ private static function parse(string $file): array { ]), ]); + // Parse YAML file and clean up tags for validation. $recipe_data = Yaml::decode($recipe_contents); + $clean_data = Yaml::decodeTags($recipe_data); + /** @var \Symfony\Component\Validator\ConstraintViolationList $violations */ - $violations = Validation::createValidator()->validate($recipe_data, $constraints); + $violations = Validation::createValidator()->validate($clean_data, $constraints); if (count($violations) > 0) { throw RecipeFileException::fromViolationList($file, $violations); } + + // Replace 'translate' tags with proper translations. + $custom_tags = [ + 'translate' => function($value) use ($file) { + return (string) new TranslatableMarkup($value); + } + ]; + $recipe_data = Yaml::decodeTags($recipe_data, $custom_tags); + $recipe_data += [ 'description' => '', 'type' => '', @@ -322,6 +335,7 @@ private static function parse(string $file): array { 'config' => [], 'content' => [], ]; + return $recipe_data; } diff --git a/core/recipes/feedback_contact_form/recipe.yml b/core/recipes/feedback_contact_form/recipe.yml index c6bf74cf40c5..887ce62db164 100644 --- a/core/recipes/feedback_contact_form/recipe.yml +++ b/core/recipes/feedback_contact_form/recipe.yml @@ -6,16 +6,16 @@ install: input: recipient: data_type: email - description: 'The email address that should receive submissions from the feedback form.' + description: !translate 'The email address that should receive submissions from the feedback form.' constraints: NotBlank: [] prompt: method: ask arguments: - question: 'What email address should receive website feedback?' + question: !translate 'What email address should receive website feedback?' form: '#type': email - '#title': 'Feedback form email address' + '#title': !translate 'Feedback form email address' default: source: config config: ['system.site', 'mail'] @@ -30,8 +30,8 @@ config: actions: contact.form.feedback: createIfNotExists: - label: 'Website feedback' - message: 'Your message has been sent.' + label: !translate 'Website feedback' + message: !translate 'Your message has been sent.' redirect: '' setRecipients: - ${recipient} -- GitLab From a0d7c3944246f406fd46b73606ed0392228d8f86 Mon Sep 17 00:00:00 2001 From: Jose Reyero <consulting@reyero.net> Date: Sun, 11 May 2025 10:20:08 +0200 Subject: [PATCH 2/4] Important patch updates: - Moved all tag parsing to Yaml class. - Implemented string translation context. - Updated two other recipes for translation. - Handled yaml validation properly with Type(['string', Stringable::class]) - Fixed arguments types in ConsoleInputCollector. --- .../Drupal/Component/Serialization/Yaml.php | 54 ++++++++++++++++++- .../Core/Recipe/ConsoleInputCollector.php | 5 ++ core/lib/Drupal/Core/Recipe/Recipe.php | 19 ++----- .../Core/Recipe/RecipeInputFormTrait.php | 4 +- .../core_recommended_admin_theme/recipe.yml | 2 +- .../recipe.yml | 4 +- core/recipes/feedback_contact_form/recipe.yml | 2 +- 7 files changed, 68 insertions(+), 22 deletions(-) diff --git a/core/lib/Drupal/Component/Serialization/Yaml.php b/core/lib/Drupal/Component/Serialization/Yaml.php index 3c0f278505fb..e2d10e905134 100644 --- a/core/lib/Drupal/Component/Serialization/Yaml.php +++ b/core/lib/Drupal/Component/Serialization/Yaml.php @@ -3,6 +3,7 @@ namespace Drupal\Component\Serialization; use Drupal\Component\Serialization\Exception\InvalidDataTypeException; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Symfony\Component\Yaml\Dumper; use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Tag\TaggedValue; @@ -58,20 +59,28 @@ public static function getFileExtension() { * Tag objects will be replaced by their raw value or, if a callback * exists for that tag it will be used. * + * The only tag custom tag supported by default is the '!translate' tag. + * * @param mixed $data * Parsed yaml data * @param callable[] $tall_callbacks * Optional callbacks for tag value, indexed by tag. + * @param array $options + * Extra options to pass to tag callbacks. * * @return mixed * Parsed data with parsed tag values. */ - public static function decodeTags($data, $tag_callbacks = []) { + public static function decodeTags($data, array $tag_callbacks = [], array $options = []) { + // Replace 'translate' tags with proper translations. + $tag_callbacks += [ + 'translate' => [__CLASS__, 'tagTranslate'] + ]; if (is_array($data)) { foreach ($data as $key => $value) { if (is_object($value) && $value instanceof TaggedValue) { if (isset($tag_callbacks[$value->getTag()])) { - $data[$key] = call_user_func($tag_callbacks[$value->getTag()], $value->getValue()); + $data[$key] = call_user_func($tag_callbacks[$value->getTag()], $value->getValue(), $options); } else { $data[$key] = $value->getValue(); @@ -88,4 +97,45 @@ public static function decodeTags($data, $tag_callbacks = []) { } } + /** + * Callback for 'translate' tag value. + * + * A translatable string can be represented as a plain string, or as an array + * with 'string' and 'context' and maybe other parameters. For example: + * + * @code + * element: + * label: !translate 'Website feedback' + * another: + * label: !translate {string: 'Website feedback', context: 'Contact form'} + * @endcode + * + * In this second case, the full array minus the 'string' part will be passed + * as the '$options' parameter for the translation. + * + * @see t() + * + * @param string|array $value + * The tagged value representing a translatable string. + * @param array $options + * Extra options to pass to the translation. + * + * @return \Drupal\Core\StringTranslation\TranslatableMarkup + * The translatable string object. + */ + public static function tagTranslate($value, $options = []) { + if (is_array($value) && isset($value['string'])) { + $string = $value['string']; + unset($value['string']); + $options += $value; + } elseif (is_string($value)) { + $string = $value; + } + else { + throw new InvalidDataTypeException("Cannot parse the 'translate' tag. The tagged value is not a string nor has a 'string' element."); + } + + return new TranslatableMarkup($string, [], $options); + } + } diff --git a/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php b/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php index f1db3a342af1..ced633184df8 100644 --- a/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php +++ b/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php @@ -102,6 +102,11 @@ public function collectValue(string $name, DataDefinitionInterface $definition, // input definitions should define constraints. unset($arguments['validator']); + // Run localization before calling final method. + $arguments = array_map(function ($value) { + return is_object($value) && $value instanceof \Stringable ? (string)$value : $value; + }, $arguments); + return $this->io->$method(...$arguments); } diff --git a/core/lib/Drupal/Core/Recipe/Recipe.php b/core/lib/Drupal/Core/Recipe/Recipe.php index 1d6b5178c3ea..6e1d283ce1c9 100644 --- a/core/lib/Drupal/Core/Recipe/Recipe.php +++ b/core/lib/Drupal/Core/Recipe/Recipe.php @@ -11,7 +11,6 @@ use Drupal\Core\Extension\ThemeExtensionList; use Drupal\Component\Serialization\Yaml; use Drupal\Core\Render\Element; -use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\Validation\Plugin\Validation\Constraint\RegexConstraint; use Symfony\Component\Validator\Constraints\All; @@ -192,7 +191,7 @@ private static function parse(string $file): array { fields: [ // Every input definition must have a description. 'description' => [ - new Type('string'), + new Type(['string', \Stringable::class]), new NotBlank(), ], // There can be an optional set of constraints, which is an @@ -309,24 +308,16 @@ private static function parse(string $file): array { ]), ]); - // Parse YAML file and clean up tags for validation. $recipe_data = Yaml::decode($recipe_contents); - $clean_data = Yaml::decodeTags($recipe_data); + + // Replace 'translate' tags with proper translations. + $recipe_data = Yaml::decodeTags($recipe_data); /** @var \Symfony\Component\Validator\ConstraintViolationList $violations */ - $violations = Validation::createValidator()->validate($clean_data, $constraints); + $violations = Validation::createValidator()->validate($recipe_data, $constraints); if (count($violations) > 0) { throw RecipeFileException::fromViolationList($file, $violations); } - - // Replace 'translate' tags with proper translations. - $custom_tags = [ - 'translate' => function($value) use ($file) { - return (string) new TranslatableMarkup($value); - } - ]; - $recipe_data = Yaml::decodeTags($recipe_data, $custom_tags); - $recipe_data += [ 'description' => '', 'type' => '', diff --git a/core/lib/Drupal/Core/Recipe/RecipeInputFormTrait.php b/core/lib/Drupal/Core/Recipe/RecipeInputFormTrait.php index 5f8d8dd32d5e..850f8882eb27 100644 --- a/core/lib/Drupal/Core/Recipe/RecipeInputFormTrait.php +++ b/core/lib/Drupal/Core/Recipe/RecipeInputFormTrait.php @@ -43,7 +43,7 @@ protected function buildRecipeInputForm(Recipe $recipe): array { * 'recipe_1' => [ * 'input_1' => [ * '#type' => 'textfield', - * '#title' => 'Some input value', + * '#title' => !translate 'Some input value', * ], * 'input_2' => [ * '#type' => 'checkbox', @@ -53,7 +53,7 @@ protected function buildRecipeInputForm(Recipe $recipe): array { * 'dependency_recipe' => [ * 'input_1' => [ * '#type' => 'textarea', - * '#title' => 'An input defined by a dependency of recipe_1', + * '#title' => !translate 'An input defined by a dependency of recipe_1', * ], * ], * '#tree' => TRUE, diff --git a/core/recipes/core_recommended_admin_theme/recipe.yml b/core/recipes/core_recommended_admin_theme/recipe.yml index 61cd28e17c9c..dc134ac9fda6 100644 --- a/core/recipes/core_recommended_admin_theme/recipe.yml +++ b/core/recipes/core_recommended_admin_theme/recipe.yml @@ -27,7 +27,7 @@ config: plugin: page_title_block settings: id: page_title_block - label: 'Page title' + label: !translate 'Page title' label_display: '0' provider: core setRegion: header diff --git a/core/recipes/core_recommended_front_end_theme/recipe.yml b/core/recipes/core_recommended_front_end_theme/recipe.yml index 00faf6409ec5..fcd5cebb0f61 100644 --- a/core/recipes/core_recommended_front_end_theme/recipe.yml +++ b/core/recipes/core_recommended_front_end_theme/recipe.yml @@ -31,7 +31,7 @@ config: plugin: system_messages_block settings: id: system_messages_block - label: 'Status messages' + label: !translate 'Status messages' label_display: '0' provider: system setRegion: highlighted @@ -43,7 +43,7 @@ config: plugin: page_title_block settings: id: page_title_block - label: 'Page title' + label: !translate 'Page title' label_display: '0' provider: core setRegion: content_above diff --git a/core/recipes/feedback_contact_form/recipe.yml b/core/recipes/feedback_contact_form/recipe.yml index 887ce62db164..ff10fe500d4a 100644 --- a/core/recipes/feedback_contact_form/recipe.yml +++ b/core/recipes/feedback_contact_form/recipe.yml @@ -31,7 +31,7 @@ config: contact.form.feedback: createIfNotExists: label: !translate 'Website feedback' - message: !translate 'Your message has been sent.' + message: !translate {string: 'Your message has been sent.', context: 'Contact form'} redirect: '' setRecipients: - ${recipient} -- GitLab From 9dd9663d616c9fcbfc578767976f583f4384b4b3 Mon Sep 17 00:00:00 2001 From: Jose Reyero <consulting@reyero.net> Date: Tue, 3 Jun 2025 17:01:27 +0200 Subject: [PATCH 3/4] Fixing code formatting issues in #20 and some code improvements. Added YamlTagTranslator to fix 'No core in component' issue. Simplified tag callbacks. --- .../Drupal/Component/Serialization/Yaml.php | 59 ++---------------- core/lib/Drupal/Core/Recipe/Recipe.php | 3 +- .../StringTranslation/YamlTagTranslator.php | 61 +++++++++++++++++++ 3 files changed, 67 insertions(+), 56 deletions(-) create mode 100644 core/lib/Drupal/Core/StringTranslation/YamlTagTranslator.php diff --git a/core/lib/Drupal/Component/Serialization/Yaml.php b/core/lib/Drupal/Component/Serialization/Yaml.php index e2d10e905134..b1ed89109c65 100644 --- a/core/lib/Drupal/Component/Serialization/Yaml.php +++ b/core/lib/Drupal/Component/Serialization/Yaml.php @@ -3,7 +3,6 @@ namespace Drupal\Component\Serialization; use Drupal\Component\Serialization\Exception\InvalidDataTypeException; -use Drupal\Core\StringTranslation\TranslatableMarkup; use Symfony\Component\Yaml\Dumper; use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Tag\TaggedValue; @@ -63,24 +62,18 @@ public static function getFileExtension() { * * @param mixed $data * Parsed yaml data - * @param callable[] $tall_callbacks + * @param callable[] $tag_callbacks * Optional callbacks for tag value, indexed by tag. - * @param array $options - * Extra options to pass to tag callbacks. * * @return mixed * Parsed data with parsed tag values. */ - public static function decodeTags($data, array $tag_callbacks = [], array $options = []) { - // Replace 'translate' tags with proper translations. - $tag_callbacks += [ - 'translate' => [__CLASS__, 'tagTranslate'] - ]; + public static function decodeTags($data, array $tag_callbacks = []) { if (is_array($data)) { foreach ($data as $key => $value) { if (is_object($value) && $value instanceof TaggedValue) { if (isset($tag_callbacks[$value->getTag()])) { - $data[$key] = call_user_func($tag_callbacks[$value->getTag()], $value->getValue(), $options); + $data[$key] = call_user_func($tag_callbacks[$value->getTag()], $value); } else { $data[$key] = $value->getValue(); @@ -90,52 +83,8 @@ public static function decodeTags($data, array $tag_callbacks = [], array $optio $data[$key] = static::decodeTags($value, $tag_callbacks); } } - return $data; } - else { - return $data; - } - } - - /** - * Callback for 'translate' tag value. - * - * A translatable string can be represented as a plain string, or as an array - * with 'string' and 'context' and maybe other parameters. For example: - * - * @code - * element: - * label: !translate 'Website feedback' - * another: - * label: !translate {string: 'Website feedback', context: 'Contact form'} - * @endcode - * - * In this second case, the full array minus the 'string' part will be passed - * as the '$options' parameter for the translation. - * - * @see t() - * - * @param string|array $value - * The tagged value representing a translatable string. - * @param array $options - * Extra options to pass to the translation. - * - * @return \Drupal\Core\StringTranslation\TranslatableMarkup - * The translatable string object. - */ - public static function tagTranslate($value, $options = []) { - if (is_array($value) && isset($value['string'])) { - $string = $value['string']; - unset($value['string']); - $options += $value; - } elseif (is_string($value)) { - $string = $value; - } - else { - throw new InvalidDataTypeException("Cannot parse the 'translate' tag. The tagged value is not a string nor has a 'string' element."); - } - - return new TranslatableMarkup($string, [], $options); + return $data; } } diff --git a/core/lib/Drupal/Core/Recipe/Recipe.php b/core/lib/Drupal/Core/Recipe/Recipe.php index 6e1d283ce1c9..a83909ac60c1 100644 --- a/core/lib/Drupal/Core/Recipe/Recipe.php +++ b/core/lib/Drupal/Core/Recipe/Recipe.php @@ -11,6 +11,7 @@ use Drupal\Core\Extension\ThemeExtensionList; use Drupal\Component\Serialization\Yaml; use Drupal\Core\Render\Element; +use Drupal\Core\StringTranslation\YamlTagTranslator; use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\Validation\Plugin\Validation\Constraint\RegexConstraint; use Symfony\Component\Validator\Constraints\All; @@ -311,7 +312,7 @@ private static function parse(string $file): array { $recipe_data = Yaml::decode($recipe_contents); // Replace 'translate' tags with proper translations. - $recipe_data = Yaml::decodeTags($recipe_data); + $recipe_data = Yaml::decodeTags($recipe_data, ['translate' => YamlTagTranslator::TranslateTaggedValue(...)]); /** @var \Symfony\Component\Validator\ConstraintViolationList $violations */ $violations = Validation::createValidator()->validate($recipe_data, $constraints); diff --git a/core/lib/Drupal/Core/StringTranslation/YamlTagTranslator.php b/core/lib/Drupal/Core/StringTranslation/YamlTagTranslator.php new file mode 100644 index 000000000000..a9511f3bfc72 --- /dev/null +++ b/core/lib/Drupal/Core/StringTranslation/YamlTagTranslator.php @@ -0,0 +1,61 @@ +<?php + +namespace Drupal\Core\StringTranslation; + +use Drupal\Component\Serialization\Exception\InvalidDataTypeException; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Symfony\Component\Yaml\Tag\TaggedValue; + +/** + * Provides a callback for YAML 'translate' tags. + */ +class YamlTagTranslator { + + /** + * Callback for 'translate' tag object. + * + * A translatable string can be represented as a plain string, or as an array + * with 'string' and 'context' and maybe other parameters. For example: + * + * @code + * element: + * label: !translate 'Website feedback' + * another: + * label: !translate {string: 'Website feedback', context: 'Contact form'} + * @endcode + * + * In this second case, the full array minus the 'string' part will be passed + * as the '$options' parameter for the translation. + * + * @see t() + * + * @param \Symfony\Component\Yaml\Tag\TaggedValue $tagged_value + * The tagged value object. + * @param array $options + * Extra options to pass to the translation. + * + * @return \Drupal\Core\StringTranslation\TranslatableMarkup + * The translatable string object. + */ + public static function translateTaggedValue(TaggedValue $tagged_value, $options = []){ + $value = $tagged_value->getValue(); + if (is_array($value) && isset($value['string'])) { + $string = $value['string']; + unset($value['string']); + $options += $value; + } elseif (is_string($value)) { + $string = $value; + } + else { + throw new InvalidDataTypeException("Cannot parse the 'translate' tag. The tagged value is not a string nor has a 'string' element."); + } + + return new TranslatableMarkup($string, [], $options); + } + +} + + + + + -- GitLab From 17ae193ddda47c41256b2545d2da6bd1dd18e9cc Mon Sep 17 00:00:00 2001 From: Jose Reyero <consulting@reyero.net> Date: Wed, 4 Jun 2025 23:42:58 +0200 Subject: [PATCH 4/4] Fixed coding standards. --- .../lib/Drupal/Component/Serialization/Yaml.php | 2 +- .../Core/Recipe/ConsoleInputCollector.php | 2 +- .../StringTranslation/YamlTagTranslator.php | 17 ++++++----------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/core/lib/Drupal/Component/Serialization/Yaml.php b/core/lib/Drupal/Component/Serialization/Yaml.php index b1ed89109c65..6f93ab919358 100644 --- a/core/lib/Drupal/Component/Serialization/Yaml.php +++ b/core/lib/Drupal/Component/Serialization/Yaml.php @@ -61,7 +61,7 @@ public static function getFileExtension() { * The only tag custom tag supported by default is the '!translate' tag. * * @param mixed $data - * Parsed yaml data + * Parsed YAML data. * @param callable[] $tag_callbacks * Optional callbacks for tag value, indexed by tag. * diff --git a/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php b/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php index ced633184df8..fa76bea44e0c 100644 --- a/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php +++ b/core/lib/Drupal/Core/Recipe/ConsoleInputCollector.php @@ -104,7 +104,7 @@ public function collectValue(string $name, DataDefinitionInterface $definition, // Run localization before calling final method. $arguments = array_map(function ($value) { - return is_object($value) && $value instanceof \Stringable ? (string)$value : $value; + return is_object($value) && $value instanceof \Stringable ? (string) $value : $value; }, $arguments); return $this->io->$method(...$arguments); diff --git a/core/lib/Drupal/Core/StringTranslation/YamlTagTranslator.php b/core/lib/Drupal/Core/StringTranslation/YamlTagTranslator.php index a9511f3bfc72..ba5b1bedb4ec 100644 --- a/core/lib/Drupal/Core/StringTranslation/YamlTagTranslator.php +++ b/core/lib/Drupal/Core/StringTranslation/YamlTagTranslator.php @@ -3,7 +3,6 @@ namespace Drupal\Core\StringTranslation; use Drupal\Component\Serialization\Exception\InvalidDataTypeException; -use Drupal\Core\StringTranslation\TranslatableMarkup; use Symfony\Component\Yaml\Tag\TaggedValue; /** @@ -28,22 +27,23 @@ class YamlTagTranslator { * as the '$options' parameter for the translation. * * @see t() - * + * * @param \Symfony\Component\Yaml\Tag\TaggedValue $tagged_value * The tagged value object. * @param array $options * Extra options to pass to the translation. - * + * * @return \Drupal\Core\StringTranslation\TranslatableMarkup * The translatable string object. */ - public static function translateTaggedValue(TaggedValue $tagged_value, $options = []){ + public static function translateTaggedValue(TaggedValue $tagged_value, $options = []) { $value = $tagged_value->getValue(); if (is_array($value) && isset($value['string'])) { $string = $value['string']; unset($value['string']); $options += $value; - } elseif (is_string($value)) { + } + elseif (is_string($value)) { $string = $value; } else { @@ -53,9 +53,4 @@ public static function translateTaggedValue(TaggedValue $tagged_value, $options return new TranslatableMarkup($string, [], $options); } -} - - - - - +} -- GitLab