Adding a link inside translated content in Twig template - symfony

Inside a Twig template I would need to have a translated text that contains a link (the path should be generated by the Router, not statically embedded).
Twig does not allow to render a variable inside a trans block - I'm also aware of the following:
{% trans with {'%name%': 'Fabien'} from "app" %}
Hello %name%
{% endtrans %}
but I can't see how to use that to inject inside the translation a piece like this
privacy policy
(of course, the anchor text should be translated as well)

The approach I've taken is this:
In the translation file:
page.privacy.policy: Please read our %link_start%privacy policy%link_end%
In the twig file:
<p>{{ 'page.privacy.policy' | trans({'%link_start%' : '', '%link_end%' : ''}, 'account') | raw }}</p>
I'm not sure if this can be done using the block syntax you mentioned above as I found it didn't work unless I piped the result of the translation through the 'raw' filter. Also I use message domains to split the translations, hence the 'account' parameter.
I think the closest to your example would be:
<p>{{ 'Please read our %link_start%privacy policy%link_end%' | trans({'%link_start%' : '', '%link_end%' : ''}) | raw }}</p>
EDIT:
The only issue with this approach I've come across is where I need to programmatically follow a translated link in a unit test as there isn't a single translation representing the link text. Although messy I think it would be possible to get round this by providing a separate translation for the link text and substituting it's translated value into the full text as an additional variable.

rebdirdo's solution is not really safe as it's not escaping whole message. It is not working correctly for messages like "don't use <b> tag, use <strong> tag instead. %link_start%Here%link_end% you can find why.", because the tags will be not escaped and will be not visible.
working approach:
translation file:
advises.strong: don't use <b> tag, use <strong> tag instead. %link_start%Here%link_end% you can find why.
twig file:
{{ 'advises.strong'|trans|nl2br|replace({'%link_start%': '', '%link_end%': ''})|raw }}
Note the nl2br filter. It is necessary to put some filter there to make the raw filter working only for the link tags.

This is a better way:
{{ 'Please read our %privacy_policy%'|trans({
'%privacy_policy%': ' ' ~ 'Privacy Policy'|trans ~ ''
})|raw }}

Twig:
{{'body.term'|trans('%link_terms%' :app.request.getSchemeAndHttpHost()~path('terms')},'AcmeTerm')|raw }}
AcmeTerm.yml
body
term: >
<ul>
<li>ReadTerms.</li>
</ul>
where path('terms') is the route
like:
it__RG__terms ANY ANY ANY /it/termini-e-condizioni
en__RG__terms ANY ANY ANY /en/terms-and-conditions

Related

Theming Drupal 8 - Loop through all posted articles and print specific section

I am trying to create my first Drupal 8 theme. On the frontpage, I want to list all articles with the title, summary, date posted, etc.
I more or less achieved this using views. Basically {{ page.content }} in twig, but found it to be really inflexible and I didn't really get the results that I wanted. What I want to do is just to iterate through all the articles and print each section of that article "manually". For instance:
{% for page in pages %}
{{ page.content.title }}
{{ page.content.datePosted }}
{{ page.content.body }}
{% endfor %}
So that I can have more control of what is happening and not making a lot of configuration in the views module when deploying. What is the best soltuion to achieve this? Thanks!
I recommend to use Views. Configure you view (filter by content type, etc.), you have a lot of parameters to achieve what you need.
Set the view to show "Content" and give it a view mode (you can use the default teaser, full, or create your own view mode). Then you can create a custom template for this :
node--xxxx--teaser.html.twig
In order to know how to name your custom template file, enable Twig Debugging in sites/default/services.yml. Set the debug variable to true. And clear cache. Then, you will see in source code the template name suggestion like this :
<!-- FILE NAME SUGGESTIONS:
* node--1--full.html.twig
* node--1.html.twig
x node--oeuvre--full.html.twig
* node--oeuvre.html.twig
* node--full.html.twig
* node.html.twig
-->
In your twig, you can do that kind of templating :
{{ content.my_field_image[0] }}
<h2>{{ node.title.value }}</h2>
<p>{{ content.body }}</p>

Variable entity doesn't exist in template, how to fix it?

