2011-04-04 1 views
6

Uso UTF-8 nel mio editor, quindi tutte le stringhe visualizzate qui sono UTF-8 nel file.Errore UTF-8 con Python e gettext

Ho uno script python come questo:

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

Poi ho usato xgettext per ottenere tutto e ottenuto un file pot che può essere riassunta in:

"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 "" 

Dopo di che, msginit ho usato per ottenere un de.po, che ho riempito in questo modo:

"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\"" 

Esecuzione del script, ottengo il seguente errore:

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) 

Come posso risolvere il problema?

+0

Qual è il tipo di '_ (" utilizzo:% prog che attacca la difesa ")'? cioè cosa significa 'print type (_ (" usage:% prog attacking difending "))' stampa? – Mikel

risposta

6

Tale errore significa che hai chiamato la codifica su un bytestring, quindi cerca di decodificare in Unicode utilizzando la codifica di default del sistema (ascii su Python 2), poi ri-codificarlo con qualsiasi cosa ho specifi ed.

In genere, il modo per risolverlo è chiamare s.decode('utf-8') (o qualsiasi altra codifica in cui si trovano le stringhe) prima di provare a utilizzare le stringhe. Potrebbe anche funzionare se si utilizzano letterali unicode: u'automates...' (che dipende da come le stringhe vengono sostituite dai file .po, di cui non sono a conoscenza).

Questo tipo di comportamento di confusione è stato migliorato in Python 3, che non tenterà di convertire i byte in unicode a meno che non lo si specifichi esplicitamente.

+0

il 'u" letterale "' non funziona, ma 'decode (" utf-8 ")' funziona. Non molto bello, ma funziona. –

4

Il mio sospetto è che il problema sia causato da _("string") che restituisce una stringa di byte e non una stringa Unicode.

La soluzione ovvia è questa:

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

Ma che si sente male.

ugettext o install(True) può aiutare.

Il Python gettext docs dare questi esempi:

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

o:

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

Sto provando a riprodurre il problema, e anche se uso install(unicode=1), torno una stringa di byte (Tipo str).

O sto usando errext in modo errato, o mi manca una dichiarazione di codifica dei caratteri nel mio file .po/.mo.

Aggiornerò quando ne saprò di più.

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') 

(Un altra possibilità è quella di utilizzare fughe o punti di codice Unicode nel file .po, ma che non suona come divertimento.)

(Oppure si poteva guardare .po file del proprio sistema a vedere come gestiscono i caratteri non ASCII)