Mémo de travail que j'ai essayé i18n avec l'application Flask

** Remarque: ** Ceci est juste une note. Veuillez me pardonner même si je n'ai aucune information utile.


introduction

J'écris une application Flask comme passe-temps, mais j'aimerais la rendre utile au travail si possible. Cependant, le problème vient du japonais. L'anglais est préférable pour publier sur GitHub ou GitLab, mais la triste réalité est que si vous essayez de l'utiliser au travail, vous ne pouvez pas l'utiliser en anglais.

Donc i18n. peut être. i18n est une abréviation pour Internationalisation (?) Comme vous le savez. Au fait, j'ai aimé le système Hyper Nikki, mais le domaine du site officiel h14m.org vient de là, non? (Déraillement) Pour le moment, j'ai toujours été intéressé par la façon de faire i18n, j'ai donc profité de l'occasion pour l'essayer, c'est le contenu de cet article.

Préparation

Cet article est essentiellement basé sur [ce site (anglais)] [lien-1] et [ce site (japonais, Qiita)] [lien-3]. Il semble qu'il soit courant (ou puis-je dire?) D'utiliser [Babel] link-2 pour faire des choses i18n avec Flask of Python. Quand vous pensez à Babel, les gens qui utilisent Emacs et ceux qui utilisent JS peuvent penser à autre chose (déraillement). Ou plutôt, je n'ai pas pu écrire Babel sur l'étiquette car cela semble déroutant ... !!

Tout d'abord, installez Babel lui-même.

% pip3 install --user Babel flask_babel

C'était comme ça.

Essayez d'abord à quoi il ressemble

[Ce site (japonais, Qiita)] Essayez de cloner le dépôt github de link-3 et de l'exécuter. Tout d'abord, parlez à telnet sans penser à rien.

% 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.

C'était un ingurishu. Bonjour. L'ordre est inversé, mais il semble que le changement de langue puisse être effectué en envoyant Accept-Language dans l'en-tête de la requête http. Donc, cette fois, j'ai demandé à chacun de revenir dans son japonais préféré.

% 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 fermé par un hôte étranger.

Comme prévu, il a répondu en japonais. Je vois, c'est comme ça que ça marche. Il semble que Accept-Language puisse également être passé sous forme de liste pondérée.

Essayez de mettre Babel dans votre application Flask

Maintenant, faisons le premier pas vers le support i18n. La description suivante a été ajoutée à l'application Flask. [Site de référence (en anglais)] Dans link-1, il est écrit en __init __. Py, mais lequel est le meilleur?

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())

Ensuite, j'ai préparé les fichiers suivants.

config.py


# -*- coding: utf-8 -*-
#
# available languages
LANGUAGES = {
    'en': 'English',
    'ja': 'Japonais'
}

Il semble que l'utilisation du décorateur localeelector comme celui-ci permette de réagir à Accept-Language. Et encore une chose, il semble que le fichier de paramétrage de Babel lui-même soit également nécessaire, je l'ai donc créé comme suit. Les première et deuxième lignes sont les fichiers à traduire, et la troisième ligne semble activer l'extension de Babel. Je n'ai pas examiné les détails de l'extension.

babel.cfg


