** Note: ** This is just a note. Please forgive me even if I don't have any useful information.
I'm writing a Flask app as a hobby, but I'd like to make use of it at work if possible. However, the problem is Japanese. English is better for publishing on GitHub or GitLab, but the sad reality is that if you try to use it at work, you can not use it in English.
So i18n. maybe. i18n is an abbreviation for Internationalization (?) As you know. By the way, I liked the Hyper Nikki System, but the official website domain h14m.org comes from there, right? (Derailment) For the time being, I've always been interested in how to do i18n, so I took this opportunity to try it, which is the content of this article.
This article is basically based on [this site (English)] link-1 and [this site (Japanese, Qiita)] link-3. It seems that it is common (or can I say?) To use [Babel] link-2 to do i18n things with Python Flask. When you think of babel, people who use Emacs and people who use JS may think of something else (derailment). Or rather, I couldn't write Babel on the tag because it seems to be confusing ... !!
First, install Babel itself.
% pip3 install --user Babel flask_babel
It was like that.
[This site (Japanese, Qiita)] Try cloning the github repository of link-3 and running it. First, try talking on telnet without thinking about anything.
% telnet localhost 5000
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 11
Server: Werkzeug/0.12.2 Python/3.6.1+
Date: Wed, 14 Jun 2017 11:10:09 GMT
Hello WORLDConnection closed by foreign host.
It was an ingurishu. Hello. The order is reversed, but it seems that language switching can be done by sending Accept-Language in the http request header. So, this time, I asked everyone to come back in their favorite Japanese.
% telnet localhost 5000
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
Accept-Language: ja
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 21
Server: Werkzeug/0.12.2 Python/3.6.1+
Date: Wed, 14 Jun 2017 11:14:39 GMT
Hello World Connection closed by foreign host.
As planned, he replied in Japanese. I see, this is how it works. It seems that Accept-Language can also be passed as a weighted list.
Now, let's take the first step toward i18n support.
The following description has been added to the Flask app.
[Reference site (English)] In link-1, it is written in __init__.py
, but which one is better?
app/hoge.py
app = Flask(__name__)
app.config.from_object(__name__)
from flask_babel import Babel
babel = Babel(app)
from config import LANGUAGES
@babel.localeselector
def get_locale():
return request.accept_languages.best_match(LANGUAGES.keys())
Next, I prepared the following files.
config.py
# -*- coding: utf-8 -*-
#
# available languages
LANGUAGES = {
'en': 'English',
'ja': 'Japanese'
}
Using the localeselector decorator like this seems to be able to react to Accept-Language. And one more thing, Babel itself seems to need a configuration file, so I created it as follows. The first and second lines are the files to be translated, and the third line seems to enable Babel extension. I haven't looked into the details of the extension.
babel.cfg
[python: **.py]
[jinja2: **/templates/**.tpl.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_
First, let's play with the template. In this case, _ ()
seems to be an alias for gettext ()
, so I modified the place where it becomes "Name" in English as follows.
show_person.tpl.html
<tr>
<td>{{ _('Name') }}</td>
<td>{{ person.name }}</td>
</tr>
When translating a message to be flashed, I had to mess with the code on the Python side, but I was able to implement it as follows.
hoge.py
from flask import flash
from flask_babel import gettext as _
@app.route('/logout')
def logout():
session.pop('logged_in', None)
flash(_("You were logged out"), 'success')
return redirect(url_for('show_hoge'))
In the above, gettext is imported as _ to align with the template side. If you want to enter numbers etc.
hoge.py
flash(_("No Such Item with ID %(item_id)d", item_id=item_id), 'error')
It seems good to do it as.
Next, I ran the following command.
% pybabel extract -F babel.cfg -o message.pot hoge
This seems to create a template file. Looking at the contents of the output message.pot
message.pot
# Translations template for PROJECT.
# Copyright (C) 2017 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2017.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2017-06-14 20:54+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.4.0\n"
#: hoge/templates/show_person.tpl.html:10
msgid "Name"
msgstr ""
It was like that. It seems that there is "Name" in the place of msgid. Furthermore, it seems to make a translation file based on this file. Specifically, I hit the following command.
% pybabel init -i message.pot -d hoge/translations -l ja
creating catalog hoge/translations/ja/LC_MESSAGES/messages.po based on message.pot
The po file seemed to be easy to do using Poedit poedit introduced in [Reference site (English)] link-1. I opened the generated message.po and entered "Name" as "Name" as shown below.
Looking at the edited file, the update date was rewritten, and of course msgstr was also rewritten, and X-Generator made a self-assertion.
Originally, it seems to do pybabel compile
after this, but Poedit seems to create a mo file that is automatically compiled when it is saved (version used, 1.8.11).
In this state, when the application was displayed on the browser, "Name" was successfully replaced with "Name". In addition, I was able to confirm that "Name" is displayed again when the English priority is raised in the browser settings.
When updating, it seems that the po file is updated by the following procedure.
pybabel extract -F babel.cfg -o message.pot hoge
pybabel update -i message.pot -d hoge/translations
When it comes to sentences, it seems to be quite difficult, but my impression is that if it's about words, it's surprisingly easy to make. It seems to be troublesome to hit the command when updating, but is there any good way?
Anyway, there is no problem with using it at work or publishing it on GitHub !! Well, the biggest problem is that it is meaningless unless the development of the application itself progresses !!
Recommended Posts