translationstring icon indicating copy to clipboard operation
translationstring copied to clipboard

Appending TranslationStrings to each other

Open rightaway opened this issue 11 years ago • 6 comments

I programmatically build up TranslationStrings based on what the content of the message should be. (A common pattern when building up for example an error message based on several conditions to be displayed somewhere like a flash message in Pyramid.) Something like

message = _('phrase1', mapping={....})
if a:
    message += _('phrase2 $b')
else:
    message += _('phrase3 $b')
if b:
    message += _('phrase4', mapping={....})
return message  # Be able to apply a mapping to the appended TranslationString, to map $b above

This doesn't work when I pass it to Pyramid code for translation because by the time I've appended the TranslationStrings to each other it's already a string before it reaches Pyramid. If TranslationStrings are appended to each other it would be good if they would be retained as some kind of compound TranslationString where running the translate function on it would allow each of the sub-TranslationStrings to translate themselves from the .mo files. And to be able to apply a mapping to the compound TranslationString (the last line above) or to each TranslationString that makes it up.

The only alternatives I see to this solution are messy. Either I return several message parts to Pyramid, like return (message1, message2, message3, message4, ...). Or each condition above has the full message, like below, which would lead to repetitive code and also duplication of effort by translators.

if a:
    message = _('phrase1 phrase2 phrase4')

rightaway avatar Jan 13 '15 10:01 rightaway

Why not leave off the _() bits in the middle, and just apply it at the end, e.g.:

    message = 'phrase1'
    mapping = {'b': 'Bar'}

    if a:
        message += 'phrase2 $b')
    else:
        message += 'phrase3 $b')

    if b:
        message += 'phrase4'

    return _(message, mapping=mapping)

tseaver avatar Jan 13 '15 14:01 tseaver

I tried it this way but then it prevents the .pot file generators (like lingua's pot-create) from including the strings in the created file.

rightaway avatar Jan 13 '15 15:01 rightaway

In my experience, making any assumptions about the structure of a sentence or phrase across languages is incorrect. Each phrase, in its entirety, needs to be translated independently, thus this type of concatenation should be avoided and you should just interpolate the $b independently for each phrase.

mmerickel avatar Jan 13 '15 16:01 mmerickel

Each phrase should be translated independently. But without concatenation, the only way to pass the TranslationString somewhere (e.g. template or flash message) would be to translate the components of the message individually, concatenate the resulting strings, then pass the result on. Like this:

ts1 = _('message1')
string1 = request.localizer.translate(ts1)
ts2 = _('message2')
string2 = request.localizer.translate(ts2)
ts3 = _('message3')
string3 = request.localizer.translate(ts3)
result = string1 + string2 + string3

But if your templates or flash messages can automatically translate a TranslationString (which is quite easy to set up in Pyramid), it would be much cleaner to do (where TranslationString's + operator is overloaded) the following, and allow a BeforeRender event or flash message function to take care of the conversion.

ts1 = _('message1')
ts2 = _('message2')
ts3 = _('message3')
result = ts1 + ts2 + ts3

After all, if you were returning a 'regular' TranslationString instead of a compound one, you would likely just do this:

ts1 = _('message1')
result = ts1

Having some sort of compound TranslationString would allow application Pyramid views to not worry about translating strings themselves, and treat 'regular' and compound TranslationStrings the same way.

Because the way I handle this now is return either 1 TranslationString, or a list of TranslationStrings. In my BeforeRender event or flash message producer, I test for whether it's been passed an instance of TranslationString or list, and have to handle those 2 cases separately to result in a single translated string. It would be nice to treat them all the same way.

rightaway avatar Jan 13 '15 18:01 rightaway

I see. I agree it would be nice if they could be appended in the way you're describing.

mmerickel avatar Jan 13 '15 18:01 mmerickel

This could perhaps be an alternative to https://github.com/Pylons/translationstring/issues/10 about nested translations, for when a TranslationString's mapping contains another TranslationString. Where instead of nesting them you could append them.

rightaway avatar Jan 13 '15 20:01 rightaway