# Flask實作_開始建置頁面內容_15_加入多語系 ###### tags: `python` `flask` 這邊假設你已經看過[Flask實作_ext_17_Flask_babel_多語系](https://hackmd.io/s/SyX5xZWz7),並且了解。 我們的網頁為了國際化,決定導入多語系,這部份在讀過`flask-babel`之後已經可以快速上手了,但是在作業之前,先將`requirments.txt`加入`flask-babel`,後續我們利用`pip install -r`的時候才不會有遺漏。 ```shell # 安裝 pip install flask-babel ``` ## 作業說明 安裝之後,我們就要加入參數,然後實作,初始化 :::success * 文件:config.py * 說明:加入flask_babel的參數 ```python import os class Config: #..中略..# BABEL_DEFAULT_LOCALE = 'en' BABEL_DEFAULT_TIMEZONE = 'UTC' # 這個部份就記得以你自己資料夾路徑來設置 BABEL_TRANSLATION_DIRECTORIES = 'Your Translation Path' ``` ::: :::success * 文件:`app_blog\__init__.py` * 說明:實作並且初始化`Babel` ```python= # 追加import from flask_babel import Babel #...中略...# babel = Babel(app) ``` ::: 實作完成,接下來我們要開始思考,我們該如何取得使用者的語系然後以這個語系來當做使用者的預設,打開『F12』,開發者工具裡面給了我們方向,『accept-language』裡面記錄著(q)語系的…權重或機率? ![](https://i.imgur.com/XK8X9JR.png) 參閱[flask官方文件](http://werkzeug.pocoo.org/docs/0.14/datastructures/#werkzeug.datastructures.LanguageAccept)可以找到request內有相對應的method可以幫助我們處理這部份的問題。 ```python request.accept_languages.best_match(list) ``` 作法上,我們將提供的語系清單以參數來設置,這也方便日後我們的維護跟程式的引用,因此,我們再追加參數。 :::success * 文件:config.py * 說明:加入flask_babel的參數 ```python= import os class Config: #..中略..# BABEL_DEFAULT_LOCALE = 'en' BABEL_DEFAULT_TIMEZONE = 'UTC' # 這個部份就記得以你自己資料夾路徑來設置 BABEL_TRANSLATION_DIRECTORIES = 'Your Translation Path' ALLOW_LANGUAGES = ['en', 'zh'] ``` 第9行:追加參數ALL_LANGUAGES,記錄提供的多語系清單,要細一點的話,en還有分很多,這部份依需求確認是否分en_US、en_GB ::: :::success * 文件:`app_blog\__init__.py` * 說明:加入`localeselector`裝飾器設取得語言設置 ```python= # 追加import request from flask import Flask, request #...中略...# # 寫在babel下面 babel = Babel(app) @babel.localeselector def get_locale(): return request.accept_languages.best_match(app.config['ALLOW_LANGUAGES']) #...下略...# ``` ::: 好了,到這邊我們已經完成了前置設置,接下來就要按著流程,並將相關文件一個一個加上`gettext`與`lazy_gettext`,這不是一個小工程,但是在執行過程中會有很多問題還需要排除,一定要自己手動處理一次,不外乎是flash message、form、html這幾個地方需要注意,範例上只會demo幾個。 步驟1: :::success * 文件:babel.cfg * 說明:新增babel配置文件 ``` [python: app_blog/**.py] [jinja2: app_blog/templates/**.html] extensions=jinja2.ext.autoescape,jinja2.ext.with_ ``` 文件置於根目錄的話,就需要設置參數`BABEL_TRANSLATION_DIRECTORIES`來指定translation的路徑,如果置於跟初始化文件相同路徑的話就不需要,依個人對專案的規劃設置(見[擴展17延伸閱讀](https://hackmd.io/s/SyX5xZWz7#%E5%BB%B6%E4%BC%B8%E9%96%B1%E8%AE%80))。 ::: 步驟2: 現在要開始將相關文件一個一個加上`gettext`與`lazy_gettext`,普遍大家建置的時候都會習慣性的以`_`做替代,但是為了讓`gettext`與`lazy_gettext`有差異,我會習慣的使用`_l`來代表`lazy_gettext`。 ```python from flask_babel import lazy_gettext as _l from flask_babel import gettext as l ``` >當我們使用`from flask_babel import lazy_gettext as _l`的時候,在產生pot檔的語法也要調整,如下說明。 ```shell= pybabel extract -F babel.cfg -k _l -o messages.pot . ``` 步驟3: 產生`pot`檔之後,就可以產生語系檔(`messages.po`) ```shell= pybabel init -i messages.pot -d translations -l zh ``` 步驟4: 翻譯文件之後就可以編譯,產生`messages.mo` ```shell= pybabel compile -d translations ``` 翻譯中記得測試是否正常顯示 ![](https://i.imgur.com/ELUjBvB.png) ## 總結 我們很順利的將多語系導入我們的專案中,如果實作中有發現無法成功翻譯的話,記得確認下資料夾路徑的設置(見[擴展17延伸閱讀](https://hackmd.io/s/SyX5xZWz7#%E5%BB%B6%E4%BC%B8%E9%96%B1%E8%AE%80))。 似乎,專案也要進入收尾階段了,剩下最後一個部份,那就是權限的控管,這一直是一個讓人頭痛的議題,但是走過去了,這個網站就成功了。 當然,如果網站的部份只是要自己拿來寫寫blog使用,然後架設在免費空間上分享知識以及文章的話,那單純利用flask_login的login_request這個decorator再加上一點簡單的邏輯判斷應該就足夠了,但是如果這網站希望可以有人參與互動,或是企業內部的使用,那可能就稍微不足。 另外,專案上我們可能還需要再補上一個語系選擇的dropdownlist,這部份不難,可能後續有另外的補充再來處理,flask_web的作者另外有mega_tutorial的文章,寫的比在下更好,附上連結供各位參考。 最後,有些網站我們會發現在網址上有把語系加上,這個要加入的話,就要連route都一併調整,步驟較多,後面有機會再來討論。 ## 參考 應用accept_languages也算是折衷,另一種方式就是統一登入的時候就是en,讓使用者有下拉選單去選擇語言,相關參考可看下面兩個連結。 [www.w3.org_1](https://www.w3.org/International/questions/qa-accept-lang-locales) [www.w3.org_2](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4) [Miguelgrinberg_mega_tutorial](https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world)