Mailing List Archive

GNU gettext: Print string translated and untranslated at the same time
X-Post: https://stackoverflow.com/q/76913082/4865723

I want to display one string in its original source (untranslated)
version and in its translated version site by site without duplicating
the string in the python source code?
It wouldn't be a big deal if it is only one word.

print('The translated string "{}" is originally
"{}".'.format(_('Hello'), 'Hello'))

But in my situation it is a multi line string containing multiple
paragraphs. It is a full text. I don't want to duplicate that string.

# Imagine 'Hello' as a 50x70 characters multi line string.
original = 'Hello'
translated = _('Hello')
print('The translated string "{}" is originally
"{}".'.format(translated, original))

I do use the "class based API" of GNU gettext. My current approach,
which is not working, is to somehow (how!?) disable (or mask) the
translation function "_()" temporarily.
But as described in the stackoverflow question (see first line of this
mail) this do not work.

def foobar(translate):
if not translate:
# I try to mask the global _() builtins-function
def _(txt):
return txt

return _('Hello')

if __name__ == '__main__':

# To ilustrate that _() is part of "builtins" namespace
print(_('No problem.'))

print('The translated string "{}" is originally "{}".'
.format(foobar(True), foobar(False)))

This is the output:

Traceback (most recent call last):
File "/home/user/ownCloud/_transfer/./z.py", line 27, in <module>
.format(foobar(True), foobar(False)))
File "/home/user/ownCloud/_transfer/./z.py", line 19, in foobar
return _('Hello')
UnboundLocalError: local variable '_' referenced before assignment

The full MWE can be found at stackoverflow
(https://stackoverflow.com/q/76913082/4865723).

The question is if this can be solved somehow or if there is an
alternative approach.
The "_()" function is installed in the builtins namespace because of
gettext class based API. This is nice.
Maybe I can somehow manipulate that builtins namespace? I tried to
import builtins and played around with it but couldn't find a way to do
it.

Thanks
Christian Buhtz

PS: This is IMHO not relevant for my question but if someone is
interested the connection to productive code can be found in this issue:
https://github.com/bit-team/backintime/issues/1473 There I describe what
I want to achive and also provide a GUI mockup.
--
https://mail.python.org/mailman/listinfo/python-list
Re: GNU gettext: Print string translated and untranslated at the same time [ In reply to ]
c.buhtz@posteo.jp wrote at 2023-8-17 07:10 +0000:
>I want to display one string in its original source (untranslated)
>version and in its translated version site by site without duplicating
>the string in the python source code?

Is it an option for you to replace the `gettext` binding
by `zope.i18nmessageid`? Its `Message` instances provide
access to all interesting attributes (id, default, mapping, domain).
Together with other packages (--> `zope.i18n` and `i18ndude`)
it is compatible with `GNU gettext` translation catalogs.

If this is not an option, use Python's inspection functionality
to learn which attributes are made available by the binding's
message class.
--
https://mail.python.org/mailman/listinfo/python-list
Re: GNU gettext: Print string translated and untranslated at the same time [ In reply to ]
Am 17.08.23 um 09:10 schrieb c.buhtz--- via Python-list:


>     UnboundLocalError: local variable '_' referenced before assignment

This is a common gotcha:

https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value

You could solve it by defining _() locally like so:


def foobar(translate):
_ = gettext.gettext
if not translate:
# I try to mask the global _() builtins-function
def _(txt):
return txt
return _('minutes')


> The question is if this can be solved somehow or if there is an alternative approach.

However, you might not need this, because the following seems to
work for me:

def orig_and_trans(msg):
return (_(msg), msg)

print('The translated string "{}" is originally
"{}".'.format(*orig_and_trans("hello")))

--
https://mail.python.org/mailman/listinfo/python-list
Re: GNU gettext: Print string translated and untranslated at the same time [ In reply to ]
> On Aug 17, 2023, at 10:02 AM, c.buhtz--- via Python-list <python-list@python.org> wrote:
>
> ?X-Post: https://stackoverflow.com/q/76913082/4865723
>
> I want to display one string in its original source (untranslated) version and in its translated version site by site without duplicating the string in the python source code?
> It wouldn't be a big deal if it is only one word.
>
> print('The translated string "{}" is originally "{}".'.format(_('Hello'), 'Hello'))
>
> But in my situation it is a multi line string containing multiple paragraphs. It is a full text. I don't want to duplicate that string.
>
> # Imagine 'Hello' as a 50x70 characters multi line string.
> original = 'Hello'
> translated = _('Hello')
> print('The translated string "{}" is originally "{}".'.format(translated, original))
>
> I do use the "class based API" of GNU gettext. My current approach, which is not working, is to somehow (how!?) disable (or mask) the translation function "_()" temporarily.
> But as described in the stackoverflow question (see first line of this mail) this do not work.
>
> def foobar(translate):
> if not translate:
> # I try to mask the global _() builtins-function
> def _(txt):
> return txt
>
> return _('Hello')
>
> if __name__ == '__main__':
>
> # To ilustrate that _() is part of "builtins" namespace
> print(_('No problem.'))
>
> print('The translated string "{}" is originally "{}".'
> .format(foobar(True), foobar(False)))
>
> This is the output:
>
> Traceback (most recent call last):
> File "/home/user/ownCloud/_transfer/./z.py", line 27, in <module>
> .format(foobar(True), foobar(False)))
> File "/home/user/ownCloud/_transfer/./z.py", line 19, in foobar
> return _('Hello')
> UnboundLocalError: local variable '_' referenced before assignment
>
> The full MWE can be found at stackoverflow (https://stackoverflow.com/q/76913082/4865723).
>
> The question is if this can be solved somehow or if there is an alternative approach.
> The "_()" function is installed in the builtins namespace because of gettext class based API. This is nice.
> Maybe I can somehow manipulate that builtins namespace? I tried to import builtins and played around with it but couldn't find a way to do it.
>
> Thanks
> Christian Buhtz
>
> PS: This is IMHO not relevant for my question but if someone is interested the connection to productive code can be found in this issue: https://github.com/bit-team/backintime/issues/1473 There I describe what I want to achive and also provide a GUI mockup.
> --
> https://mail.python.org/mailman/listinfo/python-list

One thing to remember is that the _() function, which calls gettext doesn’t need a literal string, so you can set a variable to ‘raw’ string, and then translate it to another variable, so you can have both.
--
https://mail.python.org/mailman/listinfo/python-list
Re: GNU gettext: Print string translated and untranslated at the same time [ In reply to ]
c.buhtz@posteo.jp wrote at 2023-8-17 07:10 +0000:
>I want to display one string in its original source (untranslated)
>version and in its translated version site by site without duplicating
>the string in the python source code?

You could try to translate into an unknown language: this
should give you the default translation.
--
https://mail.python.org/mailman/listinfo/python-list
Re: GNU gettext: Print string translated and untranslated at the same time [ In reply to ]
Hello Mirko,

thanks for reply.

Am 17.08.2023 18:19 schrieb Mirko via Python-list:
> You could solve it by defining _() locally like so:
>
> def foobar(translate):
> _ = gettext.gettext

I see no way to do that. It is not the "class based API" of gettext
installing _() into the builtins namespace.
My users are able to configure the language of their UI explicit. It is
a full application.

> def orig_and_trans(msg):
> return (_(msg), msg)

This will be ignored by GNU gettext utils (xgettext in my case) will
ignore this line because they do not know what "msg" is. The string
"hello" won't appear in the pot-file.
--
https://mail.python.org/mailman/listinfo/python-list
Re: GNU gettext: Print string translated and untranslated at the same time [ In reply to ]
Am 17.08.23 um 21:17 schrieb c.buhtz--- via Python-list:
> Hello Mirko,
>
> thanks for reply.
>
> Am 17.08.2023 18:19 schrieb Mirko via Python-list:
>> You could solve it by defining _() locally like so:
>>
>> def foobar(translate):
>>     _ = gettext.gettext
>
> I see no way to do that. It is not the "class based API" of gettext
> installing _() into the builtins namespace.


Does this work:

def foobar(translate):
_ = __builtins__._



> My users are able to configure the language of their UI explicit. It
> is a full application.
>
>> def orig_and_trans(msg):
>>     return (_(msg), msg)
>
> This will be ignored by GNU gettext utils (xgettext in my case) will
> ignore this line because they do not know what "msg" is. The string
> "hello" won't appear in the pot-file.


xgettext has an option "-k" which allows you to specify an
additional "keyword" (like a function name, I guess) for detecting
translatable strings. With the orig_and_trans() function, the
following command produces a messages.po with "hello" in it.

xgettext -korig_and_trans source.py
--
https://mail.python.org/mailman/listinfo/python-list
Re: GNU gettext: Print string translated and untranslated at the same time [ In reply to ]
On 17/08/23 7:10 pm, c.buhtz@posteo.jp wrote:
> def foobar(translate):
>     if not translate:
>         # I try to mask the global _() builtins-function
>         def _(txt):
>             return txt
>
>     return _('Hello')

This causes _ to become a local that is left undefined on one
branch of the if. You need to ensure it's always defined. Here's
one way that should work:

gttran = _

def foobar(translate):
def _(txt):
if translate:
return gttran(txt)
else:
return txt
return _('Hello')

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list
Re: GNU gettext: Print string translated and untranslated at the same time [ In reply to ]
> On 17 Aug 2023, at 15:01, c.buhtz--- via Python-list <python-list@python.org> wrote:
>
> I want to display one string in its original source (untranslated) version and in its translated version site by site without duplicating the string in the python source code?
> It wouldn't be a big deal if it is only one word.

The key to solving this to separate the parsing of the string into the .po file and its translation.

def i18n(s):
return s

msg = i18n(‘my message’)

print(_(msg))
print(msg)

Now you tell the xgettex, pygettext etc, to parse to use “i18n” to find strings to translate.

This is covered in the docs at https://docs.python.org/3/library/gettext.html#localizing-your-module

Barry





--
https://mail.python.org/mailman/listinfo/python-list