FlaskでのUnicode Unicode in Flask

Jinja2やWerkzeugと同様に、Flaskはテキストについては完全にUnicodeをベースにしています。Jinja2やWerkzeugのライブラリだけでなく、テキストを処理するweb関連のPythonライブラリの大部分でも同様です。今までUnicodeを知らなかった場合は、多分全てのソフトウェア開発者が絶対、前向きに知っておく必要があるUnicodeとCharacter Setsについての最小限(The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets)を読むべきでしょう。このドキュメントでは、Unicode関連のことに関する体験を喜ばしいものにするために、本当に基本を扱うだけにします。 Flask, like Jinja2 and Werkzeug, is totally Unicode based when it comes to text. Not only these libraries, also the majority of web related Python libraries that deal with text. If you don't know Unicode so far, you should probably read `The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets <https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/>`_. This part of the documentation just tries to cover the very basics so that you have a pleasant experience with Unicode related things.

自動変換 Automatic Conversion

Flaskはあなたのアプリケーションに関して(以下のような)いくつかの前提(もちろん変更することができます)を持っていて、それは基本的で苦痛のないUnicodeサポートを与えます: Flask has a few assumptions about your application (which you can change of course) that give you basic and painless Unicode support:

  • webサイトのテキスト用のエンコーディングはUTF-8 the encoding for text on your website is UTF-8

  • 内部的には、ASCII文字ポイントだけ(訳注: ASCII文字だけと同じ意味合いであり、Unicodeでは文字に対してコードポイントと呼んでいる番号を割り当てているため、「character point」という表現を使っていると思います)を使用するリテラル文字列以外のテキストは、全て常にUnicodeを使用 internally you will always use Unicode exclusively for text except for literal strings with only ASCII character points.

  • バイトが通信されることを要求するプロトコルを通してやりとりするときは、常にエンコーディングとデコーディングが発生 encoding and decoding happens whenever you are talking over a protocol that requires bytes to be transmitted.

それでは、これは何を意味するのでしょうか? So what does this mean to you?

HTTPはバイトを土台にしています。プロトコルだけでなく、サーバ上のドキュメントの場所を示すために使われる仕組み(URIまたはURLと呼ばれるもの)も同様です。しかしながら、HTTP上で普通は通信されるHTMLは、多様な文字セットに対応し、どの文字セットが使用されているかはHTTPヘッダで通信されます。これを複雑にしすぎないために、もしUnicodeを送出する場合はUTF-8にエンコードすることを望んでいるのだと(訳注: Unicodeデータ自体は文字に対応するコードポイントのデータであり特定のエンコーディングを使ったバイト列のデータではないため、HTTPで送信するときには特定のエンコーディングでバイト列のデータに変換する必要があります)、Flaskはただ仮定します。Flaskはエンコーディングと、適切なヘッダーの設定をあなたのために行います。 HTTP is based on bytes. Not only the protocol, also the system used to address documents on servers (so called URIs or URLs). However HTML which is usually transmitted on top of HTTP supports a large variety of character sets and which ones are used, are transmitted in an HTTP header. To not make this too complex Flask just assumes that if you are sending Unicode out you want it to be UTF-8 encoded. Flask will do the encoding and setting of the appropriate headers for you.

SQLAlchemyまたは似たようなORMの仕組みを利用してデータベースとやり取りする場合にも、同じことがあてはまります。ある種のデータベースは既にUnicodeを通信するプロトコルを持っており、もし持っていない場合は、SQLAlchemyまたはあなたの別のORMがUnicode処理の世話をする必要があります。 The same is true if you are talking to databases with the help of SQLAlchemy or a similar ORM system. Some databases have a protocol that already transmits Unicode and if they do not, SQLAlchemy or your other ORM should take care of that.

黄金律(The Golden Rule) The Golden Rule

