Использование символов utf-8 в шаблоне Jinja2
Я пытаюсь использовать символы utf-8 при рендеринге шаблона с помощью Jinja2. Вот как выглядит мой шаблон:
<!DOCTYPE HTML>
<html manifest="" lang="en-US">
<head>
<meta charset="UTF-8">
<title>{{title}}</title>
...
Переменная title задана примерно так:
index_variables = {'title':''}
index_variables['title'] = myvar.encode("utf8")
template = env.get_template('index.html')
index_file = open(preview_root + "/" + "index.html", "w")
index_file.write(
template.render(index_variables)
)
index_file.close()
Теперь проблема заключается в том, что myvar - это сообщение, прочитанное из очереди сообщений, и может содержать эти специальные символы utf8 (например, Séptimo Cine).
Представленный шаблон выглядит примерно так:
...
<title>S\u00e9ptimo Cine</title>
...
и я хочу, чтобы это было:
...
<title>Séptimo Cine</title>
...
Я сделал несколько тестов, но я не могу заставить это работать.
-
Я попытался установить переменную title без .encode( "utf8" ), но она выдает исключение (ValueError: ожидается объект байтов, а не объект unicode), поэтому я предполагаю, что начальное сообщение является unicode
-
Я использовал chardet.detect, чтобы получить кодировку сообщения (это "ascii" ), а затем выполнил следующее: myvar.decode( "ascii" ). encode ( "cp852" ), но заголовок все еще не отображается правильно.
-
Я также убедился, что мой шаблон является файлом UTF-8, но это не повлияло.
Любые идеи о том, как это сделать?
Ответы
Ответ 1
TL; ДР:
- Пропустить Unicode до
template.render()
- Кодировать результат рендеринга unicode к байтовой строке перед записью в файл
Это немного озадачило меня. Потому что вы делаете
index_file.write(
template.render(index_variables)
)
в одном утверждении, что в основном только одна строка, в которой находится Python, так что трассировка, которую вы получаете, вводит в заблуждение: исключение, которое я получил, когда воссоздание тестового примера не произошло в template.render(index_variables)
, а в index_file.write()
. Итак, разделив код таким образом
output = template.render(index_variables)
index_file.write(output)
был первым шагом для диагностики того, где именно происходит UnicodeEncodeError
.
Jinja возвращает unicode, чтобы вы могли визуализировать шаблон. Поэтому вам нужно закодировать результат до байта, прежде чем вы сможете записать его в файл:
index_file.write(output.encode('utf-8'))
Вторая ошибка заключается в том, что вы передаете utf-8
закодированную bytestring на template.render()
- Jinja хочет unicode. Итак, если ваш myvar
содержит UTF-8, вам нужно сначала его декодировать в Юникод:
index_variables['title'] = myvar.decode('utf-8')
Итак, чтобы все вместе, это работает для меня:
# -*- coding: utf-8 -*-
from jinja2 import Environment, PackageLoader
env = Environment(loader=PackageLoader('myproject', 'templates'))
# Make sure we start with an utf-8 encoded bytestring
myvar = 'Séptimo Cine'
index_variables = {'title':''}
# Decode the UTF-8 string to get unicode
index_variables['title'] = myvar.decode('utf-8')
template = env.get_template('index.html')
with open("index_file.html", "w") as index_file:
output = template.render(index_variables)
# jinja returns unicode - so `output` needs to be encoded to a bytestring
# before writing it to a file
index_file.write(output.encode('utf-8'))
Ответ 2
Попробуйте изменить команду визуализации на это...
template.render(index_variables).encode( "utf-8" )
Документация Jinja2 говорит: "Это вернет обработанный шаблон в виде строки в Юникоде".
http://jinja.pocoo.org/docs/api/?highlight=render#jinja2.Template.render
Надеюсь, это поможет!
Ответ 3
И если ничего не работает, потому что у вас есть сочетание языков, как в моем случае, просто замените "utf-8" на "utf-16"
Все параметры кодировки здесь:
https://docs.python.org/2.4/lib/standard-encodings.html
Ответ 4
Добавьте следующие строки в начало вашего script, и он будет работать нормально без каких-либо дальнейших изменений:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding("utf-8")