Procedure to create a multilingual webapp2 application with pybabel and Jinja2 and deploy it to GAE.
--webapp2: Python web app framework. - https://webapp2.readthedocs.io/en/latest/
--Jinja2: Python template engine. - http://jinja.pocoo.org/docs/2.9/ --pybabel (Babel): A tool for managing the locale-specific catalog of translated parts. It's confusing, but it's not the JS compiler Babel. - http://babel.pocoo.org/en/latest/cmdline.html
Eventually it will be like this.
$ tree
.
├── app.yaml
├── appengine_config.py
├── appengine_config.pyc
├── babel.cfg
├── lib
│ ├── Babel-2.3.4.dist-info
│ ├── babel
│ ├── pytz
│ └── pytz-2016.10.dist-info
├── locale
│ ├── ja_JP
│ │ └── LC_MESSAGES
│ │ ├── messages.mo
│ │ └── messages.po
│ └── message.pot
├── main.py
├── main.pyc
├── requirements.txt
└── templates
└── index.html
33 directories, 1395 files
I created a repository for reference.
$ mkdir webapp2-example && cd webapp2-example
Install the Babel library used by the webapp2 i18n extension in your project
requirements.txt
Babel==2.3.4
$ pip install -t lib -r requirements.txt
Collecting Babel==2.3.4 (from -r requirements.txt (line 1))
Using cached Babel-2.3.4-py2.py3-none-any.whl
Collecting pytz>=0a (from Babel==2.3.4->-r requirements.txt (line 1))
Using cached pytz-2016.10-py2.py3-none-any.whl
Installing collected packages: pytz, Babel
Successfully installed Babel-2.3.4 pytz-2016.10
appengine_config.py
from google.appengine.ext import vendor
vendor.add('lib')
app.yaml
application: webapp2-example
version: 1
runtime: python27
api_version: 1
threadsafe: yes
handlers:
- url: .*
script: main.app
libraries:
- name: webapp2
version: "2.5.2"
- name: jinja2
version: latest
It doesn't matter how you get the locale, but here we will read it from the request parameters.
main.py
import webapp2
from webapp2_extras import i18n
import os
import jinja2
JINJA_ENVIRONMENT = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.i18n', 'jinja2.ext.autoescape'],
autoescape=True)
JINJA_ENVIRONMENT.install_gettext_translations(i18n)
class HelloWorldHandler(webapp2.RequestHandler):
def get(self):
locale = self.request.GET.get('locale', 'en_US')
i18n.get_i18n().set_locale(locale)
print(locale)
template_values = {}
template = JINJA_ENVIRONMENT.get_template('templates/index.html')
self.response.write(template.render(template_values))
app = webapp2.WSGIApplication([
('/', HelloWorldHandler),
], debug=True)
def main():
app.run()
if __name__ == '__main__':
main()
$ mkdir templates
Let's write a case that uses a placeholder.
_
is an alias for gettext
, so you can use either one.
templates/index.html
<html>
<body>
{{ _("Hello, %(username)s", username='satzz') }}
</body>
</html>
It has not been multilingualized yet, but at this stage we will check the operation on the GAE development server.
Start development server
$ dev_appserver.py .
INFO 2017-03-17 06:07:29,597 sdk_update_checker.py:229] Checking for updates to the SDK.
INFO 2017-03-17 06:07:30,185 api_server.py:204] Starting API server at: http://localhost:63035
INFO 2017-03-17 06:07:30,189 dispatcher.py:197] Starting module "default" running at: http://localhost:8080
INFO 2017-03-17 06:07:30,192 admin_server.py:118] Starting admin server at: http://localhost:8000
Browser access to http: // localhost: 8080 where module is running
Although it deviates a little from i18n, check the operation with GAE.
Create a project with the same name as written in ʻapp.yaml`.
Application creation
Open the installed Google App Engine Launcher and specify the locally created application. Application ID is empty and ok
Confirm addition (2nd line)
Deploy with Cmd + D and wait for Deployment successful
to appear in the log.
You can check the operation with.
From here i18n of the main subject. Install the pybabel command to create a catalog.
$ pip install babel
Collecting babel
Using cached Babel-2.3.4-py2.py3-none-any.whl
Requirement already satisfied: pytz>=0a in /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python (from babel)
Installing collected packages: babel
Successfully installed babel-2.3.4
Set multilingual target etc.
babel.cfg
[jinja2: templates/**.html]
encoding = utf-8
$ mkdir locale
The flow of catalog creation
Will be.
Create a POT based on the Jinja2 template.
$ pybabel extract -F ./babel.cfg -o ./locale/message.pot .
extracting messages from templates/index.html (encoding="utf-8")
writing PO template file to ./locale/message.pot
When you open the POT, it automatically lists the msgid and where it is used. This POT is a template so you don't have to mess with it.
locale/message.pot
#: templates/index.html:3
#, python-format
msgid "Hello, %(username)s"
msgstr ""
Create a locale PO based on the POT. (Pybabel update
if PO has been created)
$ pybabel init -l ja_JP -d ./locale -i ./locale/message.pot
creating catalog ./locale/ja_JP/LC_MESSAGES/messages.po based on ./locale/message.pot
Edit the PO file created here. When using a placeholder, it looks like this.
locale/ja_JP/LC_MESSAGES/messages.po
msgid "Hello, %(username)s"
msgstr "%(username)s's, Hello"
Compile. The created MO file will be a binary file.
$ pybabel compile -f -d ./locale
compiling catalog ./locale/ja_JP/LC_MESSAGES/messages.po to ./locale/ja_JP/LC_MESSAGES/messages.mo
Add a locale to the request parameter and try accessing it.
If you deploy it again, you can see the behavior on GAE.
After this, repeat the following to grow the catalog.
--Translation and msgid are updated-> POT update with pybabel extract
--POT updated-> PO update with pybabel update
--Add locale-> Create PO with pybabel init
--Created / updated by PO-> Create / update MO with pybabel compile