- πͺπΈSpain jose reyero
While considering configuration schema for this task, I'm thinking that will introduce a great deal of complexity and dependencies so I'm looking into some simpler options.
This is a rough first patch presenting some alternate approach, using Symfony YAML tags to mark translatable strings in YAML files. The idea has been presented and discussed in this related thread https://www.drupal.org/project/drupal/issues/3488972#comment-15867505 β¨ Make recipes translatable Active
This is how translatable strings would look like in yaml. Note the newly introduced '!translate' tags.
actions: contact.form.feedback: createIfNotExists: label: !translate 'Website feedback' message: !translate 'Your message has been sent.' redirect: ''
So far I've only added these tags for the 'feedback_contact_form' recipe, which is an interesting example because it has both 'input' and 'config/actions' translatable strings. Not sure about using them for 'input' strings but since it was easy enough...
To manually test it, try applying the recipe with a different default language. You'll get translatable/translated strings for prompts and the newly created feedback form :
- Apply patch
- Enable language, locale modules
- Set a new default language
- Try: drush recipe core/recipes/feedback_contact_form
- The first time you'll get English strings but they will be available for translation. Once translated they will be used when re-applying the recipe. - πΊπΈUnited States smustgrave
Have not tested but patches should be in MRs please. Also can issue summary sections be filled in
- π¬π§United Kingdom alexpott πͺπΊπ
@jose reyero awesome to see you in this issue! And great idea.
Given we're only using Symfony's YAML parser now the idea of using tags is viable. The thing that jumps out is what about translation context? I don't think there is a way to provide an argument to a tag unless we agree some funky character with which to split the string... wouldn't be the first time we've used such an approach in translation. Also I really wish that translation did a fallback approach to context. If it did we could add the action ID as a context to all strings and be done.
- πͺπΈSpain jose reyero
Hi @alexpott,
It's actually Gabor's idea :)
About translation context, yes, that is a hard one... Looking at how it's done in existing yaml files (module links.yml, routing.yml ...) I don't think that will work here (adding 'title_context' keys ) ... for more info see 'Translation string sharing and context' here https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Language%...
So I'm thinking some other options - that I've tested, and are ok with the parser - let me know which one looks better, or any better idea...:
input: recipient: data_type: email # Plain list, faster to write, but not that clear description: !translate ['The email address that should receive submissions from the feedback', 'First context'] prompt: method: ask arguments: # Yup, tags work for nested elements ! :) question: !translate string: 'What email address should receive website feedback?' context: 'Second context' # Same as previous one, just formatting it differently form: '#type': email '#title': !translate { string: 'Feedback form email address', context: 'Third context' }
And still we can have the original '!translate' tag with a simple string, same tag can handle all cases.,
- ππΊHungary GΓ‘bor Hojtsy Hungary
I like this version best :) Will post in Slack to get more feedback :)
input: recipient: data_type: email # Plain list, faster to write, but not that clear description: !translate ['The email address that should receive submissions from the feedback', 'First context']
- πͺπΈSpain penyaskito Seville π, Spain πͺπΈ, UTC+2 πͺπΊ
So I'm thinking some other options - that I've tested, and are ok with the parser
I was inclined for the third one because might be easier to handle from potx extraction. But if the three are feasible, I don't have an strong opinion.
input: recipient: data_type: email # Plain list, faster to write, but not that clear description: !translate ['The email address that should receive submissions from the feedback', 'First context']
What if the author wants no context?
description: !translate ['The email address that should receive submissions from the feedback']
Could that be shortcut to
description: !translate 'The email address that should receive submissions from the feedback'
?
Then recipe writers I assume would prefer that one. - π§πͺBelgium svendecabooter Gent
That looks like a great approach to add translation options to recipes.
I don't have strong feelings regarding the exact syntax, but personally prefer the options where the parameters are named explicitly (so 2nd or 3rd).
I'm assuming the 3rd could also be written as
form: '#type': email '#title': !translate { string: 'Feedback form email address', context: 'Third context' }
As it would avoid having everything on 1 line, especially with larger strings you would need to do some horizontal scrolling in your IDE.
Come to think of it, then I probably prefer the 2nd version, as it avoids the extra brackets as well.. - πͺπΈSpain jose reyero
Done some patch update, the important changes:
- Moved all tag parsing to Yaml class. This will allow reusability for things other than recipes. Still looking into simplifying this part.
- Implemented string translation context, with the option 2/3 - named parameters -. This doesn't need to be a definitive one but I was needing some working implementation to move on...
- Updated two other recipes for translation: core_recommended_admin_theme, core_recommended_front_end_theme
- Handled yaml validation properly with Type(['string', Stringable::class])
- Fixed arguments types in ConsoleInputCollector.About the context thing / notation:
- Yes, when no context it can be written as a simple string: !translate 'My simple string'
- About the option implemented I think it has some advantages: it is self documenting, looks better for potx parsing - as pointed out by @penyaskito - and allows extendability with more parameters... (plurals maybe for other usages). Anyway this context thing doesn't happen that often and it is usually needed only for very short strings.So just to clarify, it currently looks like:
message: !translate {string: 'Your message has been sent.', context: 'Contact form'} description: !translate 'Just a plain string when no context is needed'
- π¬π§United Kingdom alexpott πͺπΊπ
I think explicit options that match the arguments of the object is definitely the way to go. Really like the way this is going. Lovely work.
- πͺπΈSpain jose reyero
@alexpott,
Yes, sorry, I forgot to mention I'm using the MR workflow instead of patch files for further development. - @alexpott opened merge request.
- π¬π§United Kingdom alexpott πͺπΊπ
@jose reyero I created the merge request for you - https://git.drupalcode.org/project/drupal/-/merge_requests/12121
The Needs Review Queue Bot β tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide β to find step-by-step guides for working with issues.
- Status changed to Needs work
about 1 month ago 9:17am 10 June 2025 - πͺπΈSpain jose reyero
Fixed coding standards issues and the 'No core in component' one by moving the callback function to
Drupal\Core\StringTranslation\YamlTagTranslator.phpStill cannot get over this one:
53 | WARNING | Only string literals should be passed to t() where possible | | (Drupal.Semantics.FunctionT.NotLiteralString
which is caused by this line we need:
return new TranslatableMarkup($string, [], $options);
Any idea about how to get rid of this warning?
- πͺπΈSpain jose reyero
Ok, fixed that issue, thx @goba @penyaskito @anjali15
Still, working on the patch a bit more. As we talked on the chat, I'm going to trim down this feature, just translating the 'config/actions' part and leaving the 'input' outside of this scope, creating a new task for that one. On one side it's looking to me more like a different case, and we may want to use the '!translate' tag for it or not, and also there are a lot of 'input' strings in the yaml files.
So let's focus on:
* config/actions
* new yaml !translate tagThen once we have the feature in place, we can easily use it for more strings - or not.
- πͺπΈSpain jose reyero
Looks like tests are passing, finally, just re-running them. This is ready for review now.