[Python-ideas] Fix the DRY problem (was Re: PEP 501 - i18n with marked strings)

Eric V. Smith eric at trueblade.com
Thu Aug 13 15:40:43 CEST 2015


On 08/13/2015 08:23 AM, MRAB wrote:
> On 2015-08-13 12:58, Eric V. Smith wrote:
>> On 08/13/2015 12:37 AM, Guido van Rossum wrote:
>>> On Wed, Aug 12, 2015 at 6:06 PM, Barry Warsaw <barry at python.org
>>> <mailto:barry at python.org>> wrote:
>>
>>>
>>>         placeholders = source_string.extract_placeholders()
>>>         substitutions = scope(*placeholders)
>>>         translated_string = i18n.lookup(source_string)
>>>         return translated_string.safe_substitute(substitutions)
>>>
>>>     That would actually be quite useful.
>>>
>>>
>>> Agreed. But whereas you are quite happy having only simple variable
>>> names in i18n templates, the feature required for the non-i18n use case
>>> really needs arbitrary expressions. If we marry the two, your i18n code
>>> will just have to yell at the programmer if they use something too
>>> complex for the translators as a substitution. So possibly PEP 501 can
>>> be rescued. But I think we need separate prefixes for the PEP 498 and
>>> PEP 501 use cases; perhaps f'{...}' and _'{...}'. (But it would not be
>>> up to the compiler to limit the substitution syntax in _'{...}')
>>
>> For the sake of the following argument, let's agree to disagree on:
>> - arbitrary expressions: we'll say yes
>> - string prefix character: we'll say 'f'
>> - how to identify expressions in a string: we'll say {...}
>>
>> I promise we can bikeshed about these later. I'm just using the PEP 498
>> version because I'm more familiar with it.
>>
>> And let's say that PEP 498 will take this:
>>
>> name = 'Eric'
>> dog_name = 'Fluffy'
>> f"My name is {name}, my dog's name is {dog_name}"
>>
>> And convert it to this (inspired by Victor):
>>
>> "My name is {0}, my dog's name is {1}".format('Eric', 'Fluffy')
>> Resulting in:
>> "My name is Eric, my dog's name is Fluffy"
>>
>> It seems to me that all you need for i18n is to instead make it produce:
>>
>> __i18n__("My name is {0}, my dog's name is {1}").format('Eric', 'Fluffy')
>>
>> The __i18n__ function would do whatever lookup is needed to produce the
>> translated string. So, in some English dialect where pet names had to
>> come first, it could return:
>> 'The owner of the dog {1} is named {0}'
>>
>> So the result would be:
>> 'The owner of the dog Fluffy is named Eric'
>>
> I think that looking up only the translation string and then inserting
> the values isn't good enough.
> 
> For example, what if the string was "Found {0} matches"?
> 
> If the number of matches was 1, you'd get "Found 1 matches".
> 
> Ideally, you'd want to pass the values too, so that the lookup could
> pick the correct translation.

That's certainly doable. You could pass in the values as a tuple, and
either have __i18n__ call .format itself, or still just return the
translated string and then call .format on the result.

def __i18n__(message, values):
    return message

But I'm not sure how much of this to build in to the f-string machinery.
gettext.gettext doesn't solve this problem by itself, either.

Eric.



More information about the Python-ideas mailing list