symfony / symfony-docs

The Symfony documentation
https://symfony.com/doc
Other
2.16k stars 5.11k forks source link

Documentation is confusing about use of {placeholders} in translations #19593

Open php4fan opened 7 months ago

php4fan commented 7 months ago

I was looking at the documentation about translations here: https://symfony.com/doc/5.x/translation.html#basic-translation

and I was looking for the part about parameters, or should I say placeholders. What I mean with parameters/placeholders is when you have a phrase somephrase whose translation is "Hello {username} and you call:

$translator->trans('somephrase', ['username' => 'John']) ;

ane the result is "Hello John".

I think those are called Placeholders.

So, the only place where the page above says something about that is here: https://symfony.com/doc/5.x/translation.html#message-format

To manage these situations, Symfony follows the ICU MessageFormat syntax by using PHP's MessageFormatter class. Read more about this in How to Translate Messages using the ICU MessageFormat.

So, I follow that link and it says:

In order to use the ICU Message Format, the message domain has to be suffixed with +intl-icu:

and then it explains, among other things, how placeholders work, besides pluralization and other stuff.

This seems to be very clear: in order to use placeholders, as well as pluralization and other features, the message domains has to be suffixed with +intl-icu

However, I have tried using basic translations with placeholders with the default domain messages without any suffix, and placeholders work. I don't know about pluralization and other stuff.

So, the documentation wrongly suggests that, in order to be able to use placeholders, you need to suffix the domain names with that string, but that's not true.

I don't know if that's true for other features such as pluralization; if that's the case, then it's not clear.

php4fan commented 7 months ago

It seems to be even worse than that.

Apparently, this:

$translator->trans('somephrase', ['username' => 'John']) ;

will not replace occurrences of the string "{username}" but rather of the string "username".

That is, the second argument passed to Translator::trans() is just an array of arbitrary replacements where the keys can be any strings, not necessarily wrapped in {}.

This isn't mentioned in the documentation, nor does it explain how this interferes with messages that do use the ICU format.

94noni commented 6 months ago

I think there is/may be typo indeed here https://symfony.com/doc/current/reference/formats/message_format.html#message-placeholders Should be {name} as key parameter to match translation message containing placeholder At least that how i use it on my projects Perhaps the translator handle under the hood the addition of { } if not provided but can be misleading if so

php4fan commented 6 months ago

I think there is/may be typo indeed here

I'm not sure. Could it be that:

In fact I'm pretty sure the second half is true (the source code seems to be using strstr, and I tested it) but I haven't checked the first half.

At least that how i use it on my projects

Do you use the ICU format?

94noni commented 6 months ago

I use icu in some of them, mostly with twig; after i upgraded from older logic I will double check tomorrow (on computer) on how my file are named and how i use trans methods Perhaps i myself am confused with this prefix and how i call in the code

94noni commented 6 months ago

I've checked and I use things like the doc

# emails+intl-icu.fr.yaml
proposition_accepted_user.subject: "{company_name} - foo bar n°{number}"
{{ 'proposition_accepted_user.subject'|trans({
    'company_name': 'from.name'|trans({}, locale = locale),
    'number': number
}, locale = locale) }}

so to me I only use the "full" ICU logic now, I was confusing probably with old maner

wkania commented 1 month ago

Yes, the built-in non-standard Symfony way for translations is not documented.

For the not ICU MessageFormat filenames, you can use Twig like placeholders:

# translations/messages.en.yaml
say_hello: Hello %name%. Symfony is %what%!
// prints "Hello Fabien. Symfony is awesome!"
echo $translator->trans('say_hello', ['%name%' => 'Fabien', '%what%' => 'awesome'])

The Translator engine will replace everything so this would work also:

# translations/messages.en.yaml
say_hello: Hello name. Symfony is {what}!
// prints "Hello Fabien. Symfony is awesome!"
echo $translator->trans('say_hello', ['name' => 'Fabien', '{what}' => 'awesome'])

The same about pluralization which was documented in the Symfony 1. Currently, it's still in the code and tests, but not documented or deprecated. Turns a string with “|” separators into an array and selects the appropriate translation based on the location and %count% value. The selection is based on the position (0-5) in the table or the value in {}. The |whatever: fragment is ignored and is descriptive.

# translations/messages.en.yaml
num_of_apples: 'There is one apple|There are %count% apples'
# the same as the above
# num_of_apples: 'one: There is one apple|more: There are %count% apples'
# The condition with 0
# num_of_apples: '{0} There are no apples|one: There is one apple|other: There are %count% apples'
// prints "There is one apple"
echo $translator->trans('num_of_apples', ['%count%' => 1])

The var must be named %count%.

There is only a note about ranges, but they still work.

ICU MessageFormat is standardized and covers more cases like genders. Only ranges are missing.

@javiereguiluz The Translator documentation is based on normal file name examples, so why this is not documented?