# Flask實作_ext_16_Flask_babel_日期時間
###### tags: `flask` `flask_ext` `python` `babel`
:::danger
官方文件:
* [flask_babel](https://pythonhosted.org/Flask-Babel/)
* [flask_babel_簡中文件](http://www.pythondoc.com/flask-babel/)
* [babel](http://babel.pocoo.org/en/latest/)
:::
`flask_babel`包裝了`babel`讓Flask用戶可以便捷的使用它,不管如何,官方文件都很建議要閱讀過一次,至少知道這個package的用途,當然,其它還有如`gettext`、`pytz`、`speaklater`也有其相關性,在了解如何應用之後也記得往下深入理解。
## 安裝
```shell
pip install Flask-Babel
```
安裝的時候會將相依套件`babel`一併安裝,不需要各別安裝。
## 說明
直觀來看,`babel`的應用包括了本地時間、日期、數值的格式化以及多語系的應用,本地(locale)所指的即為`en_US`、`zh_TW`....等設置。
下面是一個官方文件上簡單的設置說明,利用`Locale`來設置語系,案例中利用`Locale.parse`來設置語系為`zh_TW`,如下:
```python=
>>>from babel import Locale
>>>locale = Locale.parse('zh_TW')
>>>locale
Locale('zh', territory='TW', script='Hant')
```
設置本地語系之後,還可以再套其它語系來顯示想顯示的資訊,雖然本地語系已經設置為`zh_TW`,但是還是可以再讓顯示的資訊以`en_US`來呈現,如下範例:
```python=
>>>locale.get_display_name()
'中文 (繁體, 台灣)'
>>>locale.get_display_name('en_US')
'Chinese (Traditional, Taiwan)'
```
上述只是一個簡單的案例來快速理解『本地』所指的意函,因此當語系切換的時候,呈現的資訊就可以依著語系來變動。
時間與日期的部份可以結合Python的`datetime`、`date`、`time`等package一起使用,更細部份的部份當然還是會希望直接的看官方文件一次,至少理解到包裝起來的`babel`能提供的功能。
下面案例是一個日期時間的格式化,將Python`datetime`物件做為`format_datetime`的參數,再搭配`locale`來做不同語系的呈現。
```python=
>>>from datetime import datetime
>>>from babel.dates import format_datetime
>>>dt = datetime(2018, 6, 25, 22, 30)
>>>format_datetime(dt, locale=locale)
'2018年6月25日 下午10:30:00'
>>>format_datetime(dt, locale='en_US')
'Jun 25, 2018, 10:30:00 PM'
```
把鏡頭帶回來`flask_babel`,Flask的擴展應該可以快速上手了,實作,接著初始化參數,`flask_babel`的參數不多,只有兩個:
* BABEL_DEFAULT_LOCALE
* 預設的語系,沒有設置的話則為`en`
* BABEL_DEFAULT_TIMEZONE
* 預設時區,沒有設置的話則為`UTC`
了解參數之後,我們就來做實作並初始化,如下:
```python=
from flask import Flask
from flask.ext.babel import Babel
app = Flask(__name__)
app.config['SECRET_KEY'] = 'development'
app.config['BABEL_DEFAULT_LOCALE'] = 'en'
app.config['BABEL_DEFAULT_TIMEZONE']='UTC'
babel = Babel(app)
```
上面我們預設了`locale`為`en`,`timezone=UTC`,當有不同語系的使用者登入的時候,我們可以在登入的時候利用`refresh()`來變更。依官方文件說明,`babel`第一次需要當前用戶的地區的時候,會呼叫`localeselector`,如果需要時區的時候則是呼叫`timezoneselector`,如果回傳`None`的話,就會取參數設置的預設值了。
## 範例
千言萬語都不如動手來操作,剛才我們看過了`babel`的簡單示範,現在來認識一下`flask-babel`。
範例的部份都是直接在Command上操作,所以有『>>>』就是指令,沒有的就是結果
```python=
>>>from flask import Flask
>>>from flask_babel import Babel
>>>from flask_babel import format_datetime, get_locale
>>>from datetime import datetime
>>>app = Flask('tt')
>>>babel = Babel(app)
>>>dt = datetime(2018, 6, 26, 21, 30)
>>>print(dt)
datetime.datetime(2018, 6, 26, 21, 30)
# 未推入一個request之前如果使用get_locale,雖然不會報錯,但是不會有回傳的值
>>>get_locale()
# 測試用,加入一個request,如果沒有加入會報錯
>>>app.test_request_context().push()
>>>format_datetime(dt)
'Jun 26, 2018, 9:30:00 PM'
>>>babel.default_locale
Locale('en')
```
第7行:單純的設置一個`datetime`物件`dt`,年、月、日、時、分
第11行:測試的時候可以透過`test_request_context().push()`來手動模擬一個`request`
第12行:格式化日期,回傳的格式是很明顯的是`en`
第14行:檢查預設的`default_locale`,可以發現到,即使我們沒有設置參數,預設上還是以`en`為主。
接續著上例,如果現在切換語言至`zh_TW`,那可以透過`refresh()`來做一個`locale`的更新
```python=
>>>y = lambda: 'zh'
>>>babel.localeselector(y)
>>>get_locale()
Locale('en')
>>>refresh()
>>>get_locale()
Locale('zh')
>>>format_datetime(dt)
'2018年6月26日 下午9:30:00'
>>>format_datetime(dt, 'short')
'2018/6/26 下午9:30'
```
第1行:利用`lambda`來設置一個簡單的函數,回傳`zh`
第2行:利用`babel.localeselector`來模擬用戶登入之後取得他的語系
第3行:執行`refresh`之前還是回傳`en`
第5行:執行`refresh`之後還是回傳`zh`
第7行:執行`format_datetime`顯示的格式已經是`zh_TW`的格式
第9行:加入參數`short`,另外還有不少調控的格式,這部份請參閱官方文件
## 總結
這篇很快速的了解了`babel`於日期、時間格式化的應用,簡單的幾個案例,我們大概對將`babel`加入專案的時候該怎麼結合登入功能的部份心裡有底,另篇會針對`babel`應用在多語系說明,繼續了解。
**Flask_babel_多語系:**[Flask實作_ext_17_Flask_babel_多語系](https://hackmd.io/s/SyX5xZWz7)