[Python-ideas] Combine f-strings with i18n
Eric V. Smith
eric at trueblade.com
Mon Sep 17 14:10:52 EDT 2018
See also PEP 501, which could be used for i18n.
Eric
On 9/17/2018 1:42 PM, Stephen J. Turnbull wrote:
> Hans Polak writes:
> > On 17/09/18 09:53, Niki Spahiev wrote:
> > >
> > > Is it possible to use f-strings when making multilingual software?
> > > When i write non-hobby software translation is hard requirement.
> >
> > At this moment, it seems that this is not possible.
>
> No, it's not possible.
>
> > If a user has the navigator configured for English, I have to
> > return English (if I am doing i18n).
>
> This is understood. Nobody is telling you what you want is an
> unreasonable desire. I'm telling you that I'm pretty sure your
> proposed syntax isn't going to happen, because it requires deep
> changes in the way Python evaluates expressions as far as I can see.
>
> > That's why I would like to see a parameter that can be passed to
> > the f-string.
>
> This doesn't make sense to me. Such configurations are long-lasting.
> In this context, the POSIX model (where the target language, or
> priority list of languages, is configured in the environment) is
> reasonable. There's no good reason for passing the language every
> time a string is formatted throughout an interaction with such a user.
>
> What we want is a way to tell the f-string to translate itself, and
> optionally specify a language.
>
> > I don't think this should be too problematic, really.
>
> Your proposal to use method syntax is *definitely* problematic. The
> f-string is an expression, and must be evaluated to a str first
> according to the language definition.
>
> > The compiler can then rewrite these to normal unicode strings. For
> > instance: f'Hi {user}'.language('es') would become T(_('Hi {user}'),
> > 'es', user=user)
>
> It could, but it's not going to. Implementing that with a reasonable
> amount of backward compatibility requires two tokens of lookahead and
> a new keyword as far as I can see. The problem is that unless the
> .language method is invoked on the f-string in the same expression,
> the f-string needs to be converted to a string immediately, as it is
> in Python 3.6 and 3.7. To decide whether to do this in the case where
> there is a method invoked, the parser needs to read the f-string
> (lookahead = 0), the "." (lookahead = 1), and the token "language"
> (lookahead = 2), and then for the parser to know that this is the
> special construct, it needs to know the special token. "Keyword" in
> this context simply means "a token that the parser knows about", but
> in general in Python we want keywords to be reserved to the language,
> which is considered a very high cost.
>
> What could work is an extension to the formatting language. I suggest
> abusing the *conversion flag*. (It's an abuse because I'm going to
> apply it to the whole f-string, while the current Language Reference
> says it's applied to the value being formatted.[1]) This flag would only
> be allowed as the first item in the string. The idea is that
> `f"{lang!g}Hello, {user}!"` would be interpreted as
>
> _ = get_gettext(lang)
> _("Hello, {user}!").format(user=user)
>
> and `f"{!g}Hello, {user}!"` as `_("Hello, {user}!").format(user=user)`,
> reusing the the most recent value of `_`. The "g" in "!g" stands for
> "gettext", of course. GNU xgettext can be taught to recognize things
> like `f"{...!g}` as translatable string markers; I'm sure pygettext
> can too.
>
> I'm assuming the implementation of get_gettext from my earlier post,
> reproduced at the end for reader convenience.
>
> One warning about this syntax: I think the gettext module is a pretty
> popular way to implement message localization. However, I'm not sure
> it's the only way, and I would guess that folks who use something else
> would want to be able to use f-strings with that package, too. So
> there may need to be a way to configure the translation engine.
>
>> # Use duck-typing of gettext.translation objects
>> class NullTranslation:
>> def __init__(self):
>> self.gettext = lambda s: s
>>
>> def get_gettext(language, translation={'C': NullTranslation()}):
>> if language not in translation:
>> translation[language] = \
>> gettext.translation('myapplication', languages=[language])
>> return translation[language].gettext
>>
>> and
>>
>> # This could be one line, but I guess in many cases you're likely
>> # to use use the gettext function repeatedly. Also, use of the
>> # _() idiom marks translatable string for translators.
>> _ = get_gettext(language)
>> _(translatable_string).format(key=value...)
>
>
> Footnotes:
> [1] I'm not sure whether "the g conversion is applied to the 'lang'
> variable, and the effect is to set the global 'translate' function" is
> pure sophistry or not, but I don't find it convincing. YMMV
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
More information about the Python-ideas
mailing list