RU | EN

Разработка на 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) >>>

Источники:
developers.org.ua

Автор: Ищенко М.

Комментарии: