Ошибка UTF-8 с Python и gettext - PullRequest
6 голосов
/ 05 апреля 2011

Я использую UTF-8 в своем редакторе, поэтому все отображаемые здесь строки - это UTF-8 в файле.

У меня есть такой скрипт на python:

# -*- coding: utf-8 -*-
...
parser = optparse.OptionParser(
  description=_('automates the dice rolling in the classic game "risk"'), 
  usage=_("usage: %prog attacking defending"))

Затем я использовал xgettext, чтобы получить все, и получил файл .pot, который можно свести к:

"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#: auto_dice.py:16
msgid "automates the dice rolling in the classic game \"risk\""
msgstr ""

После этого я использовал msginit, чтобы получить de.po, который я заполнил следующим образом:

"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: auto_dice.py:16
msgid "automates the dice rolling in the classic game \"risk\""
msgstr "automatisiert das Würfeln bei \"Risiko\""

Запустив скрипт, я получаю следующую ошибку:

  File "/usr/lib/python2.6/optparse.py", line 1664, in print_help
    file.write(self.format_help().encode(encoding, "replace"))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 60: ordinal not in range(128)

Как я могу это исправить?

Ответы [ 3 ]

7 голосов
/ 05 апреля 2011

Эта ошибка означает, что вы вызвали кодирование для строки байтов, поэтому она пытается декодировать ее в Unicode, используя системную кодировку по умолчанию (ascii на Python 2), а затем перекодировать ее с тем, что вы указали.

Как правило, способ ее решения состоит в том, чтобы вызвать s.decode('utf-8') (или любую другую кодировку строк), прежде чем пытаться использовать строки. Это также может работать, если вы просто используете литералы Unicode: u'automates...' (это зависит от того, как строки подставляются из файлов .po, о которых я не знаю).

Этот тип сбивающего с толку поведения улучшен в Python 3, который не будет пытаться конвертировать байты в юникод, если вы не указали это специально.

5 голосов
/ 05 апреля 2011

Я подозреваю, что проблема вызвана тем, что _("string") возвращает строку байтов, а не строку Unicode.

Очевидный обходной путь:

parser = optparse.OptionParser(
        description=_('automates the dice rolling in the classic game "risk"').decode('utf-8'),
        usage=_("usage: %prog attacking defending").decode('utf-8'))

Но это неправильно.

ugettext или install (True) может помочь.

Документы gettext Python дают следующие примеры:

import gettext
t = gettext.translation('spam', '/usr/share/locale')
_ = t.ugettext

или

import gettext
gettext.install('myapplication', '/usr/share/locale', unicode=1)

Я пытаюсь воспроизвести вашу проблему, и даже если я использую install(unicode=1), я получаю строку байтов (тип str).

Либо я неправильно использую gettext, либо в моем файле .po / .mo отсутствует объявление кодировки символов.

Я обновлюсь, когда узнаю больше.

xlt = _('automates the dice rolling in the classic game "risk"')
print type(xlt)
if isinstance(xlt, str):
    print 'gettext returned a str (wrong)'
    print xlt
    print xlt.decode('utf-8').encode('utf-8')
elif isinstance(xlt, unicode):
    print 'gettext returned a unicode (right)'
    print xlt.encode('utf-8')

(Еще одна возможность - использовать escape-коды или кодовые точки Unicode в .po-файле, но это не похоже на забаву.)

(Или вы можете посмотреть .po файлы вашей системы, чтобы увидеть, как они обрабатывают не-ASCII символы.)

3 голосов
/ 05 апреля 2011

Я не знаком с этим, но, похоже, это известная ошибка в 2.6, которая была исправлена ​​в 2.7:

http://bugs.python.org/issue2931

Если вы не можете использовать 2.7, попробуйте этот обходной путь:

http://mail.python.org/pipermail/python-dev/2006-May/065458.html

...