In messages.en.yml, I have
confirmed: Congrats %username%, your account is now activated.
But I want to 'bold' username to example ... how can I made this ?
confirmed: Congrats <span class='bold'>%username%</span>, your account is now activated.
Of course I could use two sentence in this example like
first: Congrats
second: , your account ...
and inside twig use the html tag but this seems very dirty.
Update 2
In such cases, I started to use like this:
confirmed: Congrats %start_link%%username%%end_link%, your account is now activated
Since separation of concerns is maintained, this way is strongly recommended.
Update
In YAML, I have used translations like this without any problem:
trans.key: click here to continue
Although translations and design should be kept separated there are always some situations that you must use html tags inside translation files as it is also seen in huge projects like Facebook and Twitter.
In such situations, you can use XLIFF format which is being recommended by Symfony. Inside translation file:
<trans-unit id="1">
<source>confirmed</source>
<target>Congrats <![CDATA[<span class='bold'>%username%</span>]]> , your account is now activated.</target>
</trans-unit>
Twig's Raw Filter
I don't know if this was an option back in 2013 but when using translation, you can apply the raw twig filter having this translation string:
confirmed: Congrats <span class='bold'>%username%</span>,
your account is now activated.
And use it in twig like this:
{{ 'confirmed'|trans|raw }}
This will not escape the html inside the string and will display the username as bold.
Update: I haven't seen the comment the first time, but Rvanlaak had proposed the raw filter solution in the first place.
Security issues
Note that the content of those translation strings must not be user provided, because it could open up your application to XSS attacks. Using the raw filter allows JavaScript to be executed if a malicious user is able to input custom data into the translation strings (Community based translations for example)
Separation of concerns
Using the raw filter does not comply with separation of concerns as the content and styling are bound together. As Ferhad mentioned, using his method, separation of concern will be maintained. But in my case, I preferred using a simple raw filter. I felt that for my case, Ferhad's method was a bit overkill for me, though it would be more recommended his way
My approach is although still ugly, but at least respects the separation of concerns. Escape filter is used to escape a variable, making the final result is pretty safe from XSS, because all other sources considered to be hard-coded.
translations.yml
points: You have %num% points left.
template.html.twig
{% set pointsFormatted = '<span class="points">' ~ num | escape ~ '</span>' %}
{{ 'pages.score.points' | trans({'%num%' : pointsFormatted}) | raw }}
I've just found something out, you can use this in your YAML file:
mind: >
<i>Mind is a nice thing to have</i>
So this ">" sign in the first row achieves it. I think this would be the preferred way, better than handling the escapes etc in TWIG.
I've looked it up now and it is actually a YAML feature. Check here :)
Also, there's an earlier question with similar subject: How can I get YAML to ignore raw HTML in same file.
some yml:
dashboard:
hello: Hello <b>%username%</b>
+
{{ 'dashboard.hello'|trans({'%username%': app.user.username}, 'General') | raw }}
this | raw part worked for me
In my opinion, this is the best solution today:
'key'|trans({'%username%': '<strong>' ~ suspiciousVar|escape ~ '</strong>'})|raw
The only risk here is stored XSS in your translation files.
Holding HTML stuff in translations is wrong, because translators usually break it. But if you really need it:
Twig:
{% trans %}confirmed{% endtrans %}
Yaml translation file:
confirmed: 'Congrats <span class="bold">%username%</span>, your account is now activated.'
Discussion about this:
https://github.com/symfony/symfony/issues/2713
We could use separate twig snippets for different languages if situation requires heavy formatting differences. I wrote a little blog on this.
{# templates/translations/user_message.pl.html.twig #}
{{ 'msg.my_favourite_language_is' }}<b>{{ 'langnames.elfic_language' | trans | lower }}</b>!
{# templates/translations/user_message.en.html.twig #}
{{ 'msg.my_favourite_language_is' }}<i>{{ 'langnames.elfic_language' | trans | ucfirst }}</i>!
{# templates/pages/index.html.twig #}
{% set locale=app.request.locale[:2] %}
{% include 'translations/calculator_message.' ~ locale ~ '.html.twig' %}
Translation files are for translations, design and layout is part of the view layer (namely: template engine (twig)). You can split it into two pieces: congrats and account.activated.
Related
I have a problem with flash messages in Symfony 4 and translation.
Translation of simple flash messages is working fine:
$this->addFlash('success', 'flashmessage.project_deleted');
But now I want to add some parameters to the flash messages and I have no idea how to handle it. I tried a lot, but nothing is working. I want to show in the flash messages the title of projects after f.e. removing. For example:
$this->addFlash('success', sprintf('flashmessage.project_deleted: %s', $project->getTitle()));
But the translation is not recognized, because the parameter is replaces before translation happens (I think so). And it should also be possible to have parameters in the middle of a string and not only at the end or at the beginning and ideally more than one parameter.
I'm using this in my Controller which extends AbstractController.
Does anybody has a solution for this?
Usually you would pass in the parameters to the translation, so your code snippet should probably look your first example and then in twig you would have something like this:
{% for message in app.flashes('success') %}
<div class="alert alert-success">
{{ message|trans({ 'title': project.title }) }}
</div>
{% endfor %}
The translation then should contain the parameter that is replaced:
flashmessage:
project_created: 'The project "%title%" was created successfully.'
project_deleted: 'You successfully deleted the project "%title%".'
...
Obviously the downside is that you have to dynamically pass in the variables which does not make much sense for flash messages, as not all of them will require these parameters. Also, as you already mentioned, when you deleted the project you will probably not have it available anymore in the template.
Instead I would recommend translating the message before passing it into the flash bag:
$this->addFlash(
'success',
$this->translator->translate(
'flashmessage.project_deleted',
[
'title' => $project->getTitle(),
]
)
);
This will require that you pass in the translator to your controller. You could either create your own base controller similar to Symfony's AbstractController for this and create something like a $this->trans()-method to make it easier to translate things inside your controller. Also, you will still have to make sure that $project->getTitle() will still return a value, so you probably want to call this before you actually delete the entry or have the data in memory.
When you do it this way, then you should not translate the flash messages in the template itself because they are already translated. This will still work because when Symfony tries to translate the already translated message, e.g. You successfully deleted the project "foo". then it will not find a translation and just print the original text instead, but you will get warnings in your logs about missing translations. The solution is to remove the |trans in your template (see first snippet).
A possible solution is to add another flash with serialized parameters.
Then, when you display your flash message, check if that extra flash exists and, if so, deserialize it and use it as argument.
Example follows.
In controller:
$this->addFlash('success', 'flashmessage.project_deleted');
$this->addFlash('_params', serialize(['%project%' => $project->getTitle()]));
In template:
{% flashMessage = app.session.flashbag.get('info') %}
{% if app.session.flashbag.has('_params') %}
{% set flashParams = app.session.flashbag.get('_params')|first|unserialize %}
{{ flashMessage|trans(flashParams) }}
{% else %}
{{ flashMessage|trans }}
{% endif %}
You need to create a Twig extension that defines an unserialize filter (or use a library that provides it)
Since Symfony 5.2 you can use the TranslatableMessage object to achieve this.
https://symfony.com/doc/current/translation.html#translatable-objects
use Symfony\Component\Translation\TranslatableMessage;
$this->addFlash(
'success',
new TranslatableMessage(
'flashmessage.project_deleted',
['%project%' => $project->getTitle()]
)
);
Then in your Twig template you only need to use {{ flashMessage|trans }}.
This works without injecting the Translator service, or messing about with anything in Twig.
Have a look at the ICU Message Format: https://symfony.com/doc/current/translation/message_format.html
I have seen the twig documentation about do tag, but I don't understand its use/useful.
The docs says the follow:
The do tag works exactly like the regular variable expression ({{ ...
}}) just that it doesn't print anything:
and show an example:
{% do 1 + 2 %}
What to solve exactly this tag ?
Good question! I found a link on GitHub to when this was proposed which might add some further info:
Sometimes you want to do things, or call some stuff, and ignore the output. For example if you use a |shift filter to remove some data from an array, doing {{ arr|shift }} will output the removed item, which is not always desirable.
Of course it's possible to do {% set null = arr|shift %}, which won't
output anything, but it also looks weird.
The example in the docs is poor as it explains nothing at all, as you pointed out.
Are there any ways for pluralizing a string in Symfony 3? For example: I have "Object" and I would like to get "Objects".
pluralization is a very complex topic and Symfony embraces it as part if the Translation Component:
Message pluralization is a tough topic as the rules can be quite complex.
So you basically would need to activate translations for your system and translate the needed strings using the transChoice() method of the translator service or the 'transchoice' tag / filter in your twig template.
To handle this, use the transChoice() method or the transchoice tag/filter in your template.
using the translator service
// the %count% placeholder is assigned to the second argument...
$translator->transChoice(
'There is one apple|There are %count% apples',
10
);
// ...but you can define more placeholders if needed
$translator->transChoice(
'Hurry up %name%! There is one apple left.|There are %count% apples left.',
10,
// no need to include %count% here; Symfony does that for you
array('%name%' => $user->getName())
);
twig tags
{% trans %}Hello %name%{% endtrans %}
{% transchoice count %}
{0} There are no apples|{1} There is one apple|]1,Inf[ There are %count% apples
{% endtranschoice %}
UPDATE
If you do not know the string beforehand you can use the internal Inflector Component, but be aware of the disclaimer and the fact that this would only work for strings in English:
This component is currently marked as internal. Do not use it in your own code. Breaking changes may be introduced in the next minor version of Symfony, or the component itself might even be removed completely.
An alternative would be to create your own inflector class, e.g. something like this and create a service from it.
Im trying to modify records from my wep page using bolt, for lets say an comment section. If someone posts an answer underneath an news item how do i put that info into an record. And if they want to edit their reaction how would I update it.
So i was trying something at this point with the status. My base status is always published.
{{ record.status == draft }} <-- tried this way
{% set record.status == record.status = draft %} <-- tried SET
{% set record.status == record.status = "draft" %} <-- tried adding ""
After my try and error period I went to all the documentation on bolt and twig. But I cant seem to find out how to do this.
So I hope someone knows how to do this, thank you in advance.
short anwser is - you can't modify database records directly from twig.
Twig it's template system (idea is to show data with it) .
To dwhat you want you need to write all this "stuff" by yourself . It can be done (best way is to learn about creating custom modules - but you need to be quite good with OOPHP , symfony components etc. )
I use the Symfony2.1 and have the default config.yml
Documentation said:
{# but static strings are never escaped #}
{{ '<h3>foo</h3>'|trans }}
But if I copy and paste it into the my empty template (without any additional autoescapes or another) I got the escaped string <h3>foo</h3>. What I do wrong?
Try it with the twig raw filter:
{{ '<h3>foo</h3>' | trans | raw }}
However, do not use the raw filter if you are processing any user input! It allows for cross-site-scripting attacks, according to the creators of Symfony. See this similar question for a secure but more tedious alternative.
Holding HTML stuff in translations is wrong, because translators usually break it. But if you really need it:
{% trans %}<h3>foo</h3>{% endtrans %}
https://github.com/symfony/symfony/issues/2713#issuecomment-12510417