それでは大まかなルールです: もしもバイナリデータを扱っていない場合は、Unicodeを使います。Python 2.xでUnicodeを使った処理とはどのようなものでしょうか? So the rule of thumb: if you are not dealing with binary data, work with Unicode. What does working with Unicode in Python 2.x mean?

  • ASCIIコードポイント(基本的な数字や、ラテン文字のいくつかの特殊文字のうちウムラートおよび装飾的なものをなにも含まないもの)だけを使っている限り、通常の文字列リテラル('Hello World')を使用できます。 as long as you are using ASCII code points only (basically numbers, some special characters of Latin letters without umlauts or anything fancy) you can use regular string literals (``'Hello World'``).

  • もしも文字列の中で何であれASCII以外のものが必要な場合、(u'Hänsel und Gretel'のように)先頭に小文字のuを使ってその文字列がUnicode文字列だと目印をつける必要があります。 if you need anything else than ASCII in a string you have to mark this string as Unicode string by prefixing it with a lowercase `u`. (like ``u'Hänsel und Gretel'``)

  • もし自分のPythonファイルの中でUnicodeではない文字(訳注: ここでは「u'...'」のように最初に「u」がついてない文字のことだと思います)を使用している場合、そのファイルがどのエンコーディングを使っているかをPythonに教える必要があります。繰り返しますが、この目的(訳注: ファイルのエンコーディングのことだと思います)にはUTF-8を推奨します。インタプリタにエンコーディングを教えるには、Pythonのソースファイルの1行目もしくは2行目に# -*- coding: utf-8 -*-を置くことができます。 if you are using non-Unicode characters in your Python files you have to tell Python which encoding your file uses. Again, I recommend UTF-8 for this purpose. To tell the interpreter your encoding you can put the ``# -*- coding: utf-8 -*-`` into the first or second line of your Python source file.

  • JinjaはテンプレートファイルをUTF-8からデコードするように構成されています。そのため、自分のエディタも確実にUTF-8でファイルを保存するようにしてください。 Jinja is configured to decode the template files from UTF-8. So make sure to tell your editor to save the file as UTF-8 there as well.

自分で行うエンコーディングとデコーディング Encoding and Decoding Yourself

もしもUnicodeを実際にはベースにしていないファイルシステムや何かしらとやり取りする場合、Unicodeのインタフェースを使って作業するときは確実に自分で適切なデコードをする必要があるでしょう。従って例えば、もしもファイルシステム上のファイルを読み込みJinja2のテンプレートに埋め込みたい場合、そのファイルのエンコーディングからファイルをデコードする必要があるでしょう。ここで、テキストファイルは自分のエンコーディングを指定しない(訳注: テキストファイル自身は自分のエンコーディングが何かを定義するメタ情報を持たないということ)という、古くからある問題が出てきます。ですから、自分のためになるように、テキストファイルもUTF-8だけを使うように自分で制限すると良いでしょう(訳注: ファイルによってエンコーディングが違うと不便なのでUTF-8に統一した方が良いということ)。 If you are talking with a filesystem or something that is not really based on Unicode you will have to ensure that you decode properly when working with Unicode interface. So for example if you want to load a file on the filesystem and embed it into a Jinja2 template you will have to decode it from the encoding of that file. Here the old problem that text files do not specify their encoding comes into play. So do yourself a favour and limit yourself to UTF-8 for text files as well.

いずれにしろ、Unicodeを使ってそのようなファイルを読み込むには、組み込みのstr.decode()メソッドを使用できます: Anyways. To load such a file with Unicode you can use the built-in :meth:`str.decode` method::

def read_file(filename, charset='utf-8'):
    with open(filename, 'r') as f:
        return f.read().decode(charset)

UnicodeからUTF-8のような特定の文字セットにするにはunicode.encode()メソッドを使用できます: To go from Unicode into a specific charset such as UTF-8 you can use the :meth:`unicode.encode` method::

def write_file(filename, contents, charset='utf-8'):
    with open(filename, 'w') as f:
        f.write(contents.encode(charset))

エディタの設定 Configuring Editors

殆どのエディタは最近では既定値としてUTF-8で保存しますが、自分のエディタがそうするように設定されていない場合、自分で変える必要があります。自分のエディタでUTF-8として保存するための、いくつかのありがちなやり方は以下の通りです: Most editors save as UTF-8 by default nowadays but in case your editor is not configured to do this you have to change it. Here some common ways to set your editor to store as UTF-8:

  • Vim: set enc=utf-8を自分の.vimrcに置きます。 Vim: put ``set enc=utf-8`` to your ``.vimrc`` file.

  • Emacs: encoding cookieを使うか、自分の.emacsファイルに以下を置きます: Emacs: either use an encoding cookie or put this into your ``.emacs`` file::

    (prefer-coding-system 'utf-8)
    (setq default-buffer-file-coding-system 'utf-8)
    
  • Notepad++:

    1. Settings -> Preferences ...に進みます Go to *Settings -> Preferences ...*

    2. 「New Document/Default Directory」タブを選びます Select the "New Document/Default Directory" tab

    3. 「UTF-8 without BOM」をエンコーディングに選びます Select "UTF-8 without BOM" as encoding

    Unixの改行形式を使用することも推奨されていて、同じパネルから選択できますが、それは必須ではありません。 It is also recommended to use the Unix newline format, you can select it in the same panel but this is not a requirement.