typo3typo3-8.xtypo3-extensionstypo3-8.7.x

TYPO3 8.7 multiple arguments in locallang translations


I recently found that one can pass arguments to translations either in fluid

<f:translate key="something.test" arguments="{0: 'something'}" />

or in PHP

\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('something.test', $extKey, $arguments);

And with the latter I realized that I do not understand how exactly this works and I couldn't find the documentation for these arguments. And I got stuck trying to pass multiple arguments.

The translation with the argument looks something like the following:

<trans-unit id="something.test">
    <source>this is the argument: %1$s</source>
</trans-unit>

What I do not understand is why has the placeholder the following format: %1$s? Does the number "1" have to do anything with the index of the arguments? If yes, why does it start with 1 if I pass the argument with key 0?

I understood that it's possible to pass multiple arguments by passing an array, but I don't know how to put correct placeholders at the corresponding places.

What I want to do is the following:

Controller:

$arguments = array('something1', 'something2', 'something3');
\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('something.test', $extKey, $arguments);

locallang.xlf:

<trans-unit id="something.test">
    <source>Test: [placeholder for something1]  [placeholder for something2] [placeholder for something3]</source>
</trans-unit>

Could someone explain to me how this works? Thanks beforehand :-)


Solution

  • What you see in your format string (%1$s) is what's called argument swapping (see examples 1-4 for a thorough understanding).

    You'd use it if the order of your placeholders is different from the order of the arguments. An example:

    You have the string

    $str = "%s had a %s %s";
    

    and the array

    $args = [
      'Mary',
      'little',
      'lamb',
    ];
    

    And your formatting result would be "Mary had a little lamb". But what would happen if the arguments were in a different order, like this:

    $args = [
      'lamb',
      'Mary',
      'little',
    ];
    

    Then you would get "lamb had a Mary little". By using argument swapping (confusing name, I know), you tell the formatter where exactly to look for a given argument. These placeholders are configured position-wise not index-wise, so they start from 1, not from 0.

    So to get the correct output for the above mentioned, unordered arguments, you would need the format string to be:

    $str = "%2$s had a %3$s %1$s";
    

    Note that argument swapping makes sense if, and only if you can guarantee that the order of the arguments in your array will always be the same. Also, if you can't control the order of the arguments (but can guarantee it will be the same), you would most likely need to use it, too.

    As noted by Bernd Wilke πφ, argument swapping is very helpful when dealing with localization, such as in your case.

    Different languages have different linguistic typologies, that is, where e.g. subject, verb and object are placed in a sentence or even how a date is written.

    The standard English date format is, for example, month-day-year. In Germany, it is formatted as day.month.year and the Japanese format it as year-month-date. Now, when you get your argument array from wherever, containing the values for year, month and day, in this order

    $arguments = [
      "2019",
      "03",
      "20",
    ];
    

    you would not get around using argument swapping to place the elements in the correct order.

    In English, your format string would be %2$s-%3$s-%1$s, for German %3$.%2$.%1$ and for Japanese either %1$s-%2$s-%3$s or even %s-%s-%s (as coincidentally, the arguments are already in the correct order, but to avoid confusion and stay consistent, you should use the positional formatting as with the other languages).

    When you can control the argument order, it is usually easier to use a non-positional formatstring, but as explained above, this does not work well for localization, if at all.