четверг, 17 февраля 2011 г.

Как подружить шаблоны Django в кодировке utf-8 c BOM байтами?

При работе с Django шаблонами периодически сталкиваюсь с проблемой, когда в браузере появляются "пробелы"(белые зоны) в дизайне. Первое рассмотрение проблемы, используя FireBug, заводит в тупик. Свёрстанный макет отображается нормально, а вот та же страница, собранная из нескольких файловых шаблонов в Django имеет при отображении "пробелы". Анализ результирующих html страниц показал, что на "бракованной" странице появляется череда байтов "EF BB BF".

Небольшое отступление... Череда байтов "EF BB BF", именуемая меткой порядка байтов (byte order mark, BOM), применяется для обозначения формата UTF-8, хотя к этому формату и неприменимо понятие порядка байтов.
Поиск решений
Поискав решение проблемы наткнулся на пару топиков:
- Template adds extra characters when using utf8 file encoding.

"The first bytes of your header.html file are EF BB BF. That's the UTF-8 encoding of the BOM...It proposes noting, stripping, and relocating the BOM to the front of the ultimately rendered template."

- Django Templates and BOM (byte order marks).

"If I will render page.html output will contain TWO byte order marks:
!UTF_8_BOM!!UTF8_BOM!<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN" ... "

- weird problem with django templates.

"...when templates are being rendered (i guess), in code, right before the doctype, strange character is being placed. I call it "strange" because if I select it, copy it and try to paste nothing is pasted. This "dot" is seen only if I do "view source" in webkit browsers..."

Все решения сводятся к одному - сохраняйте файлы шаблонов в формате UTF-8 без BOM! :) А что делать, если редактор не позволяет сохранять файлы в кодировке UTF-8 без BOM?

Тут есть несколько решений:
1. Запустить скрипт, который удалит все BOM символы в шаблонах.
2. Использовать обработку шаблонов при загрузке.

Например, в качестве IDE я использую Eclipse и кодировку UTF-8 для файлов. Ну и вот этот "паршивец" считает своим долгом поместить в каждый файл шаблона BOM байты (поиск решение по отключению этого эффекта не дал результата). А каждый раз запускать скрипт не удобно, так что выбираем второе решение.

Обработка шаблонов для удаления BOM символов при загрузке
Смотрим какие загрузчики нужно поправить (settings.py):
TEMPLATE_LOADERS = (    'django.template.loaders.filesystem.load_template_source',    'django.template.loaders.app_directories.load_template_source',
)
Писать наследников "лень", так что используем monkey patching. Пишем небольшую корректирующую функцию :), помещаем ее и инициализацию в файл urls.py.

def patch_load_template_source(func):
    def decorator(self, template_name, template_dirs=None):
        item = func(self, template_name, template_dirs)
        //для сравнения, по хорошему, bom байты нужно переводить в ту же кодировку, что и кодировка загруженного файла. опустил этот момент.
        if item[0][:1]==u'\ufeff':
            return (item[0][1:], item[1])
        return item
    return decorator

//патчим filesystem.Loader
from django.template.loaders import filesystem
filesystem.Loader.load_template_source = patch_load_template_source(filesystem.Loader.load_template_source)

//патчим app_directories.Loader
from django.template.loaders import app_directories
app_directories.Loader.load_template_source = patch_load_template_source(app_directories.Loader.load_template_source)
ЗЫ: Данный пример не претендует на звание идеального, а лишь демонстрирует рабочую версию одного из решений :).

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

Отправить комментарий