×Закрыть

Разработка на Python: i18n

Пояснение. Изначально я собирался описывать конкретные особенности TurboGears, но понял что текст получается большой и достаточно общий и решил разбить его на две части. В этой части пойдет речь о Python вообще, а в следующей — о TurboGears в частности.

Итак, о создании «интернационализированных» (уф!) приложений на Python.

Основные компоненты этой системы:

  • поддержка национальных (местных) особенностей: сортировка с учетом национального алфавита, представление дат и чисел и прочее, модуль locale;
  • локализация приложений: перевод сообщений на разные языки, модуль gettext;
  • поддержка различных форматов кодирования текста: фактически сводится к поддержке стандарта Unicode, различных кодировок (Latin-1, UTF-8, WIN1251) и преобразований текста из одной кодировки в другую.
Подробнее остановлюсь на поддержке Unicode, как о наименее очевидной функции. Пример:
>>> ut = 'тест'.decode('cp1251')
>>> print repr(ut)
u'u0442u0435u0441u0442'
>>> print repr(ut.encode('utf-8'))
'xd1x82xd0xb5xd1x81xd1x82'
Пояснение: я использовал cp1251 т.к. эта кодировка, которую использует IDLE на платформе Windows.

Главная особенность Python в отличии от, скажем, Java: различие между обычными строками (str) и юникодными (unicode). При выводе юникодные строки можно отличить по букве u перед строкой, а программно — при помощи функций isinstance() или type().

Кому-то такое разделение нравится, кому-то нет, но про него всегда следует помнить, в противном случае вы рискуете получить UnicodeEncodeError в самом неожиданном месте:

>>> str(ut)
Traceback (most recent call last):
...
UnicodeEncodeError: 'ascii' codec can't encode characters ...
>>> print type(ut), type(ut.encode('cp866'))
Эта ошибка произошла из-за того, что функция str пытается преобразовать юникодную строку в обычную, но используя неподходящую кодировку (ascii). И ошибку такую получить достаточно легко, благо str() или __str__() вызывается часто неявно, e.g.: print.

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

Правило простое и практически на 100% надежное. «Практически» — потому что некоторые библиотеки (в т.ч. из stdlib) могут некорректно обрабатывать юникодные строки, так что при использовании внешних библиотек следует быть внимательным. К счастью, такое встречается все реже а, скажем, некоторые DB-API драйверы (psycopg) уже научились принимать и отдавать юникодные строки.

Да, для ASCII-текста можно использовать юникодные строки, а можно продолжать пользоваться обычными: т.к. неявные преобразования используют кодировку ’ascii’ вы гарантированно не получите UnicodeEncodeError. Еще одно отступление: в принципе, можно заставить Python использовать другую кодировку вместо ascii при помощи site.setencoding() или sitecustomize но я так не делаю и не советую.

Есть и библиотечные модули, ориентированные на работу с юникодным текстом. Например, модуль codecs позволяет легко огранизовать чтение/запись файлов:

>>> for line in codecs.open(fname, 'r', 'utf-8'):
...    assert isinstance(line, unicode)
>>>
LinkedIn

Нет комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

Подписаться на комментарии