Here is my template architecture :
list.html.twig => question.html.twig => tagList.html.twig => tagBadge.html.twig
In my tag list, I have a tag variable that is well recognized, but in the tagBadge that is included, I get the error Variable tag does not exist.
I don't know what is the origin of the error. Maybe Twig can't follow the track of variables after a certain depth of inclusion ? I checked for invisible characters in my files. I verified my syntax again and again, but maybe my error is simple...
tagList.html.twig
{% for tag in tags %}
{{tag.name}}{# tag is recognized #}
{% include 'tag/partials/tagBadge.html.twig' with {'tag': tag} %}
{# tag is not recognized in template #}
{% endfor %}
tagBadge.html.twig
{{tag.name}}
My question: why tag is not recognized in my second template 'tagBadge'. I'm working with Symfony 4.2.
Ok, I found this week end the mistake I did. It appeared that I used my template in to different places of my view. It wasn't that use of the template which throw the error, but another I totally forgot, to which I didn't pass the variable... I feel dumb ;) let my mistake be useful for others !

I have this in Twig and the variable spits out all the debug code rather just a link, What do I do?

Here is the twig variable being set
{% set link = content.field_external_quote_link %}
When I just display the variable, it is coming out wrong.
For example if I do this in the HTML below:
TEXT EXAMPLE
It is dumping out devel code and other things I don't want. Is there something I need to do with the original variable set to get it to just dump the url in plain text?
{{ link.0.url }}
or
{{ link[0].url }}
or
You can make {{ link }} work, if you change your field settings within the node type display setting page, like this:
Goto your content type settings.
Goto: Manage Display
For the desired field, change format to display value as plain text or URL only.
WHich will tell drupal not to render it.
Now, clear cache. And, check again. It should work.

Twig - Get URL for canonical tag

I'm looking to create a dynamic rel="canonical" tag in my application which pulls in the current URL but want to ensure any query parameters are removed. E.g http://www.example.com/test/?page=2 should have the canonical as http://www.example.com/test/, therefore {{ app.request.uri }} doesn't work as this pulls in ?page=2 as well.
Does anyone know how to pull in the absolute path of a page without the query parameters?
This will work,
{{ url(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')) }}
I just tried to dump baseUrl and can confirm that it does not work.
However, this works:
{{ app.request.getSchemeAndHttpHost ~ app.request.baseUrl ~ app.request.pathInfo }}
I know, it's not pretty but it does the job :)

How to reference twig for custom field types in dedicated bundle?

I am (still) trying to introduce http://xoxco.com/clickable/jquery-tags-input into a dedicated bundle. As far, I have a type as a child of text and a data transformer that converts comma-separated strings into arrays of Objects and vice versa.
Now I want to decorate the text field with the JQuery code linked above. As far as I understand, I have to define a block like
{% block manytomanycomboselector_widget %}
{% spaceless %}
{{ block('text_widget') }}
<script>
$(function(){
$("#{{ id }}").tagsInput();
});
</script>
{% endspaceless %}
{% endblock manytomanycomboselector_widget %}
in [MyTypeBundle]Resources/views/Form/fields.html.twig
Now, both the documentation and the answers for this question at StackOverflow state that I have to reference fields.html.twig somewhere either in the template that uses the form or in app/, but this doesn't seem to be necessarily for other field-type bundles, though I cannot see in their code why.
What do I have to configure inside the bundle besides this block in this file?
Also I didn't get where I have to put the css and js requirements for the header and how I deal with general requirements like jQuery itself.
I have the same issue & I resolve it by merging my field template in the twig.form.resources parameter.
So, in the DI extension of my bundle (MyBundle/DependencyInjection/MyBundleExtension.php), I add:
$container->setParameter('twig.form.resources', array_merge(
array('MyBundle:Form:field_widget.html.twig'),
$container->getParameter('twig.form.resources')
));
Be aware, your bundle must be registered after the TwigBundle in your AppKernel.
EDIT:
A form field is not linked to any JS or CSS. So, IMO, you have 2 solutions.
Firstly, you directly wrap your JS & CSS in your field template and your bundle stays stand-alone.
Secondly, you instruct final users that they need to include manually some JSS & CSS each time they use your field type.
The IoFormBundle & GenemuFormBundle uses the second solution like explain in their documentation.

Resources