[python: **.py]
[jinja2: **/templates/**.tpl.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_

Traduisez en fait

Touchez le modèle

Tout d'abord, jouons avec le modèle. Dans ce cas, _ () semble être un alias pour gettext (), donc j'ai modifié l'endroit où il devient "Nom" en anglais comme suit.

show_person.tpl.html


      <tr>
        <td>{{ _('Name') }}</td>
        <td>{{ person.name }}</td>
      </tr>

Touchez le code Python (2017-06-17 ajouté)

Lors de la traduction d'un message à flasher, j'ai dû jouer avec le code côté Python, mais j'ai pu l'implémenter comme suit.

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'))

Dans ce qui précède, gettext est importé en tant que _ afin de s'aligner avec le côté du modèle. Si vous souhaitez saisir des chiffres, etc.

hoge.py


        flash(_("No Such Item with ID %(item_id)d", item_id=item_id), 'error')

Il semble bon de le faire comme.

Créer un fichier de traduction

Ensuite, j'ai exécuté la commande suivante.

% pybabel extract -F babel.cfg -o message.pot hoge

Cela semble créer un fichier modèle. En regardant le contenu du message de sortie.

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 ""

C'était comme ça. Il semble qu'il y ait "Nom" à la place de msgid, qui a été utilisé pour gettext plus tôt. De plus, il semble créer un fichier de traduction basé sur ce fichier. Plus précisément, j'ai frappé la commande suivante.

% pybabel init -i message.pot -d hoge/translations -l ja
creating catalog hoge/translations/ja/LC_MESSAGES/messages.po based on message.pot

Le fichier po semblait être facile à faire en utilisant Poedit poedit introduit dans [Site de référence (anglais)] link-1. J'ai ouvert le message.po généré et entré "Nom" comme "Nom" comme indiqué ci-dessous.

poedit.png

En regardant le fichier édité, la date de mise à jour a été réécrite, et bien sûr msgstr a également été réécrit, et X-Generator a fait une affirmation de soi. À l'origine, il semble faire pybabel compile après cela, mais lors de l'utilisation de Poedit, il semble qu'il créera automatiquement un fichier mo qui sera compilé lors de son enregistrement (utilisez la version 1.8.11).

Dans cet état, lorsque l'application a été affichée sur le navigateur, "Nom" a été remplacé avec succès par "Nom". De plus, j'ai pu confirmer que "Nom" s'affiche à nouveau lorsque la priorité anglaise est augmentée dans les paramètres du navigateur.

Qu'en est-il des mises à jour ultérieures?

Lors de la mise à jour, il semble que le fichier po soit mis à jour par la procédure suivante.

pybabel extract -F babel.cfg -o message.pot hoge
pybabel update -i message.pot -d hoge/translations

Impressions

Quand il s'agit de phrases, cela semble assez difficile, mais j'ai l'impression que s'il s'agit de mots, c'est étonnamment facile à faire. Il semble difficile d'appuyer sur la commande lors de la mise à jour, mais y a-t-il un bon moyen?

Quoi qu'il en soit, il n'y a aucun problème à utiliser cela au travail ou à publier GitHub !! Eh bien, le plus gros problème est que cela n'a aucun sens à moins que le développement de l'application elle-même ne progresse !!

Les références

Recommended Posts

Mémo de travail que j'ai essayé i18n avec l'application Flask
J'ai essayé linebot avec flacon (anaconda) + heroku
[Python] Un mémo que j'ai essayé de démarrer avec asyncio
Une histoire qui n'a pas fonctionné lorsque j'ai essayé de me connecter avec le module de requêtes Python
Un mémo que j'ai écrit un tri rapide en Python
J'ai essayé d'intégrer Keras dans TFv1.1
J'ai essayé Flask avec des conteneurs distants de VS Code
Je veux faire la transition avec un bouton sur le ballon
Je veux travailler avec un robot en python.
Un mémo que j'ai touché au magasin de données avec python
Notez que j'ai traité du HTML dans Beautiful Soup
J'ai essayé de faire une application mémo qui peut être pomodoro, mais un enregistrement de réflexion
J'ai essayé fp-growth avec python
J'ai essayé de gratter avec Python
J'ai essayé Learning-to-Rank avec Elasticsearch!
J'ai essayé d'utiliser easydict (mémo).
J'ai essayé le clustering avec PyCaret
J'ai essayé gRPC avec Python
J'ai essayé de gratter avec du python
Mémo que je suis resté coincé dans l'introduction de Mezzanine
J'ai essayé "un programme qui supprime les déclarations en double en Python"
J'ai essayé de créer un article dans Wiki.js avec SQL Alchemy
J'ai essayé de décrire le trafic en temps réel avec WebSocket
J'ai essayé le mouvement Python3 qui change la direction dans le système de coordonnées
J'ai essayé de résumer des phrases avec summpy
[Mémo] Liens lors du développement avec Flask
J'ai essayé l'apprentissage automatique avec liblinear
J'ai essayé webScraping avec python.
Exécutez l'application avec Flask + Heroku
J'ai essayé de déplacer de la nourriture avec SinGAN
J'ai essayé de traiter l'image en "style croquis" avec OpenCV
J'ai essayé d'implémenter DeepPose avec PyTorch
J'ai essayé d'exécuter GAN dans Colaboratory
J'ai essayé la détection de visage avec MTCNN
Hello World avec Flask [Mémo approprié]
J'ai essayé de traiter l'image dans un "style de dessin au crayon" avec OpenCV
J'ai essayé un outil qui imite le modèle de Goch avec l'IA
J'ai essayé d'améliorer l'efficacité du travail quotidien avec Python
J'ai essayé d'exécuter prolog avec python 3.8.2.
J'ai essayé la notification de ligne en Python
J'ai essayé la communication SMTP avec Python
J'ai essayé la génération de phrases avec GPT-2
J'ai essayé de me connecter automatiquement à Twitter avec du sélénium (RPA, scraping)
J'ai essayé d'apprendre LightGBM avec Yellowbrick
J'ai essayé la reconnaissance faciale avec OpenCV
J'ai essayé de mettre en œuvre un apprentissage en profondeur qui n'est pas profond avec uniquement NumPy
J'ai essayé de mettre en œuvre une blockchain qui fonctionne réellement avec environ 170 lignes
J'ai essayé de développer un formateur qui génère des journaux Python en JSON
Je suis resté coincé dans la redirection d'une application flask avec un proxy inverse entre les deux
J'ai essayé d'implémenter PLSA en Python
Stockage de table Azure avec l'application PTVS Flask
J'ai essayé l'analyse de régression multiple avec régression polypoly
J'ai essayé d'envoyer un SMS avec Twilio
J'ai essayé d'utiliser Amazon SQS avec django-celery
J'ai essayé d'implémenter Autoencoder avec TensorFlow
J'ai essayé d'implémenter la permutation en Python
Déployer l'application flask avec mod_wsgi (à l'aide de pipenv)