2016-11-21 64 views
6

我正在使用Django的國際化功能爲webapp生成翻譯字符串。調用Django i18n makemessages命令時出現UnicodeError錯誤

一個問題是情況下產生我嘗試打電話makemessages,和現有的語言.po文件包含特殊字符(如$£等)。

如果其中一個存在,makemessages會嘗試加載現有的.po文件並對其進行解碼。這樣做時,我得到一個錯誤:

Traceback (most recent call last): 
File "manage.py", line 18, in <module> 
    execute_from_command_line(sys.argv) 
File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 354, in execute_from_command_line 
    utility.execute() 
File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 346, in execute 
    self.fetch_command(subcommand).run_from_argv(self.argv) 
File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 394, in run_from_argv 
    self.execute(*args, **cmd_options) 
File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 445, in execute 
    output = self.handle(*args, **options) 
File "/usr/local/lib/python2.7/dist-packages/django/core/management/commands/makemessages.py", line 325, in handle 
    self.write_po_file(potfile, locale) 
File "/usr/local/lib/python2.7/dist-packages/django/core/management/commands/makemessages.py", line 458, in write_po_file 
    msgs, errors, status = gettext_popen_wrapper(args) 
File "/usr/local/lib/python2.7/dist-packages/django/core/management/commands/makemessages.py", line 51, in gettext_popen_wrapper 
    stdout = stdout.decode(stdout_encoding) 
File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode 
    return codecs.utf_8_decode(input, errors, True) 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa2' in position 2105: ordinal not in range(128) 

我試圖挖回來經過這裏的追蹤,但我在茫然,發生了什麼。

它好像Django的嘗試將現有.po文件解碼爲UTF8,但隨後重新編碼它的時候,它的使用ASCII編解碼器。

任何有關錯誤的見解都將受到大力讚賞。


編輯:

  • 操作系統:Ubuntu的15.10和OS X 10.11.6
  • 的Python:2.7.10和2.7.11
  • Django的:1.8.14
  • 六:1.10.0

我試過重新安裝按照建議,Django/Six,但錯誤仍然存​​在。

Ubuntu的localedef --list-archive

en_AG 
en_AG.utf8 
en_AU.utf8 
en_BW.utf8 
en_CA.utf8 
en_DK.utf8 
en_GB.utf8 
en_HK.utf8 
en_IE.utf8 
en_IN 
en_IN.utf8 
en_NG 
en_NG.utf8 
en_NZ.utf8 
en_PH.utf8 
en_SG.utf8 
en_US.utf8 
en_ZA.utf8 
en_ZM 
en_ZM.utf8 
en_ZW.utf8 

內容類型有問題的翻譯文件:

"Content-Type: text/plain; charset=UTF-8\n" 
+0

http://stackoverflow.com/questions/22106777/unicode-issue-with-makemessages-all-django-1-6-2-python-3-3 – trinchet

+0

試試這個:'LC_CTYPE = en_US.UTF-8 python manage.py makemessages';它工作嗎? –

+1

@ nobe4:當你用'LC_CTYPE = en_US.UTF-8 python manage.py makemessages'運行它時它有什麼區別嗎?而且,順便說一下,你的操作系統和版本是什麼? –

回答

3

注意,這是從this similar question在評論中提到一個不同的異常位置。

在我看來,這可能發生的唯一方法就是如果有去過你的Django修改安裝或有在Python 2.7版中的錯誤。

你的籌碼是:

> msgs, errors, status = gettext_popen_wrapper(args) 
> stdout = stdout.decode(stdout_encoding) 

gettext_popen_wrapper(?上的Django 1.8,這是我認爲你正在使用,您可以確認),並popen_wrapper它創建stdout(刪除註釋/文檔字符串後再次縮進爲清楚起見,請popen_wrappergettext_popen_wrapper在GitHub上的純粹的代碼):

def popen_wrapper(args, os_err_exc_type=CommandError, universal_newlines=True): 
    try: 
     p = Popen(args, shell=False, stdout=PIPE, stderr=PIPE, 
       close_fds=os.name != 'nt', universal_newlines=universal_newlines) 
    except OSError as e: 
     strerror = force_text(e.strerror, DEFAULT_LOCALE_ENCODING, 
           strings_only=True) 
     six.reraise(os_err_exc_type, os_err_exc_type('Error executing %s: %s' % 
        (args[0], strerror)), sys.exc_info()[2]) 
    # NB: subprocess.Popen.communicate() should return two bytes 
    # (i.e. str in python 2) objects 
    output, errors = p.communicate() 
    return (
     output, 
     force_text(errors, DEFAULT_LOCALE_ENCODING, strings_only=True), 
     p.returncode 
    ) 

def gettext_popen_wrapper(args, 
          os_err_exc_type=CommandError, 
          stdout_encoding="utf-8"): 
    manual_io_wrapper = six.PY3 and stdout_encoding != DEFAULT_LOCALE_ENCODING 

    stdout, stderr, status_code = popen_wrapper(
     args, os_err_exc_type=os_err_exc_type, 
     universal_newlines=not manual_io_wrapper) 

    if manual_io_wrapper: 
     stdout = io.TextIOWrapper(io.BytesIO(stdout), encoding=stdout_encoding).read() 
    if six.PY2: 
     # EXCEPTION HIT ON THE FOLLOWING LINE 
     stdout = stdout.decode(stdout_encoding) 
    return stdout, stderr, status_code 

所以stdout建議立即進行刪除d是一個普通的對象(即,一堆需要解碼的字節)到我們稱之爲stdout.decode()的時候。但是,如果是這種情況,那麼爲什麼在en編碼的例外?如果對象已經是一個unicode對象,即它是unicode類型,我們只需要進行編碼。果然,如果我們之前

stdout = stdout.decode(stdout_encoding) 

現在decode方法首先嚐試添加一行

stdout = stdout.decode('utf-8') 

然後encode unicode的stdout,使用default encoding of ascii,這會導致你見過例外。我還通過設置manual_io_wrapperTrue,這引起了stdout = io.TextWrapper(...)線以及(產生一個Unicode也一樣)發生了同樣的錯誤,但是這不應該是True,因爲你是在蟒蛇2不3

所以我認爲無論是:

  • 你已經有了一個壞安裝的djangosix,或者它被編輯。嘗試重新安裝它們。
  • 你已經打了一個錯誤的subprocess.Popen.communicate(),由於某種原因它返回一個unicode不是str(我相信在Python 3這是可能的,如果universal_newlines are turned on。您可以重新安裝Python或升級到更高版本獲得的里程。

我主要是,雖然我不認爲這是一個環境問題,這將是有趣的,知道任何跟進:

  • 你在
  • 什麼蟒蛇2.7什麼平臺你正在使用
  • 你正在使用什麼django。
+0

感謝您的回答,我會更新我的問題。 – nobe4

1

在以下行,不知何故,stdout不是字節str但其unicodeunicode的隱性編碼過程中你得到例外。

stdout = stdout.decode('utf-8') 

那是因爲那decode()應字節str進行,並且當我們試圖呼籲unicodedecode,在Python 2.7的事實,將會有以encodeunicodedecode之前隱式調用,這致電encode將使用默認charset這是在Python中ascii

unicode.encode() --> byte # results in str 
byte.decode() --> unicode # results in unicode 
unicode.decode() --> unicode.encode().decode() # implicit encode call 

於是,開始是什麼導致了標準輸出是unicode調查。

謝謝。

相關問題