ïŒ2018幎çïŒ
ãã²ã«ã»ã°ãªã³ããŒã°
ããã¯ãFlaskã®14çªç®ã®éšåã§ããk Mega-Tutorialã§ãMicrosoft翻蚳ãµãŒãã¹ãšããã€ãã®JavaScriptã䜿çšããŠããªã¢ã«ã¿ã€ã ã®ããã¹ã翻蚳æ©èœãè¿œå ããŸãã
ãã¿ãã¬ã®äžã«ã¯ããã®2018幎ã·ãªãŒãºã®ãã¹ãŠã®èšäºã®ãªã¹ãããããŸãã
- 第1ç« ïŒHello worldïŒ
- 第2ç« ïŒãã³ãã¬ãŒã
- 第3ç« ïŒWebãã©ãŒã
- 第4ç« ïŒããŒã¿ããŒã¹
- 第5ç« ïŒãŠãŒã¶ãŒãã°ã€ã³
- 第6ç« ïŒãããã£ãŒã«ããŒãžãšã¢ãã¿ãŒ
- 第7ç« ïŒãšã©ãŒåŠç
- 第8ç« ïŒãµãã¹ã¯ã©ã€ããŒãé£çµ¡å ãããã³ãã¬ã³ã
- 第9ç« ïŒããŒãžããŒã·ã§ã³
- 第10ç« ïŒã¡ãŒã«ãµããŒã
- 第11ç« ïŒåæ§æ
- 第12ç« ïŒæ¥ä»ãšæå»
- 第13ç« ïŒI18nããã³L10n
- 第14ç« ïŒAjax ïŒãã®èšäºïŒ
- 第15ç« ïŒã¢ããªã±ãŒã·ã§ã³æ§é ã®æ¹å
- 第16ç« ïŒå šææ€çŽ¢
- 第17ç« ïŒLinuxã®å±é
- 第18ç« ïŒHerokuã§ã®å±é
- 第19ç« ïŒDockerã³ã³ãããŒã§ã®å±é
- 第20ç« ïŒJavaScriptããžãã¯
- 第21ç« ïŒãŠãŒã¶ãŒéç¥
- 第22ç« ïŒããã¯ã°ã©ãŠã³ãã¿ã¹ã¯
- 第23ç« ïŒã¢ããªã±ãŒã·ã§ã³ããã°ã©ãã³ã°ã€ã³ã¿ãŒãã§ã€ã¹ïŒAPIïŒ
泚1ïŒãã®ã³ãŒã¹ã®å€ãããŒãžã§ã³ããæ¢ãã®å Žåã¯ããã¡ããã芧ãã ãã ã
泚2ïŒç§ïŒãã²ã«ïŒã®ä»äºãæ¯æããŠçªç¶å£°ãããããå ŽåããŸãã¯1é±éèšäºãåŸ ã€å¿èããªãå Žåãç§ïŒãã²ã«ã°ãªãŒã³ããŒã°ïŒã¯ãã®ã¬ã€ãã®å®å šçïŒè±èªïŒãé»åæžç±ãŸãã¯ãããªã®åœ¢åŒã§æäŸããŸãã 詳现ã«ã€ããŠã¯ã learn.miguelgrinberg.comãã芧ãã ãã ã
ãã®èšäºã§ã¯ããµãŒããŒåŽã®éçºã®ãã»ãŒããŸãŒã³ãã«ç§»åããåæ§ã«éèŠãªãµãŒããŒã³ã³ããŒãã³ããšã¯ã©ã€ã¢ã³ãã³ã³ããŒãã³ããæã€æ©èœã«åãçµã¿ãŸãã äžéšã®ãµã€ãã«ãŠãŒã¶ãŒãäœæããã³ã³ãã³ãã®æšªã«è¡šç€ºããã翻蚳ãªã³ã¯ãèŠãŸãããïŒ ãããã¯ããªã¢ã«ã¿ã€ã ã§ãŠãŒã¶ãŒã®æ¯åœèªãšã¯ç°ãªãã³ã³ãã³ãã®èªå翻蚳ãããªã¬ãŒãããªã³ã¯ã§ãã 翻蚳ãããã³ã³ãã³ãã¯éåžžãå ã®ããŒãžã§ã³ã®äžã«å ¥åãããŸãã Googleã¯å€åœèªã§æ€çŽ¢çµæã衚瀺ããŸãã Facebookã¯æçš¿ã®ããã«ãããè¡ããŸãã Twitterã¯ãã€ãŒãã®ããã«ãããè¡ããŸãã ä»æ¥ã¯ãåãæ©èœããã€ã¯ãããã°ã«è¿œå ããæ¹æ³ã玹ä»ããŸãïŒ
ãã®ç« ã®GitHubãªã³ã¯ïŒ Browse ã Zip ã Diff ã
ãµãŒããŒãšã¯ã©ã€ã¢ã³ãåŽ
ãããŸã§åŸã£ãŠããåŸæ¥ã®ãµãŒããŒã¢ãã«ã«ã¯ãã¢ããªã±ãŒã·ã§ã³ãµãŒããŒãžã®HTTPèŠæ±ãå®è¡ããã¯ã©ã€ã¢ã³ãïŒãŠãŒã¶ãŒãå¶åŸ¡ããWebãã©ãŠã¶ãŒïŒããããŸãã ãªã¯ãšã¹ãã¯ãããšãã°ã ãããã£ãŒã« ããªã³ã¯ãã¯ãªãã¯ãããšãã«HTMLããŒãžããªã¯ãšã¹ããããããããã£ãŒã«æ å ±ã®ç·šéåŸã«ãéä¿¡ããã¿ã³ãã¯ãªãã¯ãããšãã«ã¢ã¯ã·ã§ã³ãããªã¬ãŒãããã§ããŸãã ã©ã¡ãã®ã¿ã€ãã®ãªã¯ãšã¹ãã§ãããµãŒããŒã¯æ°ããWebããŒãžãçŽæ¥ãŸãã¯ãªãã€ã¬ã¯ãããŠã¯ã©ã€ã¢ã³ãã«éä¿¡ããããšã«ããããªã¯ãšã¹ããå®è¡ããŸãã 次ã«ãã¯ã©ã€ã¢ã³ãã¯çŸåšã®ããŒãžãæ°ããããŒãžã«çœ®ãæããŸãã ãŠãŒã¶ãŒãã¢ããªã±ãŒã·ã§ã³Webãµã€ãã«ãšã©ãŸã£ãŠããéããã®ãµã€ã¯ã«ãç¹°ãè¿ãããŸãã ãã®ã¢ãã«ã§ã¯ããµãŒããŒããã¹ãŠã®äœæ¥ãè¡ããã¯ã©ã€ã¢ã³ãã¯åçŽã«WebããŒãžã衚瀺ãããŠãŒã¶ãŒå ¥åãåãå ¥ããŸãã
ã¯ã©ã€ã¢ã³ããããç©æ¥µçãªåœ¹å²ãæããå¥ã®ã¢ãã«ããããŸãã ãã®ã¢ãã«ã§ã¯ãã¯ã©ã€ã¢ã³ãã¯ãµãŒããŒã«ãªã¯ãšã¹ããçºè¡ãããµãŒããŒã¯WebããŒãžã§å¿çããŸãããåã®ã±ãŒã¹ãšã¯ç°ãªããããŒãžããŒã¿ã®ãã¹ãŠãHTMLã§ãããšã¯éãããéåžžJavascriptã§èšè¿°ãããã³ãŒããå«ãããŒãžã®ã»ã¯ã·ã§ã³ããããŸãã ã¯ã©ã€ã¢ã³ãã¯ããŒãžãåä¿¡ãããšããã«ãHTMLãã©ã°ã¡ã³ãã衚瀺ããã³ãŒããå®è¡ããŸãã ããããã¯ããµãŒããŒãšéä¿¡ããã«ç¬ç«ããŠåäœã§ããã¢ã¯ãã£ããªã¯ã©ã€ã¢ã³ããã§ããŸããã å³å¯ãªã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ã§ã¯ãã¢ããªã±ãŒã·ã§ã³å šäœãéå§ããŒãžã®ãªã¯ãšã¹ããšãšãã«ã¯ã©ã€ã¢ã³ãã«ããŠã³ããŒãããããã®åŸã¢ããªã±ãŒã·ã§ã³ã¯ã¯ã©ã€ã¢ã³ãäžã§å®å šã«å®è¡ãããŸããããŒã¿ãåä¿¡ãŸãã¯ä¿åããæåã§å¯äžã®WebããŒãžã®ã¿ã®å€èŠ³ãåçã«å€æŽããããã«ãµãŒããŒã«æã ã¢ã¯ã»ã¹ããã ãã§ãã ãã®ã¿ã€ãã®ã¢ããªã±ãŒã·ã§ã³ã¯ã ã·ã³ã°ã«ããŒãžã¢ããªã±ãŒã·ã§ã³ãŸãã¯SPAãšåŒã°ããŸãã
ã»ãšãã©ã®ã¢ããªã±ãŒã·ã§ã³ã¯ã2ã€ã®ã¢ãã«ã®ãã€ããªããã§ãããäž¡æ¹ã®ãã¯ãããžãŒãçµã¿åãããŠããŸãã ç§ã®ãã€ã¯ãããã°ã¢ããªã±ãŒã·ã§ã³ã¯åºæ¬çã«ãµãŒããŒã¢ããªã±ãŒã·ã§ã³ã§ãããä»æ¥ã¯ã¯ã©ã€ã¢ã³ãåŽã®ã¢ã¯ã·ã§ã³ãããã€ãè¿œå ããŸãã ã¡ãã»ãŒãžããªã¢ã«ã¿ã€ã ã§ç¿»èš³ããããã«ãã¯ã©ã€ã¢ã³ããã©ãŠã¶ãŒã¯éåæãªã¯ãšã¹ãããµãŒããŒã«éä¿¡ããŸãããµãŒããŒã¯ããŒãžãæŽæ°ããã«ãµãŒããŒã«å¿çããŸãã ãã®åŸãã¯ã©ã€ã¢ã³ãã¯çŸåšã®ããŒãžã«åçã«ç¿»èš³ãæ¿å ¥ããŸãã ãã®ã¡ãœããã¯AjaxãšåŒã°ããéåæJavaScriptããã³XMLã®ç¥ã§ãïŒãã ããæè¿ã§ã¯XMLãJSONã«çœ®ãæããããããšããããããŸãïŒã
ãªã¢ã«ã¿ã€ã 翻蚳ã¯ãŒã¯ãããŒ
Flask-Babelã®ãããã§ããã®ã¢ããªã±ãŒã·ã§ã³ã¯å€åœèªãååã«ãµããŒãããŠããŸããFlask-Babel㯠ã翻蚳è ãèŠã€ããããéãå€ãã®èšèªããµããŒãããŸãã ãããããã¡ããã1ã€ã®èŠçŽ ãæ¬ èœããŠããŸãã ãŠãŒã¶ãŒã¯æ¯åœèªã§ããã°æçš¿ãäœæããŸãã ãããã£ãŠããŠãŒã¶ãŒãç¥ããªãèšèªã§æžãããæçš¿ã«ééããå¯èœæ§ããããŸãã èªå翻蚳ã®å質ã¯åžžã«åªããŠãããšã¯éããŸããããã»ãšãã©ã®å Žåãå¥ã®èšèªã®ããã¹ããäœãæå³ããã®ããåºæ¬çã«ç解ããŠããã°ååã§ãã
ããã¯ãAJAXãµãŒãã¹ãå®è£ ããçæ³çãªæ©äŒã§ãã ã€ã³ããã¯ã¹ããŒãžãŸãã¯æ¢çŽ¢ããŒãžã«ã¯è€æ°ã®æçš¿ã衚瀺ãããå Žåãããããã®ãã¡ã®ããã€ãã¯å€åœèªã§ããå ŽåããããŸãã åŸæ¥ã®ãµãŒããŒåŽã®æ¹æ³ã䜿çšããŠç¿»èš³ãå®è£ ãããšã翻蚳ãªã¯ãšã¹ãã«ããå ã®ããŒãžãæ°ããããŒãžã«çœ®ãæããããŸãã å®éã«ã¯ã衚瀺ãããŠããå€ãã®ããã°æçš¿ã®1ã€ã翻蚳ãããªã¯ãšã¹ãã¯ãããŒãžå šäœãæŽæ°ããã®ã«ååãªå€§ããã§ã¯ãªãããã翻蚳ãããããã¹ãããœãŒã¹ããã¹ãã®äžã«åçã«æ¿å ¥ãããããŒãžã®æ®ãã®éšåããã®ãŸãŸæ®ãããŠããå Žåããã®æ©èœã¯éåžžã«ããŸãæ©èœããŸãã
èªåãªã¢ã«ã¿ã€ã 翻蚳ãå®çŸããã«ã¯ãããã€ãã®æé ãå¿ èŠã§ãã ãŸãã翻蚳ããããã¹ãã®ãœãŒã¹èšèªã決å®ããæ¹æ³ãå¿ èŠã§ãã ãŸããä»ã®èšèªã§æžãããã¡ãã»ãŒãžã«å¯ŸããŠã®ã¿ã翻蚳ããªã³ã¯ã衚瀺ãããããåãŠãŒã¶ãŒã®åªå èšèªãç¥ãå¿ èŠããããŸãã 翻蚳ãžã®ãªã³ã¯ãæäŸããããŠãŒã¶ãŒãã¯ãªãã¯ãããšããµãŒããŒã«AJAXãªã¯ãšã¹ããéä¿¡ããå¿ èŠãããããµãŒããŒã¯ãµãŒãããŒãã£ã®ç¿»èš³APIã«æ¥ç¶ããŸãã ãµãŒããŒã翻蚳ãããããã¹ããå«ãå¿çãéä¿¡ããåŸãã¯ã©ã€ã¢ã³ãã®javascriptã³ãŒãã¯ãã®ããã¹ããããŒãžã«åçã«æ¿å ¥ããŸãã ãæ°ã¥ãã®ããã«ãããã€ãã®éèŠãªåé¡ããããŸãã ããããäžã€äžã€æ€èšããŠãã ããã
èšèªèå¥
æåã®åé¡ã¯ããšã³ããªãèšè¿°ãããèšèªãå€æããããšã§ãã èšèªãæ確ã«èå¥ããããšã¯åžžã«å¯èœã§ãããšã¯éããªããããããã¯æ£ç¢ºãªç§åŠã§ã¯ãããŸããããã»ãšãã©ã®å Žåãèªåæ€åºã¯éåžžã«ããŸãæ©èœããŸãã Pythonã«ã¯guess_language
ãšåŒã°ããåªããèšèªç»é²ã©ã€ãã©ãªãguess_language
ãŸãã ãã®ããã±ãŒãžã®å
ã®ããŒãžã§ã³ã¯éåžžã«å€ããPython 3ã«ç§»æ€ãããããšããªããããPython 2ããã³3ããµããŒããã掟çããŒãžã§ã³ãã€ã³ã¹ããŒã«ããŸãã
(venv) $ pip install guess-language_spirit
èšç»ã§ã¯ãåããã°æçš¿ããã®ããã±ãŒãžã«ãã£ãŒãããŠãèšèªã決å®ããããšããŸãã ãã®åæã«ã¯æéãããããããããŒãžã«ã¡ãã»ãŒãžã衚瀺ããããã³ã«ãã®äœæ¥ãç¹°ãè¿ããããããŸããã ç§ãããããšããŠããã®ã¯ãã¡ãã»ãŒãžã®éä¿¡äžã«ã¡ãã»ãŒãžã®ãœãŒã¹èšèªãèšå®ããããšã§ãã æ€åºãããèšèªã¯ã[æçš¿]ããŒãã«ã«ä¿åãããŸãã
æåã®ã¹ãããã¯ã language
ãã£ãŒã«ããPost
ã¢ãã«ã«è¿œå ããããšlanguage
ã
app / models.py ïŒæ€åºãããèšèªãæçš¿ã¢ãã«ã«è¿œå ããŸãã
class Post(db.Model): # ... language = db.Column(db.String(5))
èŠããŠããããã«ãããŒã¿ããŒã¹ã¢ãã«ã«å€æŽããããã³ã«ãããŒã¿ããŒã¹ã®ç§»è¡ãå®è¡ããå¿ èŠããããŸãã
(venv) $ flask db migrate -m "add language to posts" INFO [alembic.runtime.migration] Context impl SQLiteImpl. INFO [alembic.runtime.migration] Will assume non-transactional DDL. INFO [alembic.autogenerate.compare] Detected added column 'post.language' Generating migrations/versions/2b017edaa91f_add_language_to_posts.py ... done
次ã«ãããŒã¿ããŒã¹ã«ç§»è¡ãé©çšããå¿ èŠããããŸãã
(venv) $ flask db upgrade INFO [alembic.runtime.migration] Context impl SQLiteImpl. INFO [alembic.runtime.migration] Will assume non-transactional DDL. INFO [alembic.runtime.migration] Upgrade ae346256b650 -> 2b017edaa91f, add language to posts
ããã§ãã¡ãã»ãŒãžãéä¿¡ãããšãã«èšèªãæ€åºããŠä¿åã§ããŸãã
app / routes.py ïŒæ°ããæçš¿ã®èšèªãä¿åããŸãã
from guess_language import guess_language @app.route('/', methods=['GET', 'POST']) @app.route('/index', methods=['GET', 'POST']) @login_required def index(): form = PostForm() if form.validate_on_submit(): language = guess_language(form.post.data) if language == 'UNKNOWN' or len(language) > 5: language = '' post = Post(body=form.post.data, author=current_user, language=language) # ...
ãã®å€æŽã«ãããã¡ãã»ãŒãžãéä¿¡ããããã³ã«ã guess_language
é¢æ°ã«ããã¹ããæž¡ããŠèšèªã決å®ããããšããŸãã èšèªãäžæãšããŠè¿ãããå ŽåããŸãã¯äºæããªãã»ã©é·ãçµæãåŸãããå Žåãå®å
šã«åçãã空ã®æååãããŒã¿ããŒã¹ã«ä¿åããŸãã å²ãåœãŠãããå€ã空ã®æååã§ããèšèªãå«ãã¡ãã»ãŒãžã¯ãæªç¥ã®èšèªãæã£ãŠãããšæ³å®ããããšããåæã«åæããŸãã
翻蚳ãªã³ã¯ã衚瀺ãã
2çªç®ã®ã¹ãããã¯éåžžã«ç°¡åã§ãã çŸåšã®ãŠãŒã¶ãŒã«å¯ŸããŠã¢ã¯ãã£ãã«ãªã£ãŠããèšèªãšç°ãªãã¡ãã»ãŒãžã®æšªã«ã翻蚳ããªã³ã¯ãè¿œå ããŸãã
app/templates/_post.html
ïŒæçš¿ã«ç¿»èš³ãªã³ã¯ãè¿œå ããŸãã
{% if post.language and post.language != g.locale %} <br><br> <a href="#">{{ _('Translate') }}</a> {% endif %}
ããã_post.html
ãµããã¿ãŒã³ã§è¡ãããšã§ãããã°ãšã³ããªã衚瀺ããããŒãžã«ãã®æ©èœã衚瀺ãããããã«ããŸãã 翻蚳ãžã®ãªã³ã¯ã¯ãèšèªãæ€åºãããã¡ãã»ãŒãžã«ã®ã¿è¡šç€ºããããã®èšèªã¯ã localeselector
Flask-Babelã§è£
食ãããé¢æ°ã«ãã£ãŠéžæãããèšèªã«å¯Ÿå¿ããŸããã éžæãããã±ãŒã«ã¯g.locale
ãšããŠä¿åãããããšã第13ç« ããæãåºããŠãã ããã ãªã³ã¯ããã¹ãã¯ãFlask-Babelã§ç¿»èš³ã§ããããã«è¿œå ããå¿
èŠãããããã _()
é¢æ°ã䜿çšããŠæ±ºå®ããŸãã
ãã®ãªã³ã¯ã«ã¯ãŸã ã¢ã¯ã·ã§ã³ãé¢é£ä»ããŠããªãããšã«æ³šæããŠãã ããã æåã«ãå®éã®ç¿»èš³ãè¡ãæ¹æ³ãç解ããããšæããŸãã
ãµãŒãããŒãã£ã®ç¿»èš³ãµãŒãã¹ã䜿çšãã
2ã€ã®äž»èŠãªç¿»èš³ãµãŒãã¹ã¯ã Google Cloud Translation APIãšMicrosoft Translator Text APIã§ãã ã©ã¡ããææãµãŒãã¹ã§ãããMicrosoftã®æäŸã«ã¯ãå°éã®è»¢éã®ããã®ãšã³ããªã¬ãã«ã®ãªãã·ã§ã³ããããããã¯ç¡æã§ãã Googleã¯éå»ã«ç¡æã®ç¿»èš³ãµãŒãã¹ãæäŸããŠããŸããããä»æ¥ã§ã¯æäœã¬ãã«ã®ãµãŒãã¹ã§ãããæ¯æãããŠããŸãã è²»çšããããã«ç¿»èš³ãè©ŠããŠã¿ããã®ã§ããã€ã¯ããœããã®ãœãªã¥ãŒã·ã§ã³ãå®è£ ããŸãã
ã泚æ PodvodchikaïŒãã²ã«ãç¥ããªãããã«èŠããYandexããŸã ãããŸãã ææªã®APIã§ã¯ãããŸããïŒ Microsoftã®å Žåã1ãæããã200äžæåã«å¯ŸããŠã1ãæããã200äžæåãŸã§ã1ãæããã10 MãŸã§ã®ç¡æãªãã·ã§ã³ããããŸãã
Microsoft Translator APIã䜿çšããåã«ãMicrosoftã®ã¯ã©ãŠããµãŒãã¹ã§ããAzureã®ã¢ã«ãŠã³ããå¿ èŠã§ãã ç»é²ããã»ã¹äžã«ã¯ã¬ãžããã«ãŒãçªå·ãæäŸãããªãã¡ãŒäžã«ãç¡æã®ã¬ãã«ãéžæã§ããŸãã ãã®ã¬ãã«ã®ãµãŒãã¹ã«æ»åšããŠããéãã«ãŒãã¯è«æ±ãããŸããã
Azureã¢ã«ãŠã³ããååŸããããAzureããŒã¿ã«ã«ç§»åããŠãå·Šäžé ã®[æ°èŠ]ãã¿ã³ãã¯ãªãã¯ãã[Translator Text API]ãå ¥åãŸãã¯éžæããŸãã ãäœæããã¯ãªãã¯ãããšãã¢ã«ãŠã³ãã«è¿œå ãããæ°ãã翻蚳è ãªãœãŒã¹ãå®çŸ©ãããã©ãŒã ã衚瀺ãããŸãã 以äžã«ããã©ãŒã ãžã®èšå ¥æ¹æ³ã瀺ããŸãã
[äœæ]ãã¿ã³ãããäžåºŠã¯ãªãã¯ãããšãã€ã³ã¿ãŒããªã¿ãŒAPIãªãœãŒã¹ãã¢ã«ãŠã³ãã«è¿œå ãããŸãã æ°ç§åŸ
ã€ãšãããã«ã®äžéšã®è¡ã«ããã©ã³ã¹ã¬ãŒã¿ãŒããããã€ããããšããéç¥ãå±ããŸãã éç¥ã®[ãªãœãŒã¹ã«ç§»å]ãã¿ã³ãã¯ãªãã¯ããŠãããå·ŠåŽã®ãµã€ãããŒã®[ããŒ]ãªãã·ã§ã³ãã¯ãªãã¯ããŸãã ãããŒ1ããšãããŒ2ããšããŠããŒã¯ããã2ã€ã®ããŒã衚瀺ãããŸãã ããŒã®1ã€ãã¯ãªããããŒãã«ã³ããŒããã¿ãŒããã«ã®ç°å¢å€æ°ã«å
¥åããŸãïŒMicrosoft Windowsã䜿çšããŠããå Žåã¯ã export
ãset
ã«çœ®ãæãexport
ïŒã
(venv) $ export MS_TRANSLATOR_KEY=<paste-your-key-here>
ãã®ããŒã¯ã翻蚳ãµãŒãã¹ã䜿çšããèªèšŒã«äœ¿çšããããããã¢ããªã±ãŒã·ã§ã³æ§æã«è¿œå ããå¿ èŠããããŸãã
config.pyïŒMicrosoft Translator APIããŒãæ§æã«è¿œå ããŸãã
class Config(object): # ... MS_TRANSLATOR_KEY = os.environ.get('MS_TRANSLATOR_KEY')
æ§æå€ãšåæ§ã«ãããããç°å¢å€æ°ã«èšå®ããããããFlaskæ§æã«ã€ã³ããŒãããããšã奜ã¿ãŸãã ããã¯ãããŒããã¹ã¯ãŒããªã©ã®ãµãŒãããŒãã£ãµãŒãã¹ãžã®ã¢ã¯ã»ã¹ãæäŸããæ©å¯æ å ±ãããå Žåã«ç¹ã«éèŠã§ãã ããªãã¯ééããªãããããã³ãŒãã§æ瀺çã«æžããããããŸããã
Microsoft Translator APIã¯ãHTTPèŠæ±ãåãå
¥ããWebãµãŒãã¹ã§ãã Pythonã«ã¯ããã€ãã®HTTPã¯ã©ã€ã¢ã³ãããããŸãããæã人æ°ããããæãç°¡åã«äœ¿çšã§ããã®ã¯requests
ããã±ãŒãžã§ãã ä»®æ³ç°å¢ã«ã€ã³ã¹ããŒã«ããŸãããïŒ
(venv) $ pip install requests
以äžã«ãMicrosoft Translator APIã䜿çšããŠããã¹ãã翻蚳ããããã«ãšã³ã³ãŒãããé¢æ°ã瀺ããŸãã æ°ããã¢ãžã¥ãŒã«app / translate.pyãè¿œå ããŸãã
app / translate.py ïŒããã¹ã翻蚳æ©èœã
import json import requests from flask_babel import _ from app import app def translate(text, source_language, dest_language): if 'MS_TRANSLATOR_KEY' not in app.config or \ not app.config['MS_TRANSLATOR_KEY']: return _('Error: the translation service is not configured.') auth = {'Ocp-Apim-Subscription-Key': app.config['MS_TRANSLATOR_KEY']} r = requests.get('https://api.microsofttranslator.com/v2/Ajax.svc' '/Translate?text={}&from={}&to={}'.format( text, source_language, dest_language), headers=auth) if r.status_code != 200: return _('Error: the translation service failed.') return json.loads(r.content.decode('utf-8-sig'))
ãã®é¢æ°ã¯ç¿»èš³å¯Ÿè±¡ã®ããã¹ããåãåãããœãŒã¹èšèªãšã¿ãŒã²ããèšèªã¯åŒæ°ãšããŠãšã³ã³ãŒãããã翻蚳ãããããã¹ããå«ãæååãè¿ããŸãã ã¢ã¯ã·ã§ã³ã¯ãæ§æå ã®ç¿»èš³ãµãŒãã¹ã®ããŒã確èªããããšããå§ãŸããããŒãååšããªãå Žåã¯ãšã©ãŒãè¿ããŸãã ãšã©ãŒãæååã§ãããããå€éšããã¯ç¿»èš³ãããããã¹ãã®ããã«èŠããŸãã ããã«ããããšã©ãŒãçºçããå Žåã«ããŠãŒã¶ãŒã«ãšã©ãŒã¡ãã»ãŒãžã衚瀺ãããŸãã
requests
ããã±ãŒãžã®get()
ã¡ãœããã¯ã GET
ã¡ãœãããå«ãHTTPèŠæ±ããæåã®åŒæ°ãšããŠæå®ãããURLã«éä¿¡ããŸãã URL /v2/Ajax.svc/Translateã䜿çšããŸããããã¯ã翻蚳ãJSONããŒã¿ãšããŠè¿ã翻蚳ãµãŒãã¹ãšã³ããã€ã³ãã§ãã ããã¹ãããœãŒã¹ãããã³ã¿ãŒã²ããèšèªã¯to
ããããtext
ã from
ããã³to
ãšããååã®URLã®ã¯ãšãªæåååŒæ°ãšããŠæå®ããå¿
èŠããããŸãã ãµãŒãã¹ã䜿çšããŠèªèšŒããã«ã¯ãæ§æã«è¿œå ããããŒãæž¡ãå¿
èŠããããŸãã ãã®ããŒã¯ã Ocp-Apim-Subscription-Key
ãšããååã®ã«ã¹ã¿ã HTTPããããŒã§æå®ããå¿
èŠããããŸãã ãã®ããããŒã§auth
èŸæžãäœæãã headers
åŒæ°ã§ãªã¯ãšã¹ãã«æž¡ããŸããã
requests.get()
ã¡ãœããã¯ããµãŒãã¹ã«ãã£ãŠæäŸããããã¹ãŠã®æ
å ±ãå«ãå¿çãªããžã§ã¯ããè¿ããŸãã æåã«ãã¹ããŒã¿ã¹ã³ãŒãã200ïŒæåããèŠæ±ã³ãŒãïŒã§ããããšã確èªããå¿
èŠããããŸãã ä»ã®ã³ãŒããååŸããå Žåããšã©ãŒãçºçããŠããããããã®å Žåã¯ãšã©ãŒæååãè¿ããŠããŸãã ã¹ããŒã¿ã¹ã³ãŒãã200ã®å Žåãå¿çæ¬æã«ã¯JSONãšã³ã³ãŒãããã翻蚳ä»ãã®æååãå«ãŸããŠãããããPythonæšæºã©ã€ãã©ãªã®json.loads()
é¢æ°ã䜿çšããŠãJSONã䜿çšå¯èœãªPythonæååã«ãã³ãŒãããã ãã§ãã å¿çå¿çãªããžã§ã¯ãã®å±æ§content
ã¯ãæªåŠçã®å¿çããã¹ãããã€ãæååãšããŠå«ãŸããŠãããutf-8æååã«å€æãããŠjson.loads()
éä¿¡ãããŸãã
以äžã«ãæ°ããtranslate()
é¢æ°ã䜿çšããPythonã³ã³ãœãŒã«ã»ãã·ã§ã³ã瀺ããŸãã
>>> from app.translate import translate >>> translate('Hi, how are you today?', 'en', 'es') # English to Spanish 'Hola, ¿cómo estás hoy?' >>> translate('Hi, how are you today?', 'en', 'de') # English to German 'Are Hallo, how you heute?' >>> translate('Hi, how are you today?', 'en', 'it') # English to Italian 'Ciao, come stai oggi?' >>> translate('Hi, how are you today?', 'en', 'fr') # English to French "Salut, comment allez-vous aujourd'hui ?"
ããªãã¯ãŒã«ã§ãããïŒ æ¬¡ã¯ããã®æ©èœãã¢ããªã±ãŒã·ã§ã³ã«çµ±åããŸãã
ãµãŒããŒããã®Ajax
ãµãŒããŒåŽã®å®è£ ããå§ããŸãã ãŠãŒã¶ãŒãã¡ãã»ãŒãžã®äžã«è¡šç€ºãããã翻蚳ããªã³ã¯ãã¯ãªãã¯ãããšãéåæHTTPèŠæ±ããµãŒããŒã«çºè¡ãããŸãã 次ã®ã»ãã·ã§ã³ã§ãããè¡ãæ¹æ³ã瀺ããŸãã®ã§ãããã§ã¯ããµãŒããŒã«ãããã®èŠæ±ã®åŠçã®å®è£ ã«çŠç¹ãåœãŠãŸãã
éåæïŒãŸãã¯AjaxïŒãªã¯ãšã¹ãã¯ãã¢ããªã±ãŒã·ã§ã³ã§äœæããã«ãŒããšè¡šç€ºæ©èœã«äŒŒãŠããŸãããå¯äžã®éãã¯ãHTMLãè¿ãããªãã€ã¬ã¯ããã代ããã«ã XMLãŸãã¯ããå€ãã®å ŽåJSONãšããŠãã©ãŒããããããããŒã¿ãè¿ãã ãã§ãã 以äžã«ãMicrosoft Translator APIãåŒã³åºãã翻蚳ãããããã¹ããJSON圢åŒã§è¿ã翻蚳衚瀺æ©èœã瀺ããŸãã
app / routes.py ïŒããã¹ã翻蚳ãã¥ãŒæ©èœã
from flask import jsonify from app.translate import translate @app.route('/translate', methods=['POST']) @login_required def translate_text(): return jsonify({'text': translate(request.form['text'], request.form['source_language'], request.form['dest_language'])})
ã芧ã®ãšãããç°¡åã§ãã POST
ãªã¯ãšã¹ããšããŠãã®ã«ãŒãããã©ããŸããã GET
ãŸãã¯POST
ïŒãŸãã¯ããŸã èŠãããšã®ãªãä»ã®ãªã¯ãšã¹ãã¡ãœããïŒããã€äœ¿çšãããã«ã€ããŠã®çµ¶å¯Ÿçãªã«ãŒã«ã¯ãããŸããã ã¯ã©ã€ã¢ã³ããããŒã¿ãéä¿¡ããããããã©ãŒã ããŒã¿ãè¡šããªã¯ãšã¹ãã«äŒŒãŠããããã POST
ãªã¯ãšã¹ãã䜿çšããããšã«ããŸããã request.form
å±æ§ã¯ãFlaskããã¥ãŒã«å«ãŸãããã¹ãŠã®ããŒã¿ãšãšãã«æäŸããèŸæžã§ãã Webãã©ãŒã ã§äœæ¥ããŠãããšããflask-WTFã¯æ£åžžã«æ©èœãããããã¹ãŠãå®è¡ããããã request.form
ãæ€çŽ¢ããå¿
èŠã¯ãããŸããã§ãããããã®å Žåãå®éã«ã¯Webãã©ãŒã ããªããããããŒã¿ã«çŽæ¥ã¢ã¯ã»ã¹ããå¿
èŠããããŸãã
ããã§ã¯ããã®é¢æ°ã§ç§ããã£ãŠããããšãèŠãŠã¿ãŸãããã åã®ã»ã¯ã·ã§ã³ã®translate()
é¢æ°ãåŒã³åºãããèŠæ±ãšãšãã«éä¿¡ãããããŒã¿ãã3ã€ã®åŒæ°ãçŽæ¥æž¡ãããŸãã çµæã¯ã text
ãšãã1ã€ã®ããŒã§ãã£ã¯ã·ã§ããªã«å«ãŸãããã£ã¯ã·ã§ããªã¯jsonify()
Flaské¢æ°ã«åŒæ°ãšããŠæž¡ããããã£ã¯ã·ã§ããªã¯ãã©ãŒããããããJSONãã€ããŒãã«å€æãããŸãã jsonify()
ããã®æ»ãå€ã¯ãã¯ã©ã€ã¢ã³ãã«éãè¿ãããHTTPå¿çã§ãã
ããšãã°ãã¯ã©ã€ã¢ã³ããæååHello, World!
ã翻蚳ãããå Žå ã¹ãã€ã³èªã§ã¯ããã®ãªã¯ãšã¹ãããã®å¿çã«ã¯æ¬¡ã®æçšãªããŒã¿ãå«ãŸããŸãã
{ "text": "Hola, Mundo!" }
ã¯ã©ã€ã¢ã³ãããã®Ajax
ãµãŒããŒãURL / translateãä»ããŠç¿»èš³ãæäŸã§ããããã«ãªã£ãã®ã§ããŠãŒã¶ãŒãäžèšã§è¿œå ãããTranslateããªã³ã¯ãã¯ãªãã¯ãããšããã®URLãåŒã³åºãå¿ èŠããããŸãã翻蚳çšã®ããã¹ããšãœãŒã¹èšèªããã³ã¿ãŒã²ããèšèªãæž¡ããŸãã ãã©ãŠã¶ã§JavaScriptã䜿çšããããšã«æ £ããŠããªãå Žåãããã¯è¯ãåŠç¿äœéšã«ãªããŸãã
ãã©ãŠã¶ã§JavaScriptã䜿çšããå ŽåãçŸåšè¡šç€ºãããŠããããŒãžã¯ãããã¥ã¡ã³ãã®ãªããžã§ã¯ãã¢ãã«ãŸãã¯DOMã®ã¿ãšããŠå éšçã«è¡šãããŸãã ããã¯ãããŒãžã«ååšãããã¹ãŠã®èŠçŽ ãåç §ããéå±€æ§é ã§ãã ãã®ã³ã³ããã¹ãã§æ©èœããJavaScriptã³ãŒãã¯ãDOMã«å€æŽãå ããŠããŒãžã®å€æŽãéå§ã§ããŸãã
æåã«ããã©ãŠã¶ãŒã§å®è¡ãããŠããJavaScriptã³ãŒããããµãŒããŒã§å®è¡ãããŠããå€æé¢æ°ã«éä¿¡ããå¿
èŠããã3ã€ã®åŒæ°ãååŸããæ¹æ³ã«ã€ããŠèª¬æããŸãã ããã¹ããååŸããã«ã¯ãããã°æçš¿ã®æ¬æãå«ãããŒããDOMã§èŠã€ããŠããã®å
容ãèªãå¿
èŠããããŸãã ããã°ãšã³ããªãå«ãDOMããŒãã®èå¥ãç°¡åã«ããããã«ãäžæã®èå¥åãè¿œå ããŸãã _post.htmlãã³ãã¬ãŒããèŠããšãã¡ãã»ãŒãžã®æ¬æã衚瀺ããè¡ã¯{{post.body}}
ãŸãã ãã®ã³ã³ãã³ãã<span>
èŠçŽ ã§ã©ããããŸãã ããã¯èŠèŠçã«ã¯äœãå€æŽããŸããããèå¥åãæ¿å
¥ã§ããå ŽæãæäŸããŸãã
app/templates/_post.html
ïŒåããã°æçš¿ã«IDãè¿œå ããŸãã
<span id="post{{ post.id }}">{{ post.body }}</span>
ããã«ãããåããã°æçš¿ã«post1
ã post2
ãªã©ã®åœ¢åŒã§äžæã®èå¥åãå²ãåœãŠãããŸããçªå·ã¯åæçš¿ã®ããŒã¿ããŒã¹èå¥åã«å¯Ÿå¿ããŸãã ãã¹ãŠã®ããã°æçš¿ã«IDå€ãæå®ãããäžæã®èå¥åããããããjQueryã䜿çšããŠãã®æçš¿ã®<span>
èŠçŽ ãèŠã€ãããã®äžã®ããã¹ããæœåºã§ããŸãã ããšãã°ãID 123ã®ã¡ãã»ãŒãžã®ããã¹ããååŸãããå Žåã次ã®ããã«ããŸãã
$('#post123').text()
ããã§ã $
èšå·ã¯jQueryã©ã€ãã©ãªã«ãã£ãŠæäŸãããé¢æ°ã®ååã§ãã ãã®ã©ã€ãã©ãªã¯Bootstrapã«ãã£ãŠäœ¿çšããããããFlask-Bootstrapã«ãã§ã«å«ãŸããŠããŸãã #
ã¯ãjQueryã䜿çšãããã»ã¬ã¯ã¿ãæ§æã®äžéšã§ããã€ãŸãã次ã¯èŠçŽ ã®èå¥åã§ãã
ãŸãã翻蚳ãããããã¹ãããµãŒããŒããåãåã£ãåŸã«åã蟌ãå Žæãå¿ èŠã§ãã ã翻蚳ããªã³ã¯ã翻蚳ãããããã¹ãã«çœ®ãæããããããã®ããŒãã®äžæã®èå¥åãå¿ èŠã§ãã
app/templates/_post.html
ïŒç¿»èš³ãªã³ã¯ã«èå¥åãè¿œå ããŸãã
<span id="translation{{ post.id }}"> <a href="#">{{ _('Translate') }}</a> </span>
ãã®ããããã®post<ID>
IDã«ã¯ãããã°æçš¿ã®post<ID>
ãšå¯Ÿå¿ããtranslation<ID>
ããŒãããããã翻蚳ããªã³ã¯ãåãåã£ããããã«ç¿»èš³ãããããã¹ãã«çœ®ãæããå¿
èŠããããŸãã
次ã®ã¹ãããã¯ããã¹ãŠã®ç¿»èš³äœæ¥ãå®è¡ã§ããé¢æ°ãäœæããããšã§ãã ãã®é¢æ°ã¯ãå ¥åããã³åºåDOMããŒããããã³ãœãŒã¹èšèªãšå®å èšèªãåãå ¥ãã3ã€ã®å¿ èŠãªåŒæ°ã䜿çšããŠãµãŒããŒã«éåæèŠæ±ãçºè¡ããæçµçã«ãµãŒããŒã®å¿çåŸã«ç¿»èš³ãªã³ã¯ã翻蚳ãããããã¹ãã«çœ®ãæããŸãã ããã¯å€ãã®äœæ¥ã®ããã«èãããŸãããå®è£ ã¯éåžžã«ç°¡åã§ãã
app / templates / base.html ïŒã¯ã©ã€ã¢ã³ãåŽã®ç¿»èš³æ©èœã
{% block scripts %} ... <script> function translate(sourceElem, destElem, sourceLang, destLang) { $(destElem).html('<img src="{{ url_for('static', filename='loading.gif') }}">'); $.post('/translate', { text: $(sourceElem).text(), source_language: sourceLang, dest_language: destLang }).done(function(response) { $(destElem).text(response['text']) }).fail(function() { $(destElem).text("{{ _('Error: Could not contact server.') }}"); }); } </script> {% endblock %}
æåã®2ã€ã®åŒæ°ã¯ãã¡ãã»ãŒãžãšç¿»èš³ããŒãã®äžæã®IDã§ãã æåŸã®2ã€ã®åŒæ°ã¯ããœãŒã¹èšèªã³ãŒããšå®å èšèªã³ãŒãã§ãã
ãã®æ©èœã¯çŽ æŽãããã¿ããã§å§ãŸããŸãïŒç¿»èš³ãªã³ã¯ã眮ãæããã¹ãããŒãè¿œå ããŠããŠãŒã¶ãŒã«ç¿»èš³ãé²è¡äžã§ããããšãç¥ãããŸãã ããã¯ãjQueryã䜿çšããŠè¡ããã $(destElem).html()
é¢æ°ã䜿çšããŠã翻蚳ãªã³ã¯ãå®çŸ©ããå
ã®HTMLã<img>
ãªã³ã¯ã«åºã¥ãæ°ããHTMLã³ã³ãã³ãã«çœ®ãæããŸãã ã¹ãããŒã«ã¯ãå°ããªã¢ãã¡ãŒã·ã§ã³GIFããã¯ã䜿çšããŸããããã¯app / static / loading.gifãã£ã¬ã¯ããªã«è¿œå ããFlaskã¯éçãã¡ã€ã«çšã«äºçŽããŠããŸãã ãã®ç»åãåç
§ããURLãçæããã«ã¯ã url_for()
é¢æ°ã䜿çšããŠãç¹å¥ãªstatic
ã«ãŒãåãæž¡ããåŒæ°ãšããŠãã¡ã€ã«åãæå®ããŸãã ãã®ç« ã®ããŠã³ããŒãããã±ãŒãžã« load.gifã€ã¡ãŒãžããããŸã ã
ããã§ãã翻蚳ããªã³ã¯ã眮ãæãããŸãšããªã¹ãããŒã¿ã€ããŒãã§ããŸããããŠãŒã¶ãŒã¯ã翻蚳ã衚瀺ããããŸã§åŸ ã€å¿ èŠãããããšãããããŸããã
次ã®ã¹ãããã¯ãåã®ã»ã¯ã·ã§ã³ã§å®çŸ©ããURL / translateã«POST
ãªã¯ãšã¹ããéä¿¡ããããšã§ãã ãŸãããã®ããã«jQueryã䜿çšããŸãããã®å Žåã¯ã $.post()
é¢æ°ã§ãã ãã®é¢æ°ã¯ããã©ãŠã¶ãWebãã©ãŒã ãéä¿¡ããæ¹æ³ãšåæ§ã®åœ¢åŒã§ããŒã¿ããµãŒããŒã«éä¿¡ããŸããããã¯ãFlaskãrequest.form
èŸæžã«ãã®ããŒã¿ãå«ããããšãã§ãããã䟿å©ã§ãã 2ã€ã®$.post()
åŒæ°ã¯ãæåã«ãªã¯ãšã¹ããéä¿¡ããURLã§ããã次ã«ãµãŒããŒãæåŸ
ãã3ã€ã®ããŒã¿èŠçŽ ãå«ãèŸæžïŒãŸãã¯JavaScriptã§åŒã³åºããããªããžã§ã¯ãïŒã§ãã
JavaScriptã¯ãã³ãŒã«ããã¯é¢æ°ãŸãã¯promiseãšåŒã°ããããé«åºŠãªåœ¢åŒã®ã³ãŒã«ããã¯ã§å€ãã®æ©èœãæããããšããåç¥ã§ãããã ããã§ããããããšã¯ããã®ãªã¯ãšã¹ããå®äºããŠãã©ãŠã¶ãå¿çãåãåã£ããšãã«äœãããããçŽæããããšã§ãã JavaScriptã«ã¯äœãæåŸ ãããããªãã®ã¯ãªãããã¹ãŠãéåæã§ãã 代ããã«ããã©ãŠã¶ãå¿çãåä¿¡ãããšãã«åŒã³åºãã³ãŒã«ããã¯é¢æ°ãæäŸããå¿ èŠããããŸãã ãã¹ãŠãå¯èœãªéãä¿¡é Œæ§ã®é«ããã®ã«ããæ¹æ³ãšåæ§ã«ããšã©ãŒãçªç¶çºçããå Žåã®å¯ŸåŠæ¹æ³ã瀺ãããã®ã§ã2çªç®ã®ã³ãŒã«ããã¯é¢æ°ã¯ãšã©ãŒåŠçã«ãªããŸãã ãããã®ã³ãŒã«ããã¯ãæå®ããæ¹æ³ã¯ããã€ããããŸããããã®å Žåãpromiseã䜿çšãããšã³ãŒããååã«æ確ã«ãªããŸãã æ§æã¯æ¬¡ã®ãšããã§ãã
$.post(<url>, <data>).done(function(response) { // success callback }).fail(function() { // error callback })
promiseæ§æã䜿çšãããšãã³ãŒã«ããã¯ãåºæ¬çã«$.post()
åŒã³åºãã®æ»ãå€ã«ãããã¯ãã§ããŸãã ã³ãŒã«ããã¯ãæåããå Žåãç§ãããªããã°ãªããªãããšã¯ã翻蚳ãããããã¹ãã§$(destElem).text()
ãåŒã³åºãããšã§ãã ãšã©ãŒãçºçããå Žåãåãããšãè¡ããŸããã衚瀺ãããããã¹ãã¯äžè¬çãªãšã©ãŒã¡ãã»ãŒãžã§ããã翻蚳å¯èœãªããã¹ããšããŠåºæ¬ãã³ãã¬ãŒãã«å
¥åãããŸãã
ãããã£ãŠããŠãŒã¶ãŒãã翻蚳ããªã³ã¯ãã¯ãªãã¯ããçµæãšããŠæ£ããåŒæ°ãæå®ããŠtranslate()
é¢æ°ãåŒã³åºãã ãã§ãã ãããè¡ãæ¹æ³ãããã€ããããŸãã ãªã³ã¯ã®href
å±æ§ã«é¢æ°åŒã³åºããåã蟌ãã ãã§ãã
app/templates/_post.html
ïŒãªã³ã¯ãã³ãã©ãŒã翻蚳ããŸãã
<span id="translation{{ post.id }}"> <a href="javascript:translate( '#post{{ post.id }}', '#translation{{ post.id }}', '{{ post.language }}', '{{ g.locale }}');">{{ _('Translate') }}</a> </span>
ãªã³ã¯ã®href
èŠçŽ ã¯ã javascript:
ãã¬ãã£ãã¯ã¹ãããå Žåãä»»æã®JavaScriptã³ãŒããåãå
¥ããããšãã§ãããããããã¯ç¿»èš³é¢æ°åŒã³åºããè¡ã䟿å©ãªæ¹æ³ã§ãã ã¯ã©ã€ã¢ã³ããããŒãžãèŠæ±ãããšãã®ãªã³ã¯ããµãŒããŒã«è¡šç€ºãããããã {{ }}
åŒã䜿çšããŠ4ã€ã®é¢æ°åŒæ°ãçæã§ããŸãã . #
, post<ID>
translation<ID>
, , ID .
Now the live translation feature is complete! If you have set a valid Microsoft Translator API key in your environment, you should now be able to trigger translations. Assuming you have your browser set to prefer English, you will need to write a post in another language to see the "Translate" link. Below you can see an example:
! Microsoft Translator API , . , , "". :
, , , :
(venv) $ flask translate update
messages.po , , GitHub.
, :
(venv) $ flask translate compile